ZTween.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. class ZTween {
  5. /**
  6. * That works:
  7. *
  8. * .use(gameObject)
  9. * .scaleFrom(Vector3)
  10. * .scaleTo(Vector3, time = 0, transition = Equations.none)
  11. * .moveFrom(Vector3)
  12. * .moveTo(Vector3, time = 0, transition = Equations.none)
  13. * .rotateFrom(Quaternion)
  14. * .rotateTo(Quaternion, time = 0, transition = Equations.none)
  15. * .call(Action)
  16. * .wait(time)
  17. *
  18. * use(getter, setter)
  19. * .
  20. * //.play()
  21. * //.pause()
  22. *
  23. * Does not work:
  24. *
  25. * use(ref float)
  26. *
  27. * TODO: decide:
  28. * . parallellize changes? how to rotate AND move something at the same time?
  29. *
  30. */
  31. /**
  32. * Examples:
  33. * .call(() => logDone("over"))
  34. * .call(someFunction)
  35. * // Getter/setter, for function pairs
  36. * ZTween.use(getValue, setValue).valueTo(1.0f, 1, Easing.quadOut).call(() => logDone("value ok"));
  37. * // Lambdas, for getter-setter or member pairs
  38. * ZTween.use(() => testNum, x => testNum = x).valueTo(1.0f, 1, Easing.quadOut).call(() => logDone("value ok"));
  39. */
  40. /*
  41. //transform.localScale = new Vector3(2, 2, 2);
  42. // http://www.createjs.com/Docs/TweenJS/modules/TweenJS.html
  43. ZTween.use(gameObject).scaleTo(new Vector3(2, 2, 2), 1.0f, Easing.quadOut).wait(1).call(Func).set("visible", false).play();
  44. ZTween.use(gameObject).pause();
  45. ZTween.use(gameObject).resume();
  46. ZTween.use(gameObject).stop();
  47. ZTween.use(gameObject, loop, useTicks);
  48. */
  49. #region ZTween static interface
  50. // Static properties
  51. private static ZTweenSurrogate tweenSurrogate;
  52. // ================================================================================================================
  53. // PUBLIC STATIC INTERFACE ----------------------------------------------------------------------------------------
  54. public static ZTweenGameObjectSequence use(GameObject gameObject) {
  55. return new ZTweenGameObjectSequence(gameObject);
  56. }
  57. public static ZTweenGetterSetterSequence use(Func<float> getValueFunction, Action<float> setValueFunction) {
  58. return new ZTweenGetterSetterSequence(getValueFunction, setValueFunction);
  59. }
  60. // ================================================================================================================
  61. // PRIVATE STATIC INTERFACE ---------------------------------------------------------------------------------------
  62. static ZTween() {
  63. GameObject surrogateObject = new GameObject("ZTween-controller");
  64. tweenSurrogate = surrogateObject.AddComponent<ZTweenSurrogate>();
  65. }
  66. #endregion
  67. // ================================================================================================================
  68. // INTERNAL CLASSES -----------------------------------------------------------------------------------------------
  69. // Aux classes
  70. class ZTweenStepMetadata {
  71. public bool hasStarted;
  72. public bool hasCompleted;
  73. public float timeStart;
  74. public float timeEnd;
  75. public float timeDuration {
  76. get {
  77. return timeEnd - timeStart;
  78. }
  79. }
  80. }
  81. internal interface IZTweenStep {
  82. void start();
  83. void update(float t);
  84. void end();
  85. float getDuration();
  86. }
  87. // Sequences
  88. internal class ZTweenSequence {
  89. // Instances
  90. private List<IZTweenStep> sequenceSteps;
  91. private List<ZTweenStepMetadata> sequenceStepsMetadatas;
  92. // Properties
  93. private bool isPlaying;
  94. private int currentStep;
  95. private float startTime;
  96. private float pauseTime;
  97. private float executedTime;
  98. private float duration;
  99. // ================================================================================================================
  100. // CONSTRUCTOR ----------------------------------------------------------------------------------------------------
  101. public ZTweenSequence() {
  102. // Create a new ZTween
  103. // Add to surrogate
  104. ZTween.tweenSurrogate.add(this);
  105. // Create lists
  106. sequenceSteps = new List<IZTweenStep>();
  107. sequenceStepsMetadatas = new List<ZTweenStepMetadata>();
  108. // Set properties
  109. isPlaying = true;
  110. currentStep = 0;
  111. startTime = Time.time;
  112. executedTime = 0;
  113. duration = 0;
  114. }
  115. // ================================================================================================================
  116. // PUBLIC INTERFACE -----------------------------------------------------------------------------------------------
  117. // Play control methods
  118. public ZTweenSequence play() {
  119. if (!isPlaying) {
  120. isPlaying = true;
  121. float timePaused = Time.time - pauseTime;
  122. startTime += timePaused;
  123. }
  124. return this;
  125. }
  126. public ZTweenSequence pause() {
  127. if (isPlaying) {
  128. isPlaying = false;
  129. pauseTime = Time.time;
  130. }
  131. return this;
  132. }
  133. // Utility methods
  134. public ZTweenSequence call(Action action) {
  135. addStep(new ZTweenStepCall(action));
  136. return this;
  137. }
  138. public ZTweenSequence wait(float duration) {
  139. duration += duration;
  140. return this;
  141. }
  142. // ================================================================================================================
  143. // PRIVATE INTERFACE ----------------------------------------------------------------------------------------------
  144. // Core tween step control methods
  145. internal void addStep(IZTweenStep step) {
  146. sequenceSteps.Add(step);
  147. ZTweenStepMetadata tweenMetadata = new ZTweenStepMetadata();
  148. tweenMetadata.timeStart = startTime + duration;
  149. duration += step.getDuration();
  150. tweenMetadata.timeEnd = startTime + duration;
  151. sequenceStepsMetadatas.Add(tweenMetadata);
  152. }
  153. internal void update() {
  154. // Update current step(s) based on the time
  155. // Check if finished
  156. if (currentStep >= sequenceSteps.Count) {
  157. // Finished all, remove itself
  158. destroy();
  159. } else {
  160. bool shouldUpdateOnce = isPlaying;
  161. while (shouldUpdateOnce && currentStep < sequenceSteps.Count) {
  162. shouldUpdateOnce = false;
  163. if (Time.time >= sequenceStepsMetadatas[currentStep].timeStart) {
  164. // Start the current tween step if necessary
  165. if (!sequenceStepsMetadatas[currentStep].hasStarted) {
  166. sequenceSteps[currentStep].start();
  167. sequenceStepsMetadatas[currentStep].hasStarted = true;
  168. }
  169. // Update the current tween step
  170. sequenceSteps[currentStep].update(Mathf.Clamp01(Mathf.InverseLerp(sequenceStepsMetadatas[currentStep].timeStart, sequenceStepsMetadatas[currentStep].timeEnd, Time.time)));
  171. // Check if it's finished
  172. if (Time.time >= sequenceStepsMetadatas[currentStep].timeEnd) {
  173. if (!sequenceStepsMetadatas[currentStep].hasCompleted) {
  174. sequenceSteps[currentStep].end();
  175. sequenceStepsMetadatas[currentStep].hasCompleted = true;
  176. executedTime += sequenceStepsMetadatas[currentStep].timeDuration;
  177. shouldUpdateOnce = true;
  178. currentStep++;
  179. }
  180. }
  181. }
  182. }
  183. }
  184. }
  185. internal void destroy() {
  186. tweenSurrogate.remove(this);
  187. }
  188. internal Func<float, float> getTransition(Func<float, float> transition) {
  189. return transition == null ? Easing.none : transition;
  190. }
  191. }
  192. internal class ZTweenGetterSetterSequence:ZTweenSequence {
  193. // Instances
  194. private Func<float> targetGet;
  195. private Action<float> targetSet;
  196. // ================================================================================================================
  197. // CONSTRUCTOR ----------------------------------------------------------------------------------------------------
  198. public ZTweenGetterSetterSequence(Func<float> targetGet, Action<float> targetSet):base() {
  199. this.targetGet = targetGet;
  200. this.targetSet = targetSet;
  201. }
  202. // ================================================================================================================
  203. // PUBLIC INTERFACE -----------------------------------------------------------------------------------------------
  204. public ZTweenGetterSetterSequence valueFrom(float value) {
  205. addStep(new ZTweenStepValueFrom(targetSet, value));
  206. return this;
  207. }
  208. public ZTweenGetterSetterSequence valueTo(float value, float duration = 0, Func<float, float> transition = null) {
  209. addStep(new ZTweenStepValueTo(targetGet, targetSet, value, duration, getTransition(transition)));
  210. return this;
  211. }
  212. }
  213. internal class ZTweenGameObjectSequence:ZTweenSequence {
  214. // Instances
  215. private GameObject targetGameObject;
  216. // ================================================================================================================
  217. // CONSTRUCTOR ----------------------------------------------------------------------------------------------------
  218. public ZTweenGameObjectSequence(GameObject gameObject):base() {
  219. this.targetGameObject = gameObject;
  220. }
  221. // ================================================================================================================
  222. // PUBLIC INTERFACE -----------------------------------------------------------------------------------------------
  223. public ZTweenGameObjectSequence scaleFrom(Vector3 scale) {
  224. addStep(new ZTweenStepScaleFrom(targetGameObject, scale));
  225. return this;
  226. }
  227. public ZTweenGameObjectSequence scaleTo(Vector3 scale, float duration = 0, Func<float, float> transition = null) {
  228. addStep(new ZTweenStepScaleTo(targetGameObject, scale, duration, getTransition(transition)));
  229. return this;
  230. }
  231. public ZTweenGameObjectSequence moveFrom(Vector3 position) {
  232. addStep(new ZTweenStepPositionFrom(targetGameObject, position));
  233. return this;
  234. }
  235. public ZTweenGameObjectSequence moveTo(Vector3 position, float duration = 0, Func<float, float> transition = null) {
  236. addStep(new ZTweenStepPositionTo(targetGameObject, position, duration, getTransition(transition)));
  237. return this;
  238. }
  239. public ZTweenGameObjectSequence rotateFrom(Quaternion rotation) {
  240. addStep(new ZTweenStepRotationFrom(targetGameObject, rotation));
  241. return this;
  242. }
  243. public ZTweenGameObjectSequence rotateTo(Quaternion rotation, float duration = 0, Func<float, float> transition = null) {
  244. addStep(new ZTweenStepRotationTo(targetGameObject, rotation, duration, getTransition(transition)));
  245. return this;
  246. }
  247. }
  248. // Steps for generic sequences
  249. class ZTweenStepCall:IZTweenStep {
  250. // Properties
  251. private Action action;
  252. // Extension functions
  253. public ZTweenStepCall(Action action) {
  254. this.action = action;
  255. }
  256. public void start() { }
  257. public void update(float t) { }
  258. public void end() {
  259. action();
  260. }
  261. public float getDuration() {
  262. return 0;
  263. }
  264. }
  265. // Steps for GetterSetter sequences
  266. class ZTweenStepValueFrom:IZTweenStep {
  267. // Properties
  268. private Action<float> targetSet;
  269. private float targetValue;
  270. // Extension functions
  271. public ZTweenStepValueFrom(Action<float> targetSet, float targetValue) {
  272. this.targetSet = targetSet;
  273. this.targetValue = targetValue;
  274. }
  275. public void start() { }
  276. public void update(float t) { }
  277. public void end() {
  278. targetSet(targetValue);
  279. }
  280. public float getDuration() {
  281. return 0;
  282. }
  283. }
  284. class ZTweenStepValueTo:IZTweenStep {
  285. // Properties
  286. private Func<float> targetGet;
  287. private Action<float> targetSet;
  288. private float duration;
  289. private float startValue;
  290. private float targetValue;
  291. private Func<float, float> transition;
  292. // Extension functions
  293. public ZTweenStepValueTo(Func<float> targetGet, Action<float> targetSet, float targetValue, float duration, Func<float, float> transition) {
  294. this.targetGet = targetGet;
  295. this.targetSet = targetSet;
  296. this.duration = duration;
  297. this.targetValue = targetValue;
  298. this.transition = transition;
  299. }
  300. public void start() {
  301. this.startValue = targetGet();
  302. }
  303. public void update(float t) {
  304. targetSet(Mathf.LerpUnclamped(startValue, targetValue, transition(t)));
  305. }
  306. public void end() {
  307. targetSet(targetValue);
  308. }
  309. public float getDuration() {
  310. return duration;
  311. }
  312. }
  313. // Steps for GameObject sequences
  314. class ZTweenStepScaleFrom:IZTweenStep {
  315. // Properties
  316. private GameObject target;
  317. private Vector3 targetValue;
  318. // Extension functions
  319. public ZTweenStepScaleFrom(GameObject target, Vector3 targetValue) {
  320. this.target = target;
  321. this.targetValue = targetValue;
  322. }
  323. public void start() { }
  324. public void update(float t) { }
  325. public void end() {
  326. target.transform.localScale = targetValue;
  327. }
  328. public float getDuration() {
  329. return 0;
  330. }
  331. }
  332. class ZTweenStepScaleTo:IZTweenStep {
  333. // Properties
  334. private GameObject target;
  335. private float duration;
  336. private Vector3 startValue;
  337. private Vector3 targetValue;
  338. private Func<float, float> transition;
  339. // Extension functions
  340. public ZTweenStepScaleTo(GameObject target, Vector3 targetValue, float duration, Func<float, float> transition) {
  341. this.target = target;
  342. this.duration = duration;
  343. this.targetValue = targetValue;
  344. this.transition = transition;
  345. }
  346. public void start() {
  347. this.startValue = target.transform.localScale;
  348. }
  349. public void update(float t) {
  350. target.transform.localScale = Vector3.LerpUnclamped(startValue, targetValue, transition(t));
  351. }
  352. public void end() {
  353. target.transform.localScale = targetValue;
  354. }
  355. public float getDuration() {
  356. return duration;
  357. }
  358. }
  359. class ZTweenStepPositionFrom:IZTweenStep {
  360. // Properties
  361. private GameObject target;
  362. private Vector3 targetValue;
  363. // Extension functions
  364. public ZTweenStepPositionFrom(GameObject target, Vector3 targetValue) {
  365. this.target = target;
  366. this.targetValue = targetValue;
  367. }
  368. public void start() { }
  369. public void update(float t) { }
  370. public void end() {
  371. target.transform.localPosition = targetValue;
  372. }
  373. public float getDuration() {
  374. return 0;
  375. }
  376. }
  377. class ZTweenStepPositionTo:IZTweenStep {
  378. // Properties
  379. private GameObject target;
  380. private float duration;
  381. private Vector3 startValue;
  382. private Vector3 targetValue;
  383. private Func<float, float> transition;
  384. // Extension functions
  385. public ZTweenStepPositionTo(GameObject target, Vector3 targetValue, float duration, Func<float, float> transition) {
  386. this.target = target;
  387. this.duration = duration;
  388. this.targetValue = targetValue;
  389. this.transition = transition;
  390. }
  391. public void start() {
  392. this.startValue = target.transform.localPosition;
  393. }
  394. public void update(float t) {
  395. target.transform.localPosition = Vector3.LerpUnclamped(startValue, targetValue, transition(t));
  396. }
  397. public void end() {
  398. target.transform.localPosition = targetValue;
  399. }
  400. public float getDuration() {
  401. return duration;
  402. }
  403. }
  404. class ZTweenStepRotationFrom:IZTweenStep {
  405. // Properties
  406. private GameObject target;
  407. private Quaternion targetValue;
  408. // Extension functions
  409. public ZTweenStepRotationFrom(GameObject target, Quaternion targetValue) {
  410. this.target = target;
  411. this.targetValue = targetValue;
  412. }
  413. public void start() { }
  414. public void update(float t) { }
  415. public void end() {
  416. target.transform.localRotation = targetValue;
  417. }
  418. public float getDuration() {
  419. return 0;
  420. }
  421. }
  422. class ZTweenStepRotationTo:IZTweenStep {
  423. // Properties
  424. private GameObject target;
  425. private float duration;
  426. private Quaternion startValue;
  427. private Quaternion targetValue;
  428. private Func<float, float> transition;
  429. // Extension functions
  430. public ZTweenStepRotationTo(GameObject target, Quaternion targetValue, float duration, Func<float, float> transition) {
  431. this.target = target;
  432. this.duration = duration;
  433. this.targetValue = targetValue;
  434. this.transition = transition;
  435. }
  436. public void start() {
  437. this.startValue = target.transform.localRotation;
  438. }
  439. public void update(float t) {
  440. target.transform.localRotation = Quaternion.SlerpUnclamped(startValue, targetValue, transition(t));
  441. }
  442. public void end() {
  443. target.transform.localRotation = targetValue;
  444. }
  445. public float getDuration() {
  446. return duration;
  447. }
  448. }
  449. }