ManualMixerTransitionAsset.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
  2. using Animancer.Units;
  3. using System;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using Object = UnityEngine.Object;
  7. namespace Animancer
  8. {
  9. /// <inheritdoc/>
  10. /// https://kybernetik.com.au/animancer/api/Animancer/ManualMixerTransitionAsset
  11. [CreateAssetMenu(menuName = Strings.MenuPrefix + "Mixer Transition/Manual", order = Strings.AssetMenuOrder + 2)]
  12. [HelpURL(Strings.DocsURLs.APIDocumentation + "/" + nameof(ManualMixerTransitionAsset))]
  13. public class ManualMixerTransitionAsset : AnimancerTransitionAsset<ManualMixerTransition>
  14. {
  15. /// <inheritdoc/>
  16. [Serializable]
  17. public new class UnShared :
  18. UnShared<ManualMixerTransitionAsset, ManualMixerTransition, ManualMixerState>,
  19. ManualMixerState.ITransition
  20. { }
  21. }
  22. /// <inheritdoc/>
  23. /// https://kybernetik.com.au/animancer/api/Animancer/ManualMixerTransition_1
  24. [Serializable]
  25. public abstract class ManualMixerTransition<TMixer> : AnimancerTransition<TMixer>,
  26. IMotion, IAnimationClipCollection, ICopyable<ManualMixerTransition<TMixer>>
  27. where TMixer : ManualMixerState
  28. {
  29. /************************************************************************************************************************/
  30. [SerializeField]
  31. [Tooltip(Strings.Tooltips.OptionalSpeed)]
  32. [AnimationSpeed]
  33. [DefaultValue(1f, -1f)]
  34. private float _Speed = 1;
  35. /// <summary>[<see cref="SerializeField"/>]
  36. /// Determines how fast the mixer plays (1x = normal speed, 2x = double speed).
  37. /// </summary>
  38. public override float Speed
  39. {
  40. get => _Speed;
  41. set => _Speed = value;
  42. }
  43. /************************************************************************************************************************/
  44. [SerializeField]
  45. [UnityEngine.Serialization.FormerlySerializedAs("_Clips")]
  46. [UnityEngine.Serialization.FormerlySerializedAs("_States")]
  47. private Object[] _Animations;
  48. /// <summary>[<see cref="SerializeField"/>] Objects that define how to create each state in the mixer.</summary>
  49. /// <remarks>See <see cref="ManualMixerState.Initialize(Object[])"/> for more information.</remarks>
  50. public ref Object[] Animations => ref _Animations;
  51. /// <summary>The name of the serialized backing field of <see cref="Animations"/>.</summary>
  52. public const string AnimationsField = nameof(_Animations);
  53. /************************************************************************************************************************/
  54. [SerializeField]
  55. [AnimationSpeed]
  56. [DefaultValue(1f, -1f)]
  57. private float[] _Speeds;
  58. /// <summary>[<see cref="SerializeField"/>]
  59. /// The <see cref="AnimancerNode.Speed"/> to use for each state in the mixer.
  60. /// </summary>
  61. /// <remarks>If the size of this array doesn't match the <see cref="Animations"/>, it will be ignored.</remarks>
  62. public ref float[] Speeds => ref _Speeds;
  63. /// <summary>The name of the serialized backing field of <see cref="Speeds"/>.</summary>
  64. public const string SpeedsField = nameof(_Speeds);
  65. /// <summary>Are there at least enough <see cref="Speeds"/> for each of the<see cref="Animations"/>?</summary>
  66. public bool HasSpeeds => _Speeds != null && _Speeds.Length >= _Animations.Length;
  67. /************************************************************************************************************************/
  68. [SerializeField]
  69. private bool[] _SynchronizeChildren;
  70. /// <summary>[<see cref="SerializeField"/>]
  71. /// The flags to be used in <see cref="MixerState.InitializeSynchronizedChildren"/>.
  72. /// </summary>
  73. /// <remarks>The array can be null or empty. Any elements not in the array will be treated as true.</remarks>
  74. public ref bool[] SynchronizeChildren => ref _SynchronizeChildren;
  75. /// <summary>The name of the serialized backing field of <see cref="SynchronizeChildren"/>.</summary>
  76. public const string SynchronizeChildrenField = nameof(_SynchronizeChildren);
  77. /************************************************************************************************************************/
  78. /// <summary>[<see cref="ITransitionDetailed"/>] Are any of the <see cref="Animations"/> looping?</summary>
  79. public override bool IsLooping
  80. {
  81. get
  82. {
  83. for (int i = _Animations.Length - 1; i >= 0; i--)
  84. {
  85. if (AnimancerUtilities.TryGetIsLooping(_Animations[i], out var isLooping) &&
  86. isLooping)
  87. return true;
  88. }
  89. return false;
  90. }
  91. }
  92. /// <inheritdoc/>
  93. public override float MaximumDuration
  94. {
  95. get
  96. {
  97. if (_Animations == null)
  98. return 0;
  99. var duration = 0f;
  100. var hasSpeeds = HasSpeeds;
  101. for (int i = _Animations.Length - 1; i >= 0; i--)
  102. {
  103. if (!AnimancerUtilities.TryGetLength(_Animations[i], out var length))
  104. continue;
  105. if (hasSpeeds)
  106. length *= _Speeds[i];
  107. if (duration < length)
  108. duration = length;
  109. }
  110. return duration;
  111. }
  112. }
  113. /// <inheritdoc/>
  114. public virtual float AverageAngularSpeed
  115. {
  116. get
  117. {
  118. if (_Animations == null)
  119. return default;
  120. var average = 0f;
  121. var hasSpeeds = HasSpeeds;
  122. var count = 0;
  123. for (int i = _Animations.Length - 1; i >= 0; i--)
  124. {
  125. if (AnimancerUtilities.TryGetAverageAngularSpeed(_Animations[i], out var speed))
  126. {
  127. if (hasSpeeds)
  128. speed *= _Speeds[i];
  129. average += speed;
  130. count++;
  131. }
  132. }
  133. return average / count;
  134. }
  135. }
  136. /// <inheritdoc/>
  137. public virtual Vector3 AverageVelocity
  138. {
  139. get
  140. {
  141. if (_Animations == null)
  142. return default;
  143. var average = new Vector3();
  144. var hasSpeeds = HasSpeeds;
  145. var count = 0;
  146. for (int i = _Animations.Length - 1; i >= 0; i--)
  147. {
  148. if (AnimancerUtilities.TryGetAverageVelocity(_Animations[i], out var velocity))
  149. {
  150. if (hasSpeeds)
  151. velocity *= _Speeds[i];
  152. average += velocity;
  153. count++;
  154. }
  155. }
  156. return average / count;
  157. }
  158. }
  159. /************************************************************************************************************************/
  160. /// <summary>Are all <see cref="Animations"/> assigned?</summary>
  161. public override bool IsValid
  162. {
  163. get
  164. {
  165. if (_Animations == null ||
  166. _Animations.Length == 0)
  167. return false;
  168. for (int i = _Animations.Length - 1; i >= 0; i--)
  169. if (_Animations[i] == null)
  170. return false;
  171. return true;
  172. }
  173. }
  174. /************************************************************************************************************************/
  175. /// <summary>Initializes the <see cref="AnimancerTransition{TState}.State"/> immediately after it is created.</summary>
  176. public virtual void InitializeState()
  177. {
  178. var mixer = State;
  179. var auto = MixerState.AutoSynchronizeChildren;
  180. try
  181. {
  182. MixerState.AutoSynchronizeChildren = false;
  183. mixer.Initialize(_Animations);
  184. }
  185. finally
  186. {
  187. MixerState.AutoSynchronizeChildren = auto;
  188. }
  189. mixer.InitializeSynchronizedChildren(_SynchronizeChildren);
  190. if (_Speeds != null)
  191. {
  192. #if UNITY_ASSERTIONS
  193. if (_Speeds.Length != 0 && _Speeds.Length != _Animations.Length)
  194. Debug.LogError(
  195. $"The number of serialized {nameof(Speeds)} ({_Speeds.Length})" +
  196. $" does not match the number of {nameof(Animations)} ({_Animations.Length}).",
  197. mixer.Root?.Component as Object);
  198. #endif
  199. var children = mixer.ChildStates;
  200. var count = Math.Min(children.Count, _Speeds.Length);
  201. while (--count >= 0)
  202. children[count].Speed = _Speeds[count];
  203. }
  204. }
  205. /************************************************************************************************************************/
  206. /// <inheritdoc/>
  207. public override void Apply(AnimancerState state)
  208. {
  209. base.Apply(state);
  210. if (!float.IsNaN(_Speed))
  211. state.Speed = _Speed;
  212. for (int i = 0; i < _Animations.Length; i++)
  213. if (_Animations[i] is ITransition transition)
  214. transition.Apply(state.GetChild(i));
  215. }
  216. /************************************************************************************************************************/
  217. /// <summary>Adds the <see cref="Animations"/> to the collection.</summary>
  218. void IAnimationClipCollection.GatherAnimationClips(ICollection<AnimationClip> clips)
  219. => clips.GatherFromSource(_Animations);
  220. /************************************************************************************************************************/
  221. /// <inheritdoc/>
  222. public virtual void CopyFrom(ManualMixerTransition<TMixer> copyFrom)
  223. {
  224. CopyFrom((AnimancerTransition<TMixer>)copyFrom);
  225. if (copyFrom == null)
  226. {
  227. _Speed = 1;
  228. _Animations = default;
  229. _Speeds = default;
  230. _SynchronizeChildren = default;
  231. return;
  232. }
  233. _Speed = copyFrom._Speed;
  234. AnimancerUtilities.CopyExactArray(copyFrom._Animations, ref _Animations);
  235. AnimancerUtilities.CopyExactArray(copyFrom._Speeds, ref _Speeds);
  236. AnimancerUtilities.CopyExactArray(copyFrom._SynchronizeChildren, ref _SynchronizeChildren);
  237. }
  238. /************************************************************************************************************************/
  239. }
  240. }