LoaderController.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. // Licensed under the MIT License. See LICENSE in the project root for license information.
  3. using UnityEngine;
  4. namespace Microsoft.MixedReality.Toolkit.UI
  5. {
  6. /// <summary>
  7. /// Controls how the standard indeterminate loader moves and behaves over time.
  8. /// </summary>
  9. /// <remarks>
  10. /// This loader is calculated dynamically based on Sine and Cosine
  11. /// </remarks>
  12. [AddComponentMenu("Scripts/MRTK/SDK/LoaderController")]
  13. public class LoaderController : MonoBehaviour
  14. {
  15. /// <summary>
  16. /// Total strength of movement of the loading animation
  17. /// </summary>
  18. [SerializeField]
  19. [Tooltip("Total strength of movement of the loading animation")]
  20. private float amplitude = 0.05f;
  21. public float Amplitude
  22. {
  23. get => amplitude;
  24. set => amplitude = value;
  25. }
  26. /// <summary>
  27. /// How often <see cref="amplitude"/> happens
  28. /// </summary>
  29. [SerializeField]
  30. [Tooltip("How often 'amplitude' happens")]
  31. private float frequency = 3.0f;
  32. public float Frequency
  33. {
  34. get => frequency;
  35. set => frequency = value;
  36. }
  37. /// <summary>
  38. /// The base local position for the dots' parent
  39. /// </summary>
  40. [SerializeField]
  41. [Tooltip("The base local position for the dots' parent")]
  42. private float dotOffset = 0.05f;
  43. public float DotOffset
  44. {
  45. get => dotOffset;
  46. set => dotOffset = value;
  47. }
  48. /// <summary>
  49. /// The base scale unit for the dots' parent
  50. /// </summary>
  51. [SerializeField]
  52. [Tooltip("The base scale unit for the dots' parent")]
  53. private float dotSetScale = 0.06f;
  54. public float DotSetScale
  55. {
  56. get => dotSetScale;
  57. set => dotSetScale = value;
  58. }
  59. /// <summary>
  60. /// Use low frequency oscillation with the Sine calculation.
  61. /// </summary>
  62. [SerializeField]
  63. [Tooltip("Use low frequency oscillation with the Sine calculation.")]
  64. private bool lFOsin = false;
  65. public bool LFOsin
  66. {
  67. get => lFOsin;
  68. set => lFOsin = value;
  69. }
  70. /// <summary>
  71. /// Use low frequency oscillation with the Cosine calculation.
  72. /// </summary>
  73. [SerializeField]
  74. [Tooltip("Use low frequency oscillation with the Cosine calculation.")]
  75. private bool lFOcos = false;
  76. public bool LFOcos
  77. {
  78. get => lFOcos;
  79. set => lFOcos = value;
  80. }
  81. /// <summary>
  82. /// Low Frequency oscillation frequency
  83. /// </summary>
  84. [SerializeField]
  85. [Tooltip("Low frequency oscillation frequency")]
  86. private float lFOfreq = 1.0f;
  87. public float LFOfreq
  88. {
  89. get => lFOfreq;
  90. set => lFOfreq = value;
  91. }
  92. /// <summary>
  93. /// Low Frequency oscillation amplitude
  94. /// </summary>
  95. [SerializeField]
  96. [Tooltip("Low Frequency oscillation amplitude")]
  97. private float lFOamp = 0.1f;
  98. public float LFOamp
  99. {
  100. get => lFOamp;
  101. set => lFOamp = value;
  102. }
  103. /// <summary>
  104. /// Reverses dots' orbit rotation path
  105. /// </summary>
  106. [SerializeField]
  107. [Tooltip("Reverses dots' orbit rotation path")]
  108. private bool reverseOrbit = false;
  109. public bool ReverseOrbit
  110. {
  111. get => reverseOrbit;
  112. set => reverseOrbit = value;
  113. }
  114. /// <summary>
  115. /// Inverts dots' position in orbit
  116. /// </summary>
  117. [SerializeField]
  118. [Tooltip("Inverts dots' position in orbit")]
  119. private bool invertOrbitOffset = false;
  120. public bool InvertOrbitOffset
  121. {
  122. get => invertOrbitOffset;
  123. set => invertOrbitOffset = value;
  124. }
  125. /// <summary>
  126. /// Multiplier to dot's rotation calculation
  127. /// </summary>
  128. [SerializeField]
  129. [Tooltip("Multiplier to dot's rotation calculation")]
  130. private float dotSpinMultiplier = 0.3f;
  131. public float DotSpinMultiplier
  132. {
  133. get => dotSpinMultiplier;
  134. set => dotSpinMultiplier = value;
  135. }
  136. /// <summary>
  137. /// Multiplier to dot's scale calculation
  138. /// </summary>
  139. [SerializeField]
  140. [Tooltip("Multiplier to dot's scale calculation")]
  141. private float dotScaleMultipler = 0.0f;
  142. public float DotScaleMultipler
  143. {
  144. get => dotScaleMultipler;
  145. set => dotScaleMultipler = value;
  146. }
  147. /// <summary>
  148. /// When enabled, the dot scale uses Cosine to determine scale with including <see cref="dotSetScale"/>.
  149. /// Otherwise, it will use Sine.
  150. /// </summary>
  151. [SerializeField]
  152. [Tooltip("When enabled, the dot scale uses Cosine to determine scale with including 'dotSetScale'. Otherwise, it will use Sine.")]
  153. private bool sinCosSplitScale = false;
  154. public bool SinCosSplitScale
  155. {
  156. get => sinCosSplitScale;
  157. set => sinCosSplitScale = value;
  158. }
  159. /// <summary>
  160. /// Calculates the time cycle for the trigonometric functions
  161. /// </summary>
  162. private float Cycles
  163. {
  164. get
  165. {
  166. if (reverseOrbit)
  167. {
  168. return (frequency < 0.0f) ? (Time.time / 0.000001f) * -1.0f : (Time.time / frequency) * -1.0f;
  169. }
  170. else
  171. {
  172. return (frequency < 0.0f) ? Time.time / 0.000001f : Time.time / frequency;
  173. }
  174. }
  175. }
  176. private float degPerSec;
  177. private Vector3 parentNewPos = Vector3.zero;
  178. private Transform dot01;
  179. private Vector3 dot01NewPos = Vector3.zero;
  180. private Vector3 dot01NewScale = Vector3.zero;
  181. private Vector3 dot01NewRot = Vector3.zero;
  182. private Transform dot02;
  183. private Vector3 dot02NewPos = Vector3.zero;
  184. private Vector3 dot02NewScale = Vector3.zero;
  185. private Vector3 dot02NewRot = Vector3.zero;
  186. private const float tau = Mathf.PI * 2.0f;
  187. private void OnEnable()
  188. {
  189. if (dot01 == null)
  190. {
  191. dot01 = gameObject.transform.GetChild(0);
  192. }
  193. if (dot02 == null)
  194. {
  195. dot02 = gameObject.transform.GetChild(1);
  196. }
  197. }
  198. private void Update()
  199. {
  200. degPerSec = Time.deltaTime * 360f;
  201. AnimateParent();
  202. AnimateDotTransforms();
  203. }
  204. private void AnimateParent()
  205. {
  206. float cosX = Mathf.Cos(Cycles * tau) * amplitude;
  207. float sinY = Mathf.Sin(Cycles * tau) * amplitude;
  208. if (invertOrbitOffset == true)
  209. {
  210. cosX = -cosX;
  211. sinY = -sinY;
  212. }
  213. parentNewPos.Set(cosX, sinY, 0f);
  214. transform.localPosition = parentNewPos;
  215. if (lFOsin == true)
  216. {
  217. dotSpinMultiplier = Mathf.Sin(Time.time * lFOfreq) * lFOamp;
  218. }
  219. else if (lFOcos == true)
  220. {
  221. dotSpinMultiplier = Mathf.Cos(Time.time * lFOfreq) * lFOamp;
  222. }
  223. transform.Rotate(Vector3.forward * (degPerSec * dotSpinMultiplier));
  224. }
  225. private void AnimateDotTransforms()
  226. {
  227. // Set dot groups' scale
  228. float sinScaleCalc = dotSetScale + Mathf.Sin(Cycles * tau / 2) * dotScaleMultipler;
  229. float cosScaleCalc = dotSetScale + Mathf.Cos(Cycles * tau / 2) * dotScaleMultipler;
  230. if (sinCosSplitScale == true)
  231. {
  232. dot01NewPos.Set(cosScaleCalc, cosScaleCalc, cosScaleCalc);
  233. }
  234. else
  235. {
  236. dot01NewPos.Set(sinScaleCalc, sinScaleCalc, sinScaleCalc);
  237. }
  238. dot01.localScale = dot01NewPos;
  239. dot02NewPos.Set(sinScaleCalc, sinScaleCalc, sinScaleCalc);
  240. dot02.localScale = dot02NewPos;
  241. // Set dot groups' position Offset from Parent-Null Center
  242. dot01NewPos.Set(dotOffset, dotOffset, 0f);
  243. dot02NewPos.Set(-dotOffset, -dotOffset, 0f);
  244. dot01.transform.localPosition = dot01NewPos;
  245. dot02.transform.localPosition = dot02NewPos;
  246. }
  247. }
  248. }