ManualMixerState.cs 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 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]
  13. /// An <see cref="AnimancerState"/> which blends multiple child states
  14. /// by allowing you to control their <see cref="AnimancerNode.Weight"/> manually.
  15. /// </summary>
  16. /// <remarks>
  17. /// This mixer type is similar to the Direct Blend Type in Mecanim Blend Trees.
  18. /// The official <see href="https://learn.unity.com/tutorial/5c5152bcedbc2a001fd5c696">Direct Blend Trees</see>
  19. /// tutorial explains their general concepts and purpose which apply to <see cref="ManualMixerState"/>s as well.
  20. /// <para></para>
  21. /// <strong>Documentation:</strong>
  22. /// <see href="https://kybernetik.com.au/animancer/docs/manual/blending/mixers">
  23. /// Mixers</see>
  24. /// </remarks>
  25. /// https://kybernetik.com.au/animancer/api/Animancer/ManualMixerState
  26. ///
  27. public partial class ManualMixerState : AnimancerState,
  28. ICopyable<ManualMixerState>,
  29. IParametizedState,
  30. IUpdatable
  31. {
  32. /************************************************************************************************************************/
  33. #region Properties
  34. /************************************************************************************************************************/
  35. /// <summary>The states connected to this mixer.</summary>
  36. /// <remarks>Only states up to the <see cref="ChildCount"/> should be assigned.</remarks>
  37. protected AnimancerState[] ChildStates { get; private set; }
  38. = Array.Empty<AnimancerState>();
  39. /************************************************************************************************************************/
  40. private int _ChildCount;
  41. /// <inheritdoc/>
  42. public sealed override int ChildCount
  43. => _ChildCount;
  44. /************************************************************************************************************************/
  45. /// <summary>The size of the internal array of <see cref="ChildStates"/>.</summary>
  46. /// <remarks>This value starts at 0 then expands to <see cref="ChildCapacity"/> when the first child is added.</remarks>
  47. public int ChildCapacity
  48. {
  49. get => ChildStates.Length;
  50. set
  51. {
  52. if (value == ChildStates.Length)
  53. return;
  54. #if UNITY_ASSERTIONS
  55. if (value <= 1 && OptionalWarning.MixerMinChildren.IsEnabled())
  56. OptionalWarning.MixerMinChildren.Log(
  57. $"The {nameof(ChildCapacity)} of '{this}' is being set to {value}." +
  58. $" The purpose of a mixer is to mix multiple child states so this may be a mistake.",
  59. Graph?.Component);
  60. #endif
  61. var newChildStates = new AnimancerState[value];
  62. if (value > _ChildCount)// Increase size.
  63. {
  64. Array.Copy(ChildStates, newChildStates, _ChildCount);
  65. }
  66. else// Decrease size.
  67. {
  68. for (int i = value; i < _ChildCount; i++)
  69. ChildStates[i].Destroy();
  70. Array.Copy(ChildStates, newChildStates, value);
  71. _ChildCount = value;
  72. }
  73. ChildStates = newChildStates;
  74. if (_Playable.IsValid())
  75. {
  76. _Playable.SetInputCount(value);
  77. }
  78. else if (Graph != null)
  79. {
  80. CreatePlayable();
  81. }
  82. OnChildCapacityChanged();
  83. }
  84. }
  85. /// <summary>Called when the <see cref="ChildCapacity"/> is changed.</summary>
  86. protected virtual void OnChildCapacityChanged() { }
  87. /// <summary><see cref="ChildCapacity"/> starts at 0 then expands to this value when the first child is added.</summary>
  88. /// <remarks>Default 8.</remarks>
  89. public static int DefaultChildCapacity { get; set; } = 8;
  90. /// <summary>
  91. /// Ensures that the remaining unused <see cref="ChildCapacity"/>
  92. /// is greater than or equal to the specified `minimumCapacity`.
  93. /// </summary>
  94. public void EnsureRemainingChildCapacity(int minimumCapacity)
  95. {
  96. minimumCapacity += _ChildCount;
  97. if (ChildCapacity < minimumCapacity)
  98. {
  99. var capacity = Math.Max(ChildCapacity, DefaultChildCapacity);
  100. while (capacity < minimumCapacity)
  101. capacity *= 2;
  102. ChildCapacity = capacity;
  103. }
  104. }
  105. /************************************************************************************************************************/
  106. /// <inheritdoc/>
  107. public sealed override AnimancerState GetChild(int index)
  108. => ChildStates[index];
  109. /// <inheritdoc/>
  110. public sealed override FastEnumerator<AnimancerState> GetEnumerator()
  111. => new(ChildStates, _ChildCount);
  112. /************************************************************************************************************************/
  113. /// <inheritdoc/>
  114. protected override void OnSetIsPlaying()
  115. {
  116. var isPlaying = IsPlaying;
  117. for (int i = _ChildCount - 1; i >= 0; i--)
  118. ChildStates[i].IsPlaying = isPlaying;
  119. }
  120. /************************************************************************************************************************/
  121. /// <summary>If greater than 0 then <see cref="IsLooping"/> is true.</summary>
  122. private int _LoopingChildCount;
  123. /// <summary>Are any child states looping?</summary>
  124. public override bool IsLooping
  125. => _LoopingChildCount > 0;
  126. /// <summary>Sets <see cref="IsLooping"/> and informs the <see cref="AnimancerNodeBase.Parent"/>s.</summary>
  127. private void AddIsLooping(int offset)
  128. {
  129. var wasLooping = IsLooping;
  130. _LoopingChildCount += offset;
  131. var isLooping = IsLooping;
  132. if (wasLooping != isLooping)
  133. OnIsLoopingChangedRecursive(isLooping);
  134. }
  135. /// <inheritdoc/>
  136. protected override void OnChildIsLoopingChanged(bool value)
  137. => AddIsLooping(value ? 1 : -1);
  138. /************************************************************************************************************************/
  139. /// <summary>The weighted average <see cref="AnimancerState.Time"/> of each child state.</summary>
  140. /// <remarks>
  141. /// If there are any <see cref="SynchronizedChildren"/>,
  142. /// only those states will be included in the getter calculation.
  143. /// </remarks>
  144. public override double RawTime
  145. {
  146. get
  147. {
  148. GetTimeDetails(out var totalWeight, out var normalizedTime, out var length);
  149. if (totalWeight == 0)
  150. return base.RawTime;
  151. totalWeight *= totalWeight;
  152. return normalizedTime * length / totalWeight;
  153. }
  154. set
  155. {
  156. if (value == 0)
  157. goto SetToZero;
  158. var length = Length;
  159. if (length == 0)
  160. goto SetToZero;
  161. value /= length;// Normalize.
  162. for (int i = _ChildCount - 1; i >= 0; i--)
  163. ChildStates[i].NormalizedTimeD = value;
  164. return;
  165. // If the value is 0, we can set the child times more efficiently.
  166. SetToZero:
  167. for (int i = _ChildCount - 1; i >= 0; i--)
  168. ChildStates[i].TimeD = 0;
  169. }
  170. }
  171. /************************************************************************************************************************/
  172. /// <inheritdoc/>
  173. public override void MoveTime(double time, bool normalized)
  174. {
  175. base.MoveTime(time, normalized);
  176. for (int i = _ChildCount - 1; i >= 0; i--)
  177. ChildStates[i].MoveTime(time, normalized);
  178. }
  179. /************************************************************************************************************************/
  180. /// <inheritdoc/>
  181. public override void GetEventDispatchInfo(
  182. out float length,
  183. out float normalizedTime,
  184. out bool isLooping)
  185. {
  186. GetTimeDetails(out _, out normalizedTime, out length);
  187. isLooping = _LoopingChildCount > 0;
  188. }
  189. /************************************************************************************************************************/
  190. /// <summary>
  191. /// Gets the time details based on the synchronized child states if any are active,
  192. /// otherwise recalculates based on all child states.
  193. /// </summary>
  194. private void GetTimeDetails(out float totalWeight, out float normalizedTime, out float length)
  195. {
  196. if (_SynchronizedChildren != null)
  197. {
  198. GetTimeDetails(
  199. _SynchronizedChildren,
  200. _SynchronizedChildren.Count,
  201. out totalWeight,
  202. out normalizedTime,
  203. out length);
  204. if (totalWeight > MinimumSynchronizeChildrenWeight)
  205. return;
  206. }
  207. GetTimeDetails(
  208. ChildStates,
  209. _ChildCount,
  210. out totalWeight,
  211. out normalizedTime,
  212. out length);
  213. }
  214. /// <summary>Gets the time details based on the `states`.</summary>
  215. private void GetTimeDetails(
  216. IList<AnimancerState> states,
  217. int count,
  218. out float totalWeight,
  219. out float normalizedTime,
  220. out float length)
  221. {
  222. totalWeight = 0;
  223. normalizedTime = 0;
  224. length = 0;
  225. for (int i = count - 1; i >= 0; i--)
  226. {
  227. var state = states[i];
  228. var weight = state.Weight;
  229. if (weight == 0)
  230. continue;
  231. var stateLength = state.Length;
  232. if (stateLength == 0)
  233. continue;
  234. totalWeight += weight;
  235. normalizedTime += state.Time / stateLength * weight;
  236. length += stateLength * weight;
  237. }
  238. }
  239. /************************************************************************************************************************/
  240. /// <summary>The weighted average <see cref="AnimancerState.Length"/> of each child state.</summary>
  241. public override float Length
  242. {
  243. get
  244. {
  245. var length = 0f;
  246. var totalChildWeight = 0f;
  247. if (_SynchronizedChildren != null)
  248. {
  249. for (int i = _SynchronizedChildren.Count - 1; i >= 0; i--)
  250. {
  251. var state = _SynchronizedChildren[i];
  252. var weight = state.Weight;
  253. if (weight == 0)
  254. continue;
  255. var stateLength = state.Length;
  256. if (stateLength == 0)
  257. continue;
  258. totalChildWeight += weight;
  259. length += stateLength * weight;
  260. }
  261. }
  262. if (totalChildWeight > 0)
  263. return length / totalChildWeight;
  264. totalChildWeight = CalculateTotalWeight(ChildStates, _ChildCount);
  265. if (totalChildWeight <= 0)
  266. return 0;
  267. for (int i = _ChildCount - 1; i >= 0; i--)
  268. {
  269. var state = ChildStates[i];
  270. length += state.Length * state.Weight;
  271. }
  272. return length / totalChildWeight;
  273. }
  274. }
  275. /************************************************************************************************************************/
  276. #endregion
  277. /************************************************************************************************************************/
  278. #region Initialization
  279. /************************************************************************************************************************/
  280. /// <summary>Creates and assigns the <see cref="AnimationMixerPlayable"/> managed by this state.</summary>
  281. protected override void CreatePlayable(out Playable playable)
  282. {
  283. playable = AnimationMixerPlayable.Create(Graph._PlayableGraph, ChildCapacity);
  284. }
  285. /************************************************************************************************************************/
  286. /// <summary>Connects the `state` to this mixer at its <see cref="AnimancerNode.Index"/>.</summary>
  287. protected internal override void OnAddChild(AnimancerState state)
  288. {
  289. Validate.AssertGraph(state, Graph);
  290. var capacity = ChildCapacity;
  291. if (_ChildCount >= capacity)
  292. ChildCapacity = Math.Max(DefaultChildCapacity, capacity * 2);
  293. state.Index = _ChildCount;
  294. ChildStates[_ChildCount] = state;
  295. _ChildCount++;
  296. state.IsPlaying = IsPlaying;
  297. if (Graph != null)
  298. ConnectChildUnsafe(state.Index, state);
  299. if (SynchronizeNewChildren)
  300. Synchronize(state);
  301. if (state.IsLooping)
  302. AddIsLooping(1);
  303. #if UNITY_ASSERTIONS
  304. _CachedToString = null;
  305. #endif
  306. }
  307. /************************************************************************************************************************/
  308. /// <summary>Disconnects the `state` from this mixer at its <see cref="AnimancerNode.Index"/>.</summary>
  309. protected internal override void OnRemoveChild(AnimancerState state)
  310. {
  311. DontSynchronize(state);
  312. Validate.AssertCanRemoveChild(state, ChildStates, _ChildCount);
  313. // Shuffle all subsequent children down one place.
  314. if (Graph == null || !Graph._PlayableGraph.IsValid())
  315. {
  316. Array.Copy(
  317. ChildStates, state.Index + 1,
  318. ChildStates, state.Index,
  319. _ChildCount - state.Index - 1);
  320. for (int i = state.Index; i < _ChildCount - 1; i++)
  321. ChildStates[i].Index = i;
  322. }
  323. else
  324. {
  325. Graph._PlayableGraph.Disconnect(_Playable, state.Index);
  326. for (int i = state.Index + 1; i < _ChildCount; i++)
  327. {
  328. var otherChild = ChildStates[i];
  329. Graph._PlayableGraph.Disconnect(_Playable, otherChild.Index);
  330. otherChild.Index = i - 1;
  331. ChildStates[i - 1] = otherChild;
  332. ConnectChildUnsafe(i - 1, otherChild);
  333. }
  334. }
  335. _ChildCount--;
  336. ChildStates[_ChildCount] = null;
  337. if (state.IsLooping)
  338. AddIsLooping(-1);
  339. #if UNITY_ASSERTIONS
  340. _CachedToString = null;
  341. #endif
  342. }
  343. /************************************************************************************************************************/
  344. /// <inheritdoc/>
  345. public override void Destroy()
  346. {
  347. DestroyChildren();
  348. base.Destroy();
  349. }
  350. /************************************************************************************************************************/
  351. /// <inheritdoc/>
  352. public override AnimancerState Clone(CloneContext context)
  353. {
  354. var clone = new ManualMixerState();
  355. clone.CopyFrom(this, context);
  356. return clone;
  357. }
  358. /************************************************************************************************************************/
  359. /// <inheritdoc/>
  360. public sealed override void CopyFrom(AnimancerState copyFrom, CloneContext context)
  361. => this.CopyFromBase(copyFrom, context);
  362. /// <inheritdoc/>
  363. public virtual void CopyFrom(ManualMixerState copyFrom, CloneContext context)
  364. {
  365. base.CopyFrom(copyFrom, context);
  366. DestroyChildren();
  367. var synchronizeNewChildren = SynchronizeNewChildren;
  368. var childCount = copyFrom.ChildCount;
  369. EnsureRemainingChildCapacity(childCount);
  370. for (int i = 0; i < childCount; i++)
  371. {
  372. var child = copyFrom.ChildStates[i];
  373. SynchronizeNewChildren = copyFrom.IsSynchronized(child);
  374. child = context.Clone(child);
  375. Add(child);
  376. }
  377. SynchronizeNewChildren = synchronizeNewChildren;
  378. }
  379. /************************************************************************************************************************/
  380. #endregion
  381. /************************************************************************************************************************/
  382. #region Child Configuration
  383. /************************************************************************************************************************/
  384. /// <summary>Assigns the `state` as a child of this mixer.</summary>
  385. /// <remarks>This is the same as calling <see cref="AnimancerState.SetParent"/>.</remarks>
  386. public void Add(AnimancerState state)
  387. => state.SetParent(this);
  388. /// <summary>Creates and returns a new <see cref="ClipState"/> to play the `clip` as a child of this mixer.</summary>
  389. public ClipState Add(AnimationClip clip)
  390. {
  391. var state = new ClipState(clip);
  392. Add(state);
  393. return state;
  394. }
  395. /// <summary>Calls <see cref="AnimancerUtilities.CreateStateAndApply"/> then <see cref="Add(AnimancerState)"/>.</summary>
  396. public AnimancerState Add(ITransition transition)
  397. {
  398. var state = transition.CreateStateAndApply(Graph);
  399. Add(state);
  400. return state;
  401. }
  402. /// <summary>Calls one of the other <see cref="Add(object)"/> overloads as appropriate for the `child`.</summary>
  403. public AnimancerState Add(object child)
  404. {
  405. if (child is AnimationClip clip)
  406. return Add(clip);
  407. if (child is ITransition transition)
  408. return Add(transition);
  409. if (child is AnimancerState state)
  410. {
  411. Add(state);
  412. return state;
  413. }
  414. MarkAsUsed(this);
  415. throw new ArgumentException($"Failed to {nameof(Add)} '{AnimancerUtilities.ToStringOrNull(child)}'" +
  416. $" as child of '{this}' because it isn't an" +
  417. $" {nameof(AnimationClip)}, {nameof(ITransition)}, or {nameof(AnimancerState)}.");
  418. }
  419. /************************************************************************************************************************/
  420. /// <summary>Calls <see cref="Add(AnimationClip)"/> for each of the `clips`.</summary>
  421. public void AddRange(IList<AnimationClip> clips)
  422. {
  423. var count = clips.Count;
  424. EnsureRemainingChildCapacity(count);
  425. for (int i = 0; i < count; i++)
  426. Add(clips[i]);
  427. }
  428. /// <summary>Calls <see cref="Add(AnimationClip)"/> for each of the `clips`.</summary>
  429. public void AddRange(params AnimationClip[] clips)
  430. => AddRange((IList<AnimationClip>)clips);
  431. /************************************************************************************************************************/
  432. /// <summary>Calls <see cref="Add(ITransition)"/> for each of the `transitions`.</summary>
  433. public void AddRange(IList<ITransition> transitions)
  434. {
  435. var count = transitions.Count;
  436. EnsureRemainingChildCapacity(count);
  437. for (int i = 0; i < count; i++)
  438. Add(transitions[i]);
  439. }
  440. /// <summary>Calls <see cref="Add(ITransition)"/> for each of the `transitions`.</summary>
  441. public void AddRange(params ITransition[] transitions)
  442. => AddRange((IList<ITransition>)transitions);
  443. /************************************************************************************************************************/
  444. /// <summary>Calls <see cref="Add(object)"/> for each of the `children`.</summary>
  445. public void AddRange(IList<object> children)
  446. {
  447. var count = children.Count;
  448. EnsureRemainingChildCapacity(count);
  449. for (int i = 0; i < count; i++)
  450. Add(children[i]);
  451. }
  452. /// <summary>Calls <see cref="Add(object)"/> for each of the `children`.</summary>
  453. public void AddRange(params object[] children)
  454. => AddRange((IList<object>)children);
  455. /************************************************************************************************************************/
  456. /// <summary>Removes the child at the specified `index`.</summary>
  457. public void Remove(int index, bool destroy)
  458. => Remove(ChildStates[index], destroy);
  459. /// <summary>Removes the specified `child`.</summary>
  460. public void Remove(AnimancerState child, bool destroy)
  461. {
  462. #if UNITY_ASSERTIONS
  463. if (child.Parent != this)
  464. Debug.LogWarning($"Attempting to remove a state which is not a child of this {GetType().Name}." +
  465. $" This will remove the child from its actual parent so you should directly call" +
  466. $" child.{nameof(child.Destroy)} or child.{nameof(child.SetParent)}(null, -1) instead." +
  467. $"\n• Child: {child}" +
  468. $"\n• Removing From: {this}" +
  469. $"\n• Actual Parent: {child.Parent}",
  470. Graph?.Component as Object);
  471. #endif
  472. if (destroy)
  473. child.Destroy();
  474. else
  475. child.SetParent(null);
  476. }
  477. /************************************************************************************************************************/
  478. /// <summary>Replaces the `child` at the specified `index`.</summary>
  479. public void Set(int index, AnimancerState child, bool destroyPrevious)
  480. {
  481. #if UNITY_ASSERTIONS
  482. if ((uint)index >= _ChildCount)
  483. {
  484. MarkAsUsed(this);
  485. MarkAsUsed(child);
  486. throw new IndexOutOfRangeException(
  487. $"Invalid child index. Must be 0 <= index < {nameof(ChildCount)} ({ChildCount}).");
  488. }
  489. #endif
  490. if (child.Parent != null)
  491. child.SetParent(null);
  492. var previousChild = ChildStates[index];
  493. DontSynchronize(previousChild);
  494. previousChild.SetParentInternal(null);
  495. child.SetGraph(Graph);
  496. ChildStates[index] = child;
  497. child.SetParentInternal(this, index);
  498. child.IsPlaying = IsPlaying;
  499. if (Graph != null)
  500. {
  501. Graph._PlayableGraph.Disconnect(_Playable, index);
  502. ConnectChildUnsafe(index, child);
  503. }
  504. var loopingOffset = 0;
  505. if (previousChild.IsLooping)
  506. loopingOffset--;
  507. if (child.IsLooping)
  508. loopingOffset++;
  509. if (loopingOffset != 0)
  510. AddIsLooping(loopingOffset);
  511. child.CopyIKFlags(this);
  512. if (SynchronizeNewChildren)
  513. Synchronize(child);
  514. if (destroyPrevious)
  515. previousChild.Destroy();
  516. #if UNITY_ASSERTIONS
  517. _CachedToString = null;
  518. #endif
  519. }
  520. /// <summary>Replaces the child at the specified `index` with a new <see cref="ClipState"/>.</summary>
  521. public ClipState Set(int index, AnimationClip clip, bool destroyPrevious)
  522. {
  523. var state = new ClipState(clip);
  524. Set(index, state, destroyPrevious);
  525. return state;
  526. }
  527. /// <summary>Replaces the child at the specified `index` with a <see cref="ITransition.CreateState"/>.</summary>
  528. public AnimancerState Set(int index, ITransition transition, bool destroyPrevious)
  529. {
  530. var state = transition.CreateStateAndApply(Graph);
  531. Set(index, state, destroyPrevious);
  532. return state;
  533. }
  534. /// <summary>Calls one of the other <see cref="Set(int, object, bool)"/> overloads as appropriate for the `child`.</summary>
  535. public AnimancerState Set(int index, object child, bool destroyPrevious)
  536. {
  537. if (child is AnimationClip clip)
  538. return Set(index, clip, destroyPrevious);
  539. if (child is ITransition transition)
  540. return Set(index, transition, destroyPrevious);
  541. if (child is AnimancerState state)
  542. {
  543. Set(index, state, destroyPrevious);
  544. return state;
  545. }
  546. MarkAsUsed(this);
  547. throw new ArgumentException($"Failed to {nameof(Set)} '{AnimancerUtilities.ToStringOrNull(child)}'" +
  548. $" as child of '{this}' because it isn't an" +
  549. $" {nameof(AnimationClip)}, {nameof(ITransition)}, or {nameof(AnimancerState)}.");
  550. }
  551. /************************************************************************************************************************/
  552. /// <summary>Returns the index of the specified `child` state.</summary>
  553. public int IndexOf(AnimancerState child)
  554. => Array.IndexOf(ChildStates, child, 0, _ChildCount);
  555. /************************************************************************************************************************/
  556. /// <summary>
  557. /// Destroys all <see cref="ChildStates"/> connected to this mixer. This operation cannot be undone.
  558. /// </summary>
  559. public void DestroyChildren()
  560. {
  561. for (int i = _ChildCount - 1; i >= 0; i--)
  562. ChildStates[i].Destroy();
  563. Array.Clear(ChildStates, 0, _ChildCount);
  564. _ChildCount = 0;
  565. }
  566. /************************************************************************************************************************/
  567. #endregion
  568. /************************************************************************************************************************/
  569. #region Jobs
  570. /************************************************************************************************************************/
  571. /// <summary>
  572. /// Creates an <see cref="AnimationScriptPlayable"/> to run the specified Animation Job instead of the usual
  573. /// <see cref="AnimationMixerPlayable"/>.
  574. /// </summary>
  575. ///
  576. /// <remarks>
  577. /// <strong>Example:</strong><code>
  578. /// void CreatePlayableExample(AnimancerComponent animancer)
  579. /// }
  580. /// var job = new MyJob();// A struct that implements IAnimationJob.
  581. /// var mixer = new WhateverMixerState();// e.g. LinearMixerState.
  582. /// mixer.CreatePlayable(animancer, job);
  583. /// // Use mixer.Initialize, CreateChild, and SetChild to configure the children as normal.
  584. /// }
  585. /// </code>
  586. /// See also: <seealso cref="CreatePlayable{T}(out Playable, T, bool)"/>
  587. /// </remarks>
  588. public AnimationScriptPlayable CreatePlayable<T>(
  589. AnimancerGraph graph,
  590. T job,
  591. bool processInputs = false)
  592. where T : struct, IAnimationJob
  593. {
  594. // Can't just use SetGraph normally because it would call the regular CreatePlayable method.
  595. SetGraph(null);
  596. Graph = graph;
  597. graph.States.Register(this);
  598. var playable = AnimationScriptPlayable.Create(graph._PlayableGraph, job, _ChildCount);
  599. if (!processInputs)
  600. playable.SetProcessInputs(false);
  601. for (int i = _ChildCount - 1; i >= 0; i--)
  602. ChildStates[i].SetGraph(graph);
  603. return playable;
  604. }
  605. /************************************************************************************************************************/
  606. /// <summary>
  607. /// Creates an <see cref="AnimationScriptPlayable"/> to run the specified Animation Job instead of the usual
  608. /// <see cref="AnimationMixerPlayable"/>.
  609. /// </summary>
  610. ///
  611. /// <remarks>
  612. /// <para></para>
  613. /// <strong>Documentation:</strong>
  614. /// <see href="https://kybernetik.com.au/animancer/docs/source/creating-custom-states">
  615. /// Creating Custom States</see>
  616. /// <para></para>
  617. /// <strong>Example:</strong><code>
  618. /// public class MyMixer : LinearMixerState
  619. /// {
  620. /// protected override void CreatePlayable(out Playable playable)
  621. /// {
  622. /// CreatePlayable(out playable, new MyJob());
  623. /// }
  624. ///
  625. /// private struct MyJob : IAnimationJob
  626. /// {
  627. /// public void ProcessAnimation(AnimationStream stream)
  628. /// {
  629. /// }
  630. ///
  631. /// public void ProcessRootMotion(AnimationStream stream)
  632. /// {
  633. /// }
  634. /// }
  635. /// }
  636. /// </code>
  637. /// See also: <seealso cref="CreatePlayable{T}(AnimancerGraph, T, bool)"/>
  638. /// </remarks>
  639. protected void CreatePlayable<T>(
  640. out Playable playable,
  641. T job,
  642. bool processInputs = false)
  643. where T : struct, IAnimationJob
  644. {
  645. var scriptPlayable = AnimationScriptPlayable.Create(Graph._PlayableGraph, job, ChildCount);
  646. if (!processInputs)
  647. scriptPlayable.SetProcessInputs(false);
  648. playable = scriptPlayable;
  649. }
  650. /************************************************************************************************************************/
  651. /// <summary>
  652. /// Gets the Animation Job data from the <see cref="AnimationScriptPlayable"/>.
  653. /// </summary>
  654. /// <exception cref="InvalidCastException">
  655. /// This mixer was not initialized using <see cref="CreatePlayable{T}(AnimancerGraph, T, bool)"/>
  656. /// or <see cref="CreatePlayable{T}(out Playable, T, bool)"/>.
  657. /// </exception>
  658. public T GetJobData<T>()
  659. where T : struct, IAnimationJob
  660. => ((AnimationScriptPlayable)_Playable).GetJobData<T>();
  661. /// <summary>
  662. /// Sets the Animation Job data in the <see cref="AnimationScriptPlayable"/>.
  663. /// </summary>
  664. /// <exception cref="InvalidCastException">
  665. /// This mixer was not initialized using <see cref="CreatePlayable{T}(AnimancerGraph, T, bool)"/>
  666. /// or <see cref="CreatePlayable{T}(out Playable, T, bool)"/>.
  667. /// </exception>
  668. public void SetJobData<T>(T value)
  669. where T : struct, IAnimationJob
  670. => ((AnimationScriptPlayable)_Playable).SetJobData(value);
  671. /************************************************************************************************************************/
  672. #endregion
  673. /************************************************************************************************************************/
  674. #region Updates
  675. /************************************************************************************************************************/
  676. /// <inheritdoc/>
  677. public int UpdatableIndex { get; set; } = IUpdatable.List.NotInList;
  678. /// <summary>Recalculates the weights of child states and synchronizes their times if necessary.</summary>
  679. public virtual void Update()
  680. {
  681. if (!ApplySynchronizeChildren())
  682. Graph.CancelPreUpdate(this);
  683. }
  684. /************************************************************************************************************************/
  685. /// <inheritdoc/>
  686. protected internal override void UpdateEvents()
  687. => UpdateEventsRecursive(this);
  688. /************************************************************************************************************************/
  689. /// <inheritdoc/>
  690. public override void SetGraph(AnimancerGraph graph)
  691. {
  692. if (Graph == graph)
  693. return;
  694. Graph?.CancelPreUpdate(this);
  695. base.SetGraph(graph);
  696. }
  697. /************************************************************************************************************************/
  698. #endregion
  699. /************************************************************************************************************************/
  700. #region Synchronize Children
  701. /************************************************************************************************************************/
  702. /// <summary>Should newly added children be automatically added to the synchronization list? Default true.</summary>
  703. public static bool SynchronizeNewChildren { get; set; } = true;
  704. /// <summary>The minimum total weight of all children for their times to be synchronized. Default 0.01.</summary>
  705. public static float MinimumSynchronizeChildrenWeight { get; set; } = 0.01f;
  706. /************************************************************************************************************************/
  707. private List<AnimancerState> _SynchronizedChildren;
  708. /// <summary>A copy of the internal list of child states that will have their times synchronized.</summary>
  709. /// <remarks>
  710. /// If this mixer is a child of another mixer, its synchronized children will be managed by the parent.
  711. /// <para></para>
  712. /// The getter allocates a new array if <see cref="SynchronizedChildCount"/> is greater than zero.
  713. /// </remarks>
  714. public AnimancerState[] SynchronizedChildren
  715. {
  716. get => SynchronizedChildCount > 0
  717. ? _SynchronizedChildren.ToArray()
  718. : Array.Empty<AnimancerState>();
  719. set
  720. {
  721. if (_SynchronizedChildren == null)
  722. _SynchronizedChildren = new();
  723. else
  724. _SynchronizedChildren.Clear();
  725. for (int i = 0; i < value.Length; i++)
  726. Synchronize(value[i]);
  727. }
  728. }
  729. /// <summary>The number of <see cref="SynchronizedChildren"/>.</summary>
  730. public int SynchronizedChildCount
  731. => _SynchronizedChildren != null
  732. ? _SynchronizedChildren.Count
  733. : 0;
  734. /************************************************************************************************************************/
  735. /// <summary>Is the `state` in the <see cref="SynchronizedChildren"/>?</summary>
  736. public bool IsSynchronized(AnimancerState state)
  737. {
  738. var synchronizer = GetParentMixer();
  739. return
  740. synchronizer._SynchronizedChildren != null &&
  741. synchronizer._SynchronizedChildren.Contains(state);
  742. }
  743. /************************************************************************************************************************/
  744. /// <summary>Adds the `state` to the <see cref="SynchronizedChildren"/>.</summary>
  745. /// <remarks>
  746. /// The `state` must be a child of this mixer.
  747. /// <para></para>
  748. /// If this mixer is a child of another mixer, the `state` will be added to the parent's
  749. /// <see cref="SynchronizedChildren"/> instead.
  750. /// </remarks>
  751. public void Synchronize(AnimancerState state)
  752. {
  753. if (state == null)
  754. return;
  755. #if UNITY_ASSERTIONS
  756. if (!IsChildOf(state, this))
  757. {
  758. MarkAsUsed(this);
  759. throw new ArgumentException(
  760. $"State is not a child of the mixer." +
  761. $"\n• State: {state}" +
  762. $"\n• Mixer: {this}",
  763. nameof(state));
  764. }
  765. #endif
  766. var synchronizer = GetParentMixer();
  767. synchronizer.SynchronizeDirect(state);
  768. }
  769. /// <summary>The internal implementation of <see cref="Synchronize"/>.</summary>
  770. private void SynchronizeDirect(AnimancerState state)
  771. {
  772. if (state == null)
  773. return;
  774. // If the state is a mixer, steal all its synchronized children instead of synchronizing the mixer itself.
  775. if (state is ManualMixerState mixer)
  776. {
  777. if (mixer._SynchronizedChildren != null)
  778. {
  779. for (int i = 0; i < mixer._SynchronizedChildren.Count; i++)
  780. Synchronize(mixer._SynchronizedChildren[i]);
  781. mixer._SynchronizedChildren.Clear();
  782. }
  783. return;
  784. }
  785. #if UNITY_ASSERTIONS
  786. if (OptionalWarning.MixerSynchronizeZeroLength.IsEnabled() && state.Length == 0)
  787. OptionalWarning.MixerSynchronizeZeroLength.Log(
  788. $"Adding a state with zero {nameof(AnimancerState.Length)} to the synchronization list: '{state}'." +
  789. $"\n\nSynchronization is based on the {nameof(NormalizedTime)}" +
  790. $" which can't be calculated if the {nameof(Length)} is 0." +
  791. $" Some state types can change their {nameof(Length)}, in which case you can just disable this warning." +
  792. $" But otherwise, the indicated state probably shouldn't be added to the synchronization list.",
  793. Graph?.Component);
  794. #endif
  795. _SynchronizedChildren ??= new();
  796. #if UNITY_ASSERTIONS
  797. if (_SynchronizedChildren.Contains(state))
  798. Debug.LogError($"{state} is already in the {nameof(SynchronizedChildren)} list.");
  799. #endif
  800. _SynchronizedChildren.Add(state);
  801. Graph?.RequirePreUpdate(this);
  802. }
  803. /************************************************************************************************************************/
  804. /// <summary>Removes the `state` from the <see cref="SynchronizedChildren"/>.</summary>
  805. public void DontSynchronize(AnimancerState state)
  806. {
  807. var synchronizer = GetParentMixer();
  808. if (synchronizer._SynchronizedChildren != null &&
  809. synchronizer._SynchronizedChildren.Remove(state) &&
  810. state._Playable.IsValid())
  811. state._Playable.SetSpeed(state.Speed);
  812. }
  813. /************************************************************************************************************************/
  814. /// <summary>Removes all children of this mixer from the <see cref="SynchronizedChildren"/>.</summary>
  815. public void DontSynchronizeChildren()
  816. {
  817. var synchronizer = GetParentMixer();
  818. var synchronizedChildren = synchronizer._SynchronizedChildren;
  819. if (synchronizedChildren == null)
  820. return;
  821. if (synchronizer == this)
  822. {
  823. for (int i = synchronizedChildren.Count - 1; i >= 0; i--)
  824. {
  825. var state = synchronizedChildren[i];
  826. if (state._Playable.IsValid())
  827. state._Playable.SetSpeed(state.Speed);
  828. }
  829. synchronizedChildren.Clear();
  830. }
  831. else
  832. {
  833. for (int i = synchronizedChildren.Count - 1; i >= 0; i--)
  834. {
  835. var state = synchronizedChildren[i];
  836. if (IsChildOf(state, this))
  837. {
  838. if (state._Playable.IsValid())
  839. state._Playable.SetSpeed(state.Speed);
  840. synchronizedChildren.RemoveAt(i);
  841. }
  842. }
  843. }
  844. }
  845. /************************************************************************************************************************/
  846. /// <summary>Initializes the internal <see cref="SynchronizedChildren"/> list.</summary>
  847. /// <remarks>
  848. /// The array can be null or empty. Any elements not in the array will be treated as <c>true</c>.
  849. /// <para></para>
  850. /// This method can only be called before any <see cref="SynchronizedChildren"/> are added and also before this
  851. /// mixer is made the child of another mixer.
  852. /// </remarks>
  853. public void InitializeSynchronizedChildren(params bool[] synchronizeChildren)
  854. {
  855. AnimancerUtilities.Assert(GetParentMixer() == this,
  856. $"{nameof(InitializeSynchronizedChildren)} cannot be used on a mixer that is a child of another mixer.");
  857. AnimancerUtilities.Assert(_SynchronizedChildren == null,
  858. $"{nameof(InitializeSynchronizedChildren)} cannot be used on a mixer already has synchronized children.");
  859. int flagCount;
  860. if (synchronizeChildren != null)
  861. {
  862. flagCount = synchronizeChildren.Length;
  863. for (int i = 0; i < flagCount; i++)
  864. if (synchronizeChildren[i])
  865. SynchronizeDirect(ChildStates[i]);
  866. }
  867. else flagCount = 0;
  868. for (int i = flagCount; i < _ChildCount; i++)
  869. SynchronizeDirect(ChildStates[i]);
  870. }
  871. /************************************************************************************************************************/
  872. /// <summary>
  873. /// Returns the highest <see cref="ManualMixerState"/> in the hierarchy above this mixer
  874. /// or this mixer itself if there are none above it.
  875. /// </summary>
  876. public ManualMixerState GetParentMixer()
  877. {
  878. var mixer = this;
  879. var parent = Parent;
  880. while (parent != null)
  881. {
  882. if (parent is ManualMixerState parentMixer)
  883. mixer = parentMixer;
  884. parent = parent.Parent;
  885. }
  886. return mixer;
  887. }
  888. /// <summary>Returns the highest <see cref="ManualMixerState"/> in the hierarchy above the `state` (inclusive).</summary>
  889. public static ManualMixerState GetParentMixer(AnimancerNodeBase node)
  890. {
  891. ManualMixerState mixer = null;
  892. while (node != null)
  893. {
  894. if (node is ManualMixerState parentMixer)
  895. mixer = parentMixer;
  896. node = node.Parent;
  897. }
  898. return mixer;
  899. }
  900. /************************************************************************************************************************/
  901. /// <summary>Is the `child` a child of the `parent`?</summary>
  902. public static bool IsChildOf(AnimancerNodeBase child, AnimancerNodeBase parent)
  903. {
  904. while (true)
  905. {
  906. child = child.Parent;
  907. if (child == parent)
  908. return true;
  909. else if (child == null)
  910. return false;
  911. }
  912. }
  913. /************************************************************************************************************************/
  914. /// <summary>
  915. /// Synchronizes the <see cref="AnimancerState.NormalizedTime"/>s of the <see cref="SynchronizedChildren"/> by
  916. /// modifying their internal playable speeds.
  917. /// </summary>
  918. private bool ApplySynchronizeChildren()
  919. {
  920. if (Weight == 0 ||
  921. !IsPlaying ||
  922. _SynchronizedChildren == null ||
  923. _SynchronizedChildren.Count <= 1)
  924. return false;
  925. var deltaTime = AnimancerGraph.DeltaTime * CalculateRealEffectiveSpeed();
  926. if (deltaTime == 0)
  927. return true;
  928. var count = _SynchronizedChildren.Count;
  929. // Calculate the weighted average normalized time and normalized speed of all children.
  930. var totalWeight = 0f;
  931. var weightedNormalizedTime = 0f;
  932. var weightedNormalizedSpeed = 0f;
  933. for (int i = 0; i < count; i++)
  934. {
  935. var state = _SynchronizedChildren[i];
  936. var weight = CalculateRelativeWeight(state);
  937. if (weight == 0)
  938. continue;
  939. var length = state.Length;
  940. if (length == 0)
  941. continue;
  942. totalWeight += weight;
  943. weight /= length;
  944. weightedNormalizedTime += state.Time * weight;
  945. weightedNormalizedSpeed += state.Speed * weight;
  946. }
  947. #if UNITY_ASSERTIONS
  948. if (!(totalWeight >= 0) || totalWeight == float.PositiveInfinity)// Reversed comparison includes NaN.
  949. {
  950. MarkAsUsed(this);
  951. throw new ArgumentOutOfRangeException(nameof(totalWeight), totalWeight,
  952. $"Total weight {Strings.MustBeFinite} and must be positive");
  953. }
  954. if (!weightedNormalizedTime.IsFinite())
  955. {
  956. MarkAsUsed(this);
  957. throw new ArgumentOutOfRangeException(nameof(weightedNormalizedTime), weightedNormalizedTime,
  958. $"Time {Strings.MustBeFinite}");
  959. }
  960. if (!weightedNormalizedSpeed.IsFinite())
  961. {
  962. MarkAsUsed(this);
  963. throw new ArgumentOutOfRangeException(nameof(weightedNormalizedSpeed), weightedNormalizedSpeed,
  964. $"Speed {Strings.MustBeFinite}");
  965. }
  966. #endif
  967. // If the total weight is too small, pretend they are all at Weight = 1.
  968. if (totalWeight < MinimumSynchronizeChildrenWeight)
  969. {
  970. weightedNormalizedTime = 0;
  971. weightedNormalizedSpeed = 0;
  972. var nonZeroCount = 0;
  973. for (int i = 0; i < count; i++)
  974. {
  975. var state = _SynchronizedChildren[i];
  976. var length = state.Length;
  977. if (length == 0)
  978. continue;
  979. length = 1f / length;
  980. weightedNormalizedTime += state.Time * length;
  981. weightedNormalizedSpeed += state.Speed * length;
  982. nonZeroCount++;
  983. }
  984. totalWeight = nonZeroCount;
  985. }
  986. // Increment that time value according to delta time.
  987. weightedNormalizedTime += deltaTime * weightedNormalizedSpeed;
  988. weightedNormalizedTime /= totalWeight;
  989. var inverseDeltaTime = 1f / deltaTime;
  990. // Modify the speed of all children to go from their current normalized time to the average in one frame.
  991. for (int i = 0; i < count; i++)
  992. {
  993. var state = _SynchronizedChildren[i];
  994. var length = state.Length;
  995. if (length == 0)
  996. continue;
  997. var normalizedTime = state.Time / length;
  998. var speed = (weightedNormalizedTime - normalizedTime) * length * inverseDeltaTime;
  999. state._Playable.SetSpeed(speed);
  1000. }
  1001. // After this, all the playables will update and advance according to their new speeds this frame.
  1002. return true;
  1003. }
  1004. /************************************************************************************************************************/
  1005. /// <summary>Calculates the weight of the `child` multiplied by its parents up to this mixer.</summary>
  1006. private float CalculateRelativeWeight(AnimancerState child)
  1007. {
  1008. var weight = child.Weight;
  1009. var parent = child.Parent;
  1010. while (parent != this && parent != null)
  1011. {
  1012. weight *= parent.BaseWeight;
  1013. parent = parent.Parent;
  1014. }
  1015. return weight;
  1016. }
  1017. /************************************************************************************************************************/
  1018. /// <summary>
  1019. /// The multiplied <see cref="PlayableExtensions.GetSpeed"/> of this mixer and its parents down the
  1020. /// hierarchy to determine the actual speed its output is being played at.
  1021. /// </summary>
  1022. /// <remarks>
  1023. /// This can be different from the <see cref="AnimancerNodeBase.EffectiveSpeed"/> because the
  1024. /// <see cref="SynchronizedChildren"/> have their playable speed modified without setting their
  1025. /// <see cref="AnimancerNodeBase.Speed"/>.
  1026. /// </remarks>
  1027. public float CalculateRealEffectiveSpeed()
  1028. {
  1029. var speed = _Playable.GetSpeed();
  1030. var parent = Parent;
  1031. while (parent != null)
  1032. {
  1033. speed *= parent.Playable.GetSpeed();
  1034. parent = parent.Parent;
  1035. }
  1036. return (float)speed;
  1037. }
  1038. /************************************************************************************************************************/
  1039. #endregion
  1040. /************************************************************************************************************************/
  1041. #region Inverse Kinematics
  1042. /************************************************************************************************************************/
  1043. private bool _ApplyAnimatorIK;
  1044. /// <inheritdoc/>
  1045. public override bool ApplyAnimatorIK
  1046. {
  1047. get => _ApplyAnimatorIK;
  1048. set => base.ApplyAnimatorIK = _ApplyAnimatorIK = value;
  1049. }
  1050. /************************************************************************************************************************/
  1051. private bool _ApplyFootIK;
  1052. /// <inheritdoc/>
  1053. public override bool ApplyFootIK
  1054. {
  1055. get => _ApplyFootIK;
  1056. set => base.ApplyFootIK = _ApplyFootIK = value;
  1057. }
  1058. /************************************************************************************************************************/
  1059. #endregion
  1060. /************************************************************************************************************************/
  1061. #region Other Methods
  1062. /************************************************************************************************************************/
  1063. /// <summary>Calculates the sum of the <see cref="AnimancerNode.Weight"/> of all `states`.</summary>
  1064. public static float CalculateTotalWeight(AnimancerState[] states, int count)
  1065. {
  1066. var total = 0f;
  1067. for (int i = count - 1; i >= 0; i--)
  1068. total += states[i].Weight;
  1069. return total;
  1070. }
  1071. /************************************************************************************************************************/
  1072. /// <summary>
  1073. /// Sets <see cref="AnimancerState.Time"/> for all <see cref="ChildStates"/>.
  1074. /// </summary>
  1075. public void SetChildrenTime(float value, bool normalized = false)
  1076. {
  1077. for (int i = _ChildCount - 1; i >= 0; i--)
  1078. {
  1079. var state = ChildStates[i];
  1080. if (normalized)
  1081. state.NormalizedTime = value;
  1082. else
  1083. state.Time = value;
  1084. }
  1085. }
  1086. /************************************************************************************************************************/
  1087. /// <summary>Sets the weight of all states after the `previousIndex` to 0.</summary>
  1088. protected void DisableRemainingStates(int previousIndex)
  1089. {
  1090. for (int i = previousIndex + 1; i < _ChildCount; i++)
  1091. Playable.SetChildWeight(ChildStates[i], 0);
  1092. }
  1093. /************************************************************************************************************************/
  1094. private static float[] _TemporaryWeights = Array.Empty<float>();
  1095. /// <summary>Returns an array at least as large as the `count`.</summary>
  1096. /// <remarks>
  1097. /// The same array is returned by subsequent calls as long as it's large enough
  1098. /// and it isn't cleared between calls so it will contain the previous data.
  1099. /// </remarks>
  1100. public static float[] GetTemporaryFloatArray(int count)
  1101. {
  1102. if (_TemporaryWeights.Length < count)
  1103. {
  1104. if (count <= 16)
  1105. count = 16;
  1106. else
  1107. count = Mathf.NextPowerOfTwo(count);
  1108. _TemporaryWeights = new float[count];
  1109. }
  1110. return _TemporaryWeights;
  1111. }
  1112. /************************************************************************************************************************/
  1113. /// <summary>Divides `weights` by the `totalWeight` and applies them to the child states.</summary>
  1114. public void NormalizeAndApplyWeights(float totalWeight, float[] weights)
  1115. {
  1116. totalWeight = 1f / totalWeight;
  1117. for (int i = _ChildCount - 1; i >= 0; i--)
  1118. {
  1119. var state = ChildStates[i];
  1120. var weight = weights[i] * totalWeight;
  1121. Playable.SetChildWeight(state, weight);
  1122. }
  1123. }
  1124. /************************************************************************************************************************/
  1125. /// <summary>Gets a user-friendly key to identify the `state` in the Inspector.</summary>
  1126. public virtual string GetDisplayKey(AnimancerState state)
  1127. => $"[{state.Index}]";
  1128. /************************************************************************************************************************/
  1129. /// <inheritdoc/>
  1130. public override Vector3 AverageVelocity
  1131. {
  1132. get
  1133. {
  1134. var velocity = default(Vector3);
  1135. for (int i = _ChildCount - 1; i >= 0; i--)
  1136. {
  1137. var state = ChildStates[i];
  1138. velocity += state.AverageVelocity * state.Weight;
  1139. }
  1140. return velocity;
  1141. }
  1142. }
  1143. /************************************************************************************************************************/
  1144. /// <summary>
  1145. /// Recalculates the <see cref="AnimancerState.Duration"/> of all child states so that they add up to 1.
  1146. /// </summary>
  1147. public void NormalizeDurations()
  1148. {
  1149. int divideBy = 0;
  1150. float totalDuration = 0f;
  1151. // Count the number of states that exist and their total duration.
  1152. for (int i = 0; i < _ChildCount; i++)
  1153. {
  1154. divideBy++;
  1155. totalDuration += ChildStates[i].Duration;
  1156. }
  1157. // Calculate the average duration.
  1158. totalDuration /= divideBy;
  1159. // Set all states to that duration.
  1160. for (int i = 0; i < _ChildCount; i++)
  1161. {
  1162. ChildStates[i].Duration = totalDuration;
  1163. }
  1164. }
  1165. /************************************************************************************************************************/
  1166. #if UNITY_ASSERTIONS
  1167. /// <summary>[Assert-Only] A string built by <see cref="ToString"/> to describe this mixer.</summary>
  1168. private string _CachedToString;
  1169. #endif
  1170. /// <summary>
  1171. /// Returns a string describing the type of this mixer and the name of states connected to it.
  1172. /// </summary>
  1173. public override string ToString()
  1174. {
  1175. #if UNITY_ASSERTIONS
  1176. if (NameCache.TryToString(DebugName, out var name))
  1177. return name;
  1178. if (_CachedToString != null)
  1179. return _CachedToString;
  1180. #endif
  1181. // Gather child names.
  1182. var childNames = ListPool.Acquire<string>();
  1183. var allSimple = true;
  1184. for (int i = 0; i < _ChildCount; i++)
  1185. {
  1186. var state = ChildStates[i];
  1187. if (state == null)
  1188. continue;
  1189. if (state.MainObject != null)
  1190. {
  1191. childNames.Add(state.MainObject.name);
  1192. }
  1193. else
  1194. {
  1195. childNames.Add(state.ToString());
  1196. allSimple = false;
  1197. }
  1198. }
  1199. // If they all have a main object, check if they all have the same prefix so it doesn't need to be repeated.
  1200. int prefixLength = 0;
  1201. var count = childNames.Count;
  1202. if (count <= 1 || !allSimple)
  1203. {
  1204. prefixLength = 0;
  1205. }
  1206. else
  1207. {
  1208. var prefix = childNames[0];
  1209. var shortest = prefixLength = prefix.Length;
  1210. for (int iName = 0; iName < count; iName++)
  1211. {
  1212. var childName = childNames[iName];
  1213. if (shortest > childName.Length)
  1214. {
  1215. shortest = prefixLength = childName.Length;
  1216. }
  1217. for (int iCharacter = 0; iCharacter < prefixLength; iCharacter++)
  1218. {
  1219. if (childName[iCharacter] != prefix[iCharacter])
  1220. {
  1221. prefixLength = iCharacter;
  1222. break;
  1223. }
  1224. }
  1225. }
  1226. if (prefixLength < 3 ||// Less than 3 characters probably isn't an intentional prefix.
  1227. prefixLength >= shortest)
  1228. prefixLength = 0;
  1229. }
  1230. // Build the mixer name.
  1231. var mixerName = StringBuilderPool.Instance.Acquire();
  1232. var type = GetType().Name;
  1233. if (type.EndsWith("State"))
  1234. mixerName.Append(type, 0, type.Length - 5);
  1235. else
  1236. mixerName.Append(type);
  1237. mixerName.Append('(');
  1238. if (count > 0)
  1239. {
  1240. if (prefixLength > 0)
  1241. mixerName.Append(childNames[0], 0, prefixLength).Append('[');
  1242. for (int i = 0; i < count; i++)
  1243. {
  1244. if (i > 0)
  1245. mixerName.Append(", ");
  1246. var childName = childNames[i];
  1247. mixerName.Append(childName, prefixLength, childName.Length - prefixLength);
  1248. }
  1249. mixerName.Append(']');
  1250. }
  1251. ListPool.Release(childNames);
  1252. mixerName.Append(')');
  1253. var result = mixerName.ReleaseToString();
  1254. #if UNITY_ASSERTIONS
  1255. _CachedToString = result;
  1256. #endif
  1257. return result;
  1258. }
  1259. /************************************************************************************************************************/
  1260. /// <inheritdoc/>
  1261. protected override void AppendDetails(StringBuilder text, string separator)
  1262. {
  1263. base.AppendDetails(text, separator);
  1264. text.Append(separator)
  1265. .Append("SynchronizedChildren: ");
  1266. if (SynchronizedChildCount == 0)
  1267. {
  1268. text.Append("0");
  1269. }
  1270. else
  1271. {
  1272. text.Append(_SynchronizedChildren.Count);
  1273. separator += Strings.Indent;
  1274. for (int i = 0; i < _SynchronizedChildren.Count; i++)
  1275. {
  1276. text.Append(separator)
  1277. .Append(_SynchronizedChildren[i]);
  1278. }
  1279. }
  1280. }
  1281. /************************************************************************************************************************/
  1282. /// <inheritdoc/>
  1283. public override void GatherAnimationClips(ICollection<AnimationClip> clips)
  1284. => clips.GatherFromSource(ChildStates);
  1285. /************************************************************************************************************************/
  1286. /// <inheritdoc/>
  1287. public virtual void GetParameters(List<StateParameterDetails> parameters) { }
  1288. /// <inheritdoc/>
  1289. public virtual void SetParameters(List<StateParameterDetails> parameters) { }
  1290. /************************************************************************************************************************/
  1291. #endregion
  1292. /************************************************************************************************************************/
  1293. }
  1294. }