AnimancerState.cs 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Text;
  6. using UnityEngine;
  7. using UnityEngine.Playables;
  8. using Object = UnityEngine.Object;
  9. #if UNITY_EDITOR
  10. using UnityEditor;
  11. using Animancer.Editor;
  12. #endif
  13. namespace Animancer
  14. {
  15. /// <summary>
  16. /// Base class for all states in an <see cref="AnimancerPlayable"/> graph which manages one or more
  17. /// <see cref="Playable"/>s.
  18. /// </summary>
  19. ///
  20. /// <remarks>
  21. /// This class can be used as a custom yield instruction to wait until the animation either stops playing or
  22. /// reaches its end.
  23. /// <para></para>
  24. /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/playing/states">States</see>
  25. /// </remarks>
  26. /// https://kybernetik.com.au/animancer/api/Animancer/AnimancerState
  27. ///
  28. public abstract partial class AnimancerState : AnimancerNode, IAnimationClipCollection
  29. {
  30. /************************************************************************************************************************/
  31. #region Graph
  32. /************************************************************************************************************************/
  33. /// <summary>The <see cref="AnimancerPlayable"/> at the root of the graph.</summary>
  34. public void SetRoot(AnimancerPlayable root)
  35. {
  36. if (Root == root)
  37. return;
  38. if (Root != null)
  39. {
  40. Root.CancelPreUpdate(this);
  41. Root.States.Unregister(this);
  42. if (_EventDispatcher != null)
  43. Root.CancelPostUpdate(_EventDispatcher);
  44. if (_Parent != null)
  45. {
  46. _Parent.OnRemoveChild(this);
  47. _Parent = null;
  48. }
  49. Index = -1;
  50. DestroyPlayable();
  51. }
  52. Root = root;
  53. if (root != null)
  54. {
  55. #if UNITY_ASSERTIONS
  56. GC.SuppressFinalize(this);
  57. #endif
  58. root.States.Register(this);
  59. if (_EventDispatcher != null)
  60. root.RequirePostUpdate(_EventDispatcher);
  61. CreatePlayable();
  62. }
  63. for (int i = ChildCount - 1; i >= 0; i--)
  64. GetChild(i)?.SetRoot(root);
  65. if (_Parent != null)
  66. CopyIKFlags(_Parent);
  67. }
  68. /************************************************************************************************************************/
  69. private AnimancerNode _Parent;
  70. /// <summary>The object which receives the output of the <see cref="Playable"/>.</summary>
  71. public sealed override IPlayableWrapper Parent => _Parent;
  72. /// <summary>Connects this state to the `parent` mixer at the specified `index`.</summary>
  73. /// <remarks>
  74. /// Use <see cref="AnimancerLayer.AddChild(AnimancerState)"/> instead of this method to connect a state to an
  75. /// available port on a layer.
  76. /// </remarks>
  77. public void SetParent(AnimancerNode parent, int index)
  78. {
  79. if (_Parent != null)
  80. {
  81. _Parent.OnRemoveChild(this);
  82. _Parent = null;
  83. }
  84. if (parent == null)
  85. {
  86. Index = -1;
  87. return;
  88. }
  89. SetRoot(parent.Root);
  90. Index = index;
  91. _Parent = parent;
  92. parent.OnAddChild(this);
  93. CopyIKFlags(parent);
  94. }
  95. /// <summary>[Internal]
  96. /// Called by <see cref="AnimancerNode.OnAddChild(IList{AnimancerState}, AnimancerState)"/> if the specified
  97. /// port is already occupied so it can be cleared without triggering any other calls.
  98. /// </summary>
  99. internal void ClearParent()
  100. {
  101. Index = -1;
  102. _Parent = null;
  103. }
  104. /************************************************************************************************************************/
  105. // Layer.
  106. /************************************************************************************************************************/
  107. /// <inheritdoc/>
  108. public override AnimancerLayer Layer => _Parent?.Layer;
  109. /// <summary>
  110. /// The index of the <see cref="AnimancerLayer"/> this state is connected to (determined by the
  111. /// <see cref="Parent"/>). Returns <c>-1</c> if this state is not connected to a layer.
  112. /// </summary>
  113. public int LayerIndex
  114. {
  115. get
  116. {
  117. if (_Parent == null)
  118. return -1;
  119. var layer = _Parent.Layer;
  120. if (layer == null)
  121. return -1;
  122. return layer.Index;
  123. }
  124. set
  125. {
  126. Root.Layers[value].AddChild(this);
  127. }
  128. }
  129. /************************************************************************************************************************/
  130. #endregion
  131. /************************************************************************************************************************/
  132. #region Key and Clip
  133. /************************************************************************************************************************/
  134. internal object _Key;
  135. /// <summary>
  136. /// The object used to identify this state in the root <see cref="AnimancerPlayable.States"/> dictionary.
  137. /// Can be null.
  138. /// </summary>
  139. public object Key
  140. {
  141. get => _Key;
  142. set
  143. {
  144. if (Root == null)
  145. {
  146. _Key = value;
  147. }
  148. else
  149. {
  150. Root.States.Unregister(this);
  151. _Key = value;
  152. Root.States.Register(this);
  153. }
  154. }
  155. }
  156. /************************************************************************************************************************/
  157. /// <summary>The <see cref="AnimationClip"/> which this state plays (if any).</summary>
  158. /// <exception cref="NotSupportedException">This state type doesn't have a clip and you try to set it.</exception>
  159. public virtual AnimationClip Clip
  160. {
  161. get => null;
  162. set => throw new NotSupportedException($"{GetType()} does not support setting the {nameof(Clip)}.");
  163. }
  164. /// <summary>The main object to show in the Inspector for this state (if any).</summary>
  165. /// <exception cref="NotSupportedException">This state type doesn't have a main object and you try to set it.</exception>
  166. /// <exception cref="InvalidCastException">This state can't use the assigned value.</exception>
  167. public virtual Object MainObject
  168. {
  169. get => null;
  170. set => throw new NotSupportedException($"{GetType()} does not support setting the {nameof(MainObject)}.");
  171. }
  172. /************************************************************************************************************************/
  173. /// <summary>
  174. /// Sets the `currentObject` and calls <see cref="AnimancerNode.RecreatePlayable"/>. If the `currentObject` was
  175. /// being used as the <see cref="Key"/> then it is changed as well.
  176. /// </summary>
  177. /// <exception cref="ArgumentNullException">The `newObject` is null.</exception>
  178. protected void ChangeMainObject<T>(ref T currentObject, T newObject) where T : Object
  179. {
  180. if (newObject == null)
  181. throw new ArgumentNullException(nameof(newObject));
  182. if (ReferenceEquals(currentObject, newObject))
  183. return;
  184. if (ReferenceEquals(_Key, currentObject))
  185. Key = newObject;
  186. currentObject = newObject;
  187. RecreatePlayable();
  188. }
  189. /************************************************************************************************************************/
  190. /// <summary>The average velocity of the root motion caused by this state.</summary>
  191. public virtual Vector3 AverageVelocity => default;
  192. /************************************************************************************************************************/
  193. #endregion
  194. /************************************************************************************************************************/
  195. #region Playing
  196. /************************************************************************************************************************/
  197. /// <summary>Is the <see cref="Time"/> automatically advancing?</summary>
  198. private bool _IsPlaying;
  199. /// <summary>Has <see cref="_IsPlaying"/> changed since it was last applied to the <see cref="Playable"/>.</summary>
  200. /// <remarks>
  201. /// Playables start playing by default so we start dirty to pause it during the first update (unless
  202. /// <see cref="IsPlaying"/> is set to true before that).
  203. /// </remarks>
  204. private bool _IsPlayingDirty = true;
  205. /************************************************************************************************************************/
  206. /// <summary>Is the <see cref="Time"/> automatically advancing?</summary>
  207. ///
  208. /// <example><code>
  209. /// void IsPlayingExample(AnimancerComponent animancer, AnimationClip clip)
  210. /// {
  211. /// var state = animancer.States.GetOrCreate(clip);
  212. ///
  213. /// if (state.IsPlaying)
  214. /// Debug.Log(clip + " is playing");
  215. /// else
  216. /// Debug.Log(clip + " is paused");
  217. ///
  218. /// state.IsPlaying = false;// Pause the animation.
  219. ///
  220. /// state.IsPlaying = true;// Unpause the animation.
  221. /// }
  222. /// </code></example>
  223. public bool IsPlaying
  224. {
  225. get => _IsPlaying;
  226. set
  227. {
  228. if (_IsPlaying == value)
  229. return;
  230. _IsPlaying = value;
  231. // If it was already dirty then we just returned to the previous state so it is no longer dirty.
  232. if (_IsPlayingDirty)
  233. {
  234. _IsPlayingDirty = false;
  235. // We may still need to be updated for other reasons (such as Weight),
  236. // but if not then we will be removed from the update list next update.
  237. }
  238. else// Otherwise we are now dirty so we need to be updated.
  239. {
  240. _IsPlayingDirty = true;
  241. RequireUpdate();
  242. }
  243. OnSetIsPlaying();
  244. }
  245. }
  246. /// <summary>Called when the value of <see cref="IsPlaying"/> is changed.</summary>
  247. protected virtual void OnSetIsPlaying() { }
  248. /// <summary>Creates and assigns the <see cref="Playable"/> managed by this state.</summary>
  249. /// <remarks>This method also applies the <see cref="AnimancerNode.Speed"/> and <see cref="IsPlaying"/>.</remarks>
  250. public sealed override void CreatePlayable()
  251. {
  252. base.CreatePlayable();
  253. if (_MustSetTime)
  254. {
  255. _MustSetTime = false;
  256. RawTime = _Time;
  257. }
  258. if (!_IsPlaying)
  259. _Playable.Pause();
  260. _IsPlayingDirty = false;
  261. }
  262. /************************************************************************************************************************/
  263. /// <summary>
  264. /// Returns true if this state is playing and is at or fading towards a non-zero
  265. /// <see cref="AnimancerNode.Weight"/>.
  266. /// </summary>
  267. public bool IsActive => _IsPlaying && TargetWeight > 0;
  268. /// <summary>
  269. /// Returns true if this state is not playing and is at 0 <see cref="AnimancerNode.Weight"/>.
  270. /// </summary>
  271. public bool IsStopped => !_IsPlaying && Weight == 0;
  272. /************************************************************************************************************************/
  273. /// <summary>Plays this state immediately, without any blending.</summary>
  274. /// <remarks>
  275. /// Sets <see cref="IsPlaying"/> = true, <see cref="AnimancerNode.Weight"/> = 1, and clears the
  276. /// <see cref="Events"/> (unless <see cref="AutomaticallyClearEvents"/> is disabled).
  277. /// <para></para>
  278. /// This method does not change the <see cref="Time"/> so it will continue from its current value.
  279. /// </remarks>
  280. public void Play()
  281. {
  282. IsPlaying = true;
  283. Weight = 1;
  284. if (AutomaticallyClearEvents)
  285. EventDispatcher.TryClear(_EventDispatcher);
  286. }
  287. /************************************************************************************************************************/
  288. /// <summary>Stops the animation and makes it inactive immediately so it no longer affects the output.</summary>
  289. /// <remarks>
  290. /// Sets <see cref="AnimancerNode.Weight"/> = 0, <see cref="IsPlaying"/> = false, <see cref="Time"/> = 0, and
  291. /// clears the <see cref="Events"/> (unless <see cref="AutomaticallyClearEvents"/> is disabled).
  292. /// <para></para>
  293. /// To freeze the animation in place without ending it, you only need to set <see cref="IsPlaying"/> = false
  294. /// instead. Or to freeze all animations, you can call <see cref="AnimancerPlayable.PauseGraph"/>.
  295. /// </remarks>
  296. public override void Stop()
  297. {
  298. base.Stop();
  299. IsPlaying = false;
  300. Time = 0;
  301. if (AutomaticallyClearEvents)
  302. EventDispatcher.TryClear(_EventDispatcher);
  303. }
  304. /************************************************************************************************************************/
  305. /// <summary>
  306. /// Called by <see cref="AnimancerNode.StartFade(float, float)"/>.
  307. /// Clears the <see cref="Events"/> (unless <see cref="AutomaticallyClearEvents"/> is disabled).
  308. /// </summary>
  309. protected internal override void OnStartFade()
  310. {
  311. if (AutomaticallyClearEvents)
  312. EventDispatcher.TryClear(_EventDispatcher);
  313. }
  314. /************************************************************************************************************************/
  315. #endregion
  316. /************************************************************************************************************************/
  317. #region Timing
  318. /************************************************************************************************************************/
  319. // Time.
  320. /************************************************************************************************************************/
  321. /// <summary>
  322. /// The current time of the <see cref="Playable"/>, retrieved by <see cref="Time"/> whenever the
  323. /// <see cref="_TimeFrameID"/> is different from the <see cref="AnimancerPlayable.FrameID"/>.
  324. /// </summary>
  325. private float _Time;
  326. /// <summary>
  327. /// Indicates whether the <see cref="_Time"/> needs to be assigned to the <see cref="Playable"/> next update.
  328. /// </summary>
  329. /// <remarks>
  330. /// <see cref="EventDispatcher"/> executes after all other playables, at which point changes can still be made to
  331. /// their time but not their weight which means that if we set the time immediately then it can be out of sync
  332. /// with the weight. For example, if an animation ends and you play another, the first animation would be
  333. /// stopped and rewinded to the start but would still be at full weight so it would show its first frame before
  334. /// the new animation actually takes effect (even if the previous animation was not looping).
  335. /// <para></para>
  336. /// So instead, we simply delay setting the actual playable time until the next update so that time and weight
  337. /// are always in sync.
  338. /// </remarks>
  339. private bool _MustSetTime;
  340. /// <summary>
  341. /// The <see cref="AnimancerPlayable.FrameID"/> from when the <see cref="Time"/> was last retrieved from the
  342. /// <see cref="Playable"/>.
  343. /// </summary>
  344. private ulong _TimeFrameID;
  345. /************************************************************************************************************************/
  346. /// <summary>The number of seconds that have passed since the start of this animation.</summary>
  347. ///
  348. /// <remarks>
  349. /// This value will continue increasing after the animation passes the end of its <see cref="Length"/> while
  350. /// the animated object either freezes in place or starts again from the beginning according to whether it is
  351. /// looping or not.
  352. /// <para></para>
  353. /// This property internally uses <see cref="RawTime"/> whenever the value is out of date or gets changed.
  354. /// <para></para>
  355. /// <em>Animancer Lite does not allow this value to be changed in runtime builds (except resetting it to 0).</em>
  356. /// </remarks>
  357. ///
  358. /// <example><code>
  359. /// void PlayAnimation(AnimancerComponent animancer, AnimationClip clip)
  360. /// {
  361. /// var state = animancer.Play(clip);
  362. ///
  363. /// // Skip 0.5 seconds into the animation:
  364. /// state.Time = 0.5f;
  365. ///
  366. /// // Skip 50% of the way through the animation (0.5 in a range of 0 to 1):
  367. /// state.NormalizedTime = 0.5f;
  368. ///
  369. /// // Skip to the end of the animation and play backwards.
  370. /// state.NormalizedTime = 1;
  371. /// state.Speed = -1;
  372. /// }
  373. /// </code></example>
  374. public float Time
  375. {
  376. get
  377. {
  378. var root = Root;
  379. if (root == null || _MustSetTime)
  380. return _Time;
  381. var frameID = root.FrameID;
  382. if (_TimeFrameID != frameID)
  383. {
  384. _TimeFrameID = frameID;
  385. _Time = RawTime;
  386. }
  387. return _Time;
  388. }
  389. set
  390. {
  391. #if UNITY_ASSERTIONS
  392. if (!value.IsFinite())
  393. throw new ArgumentOutOfRangeException(nameof(value), value, $"{nameof(Time)} {Strings.MustBeFinite}");
  394. #endif
  395. _Time = value;
  396. var root = Root;
  397. if (root == null)
  398. {
  399. _MustSetTime = true;
  400. }
  401. else
  402. {
  403. _TimeFrameID = root.FrameID;
  404. // Don't allow the time to be changed during a post update because it would take effect this frame but
  405. // Weight changes wouldn't so the Time and Weight would be out of sync. For example, if en event plays
  406. // a state, the old state's Time would be 0 but its Weight would not yet be 0 so it would show its
  407. // first frame before the new animation takes effect.
  408. if (AnimancerPlayable.IsRunningPostUpdate(root))
  409. {
  410. _MustSetTime = true;
  411. root.RequirePreUpdate(this);
  412. }
  413. else
  414. {
  415. RawTime = value;
  416. }
  417. }
  418. _EventDispatcher?.OnTimeChanged();
  419. }
  420. }
  421. /************************************************************************************************************************/
  422. /// <summary>
  423. /// The internal implementation of <see cref="Time"/> which directly gets and sets the underlying value.
  424. /// </summary>
  425. /// <remarks>
  426. /// Setting this value actually calls <see cref="PlayableExtensions.SetTime"/> twice to ensure that animation
  427. /// events aren't triggered incorrectly. Calling it only once would trigger any animation events between the
  428. /// previous time and the new time. So if an animation plays to the end and you set the time back to 0 (such as
  429. /// by calling <see cref="Stop"/> or playing a different animation), the next time that animation played it
  430. /// would immediately trigger all of its events, then play through and trigger them normally as well.
  431. /// </remarks>
  432. protected virtual float RawTime
  433. {
  434. get
  435. {
  436. Validate.AssertPlayable(this);
  437. return (float)_Playable.GetTime();
  438. }
  439. set
  440. {
  441. Validate.AssertPlayable(this);
  442. var time = (double)value;
  443. _Playable.SetTime(time);
  444. _Playable.SetTime(time);
  445. }
  446. }
  447. /************************************************************************************************************************/
  448. /// <summary>
  449. /// The <see cref="Time"/> of this state as a portion of the animation's <see cref="Length"/>, meaning the
  450. /// value goes from 0 to 1 as it plays from start to end, regardless of how long that actually takes.
  451. /// </summary>
  452. ///
  453. /// <remarks>
  454. /// This value will continue increasing after the animation passes the end of its <see cref="Length"/> while
  455. /// the animated object either freezes in place or starts again from the beginning according to whether it is
  456. /// looping or not.
  457. /// <para></para>
  458. /// The fractional part of the value (<c>NormalizedTime % 1</c>) is the percentage (0-1) of progress in the
  459. /// current loop while the integer part (<c>(int)NormalizedTime</c>) is the number of times the animation has
  460. /// been looped.
  461. /// <para></para>
  462. /// <em>Animancer Lite does not allow this value to be changed to a value other than 0 in runtime builds.</em>
  463. /// </remarks>
  464. ///
  465. /// <example><code>
  466. /// void PlayAnimation(AnimancerComponent animancer, AnimationClip clip)
  467. /// {
  468. /// var state = animancer.Play(clip);
  469. ///
  470. /// // Skip 0.5 seconds into the animation:
  471. /// state.Time = 0.5f;
  472. ///
  473. /// // Skip 50% of the way through the animation (0.5 in a range of 0 to 1):
  474. /// state.NormalizedTime = 0.5f;
  475. ///
  476. /// // Skip to the end of the animation and play backwards.
  477. /// state.NormalizedTime = 1;
  478. /// state.Speed = -1;
  479. /// }
  480. /// </code></example>
  481. public float NormalizedTime
  482. {
  483. get
  484. {
  485. var length = Length;
  486. if (length != 0)
  487. return Time / Length;
  488. else
  489. return 0;
  490. }
  491. set => Time = value * Length;
  492. }
  493. /************************************************************************************************************************/
  494. /// <summary>
  495. /// Sets the <see cref="Time"/> or <see cref="NormalizedTime"/>, but unlike those properties this method
  496. /// applies any Root Motion and Animation Events (but not Animancer Events) between the old and new time.
  497. /// </summary>
  498. public virtual void MoveTime(float time, bool normalized)
  499. {
  500. #if UNITY_ASSERTIONS
  501. if (!time.IsFinite())
  502. throw new ArgumentOutOfRangeException(nameof(time), time, $"{nameof(Time)} {Strings.MustBeFinite}");
  503. #endif
  504. var root = Root;
  505. if (root != null)
  506. _TimeFrameID = root.FrameID;
  507. if (normalized)
  508. time *= Length;
  509. _Time = time;
  510. _Playable.SetTime(time);
  511. }
  512. /************************************************************************************************************************/
  513. /// <summary>Prevents the <see cref="RawTime"/> from being applied.</summary>
  514. protected void CancelSetTime() => _MustSetTime = false;
  515. /************************************************************************************************************************/
  516. // Duration.
  517. /************************************************************************************************************************/
  518. /// <summary>[Pro-Only]
  519. /// The <see cref="NormalizedTime"/> after which the <see cref="AnimancerEvent.Sequence.OnEnd"/> callback will
  520. /// be invoked every frame.
  521. /// </summary>
  522. /// <remarks>
  523. /// This is a wrapper around <see cref="AnimancerEvent.Sequence.NormalizedEndTime"/> so that if the value has
  524. /// not been set (<see cref="float.NaN"/>) it can be determined based on the
  525. /// <see cref="AnimancerNode.EffectiveSpeed"/>: positive speed ends at 1 and negative speed ends at 0.
  526. /// <para></para>
  527. /// <em>Animancer Lite does not allow this value to be changed in runtime builds.</em>
  528. /// </remarks>
  529. public float NormalizedEndTime
  530. {
  531. get
  532. {
  533. if (_EventDispatcher != null)
  534. {
  535. var time = _EventDispatcher.Events.NormalizedEndTime;
  536. if (!float.IsNaN(time))
  537. return time;
  538. }
  539. return AnimancerEvent.Sequence.GetDefaultNormalizedEndTime(EffectiveSpeed);
  540. }
  541. set => Events.NormalizedEndTime = value;
  542. }
  543. /************************************************************************************************************************/
  544. /// <summary>
  545. /// The number of seconds the animation will take to play fully at its current
  546. /// <see cref="AnimancerNode.EffectiveSpeed"/>.
  547. /// </summary>
  548. ///
  549. /// <remarks>
  550. /// For the time remaining from now until it reaches the end, use <see cref="RemainingDuration"/> instead.
  551. /// <para></para>
  552. /// Setting this value modifies the <see cref="AnimancerNode.EffectiveSpeed"/>, not the <see cref="Length"/>.
  553. /// <para></para>
  554. /// <em>Animancer Lite does not allow this value to be changed in runtime builds.</em>
  555. /// </remarks>
  556. ///
  557. /// <example><code>
  558. /// void PlayAnimation(AnimancerComponent animancer, AnimationClip clip)
  559. /// {
  560. /// var state = animancer.Play(clip);
  561. ///
  562. /// state.Duration = 1;// Play fully in 1 second.
  563. /// state.Duration = 2;// Play fully in 2 seconds.
  564. /// state.Duration = 0.5f;// Play fully in half a second.
  565. /// state.Duration = -1;// Play backwards fully in 1 second.
  566. /// state.NormalizedTime = 1; state.Duration = -1;// Play backwards from the end in 1 second.
  567. /// }
  568. /// </code></example>
  569. public float Duration
  570. {
  571. get
  572. {
  573. var speed = EffectiveSpeed;
  574. if (_EventDispatcher != null)
  575. {
  576. var endTime = _EventDispatcher.Events.NormalizedEndTime;
  577. if (!float.IsNaN(endTime))
  578. {
  579. if (speed > 0)
  580. return Length * endTime / speed;
  581. else
  582. return Length * (1 - endTime) / -speed;
  583. }
  584. }
  585. return Length / Math.Abs(speed);
  586. }
  587. set
  588. {
  589. var length = Length;
  590. if (_EventDispatcher != null)
  591. {
  592. var endTime = _EventDispatcher.Events.NormalizedEndTime;
  593. if (!float.IsNaN(endTime))
  594. {
  595. if (EffectiveSpeed > 0)
  596. length *= endTime;
  597. else
  598. length *= 1 - endTime;
  599. }
  600. }
  601. EffectiveSpeed = length / value;
  602. }
  603. }
  604. /************************************************************************************************************************/
  605. /// <summary>
  606. /// The number of seconds this state will take to go from its current <see cref="NormalizedTime"/> to the
  607. /// <see cref="NormalizedEndTime"/> at its current <see cref="AnimancerNode.EffectiveSpeed"/>.
  608. /// </summary>
  609. ///
  610. /// <remarks>
  611. /// For the time it would take to play fully from the start, use the <see cref="Duration"/> instead.
  612. /// <para></para>
  613. /// Setting this value modifies the <see cref="AnimancerNode.EffectiveSpeed"/>, not the <see cref="Length"/>.
  614. /// <para></para>
  615. /// <em>Animancer Lite does not allow this value to be changed in runtime builds.</em>
  616. /// </remarks>
  617. ///
  618. /// <example><code>
  619. /// void PlayAnimation(AnimancerComponent animancer, AnimationClip clip)
  620. /// {
  621. /// var state = animancer.Play(clip);
  622. ///
  623. /// state.RemainingDuration = 1;// Play from the current time to the end in 1 second.
  624. /// state.RemainingDuration = 2;// Play from the current time to the end in 2 seconds.
  625. /// state.RemainingDuration = 0.5f;// Play from the current time to the end in half a second.
  626. /// state.RemainingDuration = -1;// Play from the current time away from the end.
  627. /// }
  628. /// </code></example>
  629. public float RemainingDuration
  630. {
  631. get => (Length * NormalizedEndTime - Time) / EffectiveSpeed;
  632. set => EffectiveSpeed = (Length * NormalizedEndTime - Time) / value;
  633. }
  634. /************************************************************************************************************************/
  635. // Length.
  636. /************************************************************************************************************************/
  637. /// <summary>The total time this state would take to play in seconds when <see cref="AnimancerNode.Speed"/> = 1.</summary>
  638. public abstract float Length { get; }
  639. /// <summary>Will this state loop back to the start when it reaches the end?</summary>
  640. public virtual bool IsLooping => false;
  641. /************************************************************************************************************************/
  642. #endregion
  643. /************************************************************************************************************************/
  644. #region Methods
  645. /************************************************************************************************************************/
  646. /// <summary>
  647. /// Updates the <see cref="AnimancerNode.Weight"/> for fading, applies it to this state's port on the parent
  648. /// mixer, and plays or pauses the <see cref="Playable"/> if its state is dirty.
  649. /// </summary>
  650. /// <remarks>
  651. /// If the <see cref="Parent"/>'s <see cref="AnimancerNode.KeepChildrenConnected"/> is set to false, this
  652. /// method will also connect/disconnect this node from the <see cref="Parent"/> in the playable graph.
  653. /// </remarks>
  654. protected internal override void Update(out bool needsMoreUpdates)
  655. {
  656. base.Update(out needsMoreUpdates);
  657. if (_IsPlayingDirty)
  658. {
  659. _IsPlayingDirty = false;
  660. if (_IsPlaying)
  661. _Playable.Play();
  662. else
  663. _Playable.Pause();
  664. }
  665. if (_MustSetTime)
  666. {
  667. _MustSetTime = false;
  668. RawTime = _Time;
  669. }
  670. }
  671. /************************************************************************************************************************/
  672. /// <summary>Destroys the <see cref="Playable"/> and cleans up this state.</summary>
  673. /// <remarks>
  674. /// This method is NOT called automatically, so when implementing a custom state type you must use
  675. /// <see cref="AnimancerPlayable.Disposables"/> if you need to guarantee that things will get cleaned up.
  676. /// </remarks>
  677. public virtual void Destroy()
  678. {
  679. if (_Parent != null)
  680. {
  681. _Parent.OnRemoveChild(this);
  682. _Parent = null;
  683. }
  684. Index = -1;
  685. EventDispatcher.TryClear(_EventDispatcher);
  686. var root = Root;
  687. if (root != null)
  688. {
  689. root.States.Unregister(this);
  690. // For some reason this is slightly faster than _Playable.Destroy().
  691. if (_Playable.IsValid())
  692. root._Graph.DestroyPlayable(_Playable);
  693. }
  694. }
  695. /************************************************************************************************************************/
  696. /// <summary>[<see cref="IAnimationClipCollection"/>] Gathers all the animations in this state.</summary>
  697. public virtual void GatherAnimationClips(ICollection<AnimationClip> clips)
  698. {
  699. clips.Gather(Clip);
  700. for (int i = ChildCount - 1; i >= 0; i--)
  701. GetChild(i).GatherAnimationClips(clips);
  702. }
  703. /************************************************************************************************************************/
  704. /// <summary>
  705. /// Returns true if the animation is playing and has not yet passed the
  706. /// <see cref="AnimancerEvent.Sequence.EndEvent"/>.
  707. /// </summary>
  708. /// <remarks>
  709. /// This method is called by <see cref="IEnumerator.MoveNext"/> so this object can be used as a custom yield
  710. /// instruction to wait until it finishes.
  711. /// </remarks>
  712. protected internal override bool IsPlayingAndNotEnding()
  713. {
  714. if (!IsPlaying)
  715. return false;
  716. var speed = EffectiveSpeed;
  717. if (speed > 0)
  718. {
  719. float endTime;
  720. if (_EventDispatcher != null)
  721. {
  722. endTime = _EventDispatcher.Events.NormalizedEndTime;
  723. if (float.IsNaN(endTime))
  724. endTime = Length;
  725. else
  726. endTime *= Length;
  727. }
  728. else endTime = Length;
  729. return Time <= endTime;
  730. }
  731. else if (speed < 0)
  732. {
  733. float endTime;
  734. if (_EventDispatcher != null)
  735. {
  736. endTime = _EventDispatcher.Events.NormalizedEndTime;
  737. if (float.IsNaN(endTime))
  738. endTime = 0;
  739. else
  740. endTime *= Length;
  741. }
  742. else endTime = 0;
  743. return Time >= endTime;
  744. }
  745. else return true;
  746. }
  747. /************************************************************************************************************************/
  748. /// <summary>
  749. /// Returns the <see cref="AnimancerNode.DebugName"/> if one is set, otherwise a string describing the type of this
  750. /// state and the name of the <see cref="MainObject"/>.
  751. /// </summary>
  752. public override string ToString()
  753. {
  754. #if UNITY_ASSERTIONS
  755. if (!string.IsNullOrEmpty(DebugName))
  756. return DebugName;
  757. #endif
  758. var type = GetType().Name;
  759. var mainObject = MainObject;
  760. if (mainObject != null)
  761. return $"{mainObject.name} ({type})";
  762. else
  763. return type;
  764. }
  765. /************************************************************************************************************************/
  766. #region Descriptions
  767. /************************************************************************************************************************/
  768. #if UNITY_EDITOR
  769. /// <summary>[Editor-Only] Returns a custom drawer for this state.</summary>
  770. protected internal virtual IAnimancerNodeDrawer CreateDrawer()
  771. => new AnimancerStateDrawer<AnimancerState>(this);
  772. #endif
  773. /************************************************************************************************************************/
  774. /// <inheritdoc/>
  775. protected override void AppendDetails(StringBuilder text, string separator)
  776. {
  777. text.Append(separator).Append($"{nameof(Key)}: ").Append(AnimancerUtilities.ToStringOrNull(_Key));
  778. var mainObject = MainObject;
  779. if (mainObject != _Key as Object)
  780. text.Append(separator).Append($"{nameof(MainObject)}: ").Append(AnimancerUtilities.ToStringOrNull(mainObject));
  781. #if UNITY_EDITOR
  782. if (mainObject != null)
  783. text.Append(separator).Append("AssetPath: ").Append(AssetDatabase.GetAssetPath(mainObject));
  784. #endif
  785. base.AppendDetails(text, separator);
  786. text.Append(separator).Append($"{nameof(IsPlaying)}: ").Append(IsPlaying);
  787. try
  788. {
  789. text.Append(separator).Append($"{nameof(Time)} (Normalized): ").Append(Time);
  790. text.Append(" (").Append(NormalizedTime).Append(')');
  791. text.Append(separator).Append($"{nameof(Length)}: ").Append(Length);
  792. text.Append(separator).Append($"{nameof(IsLooping)}: ").Append(IsLooping);
  793. }
  794. catch (Exception exception)
  795. {
  796. text.Append(separator).Append(exception);
  797. }
  798. text.Append(separator).Append($"{nameof(Events)}: ");
  799. if (_EventDispatcher != null && _EventDispatcher.Events != null)
  800. text.Append(_EventDispatcher.Events.DeepToString(false));
  801. else
  802. text.Append("null");
  803. }
  804. /************************************************************************************************************************/
  805. /// <summary>Returns the hierarchy path of this state through its <see cref="Parent"/>s.</summary>
  806. public string GetPath()
  807. {
  808. if (_Parent == null)
  809. return null;
  810. var path = ObjectPool.AcquireStringBuilder();
  811. AppendPath(path, _Parent);
  812. AppendPortAndType(path);
  813. return path.ReleaseToString();
  814. }
  815. /// <summary>Appends the hierarchy path of this state through its <see cref="Parent"/>s.</summary>
  816. private static void AppendPath(StringBuilder path, AnimancerNode parent)
  817. {
  818. var parentState = parent as AnimancerState;
  819. if (parentState != null && parentState._Parent != null)
  820. {
  821. AppendPath(path, parentState._Parent);
  822. }
  823. else
  824. {
  825. path.Append("Layers[")
  826. .Append(parent.Layer.Index)
  827. .Append("].States");
  828. return;
  829. }
  830. var state = parent as AnimancerState;
  831. if (state != null)
  832. {
  833. state.AppendPortAndType(path);
  834. }
  835. else
  836. {
  837. path.Append(" -> ")
  838. .Append(parent.GetType());
  839. }
  840. }
  841. /// <summary>Appends "[Index] -> GetType().Name".</summary>
  842. private void AppendPortAndType(StringBuilder path)
  843. {
  844. path.Append('[')
  845. .Append(Index)
  846. .Append("] -> ")
  847. .Append(GetType().Name);
  848. }
  849. /************************************************************************************************************************/
  850. #endregion
  851. /************************************************************************************************************************/
  852. #endregion
  853. /************************************************************************************************************************/
  854. }
  855. }