AnimancerLayer.cs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  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.Animations;
  8. using UnityEngine.Playables;
  9. namespace Animancer
  10. {
  11. /// <summary>
  12. /// A layer on which animations can play with their states managed independantly of other layers while blending the
  13. /// output with those layers.
  14. /// </summary>
  15. ///
  16. /// <remarks>
  17. /// This class can be used as a custom yield instruction to wait until all animations finish playing.
  18. /// <para></para>
  19. /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/blending/layers">Layers</see>
  20. /// </remarks>
  21. /// https://kybernetik.com.au/animancer/api/Animancer/AnimancerLayer
  22. ///
  23. public sealed class AnimancerLayer : AnimancerNode, IAnimationClipCollection
  24. {
  25. /************************************************************************************************************************/
  26. #region Fields and Properties
  27. /************************************************************************************************************************/
  28. /// <summary>[Internal] Creates a new <see cref="AnimancerLayer"/>.</summary>
  29. internal AnimancerLayer(AnimancerPlayable root, int index)
  30. {
  31. #if UNITY_ASSERTIONS
  32. GC.SuppressFinalize(this);
  33. #endif
  34. Root = root;
  35. Index = index;
  36. CreatePlayable();
  37. if (ApplyParentAnimatorIK)
  38. _ApplyAnimatorIK = root.ApplyAnimatorIK;
  39. if (ApplyParentFootIK)
  40. _ApplyFootIK = root.ApplyFootIK;
  41. }
  42. /************************************************************************************************************************/
  43. /// <summary>Creates and assigns the <see cref="AnimationMixerPlayable"/> managed by this layer.</summary>
  44. protected override void CreatePlayable(out Playable playable)
  45. => playable = AnimationMixerPlayable.Create(Root._Graph);
  46. /************************************************************************************************************************/
  47. /// <summary>A layer is its own root.</summary>
  48. public override AnimancerLayer Layer => this;
  49. /// <summary>The <see cref="AnimancerNode.Root"/> receives the output of the <see cref="Playable"/>.</summary>
  50. public override IPlayableWrapper Parent => Root;
  51. /// <summary>Indicates whether child playables should stay connected to this layer at all times.</summary>
  52. public override bool KeepChildrenConnected => Root.KeepChildrenConnected;
  53. /************************************************************************************************************************/
  54. /// <summary>All of the animation states connected to this layer.</summary>
  55. private readonly List<AnimancerState> States = new List<AnimancerState>();
  56. /************************************************************************************************************************/
  57. private AnimancerState _CurrentState;
  58. /// <summary>The state of the animation currently being played.</summary>
  59. /// <remarks>
  60. /// Specifically, this is the state that was most recently started using any of the Play or CrossFade methods
  61. /// on this layer. States controlled individually via methods in the <see cref="AnimancerState"/> itself will
  62. /// not register in this property.
  63. /// <para></para>
  64. /// Each time this property changes, the <see cref="CommandCount"/> is incremented.
  65. /// </remarks>
  66. public AnimancerState CurrentState
  67. {
  68. get => _CurrentState;
  69. private set
  70. {
  71. _CurrentState = value;
  72. CommandCount++;
  73. }
  74. }
  75. /// <summary>
  76. /// The number of times the <see cref="CurrentState"/> has changed. By storing this value and later comparing
  77. /// the stored value to the current value, you can determine whether the state has been changed since then,
  78. /// even it has changed back to the same state.
  79. /// </summary>
  80. public int CommandCount { get; private set; }
  81. #if UNITY_EDITOR
  82. /// <summary>[Editor-Only] [Internal] Increases the <see cref="CommandCount"/> by 1.</summary>
  83. internal void IncrementCommandCount() => CommandCount++;
  84. #endif
  85. /************************************************************************************************************************/
  86. /// <summary>[Pro-Only]
  87. /// Determines whether this layer is set to additive blending. Otherwise it will override any earlier layers.
  88. /// </summary>
  89. public bool IsAdditive
  90. {
  91. get => Root.Layers.IsAdditive(Index);
  92. set => Root.Layers.SetAdditive(Index, value);
  93. }
  94. /************************************************************************************************************************/
  95. /// <summary>[Pro-Only]
  96. /// Sets an <see cref="AvatarMask"/> to determine which bones this layer will affect.
  97. /// </summary>
  98. public void SetMask(AvatarMask mask)
  99. {
  100. Root.Layers.SetMask(Index, mask);
  101. }
  102. #if UNITY_ASSERTIONS
  103. /// <summary>[Assert-Only] The <see cref="AvatarMask"/> that determines which bones this layer will affect.</summary>
  104. internal AvatarMask _Mask;
  105. #endif
  106. /************************************************************************************************************************/
  107. /// <summary>
  108. /// The average velocity of the root motion of all currently playing animations, taking their current
  109. /// <see cref="AnimancerNode.Weight"/> into account.
  110. /// </summary>
  111. public Vector3 AverageVelocity
  112. {
  113. get
  114. {
  115. var velocity = default(Vector3);
  116. for (int i = States.Count - 1; i >= 0; i--)
  117. {
  118. var state = States[i];
  119. velocity += state.AverageVelocity * state.Weight;
  120. }
  121. return velocity;
  122. }
  123. }
  124. /************************************************************************************************************************/
  125. #endregion
  126. /************************************************************************************************************************/
  127. #region Child States
  128. /************************************************************************************************************************/
  129. /// <inheritdoc/>
  130. public override int ChildCount => States.Count;
  131. /// <summary>Returns the state connected to the specified `index` as a child of this layer.</summary>
  132. /// <remarks>This method is identical to <see cref="this[int]"/>.</remarks>
  133. public override AnimancerState GetChild(int index) => States[index];
  134. /// <summary>Returns the state connected to the specified `index` as a child of this layer.</summary>
  135. /// <remarks>This indexer is identical to <see cref="GetChild(int)"/>.</remarks>
  136. public AnimancerState this[int index] => States[index];
  137. /************************************************************************************************************************/
  138. /// <summary>Adds a new port and uses <see cref="AnimancerState.SetParent"/> to connect the `state` to it.</summary>
  139. public void AddChild(AnimancerState state)
  140. {
  141. if (state.Parent == this)
  142. return;
  143. // Set the root before expanding the States list in case it throws an exception.
  144. state.SetRoot(Root);
  145. var index = States.Count;
  146. States.Add(null);// OnAddChild will assign the state.
  147. _Playable.SetInputCount(index + 1);
  148. state.SetParent(this, index);
  149. }
  150. /************************************************************************************************************************/
  151. /// <summary>Connects the `state` to this layer at its <see cref="AnimancerNode.Index"/>.</summary>
  152. protected internal override void OnAddChild(AnimancerState state) => OnAddChild(States, state);
  153. /************************************************************************************************************************/
  154. /// <summary>Disconnects the `state` from this layer at its <see cref="AnimancerNode.Index"/>.</summary>
  155. protected internal override void OnRemoveChild(AnimancerState state)
  156. {
  157. var index = state.Index;
  158. Validate.AssertCanRemoveChild(state, States);
  159. if (_Playable.GetInput(index).IsValid())
  160. Root._Graph.Disconnect(_Playable, index);
  161. // Swap the last state into the place of the one that was just removed.
  162. var last = States.Count - 1;
  163. if (index < last)
  164. {
  165. state = States[last];
  166. state.DisconnectFromGraph();
  167. States[index] = state;
  168. state.Index = index;
  169. if (state.Weight != 0 || Root.KeepChildrenConnected)
  170. state.ConnectToGraph();
  171. }
  172. States.RemoveAt(last);
  173. _Playable.SetInputCount(last);
  174. }
  175. /************************************************************************************************************************/
  176. /// <inheritdoc/>
  177. public override FastEnumerator<AnimancerState> GetEnumerator()
  178. => new FastEnumerator<AnimancerState>(States);
  179. /************************************************************************************************************************/
  180. #endregion
  181. /************************************************************************************************************************/
  182. #region Create State
  183. /************************************************************************************************************************/
  184. /// <summary>Creates and returns a new <see cref="ClipState"/> to play the `clip`.</summary>
  185. /// <remarks>
  186. /// <see cref="AnimancerPlayable.GetKey"/> is used to determine the <see cref="AnimancerState.Key"/>.
  187. /// </remarks>
  188. public ClipState CreateState(AnimationClip clip) => CreateState(Root.GetKey(clip), clip);
  189. /// <summary>
  190. /// Creates and returns a new <see cref="ClipState"/> to play the `clip` and registers it with the `key`.
  191. /// </summary>
  192. public ClipState CreateState(object key, AnimationClip clip)
  193. {
  194. var state = new ClipState(clip)
  195. {
  196. _Key = key,
  197. };
  198. AddChild(state);
  199. return state;
  200. }
  201. /************************************************************************************************************************/
  202. /// <summary>
  203. /// Calls <see cref="GetOrCreateState(AnimationClip, bool)"/> for each of the specified clips.
  204. /// <para></para>
  205. /// If you only want to create a single state, use <see cref="CreateState(AnimationClip)"/>.
  206. /// </summary>
  207. public void CreateIfNew(AnimationClip clip0, AnimationClip clip1)
  208. {
  209. GetOrCreateState(clip0);
  210. GetOrCreateState(clip1);
  211. }
  212. /// <summary>
  213. /// Calls <see cref="GetOrCreateState(AnimationClip, bool)"/> for each of the specified clips.
  214. /// <para></para>
  215. /// If you only want to create a single state, use <see cref="CreateState(AnimationClip)"/>.
  216. /// </summary>
  217. public void CreateIfNew(AnimationClip clip0, AnimationClip clip1, AnimationClip clip2)
  218. {
  219. GetOrCreateState(clip0);
  220. GetOrCreateState(clip1);
  221. GetOrCreateState(clip2);
  222. }
  223. /// <summary>
  224. /// Calls <see cref="GetOrCreateState(AnimationClip, bool)"/> for each of the specified clips.
  225. /// <para></para>
  226. /// If you only want to create a single state, use <see cref="CreateState(AnimationClip)"/>.
  227. /// </summary>
  228. public void CreateIfNew(AnimationClip clip0, AnimationClip clip1, AnimationClip clip2, AnimationClip clip3)
  229. {
  230. GetOrCreateState(clip0);
  231. GetOrCreateState(clip1);
  232. GetOrCreateState(clip2);
  233. GetOrCreateState(clip3);
  234. }
  235. /// <summary>
  236. /// Calls <see cref="GetOrCreateState(AnimationClip, bool)"/> for each of the specified clips.
  237. /// <para></para>
  238. /// If you only want to create a single state, use <see cref="CreateState(AnimationClip)"/>.
  239. /// </summary>
  240. public void CreateIfNew(params AnimationClip[] clips)
  241. {
  242. if (clips == null)
  243. return;
  244. var count = clips.Length;
  245. for (int i = 0; i < count; i++)
  246. {
  247. var clip = clips[i];
  248. if (clip != null)
  249. GetOrCreateState(clip);
  250. }
  251. }
  252. /************************************************************************************************************************/
  253. /// <summary>
  254. /// Calls <see cref="AnimancerPlayable.GetKey"/> and returns the state which registered with that key or
  255. /// creates one if it doesn't exist.
  256. /// <para></para>
  257. /// If the state already exists but has the wrong <see cref="AnimancerState.Clip"/>, the `allowSetClip`
  258. /// parameter determines what will happen. False causes it to throw an <see cref="ArgumentException"/> while
  259. /// true allows it to change the <see cref="AnimancerState.Clip"/>. Note that the change is somewhat costly to
  260. /// performance to use with caution.
  261. /// </summary>
  262. /// <exception cref="ArgumentException"/>
  263. public AnimancerState GetOrCreateState(AnimationClip clip, bool allowSetClip = false)
  264. {
  265. return GetOrCreateState(Root.GetKey(clip), clip, allowSetClip);
  266. }
  267. /// <summary>
  268. /// Returns the state registered with the <see cref="IHasKey.Key"/> if there is one. Otherwise
  269. /// this method uses <see cref="ITransition.CreateState"/> to create a new one and registers it with
  270. /// that key before returning it.
  271. /// </summary>
  272. public AnimancerState GetOrCreateState(ITransition transition)
  273. {
  274. var state = Root.States.GetOrCreate(transition);
  275. state.LayerIndex = Index;
  276. return state;
  277. }
  278. /// <summary>
  279. /// Returns the state which registered with the `key` or creates one if it doesn't exist.
  280. /// <para></para>
  281. /// If the state already exists but has the wrong <see cref="AnimancerState.Clip"/>, the `allowSetClip`
  282. /// parameter determines what will happen. False causes it to throw an <see cref="ArgumentException"/> while
  283. /// true allows it to change the <see cref="AnimancerState.Clip"/>. Note that the change is somewhat costly to
  284. /// performance to use with caution.
  285. /// <seealso cref="AnimancerState"/>
  286. /// </summary>
  287. /// <exception cref="ArgumentException"/>
  288. /// <exception cref="ArgumentNullException">The `key` is null.</exception>
  289. /// <remarks>
  290. /// See also: <see cref="AnimancerPlayable.StateDictionary.GetOrCreate(object, AnimationClip, bool)"/>.
  291. /// </remarks>
  292. public AnimancerState GetOrCreateState(object key, AnimationClip clip, bool allowSetClip = false)
  293. {
  294. if (key == null)
  295. throw new ArgumentNullException(nameof(key));
  296. if (Root.States.TryGet(key, out var state))
  297. {
  298. // If a state exists with the 'key' but has the wrong clip, either change it or complain.
  299. if (!ReferenceEquals(state.Clip, clip))
  300. {
  301. if (allowSetClip)
  302. {
  303. state.Clip = clip;
  304. }
  305. else
  306. {
  307. throw new ArgumentException(AnimancerPlayable.StateDictionary.GetClipMismatchError(key, state.Clip, clip));
  308. }
  309. }
  310. else// Otherwise make sure it is on the correct layer.
  311. {
  312. AddChild(state);
  313. }
  314. }
  315. else
  316. {
  317. state = CreateState(key, clip);
  318. }
  319. return state;
  320. }
  321. /************************************************************************************************************************/
  322. /// <summary>Destroys all states connected to this layer. This operation cannot be undone.</summary>
  323. public void DestroyStates()
  324. {
  325. for (int i = States.Count - 1; i >= 0; i--)
  326. {
  327. States[i].Destroy();
  328. }
  329. States.Clear();
  330. }
  331. /************************************************************************************************************************/
  332. #endregion
  333. /************************************************************************************************************************/
  334. #region Play Management
  335. /************************************************************************************************************************/
  336. /// <inheritdoc/>
  337. protected internal override void OnStartFade()
  338. {
  339. for (int i = States.Count - 1; i >= 0; i--)
  340. States[i].OnStartFade();
  341. }
  342. /************************************************************************************************************************/
  343. // Play Immediately.
  344. /************************************************************************************************************************/
  345. /// <summary>Stops all other animations on this layer, plays the `clip`, and returns its state.</summary>
  346. /// <remarks>
  347. /// The animation will continue playing from its current <see cref="AnimancerState.Time"/>.
  348. /// To restart it from the beginning you can use <c>...Play(clip).Time = 0;</c>.
  349. /// <para></para>
  350. /// This method is safe to call repeatedly without checking whether the `clip` was already playing.
  351. /// </remarks>
  352. public AnimancerState Play(AnimationClip clip)
  353. => Play(GetOrCreateState(clip));
  354. /// <summary>Stops all other animations on the same layer, plays the `state`, and returns it.</summary>
  355. /// <remarks>
  356. /// The animation will continue playing from its current <see cref="AnimancerState.Time"/>.
  357. /// To restart it from the beginning you can use <c>...Play(state).Time = 0;</c>.
  358. /// <para></para>
  359. /// This method is safe to call repeatedly without checking whether the `state` was already playing.
  360. /// </remarks>
  361. public AnimancerState Play(AnimancerState state)
  362. {
  363. if (Weight == 0 && TargetWeight == 0)
  364. Weight = 1;
  365. AddChild(state);
  366. CurrentState = state;
  367. state.Play();
  368. for (int i = States.Count - 1; i >= 0; i--)
  369. {
  370. var otherState = States[i];
  371. if (otherState != state)
  372. otherState.Stop();
  373. }
  374. return state;
  375. }
  376. /************************************************************************************************************************/
  377. // Cross Fade.
  378. /************************************************************************************************************************/
  379. /// <summary>
  380. /// Starts fading in the `clip` over the course of the `fadeDuration` while fading out all others in the same
  381. /// layer. Returns its state.
  382. /// </summary>
  383. /// <remarks>
  384. /// If the `state` was already playing and fading in with less time remaining than the `fadeDuration`, this
  385. /// method will allow it to complete the existing fade rather than starting a slower one.
  386. /// <para></para>
  387. /// If the layer currently has 0 <see cref="AnimancerNode.Weight"/>, this method will fade in the layer itself
  388. /// and simply <see cref="AnimancerState.Play"/> the `state`.
  389. /// <para></para>
  390. /// This method is safe to call repeatedly without checking whether the `state` was already playing.
  391. /// <para></para>
  392. /// <em>Animancer Lite only allows the default `fadeDuration` (0.25 seconds) in runtime builds.</em>
  393. /// </remarks>
  394. public AnimancerState Play(AnimationClip clip, float fadeDuration, FadeMode mode = default)
  395. => Play(Root.States.GetOrCreate(clip), fadeDuration, mode);
  396. /// <summary>
  397. /// Starts fading in the `state` over the course of the `fadeDuration` while fading out all others in this
  398. /// layer. Returns the `state`.
  399. /// </summary>
  400. /// <remarks>
  401. /// If the `state` was already playing and fading in with less time remaining than the `fadeDuration`, this
  402. /// method will allow it to complete the existing fade rather than starting a slower one.
  403. /// <para></para>
  404. /// If the layer currently has 0 <see cref="AnimancerNode.Weight"/>, this method will fade in the layer itself
  405. /// and simply <see cref="AnimancerState.Play"/> the `state`.
  406. /// <para></para>
  407. /// This method is safe to call repeatedly without checking whether the `state` was already playing.
  408. /// <para></para>
  409. /// <em>Animancer Lite only allows the default `fadeDuration` (0.25 seconds) in runtime builds.</em>
  410. /// </remarks>
  411. public AnimancerState Play(AnimancerState state, float fadeDuration, FadeMode mode = default)
  412. {
  413. // Skip the fade if:
  414. if (fadeDuration <= 0 ||// There is no duration.
  415. (Root.SkipFirstFade && Index == 0 && Weight == 0))// Or this is Layer 0 and it has no weight.
  416. {
  417. if (mode == FadeMode.FromStart || mode == FadeMode.NormalizedFromStart)
  418. state.Time = 0;
  419. Weight = 1;
  420. return Play(state);
  421. }
  422. EvaluateFadeMode(mode, ref state, ref fadeDuration, out var layerFadeDuration);
  423. StartFade(1, layerFadeDuration);
  424. if (Weight == 0)
  425. return Play(state);
  426. AddChild(state);
  427. CurrentState = state;
  428. // If the state is already playing or will finish fading in faster than this new fade,
  429. // continue the existing fade but still pretend it was restarted.
  430. if (state.IsPlaying && state.TargetWeight == 1 &&
  431. (state.Weight == 1 || state.FadeSpeed * fadeDuration > Math.Abs(1 - state.Weight)))
  432. {
  433. OnStartFade();
  434. }
  435. else// Otherwise fade in the target state and fade out all others.
  436. {
  437. state.IsPlaying = true;
  438. state.StartFade(1, fadeDuration);
  439. for (int i = States.Count - 1; i >= 0; i--)
  440. {
  441. var otherState = States[i];
  442. if (otherState != state)
  443. otherState.StartFade(0, fadeDuration);
  444. }
  445. }
  446. return state;
  447. }
  448. /************************************************************************************************************************/
  449. // Transition.
  450. /************************************************************************************************************************/
  451. /// <summary>
  452. /// Creates a state for the `transition` if it didn't already exist, then calls
  453. /// <see cref="Play(AnimancerState)"/> or <see cref="Play(AnimancerState, float, FadeMode)"/>
  454. /// depending on the <see cref="ITransition.FadeDuration"/>.
  455. /// </summary>
  456. /// <remarks>
  457. /// This method is safe to call repeatedly without checking whether the `transition` was already playing.
  458. /// </remarks>
  459. public AnimancerState Play(ITransition transition)
  460. => Play(transition, transition.FadeDuration, transition.FadeMode);
  461. /// <summary>
  462. /// Creates a state for the `transition` if it didn't already exist, then calls
  463. /// <see cref="Play(AnimancerState)"/> or <see cref="Play(AnimancerState, float, FadeMode)"/>
  464. /// depending on the <see cref="ITransition.FadeDuration"/>.
  465. /// </summary>
  466. /// <remarks>
  467. /// This method is safe to call repeatedly without checking whether the `transition` was already playing.
  468. /// </remarks>
  469. public AnimancerState Play(ITransition transition, float fadeDuration, FadeMode mode = default)
  470. {
  471. var state = Root.States.GetOrCreate(transition);
  472. state = Play(state, fadeDuration, mode);
  473. transition.Apply(state);
  474. return state;
  475. }
  476. /************************************************************************************************************************/
  477. // Try Play.
  478. /************************************************************************************************************************/
  479. /// <summary>
  480. /// Stops all other animations on the same layer, plays the animation registered with the `key`, and returns
  481. /// that state. Or if no state is registered with that `key`, this method does nothing and returns null.
  482. /// </summary>
  483. /// <remarks>
  484. /// The animation will continue playing from its current <see cref="AnimancerState.Time"/>.
  485. /// To restart it from the beginning you can simply set the returned state's time to 0.
  486. /// <para></para>
  487. /// This method is safe to call repeatedly without checking whether the animation was already playing.
  488. /// </remarks>
  489. public AnimancerState TryPlay(object key)
  490. => Root.States.TryGet(key, out var state) ? Play(state) : null;
  491. /// <summary>
  492. /// Starts fading in the animation registered with the `key` while fading out all others in the same layer
  493. /// over the course of the `fadeDuration`. Or if no state is registered with that `key`, this method does
  494. /// nothing and returns null.
  495. /// </summary>
  496. /// <remarks>
  497. /// If the `state` was already playing and fading in with less time remaining than the `fadeDuration`, this
  498. /// method will allow it to complete the existing fade rather than starting a slower one.
  499. /// <para></para>
  500. /// If the layer currently has 0 <see cref="AnimancerNode.Weight"/>, this method will fade in the layer itself
  501. /// and simply <see cref="AnimancerState.Play"/> the `state`.
  502. /// <para></para>
  503. /// This method is safe to call repeatedly without checking whether the animation was already playing.
  504. /// <para></para>
  505. /// <em>Animancer Lite only allows the default `fadeDuration` (0.25 seconds) in runtime builds.</em>
  506. /// </remarks>
  507. public AnimancerState TryPlay(object key, float fadeDuration, FadeMode mode = default)
  508. => Root.States.TryGet(key, out var state) ? Play(state, fadeDuration, mode) : null;
  509. /************************************************************************************************************************/
  510. /// <summary>Manipulates the other parameters according to the `mode`.</summary>
  511. /// <exception cref="ArgumentException">
  512. /// The <see cref="AnimancerState.Clip"/> is null when using <see cref="FadeMode.FromStart"/> or
  513. /// <see cref="FadeMode.NormalizedFromStart"/>.
  514. /// </exception>
  515. private void EvaluateFadeMode(FadeMode mode, ref AnimancerState state, ref float fadeDuration, out float layerFadeDuration)
  516. {
  517. layerFadeDuration = fadeDuration;
  518. switch (mode)
  519. {
  520. case FadeMode.FixedSpeed:
  521. fadeDuration *= Math.Abs(1 - state.Weight);
  522. layerFadeDuration *= Math.Abs(1 - Weight);
  523. break;
  524. case FadeMode.FixedDuration:
  525. break;
  526. case FadeMode.FromStart:
  527. #if UNITY_ASSERTIONS
  528. if (!(state is ClipState))
  529. throw new ArgumentException(
  530. $"{nameof(FadeMode)}.{nameof(FadeMode.FromStart)} can only be used on {nameof(ClipState)}s." +
  531. $" State = {state}");
  532. #endif
  533. state = GetOrCreateWeightlessState(state);
  534. break;
  535. case FadeMode.NormalizedSpeed:
  536. {
  537. var length = state.Length;
  538. fadeDuration *= Math.Abs(1 - state.Weight) * length;
  539. layerFadeDuration *= Math.Abs(1 - Weight) * length;
  540. }
  541. break;
  542. case FadeMode.NormalizedDuration:
  543. {
  544. var length = state.Length;
  545. fadeDuration *= length;
  546. layerFadeDuration *= length;
  547. }
  548. break;
  549. case FadeMode.NormalizedFromStart:
  550. {
  551. #if UNITY_ASSERTIONS
  552. if (!(state is ClipState))
  553. throw new ArgumentException(
  554. $"{nameof(FadeMode)}.{nameof(FadeMode.NormalizedFromStart)} can only be used on {nameof(ClipState)}s." +
  555. $" State = {state}");
  556. #endif
  557. state = GetOrCreateWeightlessState(state);
  558. var length = state.Length;
  559. fadeDuration *= length;
  560. layerFadeDuration *= length;
  561. }
  562. break;
  563. default:
  564. throw AnimancerUtilities.CreateUnsupportedArgumentException(mode);
  565. }
  566. }
  567. /************************************************************************************************************************/
  568. #if UNITY_ASSERTIONS
  569. /// <summary>[Assert-Only]
  570. /// The maximum number of duplicate states that can be created by <see cref="GetOrCreateWeightlessState"/> for
  571. /// a single clip before it will start giving usage warnings. Default = 5.
  572. /// </summary>
  573. /// <remarks>This value can be set by <see cref="SetMaxStateDepth"/>.</remarks>
  574. public static int MaxStateDepth { get; private set; } = 5;
  575. #endif
  576. /// <summary>[Assert-Conditional] Sets the <see cref="MaxStateDepth"/>.</summary>
  577. /// <remarks>This would not need to be a separate method if C# supported conditional property setters.</remarks>
  578. [System.Diagnostics.Conditional(Strings.Assertions)]
  579. public static void SetMaxStateDepth(int depth)
  580. {
  581. #if UNITY_ASSERTIONS
  582. MaxStateDepth = depth;
  583. #endif
  584. }
  585. /************************************************************************************************************************/
  586. /// <summary>
  587. /// The maximum <see cref="AnimancerNode.Weight"/> that <see cref="GetOrCreateWeightlessState"/> will treat as
  588. /// being weightless. Default = 0.01.
  589. /// </summary>
  590. /// <remarks>This allows states with very small weights to be reused instead of needing to create new ones.</remarks>
  591. public static float WeightlessThreshold { get; set; } = 0.01f;
  592. /************************************************************************************************************************/
  593. /// <summary>
  594. /// If the `state` is not currently at low <see cref="AnimancerNode.Weight"/>, this method finds a copy of it
  595. /// which is at low or creates a new one.
  596. /// </summary>
  597. /// <remarks>"Low" weight is defined as less than or equal to the <see cref="WeightlessThreshold"/>.</remarks>
  598. /// <exception cref="InvalidOperationException">The <see cref="AnimancerState.Clip"/> is null.</exception>
  599. public AnimancerState GetOrCreateWeightlessState(AnimancerState state)
  600. {
  601. if (state.Weight > WeightlessThreshold)
  602. {
  603. var clip = state.Clip;
  604. if (clip == null)
  605. {
  606. // We could probably support any state type by giving them a Clone method, but cloning mixers and
  607. // other state types would be expensive and you'd need to control the parameters of all clones.
  608. throw new InvalidOperationException(
  609. $"{nameof(GetOrCreateWeightlessState)} can only be used on {nameof(ClipState)}s. State = " + state);
  610. }
  611. // Use any earlier state that is weightless.
  612. var keyState = state;
  613. while (true)
  614. {
  615. keyState = keyState.Key as AnimancerState;
  616. if (keyState == null)
  617. {
  618. break;
  619. }
  620. else if (keyState.Weight <= WeightlessThreshold)
  621. {
  622. state = keyState;
  623. goto GotWeightlessState;
  624. }
  625. }
  626. #if UNITY_ASSERTIONS
  627. int depth = 0;
  628. #endif
  629. // If that state is not at low weight, get or create another state registered using the previous state as a key.
  630. // Keep going through states in this manner until you find one at low weight.
  631. do
  632. {
  633. // Explicitly cast the state to an object to avoid the overload that warns about using a state as a key.
  634. state = Root.States.GetOrCreate((object)state, clip);
  635. #if UNITY_ASSERTIONS
  636. if (++depth == MaxStateDepth)
  637. {
  638. OptionalWarning.MaxStateDepth.Log(
  639. $"{nameof(AnimancerLayer)}.{nameof(GetOrCreateWeightlessState)}" +
  640. $" has created {MaxStateDepth} states for a single clip." +
  641. $" This is most likely a result of repeated calls on consecutive frames." +
  642. $" This can be avoided by using a different {nameof(FadeMode)}," +
  643. $" having the Start Time toggle disabled on a Transition," +
  644. $" or by calling {nameof(AnimancerLayer)}.{nameof(SetMaxStateDepth)}" +
  645. $" to increase the threshold for this warning.",
  646. Root?.Component);
  647. }
  648. #endif
  649. }
  650. while (state.Weight > WeightlessThreshold);
  651. }
  652. GotWeightlessState:
  653. // Make sure it's on this layer and at time 0.
  654. AddChild(state);
  655. state.Time = 0;
  656. state.Weight = 0;
  657. return state;
  658. }
  659. /************************************************************************************************************************/
  660. // Stopping
  661. /************************************************************************************************************************/
  662. /// <summary>
  663. /// Sets <see cref="AnimancerNode.Weight"/> = 0 and calls <see cref="AnimancerState.Stop"/> on all animations
  664. /// to stop them from playing and rewind them to the start.
  665. /// </summary>
  666. public override void Stop()
  667. {
  668. base.Stop();
  669. CurrentState = null;
  670. for (int i = States.Count - 1; i >= 0; i--)
  671. States[i].Stop();
  672. }
  673. /************************************************************************************************************************/
  674. // Checking
  675. /************************************************************************************************************************/
  676. /// <summary>
  677. /// Returns true if the `clip` is currently being played by at least one state.
  678. /// </summary>
  679. public bool IsPlayingClip(AnimationClip clip)
  680. {
  681. for (int i = States.Count - 1; i >= 0; i--)
  682. {
  683. var state = States[i];
  684. if (state.Clip == clip && state.IsPlaying)
  685. return true;
  686. }
  687. return false;
  688. }
  689. /// <summary>
  690. /// Returns true if at least one animation is being played.
  691. /// </summary>
  692. public bool IsAnyStatePlaying()
  693. {
  694. for (int i = States.Count - 1; i >= 0; i--)
  695. {
  696. if (States[i].IsPlaying)
  697. return true;
  698. }
  699. return false;
  700. }
  701. /// <summary>
  702. /// Returns true if the <see cref="CurrentState"/> is playing and hasn't yet reached its end.
  703. /// <para></para>
  704. /// This method is called by <see cref="IEnumerator.MoveNext"/> so this object can be used as a custom yield
  705. /// instruction to wait until it finishes.
  706. /// </summary>
  707. protected internal override bool IsPlayingAndNotEnding() => _CurrentState != null && _CurrentState.IsPlayingAndNotEnding();
  708. /************************************************************************************************************************/
  709. /// <summary>
  710. /// Calculates the total <see cref="AnimancerNode.Weight"/> of all states in this layer.
  711. /// </summary>
  712. public float GetTotalWeight()
  713. {
  714. float weight = 0;
  715. for (int i = States.Count - 1; i >= 0; i--)
  716. {
  717. weight += States[i].Weight;
  718. }
  719. return weight;
  720. }
  721. /************************************************************************************************************************/
  722. #endregion
  723. /************************************************************************************************************************/
  724. #region Inverse Kinematics
  725. /************************************************************************************************************************/
  726. private bool _ApplyAnimatorIK;
  727. /// <inheritdoc/>
  728. public override bool ApplyAnimatorIK
  729. {
  730. get => _ApplyAnimatorIK;
  731. set => base.ApplyAnimatorIK = _ApplyAnimatorIK = value;
  732. }
  733. /************************************************************************************************************************/
  734. private bool _ApplyFootIK;
  735. /// <inheritdoc/>
  736. public override bool ApplyFootIK
  737. {
  738. get => _ApplyFootIK;
  739. set => base.ApplyFootIK = _ApplyFootIK = value;
  740. }
  741. /************************************************************************************************************************/
  742. #endregion
  743. /************************************************************************************************************************/
  744. #region Inspector
  745. /************************************************************************************************************************/
  746. /// <summary>[<see cref="IAnimationClipCollection"/>]
  747. /// Gathers all the animations in this layer.
  748. /// </summary>
  749. public void GatherAnimationClips(ICollection<AnimationClip> clips) => clips.GatherFromSource(States);
  750. /************************************************************************************************************************/
  751. /// <summary>The Inspector display name of this layer.</summary>
  752. public override string ToString()
  753. {
  754. #if UNITY_ASSERTIONS
  755. if (string.IsNullOrEmpty(DebugName))
  756. {
  757. if (_Mask != null)
  758. return _Mask.name;
  759. SetDebugName(Index == 0 ? "Base Layer" : "Layer " + Index);
  760. }
  761. return base.ToString();
  762. #else
  763. return "Layer " + Index;
  764. #endif
  765. }
  766. /************************************************************************************************************************/
  767. /// <inheritdoc/>
  768. protected override void AppendDetails(StringBuilder text, string separator)
  769. {
  770. base.AppendDetails(text, separator);
  771. text.Append(separator).Append($"{nameof(CurrentState)}: ").Append(CurrentState);
  772. text.Append(separator).Append($"{nameof(CommandCount)}: ").Append(CommandCount);
  773. text.Append(separator).Append($"{nameof(IsAdditive)}: ").Append(IsAdditive);
  774. #if UNITY_ASSERTIONS
  775. text.Append(separator).Append($"{nameof(AvatarMask)}: ").Append(AnimancerUtilities.ToStringOrNull(_Mask));
  776. #endif
  777. }
  778. /************************************************************************************************************************/
  779. #endregion
  780. /************************************************************************************************************************/
  781. }
  782. }