IPlayableWrapper.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
  2. using UnityEngine;
  3. using UnityEngine.Playables;
  4. namespace Animancer
  5. {
  6. /// <summary>Interface for objects that manage a <see cref="UnityEngine.Playables.Playable"/>.</summary>
  7. /// https://kybernetik.com.au/animancer/api/Animancer/IPlayableWrapper
  8. ///
  9. public interface IPlayableWrapper
  10. {
  11. /************************************************************************************************************************/
  12. /// <summary>The object which receives the output of the <see cref="Playable"/>.</summary>
  13. IPlayableWrapper Parent { get; }
  14. /// <summary>The current blend weight of this node which determines how much it affects the final output.</summary>
  15. float Weight { get; }
  16. /// <summary>The <see cref="UnityEngine.Playables.Playable"/> managed by this object.</summary>
  17. Playable Playable { get; }
  18. /// <summary>The number of nodes using this object as their <see cref="Parent"/>.</summary>
  19. int ChildCount { get; }
  20. /// <summary>Returns the state connected to the specified `index` as a child of this object.</summary>
  21. AnimancerNode GetChild(int index);
  22. /// <summary>
  23. /// Indicates whether child playables should stay connected to the graph at all times.
  24. /// <para></para>
  25. /// If false, playables will be disconnected from the graph while they are at 0 weight to stop it from
  26. /// evaluating them every frame.
  27. /// </summary>
  28. /// <seealso cref="AnimancerPlayable.KeepChildrenConnected"/>
  29. bool KeepChildrenConnected { get; }
  30. /// <summary>How fast the <see cref="AnimancerState.Time"/> is advancing every frame.</summary>
  31. ///
  32. /// <remarks>
  33. /// 1 is the normal speed.
  34. /// <para></para>
  35. /// A negative value will play the animation backwards.
  36. /// <para></para>
  37. /// <em>Animancer Lite does not allow this value to be changed in runtime builds.</em>
  38. /// </remarks>
  39. ///
  40. /// <example><code>
  41. /// void PlayAnimation(AnimancerComponent animancer, AnimationClip clip)
  42. /// {
  43. /// var state = animancer.Play(clip);
  44. ///
  45. /// state.Speed = 1;// Normal speed.
  46. /// state.Speed = 2;// Double speed.
  47. /// state.Speed = 0.5f;// Half speed.
  48. /// state.Speed = -1;// Normal speed playing backwards.
  49. /// }
  50. /// </code></example>
  51. float Speed { get; set; }
  52. /************************************************************************************************************************/
  53. /// <summary>
  54. /// Should Unity call <c>OnAnimatorIK</c> on the animated object while this object and its children have any
  55. /// <see cref="AnimancerNode.Weight"/>?
  56. /// </summary>
  57. /// <remarks>
  58. /// This is equivalent to the "IK Pass" toggle in Animator Controller layers, except that due to limitations in
  59. /// the Playables API the <c>layerIndex</c> will always be zero.
  60. /// <para></para>
  61. /// This value starts false by default, but can be automatically changed by
  62. /// <see cref="AnimancerNode.CopyIKFlags"/> when the <see cref="Parent"/> is set.
  63. /// <para></para>
  64. /// IK only takes effect while at least one <see cref="ClipState"/> has a <see cref="AnimancerNode.Weight"/>
  65. /// above zero. Other node types either store the value to apply to their children or don't support IK.
  66. /// <para></para>
  67. /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/ik#ik-pass">IK Pass</see>
  68. /// </remarks>
  69. bool ApplyAnimatorIK { get; set; }
  70. /************************************************************************************************************************/
  71. /// <summary>Should this object and its children apply IK to the character's feet?</summary>
  72. /// <remarks>
  73. /// This is equivalent to the "Foot IK" toggle in Animator Controller states.
  74. /// <para></para>
  75. /// This value starts true by default for <see cref="ClipState"/>s (false for others), but can be automatically
  76. /// changed by <see cref="AnimancerNode.CopyIKFlags"/> when the <see cref="Parent"/> is set.
  77. /// <para></para>
  78. /// IK only takes effect while at least one <see cref="ClipState"/> has a <see cref="AnimancerNode.Weight"/>
  79. /// above zero. Other node types either store the value to apply to their children or don't support IK.
  80. /// <para></para>
  81. /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/ik#foot-ik">Foot IK</see>
  82. /// </remarks>
  83. bool ApplyFootIK { get; set; }
  84. /************************************************************************************************************************/
  85. }
  86. }
  87. /************************************************************************************************************************/
  88. #if UNITY_EDITOR
  89. /************************************************************************************************************************/
  90. namespace Animancer.Editor
  91. {
  92. /// https://kybernetik.com.au/animancer/api/Animancer.Editor/AnimancerEditorUtilities
  93. public static partial class AnimancerEditorUtilities
  94. {
  95. /************************************************************************************************************************/
  96. /// <summary>
  97. /// Adds functions to show and set <see cref="IPlayableWrapper.ApplyAnimatorIK"/> and
  98. /// <see cref="IPlayableWrapper.ApplyFootIK"/>.
  99. /// </summary>
  100. public static void AddContextMenuIK(UnityEditor.GenericMenu menu, IPlayableWrapper ik)
  101. {
  102. menu.AddItem(new GUIContent("Inverse Kinematics/Apply Animator IK ?"),
  103. ik.ApplyAnimatorIK,
  104. () => ik.ApplyAnimatorIK = !ik.ApplyAnimatorIK);
  105. menu.AddItem(new GUIContent("Inverse Kinematics/Apply Foot IK ?"),
  106. ik.ApplyFootIK,
  107. () => ik.ApplyFootIK = !ik.ApplyFootIK);
  108. }
  109. /************************************************************************************************************************/
  110. /// <summary>Re-scales the <see cref="AnimancerNode.Weight"/> of all children to add up to 1.</summary>
  111. public static void NormalizeChildWeights(this IPlayableWrapper parent)
  112. {
  113. var totalWeight = 0f;
  114. var childCount = parent.ChildCount;
  115. for (int i = 0; i < childCount; i++)
  116. {
  117. var child = parent.GetChild(i);
  118. if (child.IsValid())
  119. totalWeight += child.Weight;
  120. }
  121. if (totalWeight == 0 ||// Can't normalize.
  122. Mathf.Approximately(totalWeight, 1))// Already normalized.
  123. return;
  124. totalWeight = 1f / totalWeight;
  125. for (int i = 0; i < childCount; i++)
  126. {
  127. var child = parent.GetChild(i);
  128. if (child.IsValid())
  129. child.Weight *= totalWeight;
  130. }
  131. }
  132. /************************************************************************************************************************/
  133. }
  134. }
  135. /************************************************************************************************************************/
  136. #endif
  137. /************************************************************************************************************************/