Tweener.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. 
  2. using UnityEngine;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine.EventSystems;
  6. using System;
  7. using UnityEngine.Events;
  8. public enum Direction
  9. {
  10. Reverse = -1,
  11. Toggle = 0,
  12. Forward = 1,
  13. }
  14. public enum EnableCondition
  15. {
  16. DoNothing = 0,
  17. EnableThenPlay,
  18. }
  19. public enum DisableCondition
  20. {
  21. DisableAfterReverse = -1,
  22. DoNotDisable = 0,
  23. DisableAfterForward = 1,
  24. }
  25. /// <summary>
  26. /// Base class for all tweening operations.
  27. /// </summary>
  28. public abstract class Tweener : MonoBehaviour
  29. {
  30. /// <summary>
  31. /// Current tween that triggered the callback function.
  32. /// </summary>
  33. static public Tweener current {
  34. get;
  35. private set;
  36. }
  37. public enum Method
  38. {
  39. Linear,
  40. EaseIn,
  41. EaseOut,
  42. EaseInOut,
  43. BounceIn,
  44. BounceOut,
  45. }
  46. public enum Style
  47. {
  48. Once,
  49. Loop,
  50. PingPong,
  51. }
  52. /// <summary>
  53. /// Tweening method used.
  54. /// </summary>
  55. public Method method = Method.Linear;
  56. /// <summary>
  57. /// Does it play once? Does it loop?
  58. /// </summary>
  59. public Style style = Style.Once;
  60. /// <summary>
  61. /// Optional curve to apply to the tween's time factor value.
  62. /// </summary>
  63. public AnimationCurve animationCurve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 1f), new Keyframe(1f, 1f, 1f, 0f));
  64. /// <summary>
  65. /// How long will the tweener wait before starting the tween?
  66. /// </summary>
  67. public float delay = 0f;
  68. public bool noDelayWhenReverse = false;
  69. /// <summary>
  70. /// How long is the duration of the tween?
  71. /// </summary>
  72. public float duration = 1f;
  73. /// <summary>
  74. /// Whether the tweener will use steeper curves for ease in / out style interpolation.
  75. /// </summary>
  76. public bool steeperCurves = false;
  77. /// <summary>
  78. /// Used by buttons and tween sequences. Group of '0' means not in a sequence.
  79. /// </summary>
  80. public int tweenGroup = 0;
  81. /// <summary>
  82. /// Event delegates called when the anim finishes.
  83. /// </summary>
  84. [SerializeField, HideInInspector]
  85. UnityEvent m_OnFinished = new UnityEvent();
  86. public Action onFinished;
  87. bool mStarted = false;
  88. float mStartTime = 0f;
  89. float mDuration = 0f;
  90. float mAmountPerDelta = 1000f;
  91. float mFactor = 0f;
  92. /// <summary>
  93. /// Amount advanced per delta time.
  94. /// </summary>
  95. public float amountPerDelta {
  96. get {
  97. if (mDuration != duration)
  98. {
  99. mDuration = duration;
  100. mAmountPerDelta = Mathf.Abs((duration > 0f) ? 1f / duration : 1000f);
  101. }
  102. return mAmountPerDelta;
  103. }
  104. }
  105. /// <summary>
  106. /// Tween factor, 0-1 range.
  107. /// </summary>
  108. public float tweenFactor {
  109. get {
  110. return mFactor;
  111. }
  112. set {
  113. mFactor = Mathf.Clamp01(value);
  114. }
  115. }
  116. /// <summary>
  117. /// Direction that the tween is currently playing in.
  118. /// </summary>
  119. public Direction direction {
  120. get {
  121. return mAmountPerDelta < 0f ? Direction.Reverse : Direction.Forward;
  122. }
  123. }
  124. void Reset()
  125. {
  126. if (!mStarted)
  127. {
  128. SetStartToCurrentValue();
  129. SetEndToCurrentValue();
  130. }
  131. }
  132. protected virtual void Awake()
  133. {
  134. onFinished += m_OnFinished.Invoke;
  135. }
  136. protected virtual void Start()
  137. {
  138. Update();
  139. }
  140. void Update()
  141. {
  142. float delta = Time.deltaTime;
  143. float time = Time.time;
  144. if (!mStarted)
  145. {
  146. mStarted = true;
  147. if (noDelayWhenReverse)
  148. {
  149. if (direction == Direction.Reverse)
  150. mStartTime = time;
  151. else
  152. mStartTime = time + delay;
  153. }
  154. else
  155. {
  156. mStartTime = time + delay;
  157. }
  158. }
  159. if (time < mStartTime)
  160. return;
  161. // Advance the sampling factor
  162. mFactor += amountPerDelta * delta;
  163. // Loop style simply resets the play factor after it exceeds 1.
  164. if (style == Style.Loop)
  165. {
  166. if (mFactor > 1f)
  167. {
  168. mFactor -= Mathf.Floor(mFactor);
  169. }
  170. }
  171. else if (style == Style.PingPong)
  172. {
  173. // Ping-pong style reverses the direction
  174. if (mFactor > 1f)
  175. {
  176. mFactor = 1f - (mFactor - Mathf.Floor(mFactor));
  177. mAmountPerDelta = -mAmountPerDelta;
  178. }
  179. else if (mFactor < 0f)
  180. {
  181. mFactor = -mFactor;
  182. mFactor -= Mathf.Floor(mFactor);
  183. mAmountPerDelta = -mAmountPerDelta;
  184. }
  185. }
  186. // If the factor goes out of range and this is a one-time tweening operation, disable the script
  187. if ((style == Style.Once) && (duration == 0f || mFactor > 1f || mFactor < 0f))
  188. {
  189. mFactor = Mathf.Clamp01(mFactor);
  190. Sample(mFactor, true);
  191. // Disable this script unless the function calls above changed something
  192. if (duration == 0f || (mFactor == 1f && mAmountPerDelta > 0f || mFactor == 0f && mAmountPerDelta < 0f))
  193. enabled = false;
  194. current = this;
  195. if (onFinished != null)
  196. {
  197. onFinished();
  198. }
  199. current = null;
  200. }
  201. else
  202. Sample(mFactor, false);
  203. }
  204. /// <summary>
  205. /// Mark as not started when finished to enable delay on next play.
  206. /// </summary>
  207. void OnDisable()
  208. {
  209. mStarted = false;
  210. }
  211. /// <summary>
  212. /// Sample the tween at the specified factor.
  213. /// </summary>
  214. public void Sample(float factor, bool isFinished)
  215. {
  216. // Calculate the sampling value
  217. float val = Mathf.Clamp01(factor);
  218. if (method == Method.EaseIn)
  219. {
  220. val = 1f - Mathf.Sin(0.5f * Mathf.PI * (1f - val));
  221. if (steeperCurves)
  222. val *= val;
  223. }
  224. else if (method == Method.EaseOut)
  225. {
  226. val = Mathf.Sin(0.5f * Mathf.PI * val);
  227. if (steeperCurves)
  228. {
  229. val = 1f - val;
  230. val = 1f - val * val;
  231. }
  232. }
  233. else if (method == Method.EaseInOut)
  234. {
  235. const float pi2 = Mathf.PI * 2f;
  236. val = val - Mathf.Sin(val * pi2) / pi2;
  237. if (steeperCurves)
  238. {
  239. val = val * 2f - 1f;
  240. float sign = Mathf.Sign(val);
  241. val = 1f - Mathf.Abs(val);
  242. val = 1f - val * val;
  243. val = sign * val * 0.5f + 0.5f;
  244. }
  245. }
  246. else if (method == Method.BounceIn)
  247. {
  248. val = BounceLogic(val);
  249. }
  250. else if (method == Method.BounceOut)
  251. {
  252. val = 1f - BounceLogic(1f - val);
  253. }
  254. // Call the virtual update
  255. OnUpdate((animationCurve != null) ? animationCurve.Evaluate(val) : val, isFinished);
  256. }
  257. /// <summary>
  258. /// main Bounce logic to simplify the Sample function
  259. /// </summary>
  260. float BounceLogic(float val)
  261. {
  262. if (val < 0.363636f) // 0.363636 = (1/ 2.75)
  263. {
  264. val = 7.5685f * val * val;
  265. }
  266. else if (val < 0.727272f) // 0.727272 = (2 / 2.75)
  267. {
  268. val = 7.5625f * (val -= 0.545454f) * val + 0.75f; // 0.545454f = (1.5 / 2.75)
  269. }
  270. else if (val < 0.909090f) // 0.909090 = (2.5 / 2.75)
  271. {
  272. val = 7.5625f * (val -= 0.818181f) * val + 0.9375f; // 0.818181 = (2.25 / 2.75)
  273. }
  274. else
  275. {
  276. val = 7.5625f * (val -= 0.9545454f) * val + 0.984375f; // 0.9545454 = (2.625 / 2.75)
  277. }
  278. return val;
  279. }
  280. /// <summary>
  281. /// Play the tween forward.
  282. /// </summary>
  283. public void PlayForward()
  284. {
  285. Play(true);
  286. }
  287. /// <summary>
  288. /// Play the tween in reverse.
  289. /// </summary>
  290. public void PlayReverse()
  291. {
  292. Play(false);
  293. }
  294. /// <summary>
  295. /// Stop the tween.
  296. /// </summary>
  297. public void Stop()
  298. {
  299. enabled = false;
  300. }
  301. /// <summary>
  302. /// Manually activate the tweening process, reversing it if necessary.
  303. /// </summary>
  304. public virtual void Play(bool forward)
  305. {
  306. enabled = true;
  307. mAmountPerDelta = Mathf.Abs(amountPerDelta);
  308. if (!forward)
  309. mAmountPerDelta = -mAmountPerDelta;
  310. ResetToBeginning();
  311. Update();
  312. }
  313. /// <summary>
  314. /// Manually reset the tweener's state to the beginning.
  315. /// </summary>
  316. public void ResetToBeginning()
  317. {
  318. mStarted = false;
  319. mFactor = (mAmountPerDelta < 0f) ? 1f : 0f;
  320. Sample(mFactor, false);
  321. }
  322. /// <summary>
  323. /// Manually start the tweening process, reversing its direction.
  324. /// </summary>
  325. public void Toggle()
  326. {
  327. if (mFactor > 0f)
  328. {
  329. mAmountPerDelta = -amountPerDelta;
  330. }
  331. else
  332. {
  333. mAmountPerDelta = Mathf.Abs(amountPerDelta);
  334. }
  335. enabled = true;
  336. }
  337. /// <summary>
  338. /// Actual tweening logic should go here.
  339. /// </summary>
  340. abstract protected void OnUpdate(float factor, bool isFinished);
  341. /// <summary>
  342. /// Starts the tweening operation.
  343. /// </summary>
  344. static public T Begin<T>(GameObject go, float duration) where T : Tweener
  345. {
  346. T comp = go.GetComponent<T>();
  347. if (comp == null)
  348. comp = go.AddComponent<T>();
  349. //comp.onFinished = null;
  350. comp.mStarted = false;
  351. comp.duration = duration;
  352. comp.mFactor = 0f;
  353. comp.mAmountPerDelta = Mathf.Abs(comp.mAmountPerDelta);
  354. comp.style = Style.Once;
  355. comp.animationCurve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 1f), new Keyframe(1f, 1f, 1f, 0f));
  356. comp.enabled = true;
  357. comp.onFinished = null;
  358. comp.m_OnFinished = new UnityEvent();
  359. if (duration <= 0f)
  360. {
  361. comp.Sample(1f, true);
  362. comp.enabled = false;
  363. }
  364. return comp;
  365. }
  366. /// <summary>
  367. /// Set the 'from' value to the current one.
  368. /// </summary>
  369. public virtual void SetStartToCurrentValue()
  370. {
  371. }
  372. /// <summary>
  373. /// Set the 'to' value to the current one.
  374. /// </summary>
  375. public virtual void SetEndToCurrentValue()
  376. {
  377. }
  378. }