Timeline.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEngine.Serialization;
  6. namespace Chronos
  7. {
  8. /// <summary>
  9. /// Determines what type of clock a timeline observes.
  10. /// </summary>
  11. public enum TimelineMode
  12. {
  13. /// <summary>
  14. /// The timeline observes a LocalClock attached to the same GameObject.
  15. /// </summary>
  16. Local,
  17. /// <summary>
  18. /// The timeline observes a GlobalClock referenced by globalClockKey.
  19. /// </summary>
  20. Global
  21. }
  22. /// <summary>
  23. /// A component that combines timing measurements from an observed LocalClock or GlobalClock and any AreaClock within which it is. This component should be attached to any GameObject that should be affected by Chronos.
  24. /// </summary>
  25. [AddComponentMenu("Time/Timeline")]
  26. [DisallowMultipleComponent]
  27. [HelpURL("http://ludiq.io/chronos/documentation#Timeline")]
  28. public class Timeline : TimelineEffector
  29. {
  30. protected const float DefaultRecordingDuration = 30;
  31. public Timeline()
  32. {
  33. children = new List<TimelineChild>();
  34. areaClocks = new List<IAreaClock>();
  35. occurrences = new List<Occurrence>();
  36. handledOccurrences = new HashSet<Occurrence>();
  37. previousDeltaTimes = new Queue<float>();
  38. timeScale = lastTimeScale = 1;
  39. }
  40. protected override void OnStartOrReEnable()
  41. {
  42. timeScale = lastTimeScale = clock.timeScale;
  43. base.OnStartOrReEnable();
  44. }
  45. protected override void Update()
  46. {
  47. TriggerEvents();
  48. lastTimeScale = timeScale;
  49. timeScale = clock.timeScale; // Start with the time scale from local / global clock
  50. for (int i = 0; i < areaClocks.Count; i++) // Blend it with the time scale of each area clock
  51. {
  52. var areaClock = areaClocks[i];
  53. if (areaClock != null)
  54. {
  55. float areaClockTimeScale = areaClock.TimeScale(this);
  56. if (areaClock.innerBlend == ClockBlend.Multiplicative)
  57. {
  58. timeScale *= areaClockTimeScale;
  59. }
  60. else // if (areaClock.innerBlend == ClockBlend.Additive)
  61. {
  62. timeScale += areaClockTimeScale;
  63. }
  64. }
  65. }
  66. if (!rewindable) // Cap to 0 for non-rewindable timelines
  67. {
  68. timeScale = Mathf.Max(0, timeScale);
  69. }
  70. if (timeScale != lastTimeScale)
  71. {
  72. for (int i = 0; i < components.Count; i++)
  73. {
  74. components[i].AdjustProperties();
  75. }
  76. for (int i = 0; i < children.Count; i++)
  77. {
  78. for (int j = 0; j < children[i].components.Count; j++)
  79. {
  80. children[i].components[j].AdjustProperties();
  81. }
  82. }
  83. }
  84. float unscaledDeltaTime = Timekeeper.unscaledDeltaTime;
  85. deltaTime = unscaledDeltaTime * timeScale;
  86. fixedDeltaTime = Time.fixedDeltaTime * timeScale;
  87. time += deltaTime;
  88. unscaledTime += unscaledDeltaTime;
  89. RecordSmoothing();
  90. base.Update();
  91. if (timeScale > 0)
  92. {
  93. TriggerForwardOccurrences();
  94. }
  95. else if (timeScale < 0)
  96. {
  97. TriggerBackwardOccurrences();
  98. }
  99. }
  100. protected override void OnDisable()
  101. {
  102. ReleaseFromAll();
  103. base.OnDisable();
  104. }
  105. public override void Reset()
  106. {
  107. base.Reset();
  108. timeScale = lastTimeScale = 1;
  109. previousDeltaTimes.Clear();
  110. occurrences.Clear();
  111. handledOccurrences.Clear();
  112. nextForwardOccurrence = null;
  113. nextBackwardOccurrence = null;
  114. }
  115. #region Fields
  116. public float lastTimeScale;
  117. protected Queue<float> previousDeltaTimes;
  118. protected List<Occurrence> occurrences;
  119. protected HashSet<Occurrence> handledOccurrences;
  120. protected Occurrence nextForwardOccurrence;
  121. protected Occurrence nextBackwardOccurrence;
  122. public List<IAreaClock> areaClocks;
  123. public List<TimelineChild> children;
  124. #endregion
  125. #region Properties
  126. protected override Timeline timeline
  127. {
  128. get { return this; }
  129. }
  130. [SerializeField]
  131. private TimelineMode _mode;
  132. /// <summary>
  133. /// Determines what type of clock the timeline observes.
  134. /// </summary>
  135. public TimelineMode mode
  136. {
  137. get { return _mode; }
  138. set
  139. {
  140. _mode = value;
  141. _clock = null;
  142. }
  143. }
  144. [SerializeField, GlobalClock]
  145. private string _globalClockKey;
  146. /// <summary>
  147. /// The key of the GlobalClock that is observed by the timeline. This value is only used for the Global mode.
  148. /// </summary>
  149. public string globalClockKey
  150. {
  151. get { return _globalClockKey; }
  152. set
  153. {
  154. _globalClockKey = value;
  155. _clock = null;
  156. }
  157. }
  158. private Clock _clock;
  159. /// <summary>
  160. /// The clock observed by the timeline.
  161. /// </summary>
  162. public Clock clock
  163. {
  164. get
  165. {
  166. if (_clock == null)
  167. {
  168. _clock = FindClock();
  169. }
  170. return _clock;
  171. }
  172. }
  173. /// <summary>
  174. /// The time scale of the timeline, computed from all observed clocks. For more information, see Clock.timeScale.
  175. /// </summary>
  176. public float timeScale { get; protected set; }
  177. /// <summary>
  178. /// The delta time of the timeline, computed from all observed clocks. For more information, see Clock.deltaTime.
  179. /// </summary>
  180. public float deltaTime { get; protected set; }
  181. /// <summary>
  182. /// The fixed delta time of the timeline, computed from all observed clocks. For more information, see Clock.fixedDeltaTime.
  183. /// </summary>
  184. public float fixedDeltaTime { get; protected set; }
  185. /// <summary>
  186. /// A smoothed out delta time. Use this value if you need to avoid spikes and fluctuations in delta times. The amount of frames over which this value is smoothed can be adjusted via smoothingDeltas.
  187. /// </summary>
  188. public float smoothDeltaTime
  189. {
  190. get { return (deltaTime + previousDeltaTimes.Sum()) / (previousDeltaTimes.Count + 1); }
  191. }
  192. /// <summary>
  193. /// The amount of frames over which smoothDeltaTime is smoothed.
  194. /// </summary>
  195. public static int smoothingDeltas = 5;
  196. /// <summary>
  197. /// The time in seconds since the creation of this timeline, computed from all observed clocks. For more information, see Clock.time.
  198. /// </summary>
  199. public float time { get; protected set; }
  200. /// <summary>
  201. /// The unscaled time in seconds since the creation of this timeline. For more information, see Clock.unscaledTime.
  202. /// </summary>
  203. public float unscaledTime { get; protected set; }
  204. /// <summary>
  205. /// Indicates the state of the timeline.
  206. /// </summary>
  207. public TimeState state
  208. {
  209. get { return Timekeeper.GetTimeState(timeScale); }
  210. }
  211. #endregion
  212. #region Timing
  213. protected virtual Clock FindClock()
  214. {
  215. if (mode == TimelineMode.Local)
  216. {
  217. LocalClock localClock = GetComponent<LocalClock>();
  218. if (localClock == null)
  219. {
  220. throw new ChronosException(string.Format("Missing local clock for timeline."));
  221. }
  222. return localClock;
  223. }
  224. else if (mode == TimelineMode.Global)
  225. {
  226. GlobalClock oldGlobalClock = _clock as GlobalClock;
  227. if (oldGlobalClock != null)
  228. {
  229. oldGlobalClock.Unregister(this);
  230. }
  231. if (!Timekeeper.instance.HasClock(globalClockKey))
  232. {
  233. throw new ChronosException(string.Format("Missing global clock for timeline: '{0}'.", globalClockKey));
  234. }
  235. GlobalClock globalClock = Timekeeper.instance.Clock(globalClockKey);
  236. globalClock.Register(this);
  237. return globalClock;
  238. }
  239. else
  240. {
  241. throw new ChronosException(string.Format("Unknown timeline mode: '{0}'.", mode));
  242. }
  243. }
  244. /// <summary>
  245. /// Releases the timeline from the specified area clock's effects.
  246. /// </summary>
  247. public virtual void ReleaseFrom(IAreaClock areaClock)
  248. {
  249. areaClock.Release(this);
  250. }
  251. /// <summary>
  252. /// Releases the timeline from the effects of all the area clocks within which it is.
  253. /// </summary>
  254. public virtual void ReleaseFromAll()
  255. {
  256. foreach (IAreaClock areaClock in areaClocks.Where(ac => ac != null).ToArray())
  257. {
  258. areaClock.Release(this);
  259. }
  260. areaClocks.Clear();
  261. }
  262. protected virtual void TriggerEvents()
  263. {
  264. if (lastTimeScale != 0 && timeScale == 0)
  265. {
  266. SendMessage("OnStartPause", SendMessageOptions.DontRequireReceiver);
  267. }
  268. if (lastTimeScale == 0 && timeScale != 0)
  269. {
  270. SendMessage("OnStopPause", SendMessageOptions.DontRequireReceiver);
  271. }
  272. if (lastTimeScale >= 0 && timeScale < 0)
  273. {
  274. SendMessage("OnStartRewind", SendMessageOptions.DontRequireReceiver);
  275. }
  276. if (lastTimeScale < 0 && timeScale >= 0)
  277. {
  278. SendMessage("OnStopRewind", SendMessageOptions.DontRequireReceiver);
  279. }
  280. if ((lastTimeScale <= 0 || lastTimeScale >= 1) && (timeScale > 0 && timeScale < 1))
  281. {
  282. SendMessage("OnStartSlowDown", SendMessageOptions.DontRequireReceiver);
  283. }
  284. if ((lastTimeScale > 0 && lastTimeScale < 1) && (timeScale <= 0 || timeScale >= 1))
  285. {
  286. SendMessage("OnStopSlowDown", SendMessageOptions.DontRequireReceiver);
  287. }
  288. if (lastTimeScale <= 1 && timeScale > 1)
  289. {
  290. SendMessage("OnStartFastForward", SendMessageOptions.DontRequireReceiver);
  291. }
  292. if (lastTimeScale > 1 && timeScale <= 1)
  293. {
  294. SendMessage("OnStopFastForward", SendMessageOptions.DontRequireReceiver);
  295. }
  296. }
  297. protected virtual void RecordSmoothing()
  298. {
  299. if (deltaTime != 0)
  300. {
  301. previousDeltaTimes.Enqueue(deltaTime);
  302. }
  303. if (previousDeltaTimes.Count > smoothingDeltas)
  304. {
  305. previousDeltaTimes.Dequeue();
  306. }
  307. }
  308. #endregion
  309. #region Occurrences
  310. protected void TriggerForwardOccurrences()
  311. {
  312. handledOccurrences.Clear();
  313. while (nextForwardOccurrence != null && nextForwardOccurrence.time <= time)
  314. {
  315. nextForwardOccurrence.Forward();
  316. handledOccurrences.Add(nextForwardOccurrence);
  317. nextBackwardOccurrence = nextForwardOccurrence;
  318. nextForwardOccurrence = OccurrenceAfter(nextForwardOccurrence.time, handledOccurrences);
  319. }
  320. }
  321. protected void TriggerBackwardOccurrences()
  322. {
  323. handledOccurrences.Clear();
  324. while (nextBackwardOccurrence != null && nextBackwardOccurrence.time >= time)
  325. {
  326. nextBackwardOccurrence.Backward();
  327. if (nextBackwardOccurrence.repeatable)
  328. {
  329. handledOccurrences.Add(nextBackwardOccurrence);
  330. nextForwardOccurrence = nextBackwardOccurrence;
  331. }
  332. else
  333. {
  334. occurrences.Remove(nextBackwardOccurrence);
  335. }
  336. nextBackwardOccurrence = OccurrenceBefore(nextBackwardOccurrence.time, handledOccurrences);
  337. }
  338. }
  339. protected Occurrence OccurrenceAfter(float time, params Occurrence[] ignored)
  340. {
  341. return OccurrenceAfter(time, (IEnumerable<Occurrence>) ignored);
  342. }
  343. protected Occurrence OccurrenceAfter(float time, IEnumerable<Occurrence> ignored)
  344. {
  345. Occurrence after = null;
  346. for (int i = 0; i < occurrences.Count; i++)
  347. {
  348. var occurrence = occurrences[i];
  349. if (occurrence.time >= time &&
  350. !ignored.Contains(occurrence) &&
  351. (after == null || occurrence.time < after.time))
  352. {
  353. after = occurrence;
  354. }
  355. }
  356. return after;
  357. }
  358. protected Occurrence OccurrenceBefore(float time, params Occurrence[] ignored)
  359. {
  360. return OccurrenceBefore(time, (IEnumerable<Occurrence>) ignored);
  361. }
  362. protected Occurrence OccurrenceBefore(float time, IEnumerable<Occurrence> ignored)
  363. {
  364. Occurrence before = null;
  365. for (int i = 0; i < occurrences.Count; i++)
  366. {
  367. var occurrence = occurrences[i];
  368. if (occurrence.time <= time &&
  369. !ignored.Contains(occurrence) &&
  370. (before == null || occurrence.time > before.time))
  371. {
  372. before = occurrence;
  373. }
  374. }
  375. return before;
  376. }
  377. protected virtual void PlaceOccurence(Occurrence occurrence, float time)
  378. {
  379. if (time == this.time)
  380. {
  381. if (timeScale >= 0)
  382. {
  383. occurrence.Forward();
  384. nextBackwardOccurrence = occurrence;
  385. }
  386. else
  387. {
  388. occurrence.Backward();
  389. nextForwardOccurrence = occurrence;
  390. }
  391. }
  392. else if (time > this.time)
  393. {
  394. if (nextForwardOccurrence == null ||
  395. nextForwardOccurrence.time > time)
  396. {
  397. nextForwardOccurrence = occurrence;
  398. }
  399. }
  400. else if (time < this.time)
  401. {
  402. if (nextBackwardOccurrence == null ||
  403. nextBackwardOccurrence.time < time)
  404. {
  405. nextBackwardOccurrence = occurrence;
  406. }
  407. }
  408. }
  409. /// <summary>
  410. /// Schedules an occurrence at a specified absolute time in seconds on the timeline.
  411. /// </summary>
  412. public virtual Occurrence Schedule(float time, bool repeatable, Occurrence occurrence)
  413. {
  414. occurrence.time = time;
  415. occurrence.repeatable = repeatable;
  416. occurrences.Add(occurrence);
  417. PlaceOccurence(occurrence, time);
  418. return occurrence;
  419. }
  420. /// <summary>
  421. /// Executes an occurrence now and places it on the schedule for rewinding.
  422. /// </summary>
  423. public Occurrence Do(bool repeatable, Occurrence occurrence)
  424. {
  425. return Schedule(time, repeatable, occurrence);
  426. }
  427. /// <summary>
  428. /// Plans an occurrence to be executed in the specified delay in seconds.
  429. /// </summary>
  430. public Occurrence Plan(float delay, bool repeatable, Occurrence occurrence)
  431. {
  432. if (delay <= 0)
  433. {
  434. throw new ChronosException("Planned occurrences must be in the future.");
  435. }
  436. return Schedule(time + delay, repeatable, occurrence);
  437. }
  438. /// <summary>
  439. /// Creates a "memory" of an occurrence at a specified "past-delay" in seconds. This means that the occurrence will only be executed if time is rewound, and that it will be executed backward first.
  440. /// </summary>
  441. public Occurrence Memory(float delay, bool repeatable, Occurrence occurrence)
  442. {
  443. if (delay >= 0)
  444. {
  445. throw new ChronosException("Memory occurrences must be in the past.");
  446. }
  447. return Schedule(time + delay, repeatable, occurrence);
  448. }
  449. #region Func<T>
  450. public Occurrence Schedule<T>(float time, bool repeatable, ForwardFunc<T> forward, BackwardFunc<T> backward)
  451. {
  452. return Schedule(time, repeatable, new FuncOccurence<T>(forward, backward));
  453. }
  454. public Occurrence Do<T>(bool repeatable, ForwardFunc<T> forward, BackwardFunc<T> backward)
  455. {
  456. return Do(repeatable, new FuncOccurence<T>(forward, backward));
  457. }
  458. public Occurrence Plan<T>(float delay, bool repeatable, ForwardFunc<T> forward, BackwardFunc<T> backward)
  459. {
  460. return Plan(delay, repeatable, new FuncOccurence<T>(forward, backward));
  461. }
  462. public Occurrence Memory<T>(float delay, bool repeatable, ForwardFunc<T> forward, BackwardFunc<T> backward)
  463. {
  464. return Memory(delay, repeatable, new FuncOccurence<T>(forward, backward));
  465. }
  466. #endregion
  467. #region Action
  468. public Occurrence Schedule(float time, bool repeatable, ForwardAction forward, BackwardAction backward)
  469. {
  470. return Schedule(time, repeatable, new ActionOccurence(forward, backward));
  471. }
  472. public Occurrence Do(bool repeatable, ForwardAction forward, BackwardAction backward)
  473. {
  474. return Do(repeatable, new ActionOccurence(forward, backward));
  475. }
  476. public Occurrence Plan(float delay, bool repeatable, ForwardAction forward, BackwardAction backward)
  477. {
  478. return Plan(delay, repeatable, new ActionOccurence(forward, backward));
  479. }
  480. public Occurrence Memory(float delay, bool repeatable, ForwardAction forward, BackwardAction backward)
  481. {
  482. return Memory(delay, repeatable, new ActionOccurence(forward, backward));
  483. }
  484. #endregion
  485. #region Forward Action
  486. public Occurrence Schedule(float time, ForwardAction forward)
  487. {
  488. return Schedule(time, false, new ForwardActionOccurence(forward));
  489. }
  490. public Occurrence Plan(float delay, ForwardAction forward)
  491. {
  492. return Plan(delay, false, new ForwardActionOccurence(forward));
  493. }
  494. public Occurrence Memory(float delay, ForwardAction forward)
  495. {
  496. return Memory(delay, false, new ForwardActionOccurence(forward));
  497. }
  498. #endregion
  499. /// <summary>
  500. /// Removes the specified occurrence from the timeline.
  501. /// </summary>
  502. public void Cancel(Occurrence occurrence)
  503. {
  504. if (!occurrences.Contains(occurrence))
  505. {
  506. throw new ChronosException("Occurrence to cancel not found on timeline.");
  507. }
  508. else
  509. {
  510. if (occurrence == nextForwardOccurrence)
  511. {
  512. nextForwardOccurrence = OccurrenceAfter(occurrence.time, occurrence);
  513. }
  514. if (occurrence == nextBackwardOccurrence)
  515. {
  516. nextBackwardOccurrence = OccurrenceBefore(occurrence.time, occurrence);
  517. }
  518. occurrences.Remove(occurrence);
  519. }
  520. }
  521. /// <summary>
  522. /// Removes the specified occurrence from the timeline and returns true if it is found. Otherwise, returns false.
  523. /// </summary>
  524. public bool TryCancel(Occurrence occurrence)
  525. {
  526. if (!occurrences.Contains(occurrence))
  527. {
  528. return false;
  529. }
  530. else
  531. {
  532. Cancel(occurrence);
  533. return true;
  534. }
  535. }
  536. /// <summary>
  537. /// Change the absolute time in seconds of the specified occurrence on the timeline.
  538. /// </summary>
  539. public void Reschedule(Occurrence occurrence, float time)
  540. {
  541. occurrence.time = time;
  542. PlaceOccurence(occurrence, time);
  543. }
  544. /// <summary>
  545. /// Moves the specified occurrence forward on the timeline by the specified delay in seconds.
  546. /// </summary>
  547. public void Postpone(Occurrence occurrence, float delay)
  548. {
  549. Reschedule(occurrence, time + delay);
  550. }
  551. /// <summary>
  552. /// Moves the specified occurrence backward on the timeline by the specified delay in seconds.
  553. /// </summary>
  554. public void Prepone(Occurrence occurrence, float delay)
  555. {
  556. Reschedule(occurrence, time - delay);
  557. }
  558. #endregion
  559. #region Coroutines
  560. /// <summary>
  561. /// Suspends the coroutine execution for the given amount of seconds. This method should only be used with a yield statement in coroutines.
  562. /// </summary>
  563. public Coroutine WaitForSeconds(float seconds)
  564. {
  565. return StartCoroutine(WaitingForSeconds(seconds));
  566. }
  567. protected IEnumerator WaitingForSeconds(float seconds)
  568. {
  569. float start = time;
  570. while (time < start + seconds)
  571. {
  572. yield return null;
  573. }
  574. }
  575. #endregion
  576. #region Rewinding / Recording
  577. [SerializeField, FormerlySerializedAs("_recordTransform")]
  578. private bool _rewindable = true;
  579. /// <summary>
  580. /// Determines whether the timeline should record support rewind.
  581. /// </summary>
  582. public bool rewindable
  583. {
  584. get { return _rewindable; }
  585. set
  586. {
  587. _rewindable = value;
  588. if (particleSystem != null)
  589. {
  590. CacheComponents();
  591. }
  592. }
  593. }
  594. [SerializeField]
  595. private float _recordingDuration = DefaultRecordingDuration;
  596. /// <summary>
  597. /// The maximum duration in seconds during which snapshots will be recorded. Higher values offer more rewind time but require more memory.
  598. /// </summary>
  599. public float recordingDuration
  600. {
  601. get { return _recordingDuration; }
  602. set
  603. {
  604. _recordingDuration = value;
  605. if (recorder != null)
  606. {
  607. recorder.Reset();
  608. }
  609. }
  610. }
  611. /// <summary>
  612. /// Returns the available rewind duration in seconds.
  613. /// </summary>
  614. public float availableRewindDuration
  615. {
  616. get
  617. {
  618. return transform.availableRewindDuration;
  619. }
  620. }
  621. #endregion
  622. }
  623. }