ClipTransitionSequence.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
  2. using System;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. namespace Animancer
  6. {
  7. /// <inheritdoc/>
  8. /// <summary>A group of <see cref="ClipTransition"/>s which play one after the other.</summary>
  9. /// https://kybernetik.com.au/animancer/api/Animancer/ClipTransitionSequence
  10. ///
  11. [Serializable]
  12. public class ClipTransitionSequence : ClipTransition,
  13. ISerializationCallbackReceiver, ICopyable<ClipTransitionSequence>
  14. {
  15. /************************************************************************************************************************/
  16. [DrawAfterEvents]
  17. [SerializeField]
  18. [Tooltip("The other transitions to play in order after the first one.")]
  19. private ClipTransition[] _Others = Array.Empty<ClipTransition>();
  20. /// <summary>[<see cref="SerializeField"/>] The transitions to play in order after the first one.</summary>
  21. public ref ClipTransition[] Others => ref _Others;
  22. /// <summary>The last of the <see cref="Others"/> (or <c>this</c> if there are none).</summary>
  23. public ClipTransition LastTransition => _Others.Length > 0 ? _Others[_Others.Length - 1] : this;
  24. /************************************************************************************************************************/
  25. /// <inheritdoc/>
  26. void ISerializationCallbackReceiver.OnBeforeSerialize() { }
  27. /// <inheritdoc/>
  28. void ISerializationCallbackReceiver.OnAfterDeserialize()
  29. {
  30. if (_Others.Length <= 1)
  31. return;
  32. // Assign each of the other end events, but this first one will be set by Apply.
  33. var previous = _Others[0];
  34. for (int i = 1; i < _Others.Length; i++)
  35. {
  36. var next = _Others[i];
  37. previous.Events.OnEnd = () => AnimancerEvent.CurrentState.Layer.Play(next);
  38. previous = next;
  39. }
  40. }
  41. /************************************************************************************************************************/
  42. private Action _OnEnd;
  43. /// <inheritdoc/>
  44. public override void Apply(AnimancerState state)
  45. {
  46. // If an end event is assigned other than the one to play the next transition,
  47. // replace it and move it to be the end event of the last transition instead.
  48. if (_Others.Length > 0)
  49. {
  50. if (_OnEnd == null)
  51. _OnEnd = () => AnimancerEvent.CurrentState.Layer.Play(_Others[0]);
  52. var onEnd = Events.OnEnd;
  53. if (onEnd != _OnEnd)
  54. {
  55. Events.OnEnd = _OnEnd;
  56. onEnd -= _OnEnd;
  57. _Others[_Others.Length - 1].Events.OnEnd = onEnd;
  58. }
  59. }
  60. base.Apply(state);
  61. }
  62. /************************************************************************************************************************/
  63. /// <summary>Is everything in this sequence valid?</summary>
  64. public override bool IsValid
  65. {
  66. get
  67. {
  68. if (!base.IsValid)
  69. return false;
  70. for (int i = 0; i < _Others.Length; i++)
  71. if (!_Others[i].IsValid)
  72. return false;
  73. return true;
  74. }
  75. }
  76. /************************************************************************************************************************/
  77. /// <summary>Is the last animation in this sequence looping?</summary>
  78. public override bool IsLooping => _Others.Length > 0 ? LastTransition.IsLooping : base.IsLooping;
  79. /************************************************************************************************************************/
  80. /// <inheritdoc/>
  81. public override float Length
  82. {
  83. get
  84. {
  85. var length = base.Length;
  86. for (int i = 0; i < _Others.Length; i++)
  87. length += _Others[i].Length;
  88. return length;
  89. }
  90. }
  91. /************************************************************************************************************************/
  92. /// <inheritdoc/>
  93. public override float MaximumDuration
  94. {
  95. get
  96. {
  97. var value = base.MaximumDuration;
  98. for (int i = 0; i < _Others.Length; i++)
  99. value += _Others[i].MaximumDuration;
  100. return value;
  101. }
  102. }
  103. /************************************************************************************************************************/
  104. /// <inheritdoc/>
  105. public override float AverageAngularSpeed
  106. {
  107. get
  108. {
  109. var speed = base.AverageAngularSpeed;
  110. if (_Others.Length == 0)
  111. return speed;
  112. var duration = base.MaximumDuration;
  113. speed *= duration;
  114. for (int i = 0; i < _Others.Length; i++)
  115. {
  116. var other = _Others[i];
  117. var otherSpeed = other.AverageAngularSpeed;
  118. var otherDuration = other.MaximumDuration;
  119. speed += otherSpeed * otherDuration;
  120. duration += otherDuration;
  121. }
  122. return speed / duration;
  123. }
  124. }
  125. /************************************************************************************************************************/
  126. /// <inheritdoc/>
  127. public override Vector3 AverageVelocity
  128. {
  129. get
  130. {
  131. var velocity = base.AverageVelocity;
  132. if (_Others.Length == 0)
  133. return velocity;
  134. var duration = base.MaximumDuration;
  135. velocity *= duration;
  136. for (int i = 0; i < _Others.Length; i++)
  137. {
  138. var other = _Others[i];
  139. var otherVelocity = other.AverageVelocity;
  140. var otherDuration = other.MaximumDuration;
  141. velocity += otherVelocity * otherDuration;
  142. duration += otherDuration;
  143. }
  144. return velocity / duration;
  145. }
  146. }
  147. /************************************************************************************************************************/
  148. /// <summary>Adds the <see cref="ClipTransition.Clip"/> of everything in this sequence to the collection.</summary>
  149. public override void GatherAnimationClips(ICollection<AnimationClip> clips)
  150. {
  151. base.GatherAnimationClips(clips);
  152. for (int i = 0; i < _Others.Length; i++)
  153. _Others[i].GatherAnimationClips(clips);
  154. }
  155. /************************************************************************************************************************/
  156. /// <inheritdoc/>
  157. public virtual void CopyFrom(ClipTransitionSequence copyFrom)
  158. {
  159. CopyFrom((ClipTransition)copyFrom);
  160. if (copyFrom == null)
  161. {
  162. _Others = Array.Empty<ClipTransition>();
  163. return;
  164. }
  165. AnimancerUtilities.CopyExactArray(copyFrom._Others, ref _Others);
  166. }
  167. /************************************************************************************************************************/
  168. #region Events
  169. /************************************************************************************************************************/
  170. /// <summary>The <see cref="AnimancerEvent.Sequence.EndEvent"/> of the last transition in this sequence.</summary>
  171. public AnimancerEvent EndEvent
  172. {
  173. get => LastTransition.Events.EndEvent;
  174. set => LastTransition.Events.EndEvent = value;
  175. }
  176. /************************************************************************************************************************/
  177. /// <summary>Adds an event at the specified time relative to the entire sequence.</summary>
  178. public void AddEvent(float time, bool normalized, Action callback)
  179. {
  180. // Convert time to Seconds.
  181. if (normalized)
  182. time *= Length;
  183. if (TryAddEvent(this, base.Length, ref time, callback))
  184. return;
  185. for (int i = 0; i < _Others.Length - 1; i++)
  186. {
  187. var other = _Others[i];
  188. if (TryAddEvent(other, other.Length, ref time, callback))
  189. return;
  190. }
  191. AddEvent(LastTransition, time, callback);
  192. }
  193. /// <summary>
  194. /// Tries to add the `callback` as an event to the `transition` if the `time` is within the `length` and
  195. /// returns true if successful. Otherwise subtracts the `length` from the `time` and returns false so it can be
  196. /// tried in the next transition in the sequence.
  197. /// </summary>
  198. private static bool TryAddEvent(ClipTransition transition, float length, ref float time, Action callback)
  199. {
  200. if (time > length)
  201. {
  202. time -= length;
  203. return false;
  204. }
  205. AddEvent(transition, time, callback);
  206. return true;
  207. }
  208. /// <summary>
  209. /// Adds the `callback` as an event to the `transition` at the specified `time` (in seconds, starting from the
  210. /// <see cref="ClipTransition.NormalizedStartTime"/>).
  211. /// </summary>
  212. private static void AddEvent(ClipTransition transition, float time, Action callback)
  213. {
  214. var start = transition.NormalizedStartTime;
  215. if (float.IsNaN(start))
  216. start = AnimancerEvent.Sequence.GetDefaultNormalizedStartTime(start);
  217. time /= transition.Clip.length * (1 - start);
  218. time += start;
  219. transition.Events.Add(time, callback);
  220. }
  221. /************************************************************************************************************************/
  222. #endregion
  223. /************************************************************************************************************************/
  224. }
  225. }