MixerState.cs 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
  2. #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value.
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Text;
  6. using UnityEngine;
  7. using UnityEngine.Animations;
  8. using UnityEngine.Playables;
  9. using Object = UnityEngine.Object;
  10. namespace Animancer
  11. {
  12. /// <summary>[Pro-Only] Base class for <see cref="AnimancerState"/>s which blend other states together.</summary>
  13. /// <remarks>
  14. /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/blending/mixers">Mixers</see>
  15. /// </remarks>
  16. /// https://kybernetik.com.au/animancer/api/Animancer/MixerState
  17. ///
  18. public abstract partial class MixerState : AnimancerState
  19. {
  20. /************************************************************************************************************************/
  21. /// <summary>An <see cref="ITransition{TState}"/> that creates a <see cref="MixerState{TParameter}"/> for <see cref="Vector2"/>.</summary>
  22. public interface ITransition2D : ITransition<MixerState<Vector2>> { }
  23. /************************************************************************************************************************/
  24. #region Properties
  25. /************************************************************************************************************************/
  26. /// <summary>Returns true because mixers should always keep child playables connected to the graph.</summary>
  27. public override bool KeepChildrenConnected => true;
  28. /// <summary>A <see cref="MixerState"/> has no <see cref="AnimationClip"/>.</summary>
  29. public override AnimationClip Clip => null;
  30. /************************************************************************************************************************/
  31. /// <summary>Returns the collection of states connected to this mixer. Note that some elements may be null.</summary>
  32. /// <remarks>
  33. /// Getting an enumerator that automatically skips over null states is slower and creates garbage, so
  34. /// internally we use this property and perform null checks manually even though it increases the code
  35. /// complexity a bit.
  36. /// </remarks>
  37. public abstract IList<AnimancerState> ChildStates { get; }
  38. /// <inheritdoc/>
  39. public override int ChildCount => ChildStates.Count;
  40. /// <inheritdoc/>
  41. public override AnimancerState GetChild(int index) => ChildStates[index];
  42. /// <inheritdoc/>
  43. public override FastEnumerator<AnimancerState> GetEnumerator()
  44. => new FastEnumerator<AnimancerState>(ChildStates);
  45. /************************************************************************************************************************/
  46. /// <inheritdoc/>
  47. protected override void OnSetIsPlaying()
  48. {
  49. var childStates = ChildStates;
  50. for (int i = childStates.Count - 1; i >= 0; i--)
  51. {
  52. var state = childStates[i];
  53. if (state == null)
  54. continue;
  55. state.IsPlaying = IsPlaying;
  56. }
  57. }
  58. /************************************************************************************************************************/
  59. /// <summary>Are any child states looping?</summary>
  60. public override bool IsLooping
  61. {
  62. get
  63. {
  64. var childStates = ChildStates;
  65. for (int i = childStates.Count - 1; i >= 0; i--)
  66. {
  67. var state = childStates[i];
  68. if (state == null)
  69. continue;
  70. if (state.IsLooping)
  71. return true;
  72. }
  73. return false;
  74. }
  75. }
  76. /************************************************************************************************************************/
  77. /// <summary>
  78. /// The weighted average <see cref="AnimancerState.Time"/> of each child state according to their
  79. /// <see cref="AnimancerNode.Weight"/>.
  80. /// </summary>
  81. /// <remarks>
  82. /// If there are any <see cref="SynchronizedChildren"/>, only those states will be included in the getter
  83. /// calculation.
  84. /// </remarks>
  85. protected override float RawTime
  86. {
  87. get
  88. {
  89. RecalculateWeights();
  90. if (!GetSynchronizedTimeDetails(out var totalWeight, out var normalizedTime, out var length))
  91. GetTimeDetails(out totalWeight, out normalizedTime, out length);
  92. if (totalWeight == 0)
  93. return base.RawTime;
  94. totalWeight *= totalWeight;
  95. return normalizedTime * length / totalWeight;
  96. }
  97. set
  98. {
  99. var states = ChildStates;
  100. var childCount = states.Count;
  101. if (value == 0)
  102. goto ZeroTime;
  103. var length = Length;
  104. if (length == 0)
  105. goto ZeroTime;
  106. value /= length;// Normalize.
  107. while (--childCount >= 0)
  108. {
  109. var state = states[childCount];
  110. if (state != null)
  111. state.NormalizedTime = value;
  112. }
  113. return;
  114. // If the value is 0, we can set the child times slightly more efficiently.
  115. ZeroTime:
  116. while (--childCount >= 0)
  117. {
  118. var state = states[childCount];
  119. if (state != null)
  120. state.Time = 0;
  121. }
  122. }
  123. }
  124. /************************************************************************************************************************/
  125. /// <inheritdoc/>
  126. public override void MoveTime(float time, bool normalized)
  127. {
  128. base.MoveTime(time, normalized);
  129. var states = ChildStates;
  130. var count = states.Count;
  131. for (int i = 0; i < count; i++)
  132. states[i].MoveTime(time, normalized);
  133. }
  134. /************************************************************************************************************************/
  135. /// <summary>Gets the time details based on the <see cref="SynchronizedChildren"/>.</summary>
  136. private bool GetSynchronizedTimeDetails(out float totalWeight, out float normalizedTime, out float length)
  137. {
  138. totalWeight = 0;
  139. normalizedTime = 0;
  140. length = 0;
  141. if (_SynchronizedChildren != null)
  142. {
  143. for (int i = _SynchronizedChildren.Count - 1; i >= 0; i--)
  144. {
  145. var state = _SynchronizedChildren[i];
  146. var weight = state.Weight;
  147. if (weight == 0)
  148. continue;
  149. var stateLength = state.Length;
  150. if (stateLength == 0)
  151. continue;
  152. totalWeight += weight;
  153. normalizedTime += state.Time / stateLength * weight;
  154. length += stateLength * weight;
  155. }
  156. }
  157. return totalWeight > MinimumSynchronizeChildrenWeight;
  158. }
  159. /// <summary>Gets the time details based on all child states.</summary>
  160. private void GetTimeDetails(out float totalWeight, out float normalizedTime, out float length)
  161. {
  162. totalWeight = 0;
  163. normalizedTime = 0;
  164. length = 0;
  165. var states = ChildStates;
  166. for (int i = states.Count - 1; i >= 0; i--)
  167. {
  168. var state = states[i];
  169. if (state == null)
  170. continue;
  171. var weight = state.Weight;
  172. if (weight == 0)
  173. continue;
  174. var stateLength = state.Length;
  175. if (stateLength == 0)
  176. continue;
  177. totalWeight += weight;
  178. normalizedTime += state.Time / stateLength * weight;
  179. length += stateLength * weight;
  180. }
  181. }
  182. /************************************************************************************************************************/
  183. /// <summary>
  184. /// The weighted average <see cref="AnimancerState.Length"/> of each child state according to their
  185. /// <see cref="AnimancerNode.Weight"/>.
  186. /// </summary>
  187. public override float Length
  188. {
  189. get
  190. {
  191. RecalculateWeights();
  192. var length = 0f;
  193. var totalChildWeight = 0f;
  194. if (_SynchronizedChildren != null)
  195. {
  196. for (int i = _SynchronizedChildren.Count - 1; i >= 0; i--)
  197. {
  198. var state = _SynchronizedChildren[i];
  199. var weight = state.Weight;
  200. if (weight == 0)
  201. continue;
  202. var stateLength = state.Length;
  203. if (stateLength == 0)
  204. continue;
  205. totalChildWeight += weight;
  206. length += stateLength * weight;
  207. }
  208. }
  209. if (totalChildWeight > 0)
  210. return length / totalChildWeight;
  211. var states = ChildStates;
  212. totalChildWeight = CalculateTotalWeight(states);
  213. if (totalChildWeight <= 0)
  214. return 0;
  215. for (int i = states.Count - 1; i >= 0; i--)
  216. {
  217. var state = states[i];
  218. if (state != null)
  219. length += state.Length * state.Weight;
  220. }
  221. return length / totalChildWeight;
  222. }
  223. }
  224. /************************************************************************************************************************/
  225. #endregion
  226. /************************************************************************************************************************/
  227. #region Initialisation
  228. /************************************************************************************************************************/
  229. /// <summary>Creates and assigns the <see cref="AnimationMixerPlayable"/> managed by this state.</summary>
  230. protected override void CreatePlayable(out Playable playable)
  231. {
  232. #if UNITY_2021_2_OR_NEWER
  233. playable = AnimationMixerPlayable.Create(Root._Graph, ChildStates.Count);
  234. #else
  235. playable = AnimationMixerPlayable.Create(Root._Graph, ChildStates.Count, false);
  236. #endif
  237. RecalculateWeights();
  238. }
  239. /************************************************************************************************************************/
  240. /// <summary>
  241. /// Creates and returns a new <see cref="ClipState"/> to play the `clip` with this mixer as its parent.
  242. /// </summary>
  243. public ClipState CreateChild(int index, AnimationClip clip)
  244. {
  245. var state = new ClipState(clip);
  246. state.SetParent(this, index);
  247. state.IsPlaying = IsPlaying;
  248. return state;
  249. }
  250. /// <summary>
  251. /// Calls <see cref="AnimancerUtilities.CreateStateAndApply"/> and sets this mixer as the state's parent.
  252. /// </summary>
  253. public AnimancerState CreateChild(int index, ITransition transition)
  254. {
  255. var state = transition.CreateStateAndApply(Root);
  256. state.SetParent(this, index);
  257. state.IsPlaying = IsPlaying;
  258. return state;
  259. }
  260. /// <summary>Calls <see cref="CreateChild(int, AnimationClip)"/> or <see cref="CreateChild(int, ITransition)"/>.</summary>
  261. public AnimancerState CreateChild(int index, Object state)
  262. {
  263. if (state is AnimationClip clip)
  264. {
  265. return CreateChild(index, clip);
  266. }
  267. else if (state is ITransition transition)
  268. {
  269. return CreateChild(index, transition);
  270. }
  271. else return null;
  272. }
  273. /************************************************************************************************************************/
  274. /// <summary>Assigns the `state` as a child of this mixer.</summary>
  275. public void SetChild(int index, AnimancerState state) => state.SetParent(this, index);
  276. /************************************************************************************************************************/
  277. /// <summary>Connects the `state` to this mixer at its <see cref="AnimancerNode.Index"/>.</summary>
  278. protected internal override void OnAddChild(AnimancerState state)
  279. {
  280. OnAddChild(ChildStates, state);
  281. if (AutoSynchronizeChildren)
  282. Synchronize(state);
  283. #if UNITY_ASSERTIONS
  284. if (_IsGeneratedName)
  285. {
  286. _IsGeneratedName = false;
  287. SetDebugName(null);
  288. }
  289. #endif
  290. }
  291. /************************************************************************************************************************/
  292. /// <summary>Disconnects the `state` from this mixer at its <see cref="AnimancerNode.Index"/>.</summary>
  293. protected internal override void OnRemoveChild(AnimancerState state)
  294. {
  295. if (_SynchronizedChildren != null)
  296. _SynchronizedChildren.Remove(state);
  297. var states = ChildStates;
  298. Validate.AssertCanRemoveChild(state, states);
  299. states[state.Index] = null;
  300. Root?._Graph.Disconnect(_Playable, state.Index);
  301. #if UNITY_ASSERTIONS
  302. if (_IsGeneratedName)
  303. {
  304. _IsGeneratedName = false;
  305. SetDebugName(null);
  306. }
  307. #endif
  308. }
  309. /************************************************************************************************************************/
  310. /// <inheritdoc/>
  311. public override void Destroy()
  312. {
  313. DestroyChildren();
  314. base.Destroy();
  315. }
  316. /************************************************************************************************************************/
  317. /// <summary>
  318. /// Destroys all <see cref="ChildStates"/> connected to this mixer. This operation cannot be undone.
  319. /// </summary>
  320. public void DestroyChildren()
  321. {
  322. var states = ChildStates;
  323. for (int i = states.Count - 1; i >= 0; i--)
  324. {
  325. var state = states[i];
  326. if (state != null)
  327. state.Destroy();
  328. }
  329. }
  330. /************************************************************************************************************************/
  331. #endregion
  332. /************************************************************************************************************************/
  333. #region Jobs
  334. /************************************************************************************************************************/
  335. /// <summary>
  336. /// Creates an <see cref="AnimationScriptPlayable"/> to run the specified Animation Job instead of the usual
  337. /// <see cref="AnimationMixerPlayable"/>.
  338. /// </summary>
  339. /// <example><code>
  340. /// AnimancerComponent animancer = ...;
  341. /// var job = new MyJob();// A struct that implements IAnimationJob.
  342. /// var mixer = new WhateverMixerState();// e.g. LinearMixerState.
  343. /// mixer.CreatePlayable(animancer, job);
  344. /// // Use mixer.Initialize, CreateChild, and SetChild to configure the children as normal.
  345. /// </code>
  346. /// See also: <seealso cref="CreatePlayable{T}(out Playable, T, bool)"/>
  347. /// </example>
  348. public AnimationScriptPlayable CreatePlayable<T>(AnimancerPlayable root, T job, bool processInputs = false)
  349. where T : struct, IAnimationJob
  350. {
  351. // Can't just use SetRoot normally because it would call the regular CreatePlayable method.
  352. SetRoot(null);
  353. Root = root;
  354. root.States.Register(this);
  355. #if UNITY_ASSERTIONS
  356. if (HasEvents)
  357. Debug.LogWarning($"{nameof(CreatePlayable)} should be called before configuring any Animancer Events on this state.");
  358. #endif
  359. var playable = AnimationScriptPlayable.Create(root._Graph, job, ChildCount);
  360. if (!processInputs)
  361. playable.SetProcessInputs(false);
  362. for (int i = ChildCount - 1; i >= 0; i--)
  363. GetChild(i)?.SetRoot(root);
  364. return playable;
  365. }
  366. /************************************************************************************************************************/
  367. /// <summary>
  368. /// Creates an <see cref="AnimationScriptPlayable"/> to run the specified Animation Job instead of the usual
  369. /// <see cref="AnimationMixerPlayable"/>.
  370. /// </summary>
  371. ///
  372. /// <remarks>
  373. /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/source/creating-custom-states">Creating Custom States</see>
  374. /// </remarks>
  375. ///
  376. /// <example><code>
  377. /// public class MyMixer : LinearMixerState
  378. /// {
  379. /// protected override void CreatePlayable(out Playable playable)
  380. /// {
  381. /// CreatePlayable(out playable, new MyJob());
  382. /// }
  383. ///
  384. /// private struct MyJob : IAnimationJob
  385. /// {
  386. /// public void ProcessAnimation(AnimationStream stream)
  387. /// {
  388. /// }
  389. ///
  390. /// public void ProcessRootMotion(AnimationStream stream)
  391. /// {
  392. /// }
  393. /// }
  394. /// }
  395. /// </code>
  396. /// See also: <seealso cref="CreatePlayable{T}(AnimancerPlayable, T, bool)"/>
  397. /// </example>
  398. protected void CreatePlayable<T>(out Playable playable, T job, bool processInputs = false)
  399. where T : struct, IAnimationJob
  400. {
  401. var scriptPlayable = AnimationScriptPlayable.Create(Root._Graph, job, ChildCount);
  402. if (!processInputs)
  403. scriptPlayable.SetProcessInputs(false);
  404. playable = scriptPlayable;
  405. }
  406. /************************************************************************************************************************/
  407. /// <summary>
  408. /// Gets the Animation Job data from the <see cref="AnimationScriptPlayable"/>.
  409. /// </summary>
  410. /// <exception cref="InvalidCastException">
  411. /// This mixer was not initialized using <see cref="CreatePlayable{T}(AnimancerPlayable, T, bool)"/>
  412. /// or <see cref="CreatePlayable{T}(out Playable, T, bool)"/>.
  413. /// </exception>
  414. public T GetJobData<T>()
  415. where T : struct, IAnimationJob
  416. => ((AnimationScriptPlayable)_Playable).GetJobData<T>();
  417. /// <summary>
  418. /// Sets the Animation Job data in the <see cref="AnimationScriptPlayable"/>.
  419. /// </summary>
  420. /// <exception cref="InvalidCastException">
  421. /// This mixer was not initialized using <see cref="CreatePlayable{T}(AnimancerPlayable, T, bool)"/>
  422. /// or <see cref="CreatePlayable{T}(out Playable, T, bool)"/>.
  423. /// </exception>
  424. public void SetJobData<T>(T value)
  425. where T : struct, IAnimationJob
  426. => ((AnimationScriptPlayable)_Playable).SetJobData<T>(value);
  427. /************************************************************************************************************************/
  428. #endregion
  429. /************************************************************************************************************************/
  430. #region Updates
  431. /************************************************************************************************************************/
  432. /// <summary>Updates the time of this mixer and all of its child states.</summary>
  433. protected internal override void Update(out bool needsMoreUpdates)
  434. {
  435. base.Update(out needsMoreUpdates);
  436. if (RecalculateWeights())
  437. {
  438. // Apply the child weights immediately to ensure they are all in sync. Otherwise some of them might
  439. // have already updated before the mixer and would not apply it until next frame.
  440. var childStates = ChildStates;
  441. for (int i = childStates.Count - 1; i >= 0; i--)
  442. {
  443. var state = childStates[i];
  444. if (state == null)
  445. continue;
  446. state.ApplyWeight();
  447. }
  448. }
  449. ApplySynchronizeChildren(ref needsMoreUpdates);
  450. }
  451. /************************************************************************************************************************/
  452. /// <summary>Indicates whether the weights of all child states should be recalculated.</summary>
  453. public bool WeightsAreDirty { get; set; }
  454. /************************************************************************************************************************/
  455. /// <summary>
  456. /// If <see cref="WeightsAreDirty"/> this method recalculates the weights of all child states and returns true.
  457. /// </summary>
  458. public bool RecalculateWeights()
  459. {
  460. if (!WeightsAreDirty)
  461. return false;
  462. ForceRecalculateWeights();
  463. Debug.Assert(!WeightsAreDirty,
  464. $"{nameof(MixerState)}.{nameof(WeightsAreDirty)} was not set to false by {nameof(ForceRecalculateWeights)}().");
  465. return true;
  466. }
  467. /************************************************************************************************************************/
  468. /// <summary>
  469. /// Recalculates the weights of all child states based on the current value of the
  470. /// <see cref="MixerState{TParameter}.Parameter"/> and the thresholds.
  471. /// <para></para>
  472. /// Overrides of this method must set <see cref="WeightsAreDirty"/> = false.
  473. /// </summary>
  474. protected virtual void ForceRecalculateWeights() { }
  475. /************************************************************************************************************************/
  476. #endregion
  477. /************************************************************************************************************************/
  478. #region Synchronize Children
  479. /************************************************************************************************************************/
  480. /// <summary>Should newly added children be automatically added to the synchronization list? Default true.</summary>
  481. public static bool AutoSynchronizeChildren { get; set; } = true;
  482. /// <summary>The minimum total weight of all children for their times to be synchronized (default 0.01).</summary>
  483. public static float MinimumSynchronizeChildrenWeight { get; set; } = 0.01f;
  484. /************************************************************************************************************************/
  485. private List<AnimancerState> _SynchronizedChildren;
  486. /// <summary>A copy of the internal list of child states that will have their times synchronized.</summary>
  487. /// <remarks>
  488. /// If this mixer is a child of another mixer, its synchronized children will be managed by the parent.
  489. /// <para></para>
  490. /// The getter allocates a new array if <see cref="SynchronizedChildCount"/> is greater than zero.
  491. /// </remarks>
  492. public AnimancerState[] SynchronizedChildren
  493. {
  494. get => SynchronizedChildCount > 0 ? _SynchronizedChildren.ToArray() : Array.Empty<AnimancerState>();
  495. set
  496. {
  497. if (_SynchronizedChildren == null)
  498. _SynchronizedChildren = new List<AnimancerState>();
  499. else
  500. _SynchronizedChildren.Clear();
  501. for (int i = 0; i < value.Length; i++)
  502. Synchronize(value[i]);
  503. }
  504. }
  505. /// <summary>The number of <see cref="SynchronizedChildren"/>.</summary>
  506. public int SynchronizedChildCount => _SynchronizedChildren != null ? _SynchronizedChildren.Count : 0;
  507. /************************************************************************************************************************/
  508. /// <summary>Is the `state` in the <see cref="SynchronizedChildren"/>?</summary>
  509. public bool IsSynchronized(AnimancerState state)
  510. {
  511. var synchronizer = GetParentMixer();
  512. return
  513. synchronizer._SynchronizedChildren != null &&
  514. synchronizer._SynchronizedChildren.Contains(state);
  515. }
  516. /************************************************************************************************************************/
  517. /// <summary>Adds the `state` to the <see cref="SynchronizedChildren"/>.</summary>
  518. /// <remarks>
  519. /// The `state` must be a child of this mixer.
  520. /// <para></para>
  521. /// If this mixer is a child of another mixer, the `state` will be added to the parent's
  522. /// <see cref="SynchronizedChildren"/> instead.
  523. /// </remarks>
  524. public void Synchronize(AnimancerState state)
  525. {
  526. if (state == null)
  527. return;
  528. #if UNITY_ASSERTIONS
  529. if (!IsChildOf(state, this))
  530. throw new ArgumentException(
  531. $"State is not a child of the mixer." +
  532. $"\n - State: {state}" +
  533. $"\n - Mixer: {this}",
  534. nameof(state));
  535. #endif
  536. var synchronizer = GetParentMixer();
  537. synchronizer.SynchronizeDirect(state);
  538. }
  539. /// <summary>The internal implementation of <see cref="Synchronize"/>.</summary>
  540. private void SynchronizeDirect(AnimancerState state)
  541. {
  542. if (state == null)
  543. return;
  544. if (state is MixerState mixer)
  545. {
  546. for (int i = 0; i < mixer._SynchronizedChildren.Count; i++)
  547. Synchronize(mixer._SynchronizedChildren[i]);
  548. mixer._SynchronizedChildren.Clear();
  549. return;
  550. }
  551. #if UNITY_ASSERTIONS
  552. if (OptionalWarning.MixerSynchronizeZeroLength.IsEnabled() && state.Length == 0)
  553. OptionalWarning.MixerSynchronizeZeroLength.Log(
  554. $"Adding a state with zero {nameof(AnimancerState.Length)} to the synchronization list: '{state}'." +
  555. $"\n\nSynchronization is based on the {nameof(NormalizedTime)}" +
  556. $" which can't be calculated if the {nameof(Length)} is 0." +
  557. $" Some state types can change their {nameof(Length)}, in which case you can just disable this warning." +
  558. $" But otherwise, the indicated state probably shouldn't be added to the synchronization list.", Root?.Component);
  559. #endif
  560. if (_SynchronizedChildren == null)
  561. _SynchronizedChildren = new List<AnimancerState>();
  562. #if UNITY_ASSERTIONS
  563. if (_SynchronizedChildren.Contains(state))
  564. Debug.LogError($"{state} is already in the {nameof(SynchronizedChildren)} list.");
  565. #endif
  566. _SynchronizedChildren.Add(state);
  567. RequireUpdate();
  568. }
  569. /************************************************************************************************************************/
  570. /// <summary>Removes the `state` from the <see cref="SynchronizedChildren"/>.</summary>
  571. public void DontSynchronize(AnimancerState state)
  572. {
  573. var synchronizer = GetParentMixer();
  574. if (synchronizer._SynchronizedChildren != null &&
  575. synchronizer._SynchronizedChildren.Remove(state) &&
  576. state._Playable.IsValid())
  577. state._Playable.SetSpeed(state.Speed);
  578. }
  579. /************************************************************************************************************************/
  580. /// <summary>Removes all children of this mixer from the <see cref="SynchronizedChildren"/>.</summary>
  581. public void DontSynchronizeChildren()
  582. {
  583. var synchronizer = GetParentMixer();
  584. var SynchronizedChildren = synchronizer._SynchronizedChildren;
  585. if (SynchronizedChildren == null)
  586. return;
  587. if (synchronizer == this)
  588. {
  589. for (int i = SynchronizedChildren.Count - 1; i >= 0; i--)
  590. {
  591. var state = SynchronizedChildren[i];
  592. if (state._Playable.IsValid())
  593. state._Playable.SetSpeed(state.Speed);
  594. }
  595. SynchronizedChildren.Clear();
  596. }
  597. else
  598. {
  599. for (int i = SynchronizedChildren.Count - 1; i >= 0; i--)
  600. {
  601. var state = SynchronizedChildren[i];
  602. if (IsChildOf(state, this))
  603. {
  604. if (state._Playable.IsValid())
  605. state._Playable.SetSpeed(state.Speed);
  606. SynchronizedChildren.RemoveAt(i);
  607. }
  608. }
  609. }
  610. }
  611. /************************************************************************************************************************/
  612. /// <summary>Initializes the internal <see cref="SynchronizedChildren"/> list.</summary>
  613. /// <remarks>
  614. /// The array can be null or empty. Any elements not in the array will be treated as <c>true</c>.
  615. /// <para></para>
  616. /// This method can only be called before any <see cref="SynchronizedChildren"/> are added and also before this
  617. /// mixer is made the child of another mixer.
  618. /// </remarks>
  619. public void InitializeSynchronizedChildren(params bool[] synchronizeChildren)
  620. {
  621. AnimancerUtilities.Assert(GetParentMixer() == this,
  622. $"{nameof(InitializeSynchronizedChildren)} cannot be used on a mixer that is a child of another mixer.");
  623. AnimancerUtilities.Assert(_SynchronizedChildren == null,
  624. $"{nameof(InitializeSynchronizedChildren)} cannot be used on a mixer already has synchronized children.");
  625. int flagCount;
  626. if (synchronizeChildren != null)
  627. {
  628. flagCount = synchronizeChildren.Length;
  629. for (int i = 0; i < flagCount; i++)
  630. if (synchronizeChildren[i])
  631. SynchronizeDirect(GetChild(i));
  632. }
  633. else flagCount = 0;
  634. for (int i = flagCount; i < ChildCount; i++)
  635. SynchronizeDirect(GetChild(i));
  636. }
  637. /************************************************************************************************************************/
  638. /// <summary>
  639. /// Returns the highest <see cref="MixerState"/> in the hierarchy above this mixer or this mixer itself if
  640. /// there are none above it.
  641. /// </summary>
  642. public MixerState GetParentMixer()
  643. {
  644. var mixer = this;
  645. var parent = Parent;
  646. while (parent != null)
  647. {
  648. if (parent is MixerState parentMixer)
  649. mixer = parentMixer;
  650. parent = parent.Parent;
  651. }
  652. return mixer;
  653. }
  654. /// <summary>Returns the highest <see cref="MixerState"/> in the hierarchy above the `state` (inclusive).</summary>
  655. public static MixerState GetParentMixer(IPlayableWrapper node)
  656. {
  657. MixerState mixer = null;
  658. while (node != null)
  659. {
  660. if (node is MixerState parentMixer)
  661. mixer = parentMixer;
  662. node = node.Parent;
  663. }
  664. return mixer;
  665. }
  666. /************************************************************************************************************************/
  667. /// <summary>Is the `child` a child of the `parent`?</summary>
  668. public static bool IsChildOf(IPlayableWrapper child, IPlayableWrapper parent)
  669. {
  670. while (true)
  671. {
  672. child = child.Parent;
  673. if (child == parent)
  674. return true;
  675. else if (child == null)
  676. return false;
  677. }
  678. }
  679. /************************************************************************************************************************/
  680. /// <summary>
  681. /// Synchronizes the <see cref="AnimancerState.NormalizedTime"/>s of the <see cref="SynchronizedChildren"/> by
  682. /// modifying their internal playable speeds.
  683. /// </summary>
  684. protected void ApplySynchronizeChildren(ref bool needsMoreUpdates)
  685. {
  686. if (_SynchronizedChildren == null || _SynchronizedChildren.Count <= 1)
  687. return;
  688. needsMoreUpdates = true;
  689. var deltaTime = AnimancerPlayable.DeltaTime * CalculateRealEffectiveSpeed();
  690. if (deltaTime == 0)
  691. return;
  692. var count = _SynchronizedChildren.Count;
  693. // Calculate the weighted average normalized time and normalized speed of all children.
  694. var totalWeight = 0f;
  695. var weightedNormalizedTime = 0f;
  696. var weightedNormalizedSpeed = 0f;
  697. for (int i = 0; i < count; i++)
  698. {
  699. var state = _SynchronizedChildren[i];
  700. var weight = state.Weight;
  701. if (weight == 0)
  702. continue;
  703. var length = state.Length;
  704. if (length == 0)
  705. continue;
  706. totalWeight += weight;
  707. weight /= length;
  708. weightedNormalizedTime += state.Time * weight;
  709. weightedNormalizedSpeed += state.Speed * weight;
  710. }
  711. #if UNITY_ASSERTIONS
  712. if (!(totalWeight >= 0) || totalWeight == float.PositiveInfinity)// Reversed comparison includes NaN.
  713. throw new ArgumentOutOfRangeException(nameof(totalWeight), totalWeight,
  714. $"Total weight {Strings.MustBeFinite} and must be positive");
  715. if (!weightedNormalizedTime.IsFinite())
  716. throw new ArgumentOutOfRangeException(nameof(weightedNormalizedTime), weightedNormalizedTime,
  717. $"Time {Strings.MustBeFinite}");
  718. if (!weightedNormalizedSpeed.IsFinite())
  719. throw new ArgumentOutOfRangeException(nameof(weightedNormalizedSpeed), weightedNormalizedSpeed,
  720. $"Speed {Strings.MustBeFinite}");
  721. #endif
  722. // If the total weight is too small, pretend they are all at Weight = 1.
  723. if (totalWeight < MinimumSynchronizeChildrenWeight)
  724. {
  725. weightedNormalizedTime = 0;
  726. weightedNormalizedSpeed = 0;
  727. var nonZeroCount = 0;
  728. for (int i = 0; i < count; i++)
  729. {
  730. var state = _SynchronizedChildren[i];
  731. var length = state.Length;
  732. if (length == 0)
  733. continue;
  734. length = 1f / length;
  735. weightedNormalizedTime += state.Time * length;
  736. weightedNormalizedSpeed += state.Speed * length;
  737. nonZeroCount++;
  738. }
  739. totalWeight = nonZeroCount;
  740. }
  741. // Increment that time value according to delta time.
  742. weightedNormalizedTime += deltaTime * weightedNormalizedSpeed;
  743. weightedNormalizedTime /= totalWeight;
  744. var inverseDeltaTime = 1f / deltaTime;
  745. // Modify the speed of all children to go from their current normalized time to the average in one frame.
  746. for (int i = 0; i < count; i++)
  747. {
  748. var state = _SynchronizedChildren[i];
  749. var length = state.Length;
  750. if (length == 0)
  751. continue;
  752. var normalizedTime = state.Time / length;
  753. var speed = (weightedNormalizedTime - normalizedTime) * length * inverseDeltaTime;
  754. state._Playable.SetSpeed(speed);
  755. }
  756. // After this, all the playables will update and advance according to their new speeds this frame.
  757. }
  758. /************************************************************************************************************************/
  759. /// <summary>
  760. /// The multiplied <see cref="PlayableExtensions.GetSpeed"/> of this mixer and its parents down the
  761. /// hierarchy to determine the actual speed its output is being played at.
  762. /// </summary>
  763. /// <remarks>
  764. /// This can be different from the <see cref="AnimancerNode.EffectiveSpeed"/> because the
  765. /// <see cref="SynchronizedChildren"/> have their playable speed modified without setting their
  766. /// <see cref="AnimancerNode.Speed"/>.
  767. /// </remarks>
  768. public float CalculateRealEffectiveSpeed()
  769. {
  770. var speed = _Playable.GetSpeed();
  771. var parent = Parent;
  772. while (parent != null)
  773. {
  774. speed *= parent.Playable.GetSpeed();
  775. parent = parent.Parent;
  776. }
  777. return (float)speed;
  778. }
  779. /************************************************************************************************************************/
  780. #endregion
  781. /************************************************************************************************************************/
  782. #region Inverse Kinematics
  783. /************************************************************************************************************************/
  784. private bool _ApplyAnimatorIK;
  785. /// <inheritdoc/>
  786. public override bool ApplyAnimatorIK
  787. {
  788. get => _ApplyAnimatorIK;
  789. set => base.ApplyAnimatorIK = _ApplyAnimatorIK = value;
  790. }
  791. /************************************************************************************************************************/
  792. private bool _ApplyFootIK;
  793. /// <inheritdoc/>
  794. public override bool ApplyFootIK
  795. {
  796. get => _ApplyFootIK;
  797. set => base.ApplyFootIK = _ApplyFootIK = value;
  798. }
  799. /************************************************************************************************************************/
  800. #endregion
  801. /************************************************************************************************************************/
  802. #region Other Methods
  803. /************************************************************************************************************************/
  804. /// <summary>Calculates the sum of the <see cref="AnimancerNode.Weight"/> of all `states`.</summary>
  805. public float CalculateTotalWeight(IList<AnimancerState> states)
  806. {
  807. var total = 0f;
  808. for (int i = states.Count - 1; i >= 0; i--)
  809. {
  810. var state = states[i];
  811. if (state != null)
  812. total += state.Weight;
  813. }
  814. return total;
  815. }
  816. /************************************************************************************************************************/
  817. /// <summary>
  818. /// Sets <see cref="AnimancerState.Time"/> for all <see cref="ChildStates"/>.
  819. /// </summary>
  820. public void SetChildrenTime(float value, bool normalized = false)
  821. {
  822. var states = ChildStates;
  823. for (int i = states.Count - 1; i >= 0; i--)
  824. {
  825. var state = states[i];
  826. if (state == null)
  827. continue;
  828. if (normalized)
  829. state.NormalizedTime = value;
  830. else
  831. state.Time = value;
  832. }
  833. }
  834. /************************************************************************************************************************/
  835. /// <summary>
  836. /// Sets the weight of all states after the `previousIndex` to 0.
  837. /// </summary>
  838. protected void DisableRemainingStates(int previousIndex)
  839. {
  840. var states = ChildStates;
  841. var childCount = states.Count;
  842. while (++previousIndex < childCount)
  843. {
  844. var state = states[previousIndex];
  845. if (state == null)
  846. continue;
  847. state.Weight = 0;
  848. }
  849. }
  850. /************************************************************************************************************************/
  851. /// <summary>
  852. /// Returns the state at the specified `index` if it is not null, otherwise increments the index and checks
  853. /// again. Returns null if no state is found by the end of the <see cref="ChildStates"/>.
  854. /// </summary>
  855. protected AnimancerState GetNextState(ref int index)
  856. {
  857. var states = ChildStates;
  858. var childCount = states.Count;
  859. while (index < childCount)
  860. {
  861. var state = states[index];
  862. if (state != null)
  863. return state;
  864. index++;
  865. }
  866. return null;
  867. }
  868. /************************************************************************************************************************/
  869. /// <summary>Divides the weight of all child states by the `totalWeight`.</summary>
  870. /// <remarks>
  871. /// If the `totalWeight` is equal to the total <see cref="AnimancerNode.Weight"/> of all child states, then the
  872. /// new total will become 1.
  873. /// </remarks>
  874. public void NormalizeWeights(float totalWeight)
  875. {
  876. if (totalWeight == 1)
  877. return;
  878. totalWeight = 1f / totalWeight;
  879. var states = ChildStates;
  880. for (int i = states.Count - 1; i >= 0; i--)
  881. {
  882. var state = states[i];
  883. if (state == null)
  884. continue;
  885. state.Weight *= totalWeight;
  886. }
  887. }
  888. /************************************************************************************************************************/
  889. /// <summary>Gets a user-friendly key to identify the `state` in the Inspector.</summary>
  890. public virtual string GetDisplayKey(AnimancerState state) => $"[{state.Index}]";
  891. /************************************************************************************************************************/
  892. /// <inheritdoc/>
  893. public override Vector3 AverageVelocity
  894. {
  895. get
  896. {
  897. var velocity = default(Vector3);
  898. RecalculateWeights();
  899. var childStates = ChildStates;
  900. for (int i = childStates.Count - 1; i >= 0; i--)
  901. {
  902. var state = childStates[i];
  903. if (state == null)
  904. continue;
  905. velocity += state.AverageVelocity * state.Weight;
  906. }
  907. return velocity;
  908. }
  909. }
  910. /************************************************************************************************************************/
  911. /// <summary>
  912. /// Recalculates the <see cref="AnimancerState.Duration"/> of all child states so that they add up to 1.
  913. /// </summary>
  914. /// <exception cref="NullReferenceException">There are any states with no <see cref="Clip"/>.</exception>
  915. public void NormalizeDurations()
  916. {
  917. var childStates = ChildStates;
  918. int divideBy = 0;
  919. float totalDuration = 0f;
  920. // Count the number of states that exist and their total duration.
  921. var count = childStates.Count;
  922. for (int i = 0; i < count; i++)
  923. {
  924. var state = childStates[i];
  925. if (state == null)
  926. continue;
  927. divideBy++;
  928. totalDuration += state.Duration;
  929. }
  930. // Calculate the average duration.
  931. totalDuration /= divideBy;
  932. // Set all states to that duration.
  933. for (int i = 0; i < count; i++)
  934. {
  935. var state = childStates[i];
  936. if (state == null)
  937. continue;
  938. state.Duration = totalDuration;
  939. }
  940. }
  941. /************************************************************************************************************************/
  942. #if UNITY_ASSERTIONS
  943. /// <summary>Has the <see cref="AnimancerNode.DebugName"/> been generated from the child states?</summary>
  944. private bool _IsGeneratedName;
  945. #endif
  946. /// <summary>
  947. /// Returns a string describing the type of this mixer and the name of <see cref="Clip"/>s connected to it.
  948. /// </summary>
  949. public override string ToString()
  950. {
  951. #if UNITY_ASSERTIONS
  952. if (!string.IsNullOrEmpty(DebugName))
  953. return DebugName;
  954. #endif
  955. // Gather child names.
  956. var childNames = ObjectPool.AcquireList<string>();
  957. var allSimple = true;
  958. var states = ChildStates;
  959. var count = states.Count;
  960. for (int i = 0; i < count; i++)
  961. {
  962. var state = states[i];
  963. if (state == null)
  964. continue;
  965. if (state.MainObject != null)
  966. {
  967. childNames.Add(state.MainObject.name);
  968. }
  969. else
  970. {
  971. childNames.Add(state.ToString());
  972. allSimple = false;
  973. }
  974. }
  975. // If they all have a main object, check if they all have the same prefix so it doesn't need to be repeated.
  976. int prefixLength = 0;
  977. count = childNames.Count;
  978. if (count <= 1 || !allSimple)
  979. {
  980. prefixLength = 0;
  981. }
  982. else
  983. {
  984. var prefix = childNames[0];
  985. var shortest = prefixLength = prefix.Length;
  986. for (int iName = 0; iName < count; iName++)
  987. {
  988. var childName = childNames[iName];
  989. if (shortest > childName.Length)
  990. {
  991. shortest = prefixLength = childName.Length;
  992. }
  993. for (int iCharacter = 0; iCharacter < prefixLength; iCharacter++)
  994. {
  995. if (childName[iCharacter] != prefix[iCharacter])
  996. {
  997. prefixLength = iCharacter;
  998. break;
  999. }
  1000. }
  1001. }
  1002. if (prefixLength < 3 ||// Less than 3 characters probably isn't an intentional prefix.
  1003. prefixLength >= shortest)
  1004. prefixLength = 0;
  1005. }
  1006. // Build the mixer name.
  1007. var mixerName = ObjectPool.AcquireStringBuilder();
  1008. if (count > 0)
  1009. {
  1010. if (prefixLength > 0)
  1011. mixerName.Append(childNames[0], 0, prefixLength).Append('[');
  1012. for (int i = 0; i < count; i++)
  1013. {
  1014. if (i > 0)
  1015. mixerName.Append(", ");
  1016. var childName = childNames[i];
  1017. mixerName.Append(childName, prefixLength, childName.Length - prefixLength);
  1018. }
  1019. mixerName.Append(prefixLength > 0 ? "] (" : " (");
  1020. }
  1021. ObjectPool.Release(childNames);
  1022. var type = GetType().FullName;
  1023. if (type.EndsWith("State"))
  1024. mixerName.Append(type, 0, type.Length - 5);
  1025. else
  1026. mixerName.Append(type);
  1027. if (count > 0)
  1028. mixerName.Append(')');
  1029. var result = mixerName.ReleaseToString();
  1030. #if UNITY_ASSERTIONS
  1031. _IsGeneratedName = true;
  1032. SetDebugName(result);
  1033. #endif
  1034. return result;
  1035. }
  1036. /************************************************************************************************************************/
  1037. /// <inheritdoc/>
  1038. protected override void AppendDetails(StringBuilder text, string separator)
  1039. {
  1040. base.AppendDetails(text, separator);
  1041. text.Append(separator).Append("SynchronizedChildren: ");
  1042. if (SynchronizedChildCount == 0)
  1043. {
  1044. text.Append("0");
  1045. }
  1046. else
  1047. {
  1048. text.Append(_SynchronizedChildren.Count);
  1049. separator += Strings.Indent;
  1050. for (int i = 0; i < _SynchronizedChildren.Count; i++)
  1051. {
  1052. text.Append(separator)
  1053. .Append(_SynchronizedChildren[i]);
  1054. }
  1055. }
  1056. }
  1057. /************************************************************************************************************************/
  1058. /// <inheritdoc/>
  1059. public override void GatherAnimationClips(ICollection<AnimationClip> clips) => clips.GatherFromSource(ChildStates);
  1060. /************************************************************************************************************************/
  1061. #endregion
  1062. /************************************************************************************************************************/
  1063. }
  1064. }