AnimancerLayerList.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using UnityEngine.Playables;
  7. namespace Animancer
  8. {
  9. /// <summary>A list of <see cref="AnimancerLayer"/>s with methods to control their mixing and masking.</summary>
  10. /// <remarks>
  11. /// The default implementation of this class is <see cref="AnimancerLayerMixerList"/>.
  12. /// <para></para>
  13. /// <strong>Documentation:</strong>
  14. /// <see href="https://kybernetik.com.au/animancer/docs/manual/blending/layers">
  15. /// Layers</see>
  16. /// </remarks>
  17. /// https://kybernetik.com.au/animancer/api/Animancer/AnimancerLayerList
  18. public abstract class AnimancerLayerList :
  19. IEnumerable<AnimancerLayer>,
  20. IAnimationClipCollection
  21. {
  22. /************************************************************************************************************************/
  23. #region Fields
  24. /************************************************************************************************************************/
  25. /// <summary>The <see cref="AnimancerGraph"/> containing this list.</summary>
  26. public readonly AnimancerGraph Graph;
  27. /// <summary>The layers which each manage their own set of animations.</summary>
  28. /// <remarks>This field should never be null so it shouldn't need null-checking.</remarks>
  29. private AnimancerLayer[] _Layers;
  30. /// <summary>The number of layers that have actually been created.</summary>
  31. private int _Count;
  32. /// <summary>The <see cref="UnityEngine.Playables.Playable"/> which blends the layers.</summary>
  33. public Playable Playable { get; protected set; }
  34. /************************************************************************************************************************/
  35. /// <summary>Creates a new <see cref="AnimancerLayerList"/>.</summary>
  36. /// <remarks>The <see cref="Playable"/> must be assigned by the end of the derived constructor.</remarks>
  37. protected AnimancerLayerList(AnimancerGraph graph)
  38. {
  39. Graph = graph;
  40. _Layers = new AnimancerLayer[DefaultCapacity];
  41. }
  42. /************************************************************************************************************************/
  43. #endregion
  44. /************************************************************************************************************************/
  45. #region List Operations
  46. /************************************************************************************************************************/
  47. /// <summary>[Pro-Only] The number of layers in this list.</summary>
  48. /// <exception cref="ArgumentOutOfRangeException">
  49. /// The value is set higher than the <see cref="DefaultCapacity"/>. This is simply a safety measure,
  50. /// so if you do actually need more layers you can just increase the limit.
  51. /// </exception>
  52. /// <exception cref="IndexOutOfRangeException">The value is set to a negative number.</exception>
  53. public int Count
  54. {
  55. get => _Count;
  56. set
  57. {
  58. var count = _Count;
  59. if (value == count)
  60. return;
  61. CheckAgain:
  62. if (value > count)// Increasing.
  63. {
  64. Add();
  65. count++;
  66. goto CheckAgain;
  67. }
  68. else// Decreasing.
  69. {
  70. while (value < count--)
  71. {
  72. var layer = _Layers[count];
  73. if (layer._Playable.IsValid())
  74. Graph._PlayableGraph.DestroySubgraph(layer._Playable);
  75. layer.DestroyStates();
  76. }
  77. Array.Clear(_Layers, value, _Count - value);
  78. _Count = value;
  79. Playable.SetInputCount(value);
  80. }
  81. }
  82. }
  83. /************************************************************************************************************************/
  84. /// <summary>[Pro-Only]
  85. /// If the <see cref="Count"/> is below the specified `min`, this method increases it to that value.
  86. /// </summary>
  87. public void SetMinCount(int min)
  88. {
  89. if (Count < min)
  90. Count = min;
  91. }
  92. /************************************************************************************************************************/
  93. /// <summary>[Pro-Only]
  94. /// The maximum number of layers that can be created before an <see cref="ArgumentOutOfRangeException"/> will
  95. /// be thrown (default 4).
  96. /// <para></para>
  97. /// Lowering this value will not affect layers that have already been created.
  98. /// </summary>
  99. /// <remarks>
  100. /// <strong>Example:</strong>
  101. /// To set this value automatically when the application starts, place a method like this in any class:
  102. /// <para></para><code>
  103. /// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
  104. /// private static void SetMaxLayerCount()
  105. /// {
  106. /// Animancer.AnimancerLayerList.DefaultCapacity = 8;
  107. /// }
  108. /// </code>
  109. /// Otherwise you can set the <see cref="Capacity"/> of each individual list:
  110. /// <para></para><code>
  111. /// AnimancerComponent animancer;
  112. /// animancer.Layers.Capacity = 8;
  113. /// </code></remarks>
  114. public static int DefaultCapacity { get; set; } = 4;
  115. /// <summary>[Pro-Only]
  116. /// If the <see cref="DefaultCapacity"/> is below the specified `min`, this method increases it to that value.
  117. /// </summary>
  118. public static void SetMinDefaultCapacity(int min)
  119. {
  120. if (DefaultCapacity < min)
  121. DefaultCapacity = min;
  122. }
  123. /************************************************************************************************************************/
  124. /// <summary>[Pro-Only]
  125. /// The maximum number of layers that can be created before an <see cref="ArgumentOutOfRangeException"/> will
  126. /// be thrown. The initial capacity is determined by <see cref="DefaultCapacity"/>.
  127. /// </summary>
  128. ///
  129. /// <remarks>
  130. /// Lowering this value will destroy any layers beyond the specified value.
  131. /// <para></para>
  132. /// Changing this value will cause the allocation of a new array and garbage collection of the old one,
  133. /// so you should generally set the <see cref="DefaultCapacity"/> before initializing this list.
  134. /// </remarks>
  135. ///
  136. /// <exception cref="ArgumentOutOfRangeException">The value is not greater than 0.</exception>
  137. public int Capacity
  138. {
  139. get => _Layers.Length;
  140. set
  141. {
  142. if (value <= 0)
  143. throw new ArgumentOutOfRangeException(nameof(Capacity), $"must be greater than 0 ({value} <= 0)");
  144. if (_Count > value)
  145. Count = value;
  146. Array.Resize(ref _Layers, value);
  147. }
  148. }
  149. /************************************************************************************************************************/
  150. /// <summary>[Pro-Only] Creates and returns a new <see cref="AnimancerLayer"/> at the end of this list.</summary>
  151. /// <remarks>If the <see cref="Capacity"/> would be exceeded, it will be doubled.</remarks>
  152. public AnimancerLayer Add()
  153. {
  154. var index = _Count;
  155. if (index >= _Layers.Length)
  156. Capacity *= 2;
  157. var layer = new AnimancerLayer(Graph, index);
  158. _Count = index + 1;
  159. Playable.SetInputCount(_Count);
  160. Graph._PlayableGraph.Connect(Playable, layer._Playable, index, 0);
  161. _Layers[index] = layer;
  162. return layer;
  163. }
  164. /************************************************************************************************************************/
  165. /// <summary>Returns the layer at the specified index. If it didn't already exist, this method creates it.</summary>
  166. /// <remarks>To only get an existing layer without creating new ones, use <see cref="GetLayer"/> instead.</remarks>
  167. public AnimancerLayer this[int index]
  168. {
  169. get
  170. {
  171. SetMinCount(index + 1);
  172. return _Layers[index];
  173. }
  174. }
  175. /************************************************************************************************************************/
  176. /// <summary>Returns the layer at the specified index.</summary>
  177. /// <remarks>To create a new layer if the target doesn't exist, use <see cref="this[int]"/> instead.</remarks>
  178. public AnimancerLayer GetLayer(int index)
  179. => _Layers[index];
  180. /************************************************************************************************************************/
  181. #endregion
  182. /************************************************************************************************************************/
  183. #region Enumeration
  184. /************************************************************************************************************************/
  185. /// <summary>Returns an enumerator that will iterate through all layers.</summary>
  186. public FastEnumerator<AnimancerLayer> GetEnumerator()
  187. => new(_Layers, _Count);
  188. /// <inheritdoc/>
  189. IEnumerator<AnimancerLayer> IEnumerable<AnimancerLayer>.GetEnumerator()
  190. => GetEnumerator();
  191. /// <inheritdoc/>
  192. IEnumerator IEnumerable.GetEnumerator()
  193. => GetEnumerator();
  194. /************************************************************************************************************************/
  195. /// <summary>[<see cref="IAnimationClipCollection"/>] Gathers all the animations in all layers.</summary>
  196. public void GatherAnimationClips(ICollection<AnimationClip> clips)
  197. => clips.GatherFromSource(_Layers);
  198. /************************************************************************************************************************/
  199. #endregion
  200. /************************************************************************************************************************/
  201. #region Layer Details
  202. /************************************************************************************************************************/
  203. /// <summary>[Pro-Only]
  204. /// Is the layer at the specified index is set to additive blending?
  205. /// Otherwise it will override lower layers.
  206. /// </summary>
  207. public virtual bool IsAdditive(int index)
  208. => false;
  209. /// <summary>[Pro-Only]
  210. /// Sets the layer at the specified index to blend additively with earlier layers (if true)
  211. /// or to override them (if false). Newly created layers will override by default.
  212. /// </summary>
  213. public virtual void SetAdditive(int index, bool value) { }
  214. /************************************************************************************************************************/
  215. /// <summary>[Pro-Only]
  216. /// Sets an <see cref="AvatarMask"/> to determine which bones the layer at the specified index will affect.
  217. /// </summary>
  218. /// <remarks>
  219. /// Don't assign the same mask repeatedly unless you have modified it.
  220. /// This property doesn't check if the mask is the same
  221. /// so repeatedly assigning the same thing will simply waste performance.
  222. /// </remarks>
  223. public virtual void SetMask(int index, AvatarMask mask) { }
  224. /************************************************************************************************************************/
  225. /// <summary>[Editor-Conditional] Sets the Inspector display name of the layer at the specified index.</summary>
  226. [System.Diagnostics.Conditional(Strings.UnityEditor)]
  227. public void SetDebugName(int index, string name)
  228. => this[index].SetDebugName(name);
  229. /************************************************************************************************************************/
  230. /// <summary>
  231. /// The average velocity of the root motion of all currently playing animations,
  232. /// taking their current <see cref="AnimancerNode.Weight"/> into account.
  233. /// </summary>
  234. public Vector3 AverageVelocity
  235. {
  236. get
  237. {
  238. var velocity = default(Vector3);
  239. for (int i = 0; i < _Count; i++)
  240. {
  241. var layer = _Layers[i];
  242. velocity += layer.AverageVelocity * layer.Weight;
  243. }
  244. return velocity;
  245. }
  246. }
  247. /************************************************************************************************************************/
  248. #endregion
  249. /************************************************************************************************************************/
  250. }
  251. }