AnimancerNodeBase.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
  2. using System;
  3. using UnityEngine.Playables;
  4. namespace Animancer
  5. {
  6. /// <summary>Base class for objects that manage a <see cref="UnityEngine.Playables.Playable"/>.</summary>
  7. /// <remarks>This is the base class of <see cref="AnimancerGraph"/> and <see cref="AnimancerNode"/>.</remarks>
  8. /// https://kybernetik.com.au/animancer/api/Animancer/AnimancerNodeBase
  9. public abstract class AnimancerNodeBase
  10. {
  11. /************************************************************************************************************************/
  12. /// <summary>The <see cref="AnimancerGraph"/> containing this node.</summary>
  13. public AnimancerGraph Graph { get; internal set; }
  14. /************************************************************************************************************************/
  15. /// <summary>The object which receives the output of the <see cref="Playable"/>.</summary>
  16. /// <remarks>
  17. /// This leads from <see cref="AnimancerState"/> to <see cref="AnimancerLayer"/> to
  18. /// <see cref="AnimancerGraph"/> to <c>null</c>.
  19. /// </remarks>
  20. public AnimancerNodeBase Parent { get; protected set; }
  21. /************************************************************************************************************************/
  22. /// <summary>The root <see cref="AnimancerLayer"/> which this node is connected to (if any).</summary>
  23. public virtual AnimancerLayer Layer
  24. => Parent?.Layer;
  25. /************************************************************************************************************************/
  26. /// <summary>The number of nodes using this as their <see cref="Parent"/>.</summary>
  27. public virtual int ChildCount
  28. => 0;
  29. /// <summary>Returns the node connected to the specified `index` as a child of this node.</summary>
  30. /// <remarks>When overriding, don't call this base method because it throws an exception.</remarks>
  31. /// <exception cref="NotSupportedException">This node can't have children.</exception>
  32. protected internal virtual AnimancerNode GetChildNode(int index)
  33. {
  34. MarkAsUsed(this);
  35. throw new NotSupportedException(this + " can't have children.");
  36. }
  37. /// <summary>Should child playables stay connected to the graph at all times?</summary>
  38. /// <remarks>
  39. /// If false, playables will be disconnected from the graph while they are inactive to stop it from
  40. /// evaluating them every frame which usually improves performance.
  41. /// </remarks>
  42. /// <seealso cref="AnimancerGraph.KeepChildrenConnected"/>
  43. public virtual bool KeepChildrenConnected
  44. => true;
  45. /************************************************************************************************************************/
  46. /// <summary>Called when a child's <see cref="AnimancerState.IsLooping"/> value changes.</summary>
  47. protected virtual void OnChildIsLoopingChanged(bool value) { }
  48. /// <summary>[Internal] Calls <see cref="OnChildIsLoopingChanged"/> for each <see cref="Parent"/> recursively.</summary>
  49. protected internal void OnIsLoopingChangedRecursive(bool value)
  50. {
  51. var parent = Parent;
  52. while (parent != null)
  53. {
  54. parent.OnChildIsLoopingChanged(value);
  55. parent = parent.Parent;
  56. }
  57. }
  58. /************************************************************************************************************************/
  59. /// <summary>[Internal] Called when a child's <see cref="Parent"/> is changed from this node.</summary>
  60. /// <remarks>When overriding, don't call this base method because it throws an exception.</remarks>
  61. /// <exception cref="NotSupportedException">This node can't have children.</exception>
  62. protected internal virtual void OnRemoveChild(AnimancerState state)
  63. {
  64. MarkAsUsed(this);
  65. state.SetParentInternal(null);
  66. throw new NotSupportedException(this + " can't have children.");
  67. }
  68. /************************************************************************************************************************/
  69. /// <summary>[Internal] The <see cref="Playable"/>.</summary>
  70. protected internal Playable _Playable;
  71. /// <summary>The internal object this node manages in the <see cref="PlayableGraph"/>.</summary>
  72. /// <remarks>
  73. /// Must be set by <see cref="AnimancerNode.CreatePlayable()"/>. Failure to do so will throw the following
  74. /// exception throughout the system when using this node: "<see cref="ArgumentException"/>: The playable passed
  75. /// as an argument is invalid. To create a valid playable, please use the appropriate Create method".
  76. /// </remarks>
  77. public Playable Playable => _Playable;
  78. /************************************************************************************************************************/
  79. /// <summary>The current blend weight of this node which determines how much it affects the final output.</summary>
  80. protected internal virtual float BaseWeight => 1;
  81. /************************************************************************************************************************/
  82. #region Speed
  83. /************************************************************************************************************************/
  84. private float _Speed = 1;
  85. /// <summary>[Pro-Only] How fast the <see cref="AnimancerState.Time"/> is advancing every frame (default 1).</summary>
  86. ///
  87. /// <remarks>
  88. /// A negative value will play the animation backwards.
  89. /// <para></para>
  90. /// To pause an animation, consider setting <see cref="AnimancerState.IsPlaying"/> to false instead of setting
  91. /// this value to 0.
  92. /// <para></para>
  93. /// <em>Animancer Lite doesn't allow this value to be changed in runtime builds.</em>
  94. /// <para></para>
  95. /// <strong>Example:</strong><code>
  96. /// void SpeedExample(AnimancerComponent animancer, AnimationClip clip)
  97. /// {
  98. /// var state = animancer.Play(clip);
  99. ///
  100. /// state.Speed = 1;// Normal speed.
  101. /// state.Speed = 2;// Double speed.
  102. /// state.Speed = 0.5f;// Half speed.
  103. /// state.Speed = -1;// Normal speed playing backwards.
  104. /// state.NormalizedTime = 1;// Start at the end to play backwards from there.
  105. /// }
  106. /// </code></remarks>
  107. ///
  108. /// <exception cref="ArgumentOutOfRangeException">The value is not finite.</exception>
  109. public float Speed
  110. {
  111. get => _Speed;
  112. set
  113. {
  114. if (_Speed == value)
  115. return;
  116. #if UNITY_ASSERTIONS
  117. if (!value.IsFinite())
  118. {
  119. MarkAsUsed(this);
  120. throw new ArgumentOutOfRangeException(nameof(value), value, $"{nameof(Speed)} {Strings.MustBeFinite}");
  121. }
  122. #endif
  123. _Speed = value;
  124. if (_Playable.IsValid())
  125. _Playable.SetSpeed(value);
  126. }
  127. }
  128. /************************************************************************************************************************/
  129. /// <summary>
  130. /// The <see cref="Speed"/> of this node multiplied by the <see cref="Speed"/> of each of its parents to
  131. /// determine the actual speed it's playing at.
  132. /// </summary>
  133. public float EffectiveSpeed
  134. {
  135. get => Speed * ParentEffectiveSpeed;
  136. set => Speed = value / ParentEffectiveSpeed;
  137. }
  138. /************************************************************************************************************************/
  139. /// <summary>
  140. /// The multiplied <see cref="Speed"/> of each of the <see cref="Parent"/> down the hierarchy,
  141. /// excluding the root <see cref="Speed"/>.
  142. /// </summary>
  143. private float ParentEffectiveSpeed
  144. {
  145. get
  146. {
  147. var parent = Parent;
  148. if (parent == null)
  149. return 1;
  150. var speed = parent.Speed;
  151. while ((parent = parent.Parent) != null)
  152. {
  153. speed *= parent.Speed;
  154. }
  155. return speed;
  156. }
  157. }
  158. /************************************************************************************************************************/
  159. #endregion
  160. /************************************************************************************************************************/
  161. /// <summary>
  162. /// Should Unity call <c>OnAnimatorIK</c> on the animated object while this object and its children have any
  163. /// <see cref="AnimancerNode.Weight"/>?
  164. /// </summary>
  165. /// <remarks>
  166. /// This is equivalent to the "IK Pass" toggle in Animator Controller layers, except that due to limitations in
  167. /// the Playables API the <c>layerIndex</c> will always be zero.
  168. /// <para></para>
  169. /// This value starts false by default, but can be automatically changed by
  170. /// <see cref="AnimancerNode.CopyIKFlags"/> when the <see cref="Parent"/> is set.
  171. /// <para></para>
  172. /// IK only takes effect while at least one <see cref="ClipState"/> has a <see cref="AnimancerNode.Weight"/>
  173. /// above zero. Other node types either store the value to apply to their children or don't support IK.
  174. /// <para></para>
  175. /// <strong>Documentation:</strong>
  176. /// <see href="https://kybernetik.com.au/animancer/docs/manual/ik#ik-pass">
  177. /// IK Pass</see>
  178. /// </remarks>
  179. public abstract bool ApplyAnimatorIK { get; set; }
  180. /************************************************************************************************************************/
  181. /// <summary>Should this object and its children apply IK to the character's feet?</summary>
  182. /// <remarks>
  183. /// This is equivalent to the "Foot IK" toggle in Animator Controller states.
  184. /// <para></para>
  185. /// This value starts true by default for <see cref="ClipState"/>s (false for others), but can be automatically
  186. /// changed by <see cref="AnimancerNode.CopyIKFlags"/> when the <see cref="Parent"/> is set.
  187. /// <para></para>
  188. /// IK only takes effect while at least one <see cref="ClipState"/> has a <see cref="AnimancerNode.Weight"/>
  189. /// above zero. Other node types either store the value to apply to their children or don't support IK.
  190. /// <para></para>
  191. /// <strong>Documentation:</strong>
  192. /// <see href="https://kybernetik.com.au/animancer/docs/manual/ik#foot-ik">
  193. /// Foot IK</see>
  194. /// </remarks>
  195. public abstract bool ApplyFootIK { get; set; }
  196. /************************************************************************************************************************/
  197. /// <summary>[Internal] Applies a change to a child's <see cref="AnimancerState.IsActive"/>.</summary>
  198. protected internal virtual void ApplyChildActive(AnimancerState child, bool setActive)
  199. => child.ShouldBeActive = setActive;
  200. /************************************************************************************************************************/
  201. /// <summary>[Assert-Conditional] Prevents the `node` from causing <see cref="OptionalWarning.UnusedNode"/>.</summary>
  202. [System.Diagnostics.Conditional(Strings.Assertions)]
  203. public static void MarkAsUsed(AnimancerNodeBase node)
  204. {
  205. #if UNITY_ASSERTIONS
  206. if (node.Graph == null)
  207. GC.SuppressFinalize(node);
  208. #endif
  209. }
  210. /************************************************************************************************************************/
  211. #if UNITY_EDITOR
  212. /************************************************************************************************************************/
  213. /// <summary>[Editor-Only]
  214. /// Adds functions to show and set <see cref="ApplyAnimatorIK"/> and
  215. /// <see cref="ApplyFootIK"/>.
  216. /// </summary>
  217. public static void AddContextMenuIK(UnityEditor.GenericMenu menu, AnimancerNodeBase ik)
  218. {
  219. #if UNITY_IMGUI
  220. menu.AddItem(new("Inverse Kinematics/Apply Animator IK ?"),
  221. ik.ApplyAnimatorIK,
  222. () => ik.ApplyAnimatorIK = !ik.ApplyAnimatorIK);
  223. menu.AddItem(new("Inverse Kinematics/Apply Foot IK ?"),
  224. ik.ApplyFootIK,
  225. () => ik.ApplyFootIK = !ik.ApplyFootIK);
  226. #endif
  227. }
  228. /************************************************************************************************************************/
  229. #endif
  230. /************************************************************************************************************************/
  231. }
  232. }