123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
- using UnityEngine;
- using UnityEngine.Playables;
- namespace Animancer
- {
- /// <summary>Interface for objects that manage a <see cref="UnityEngine.Playables.Playable"/>.</summary>
- /// https://kybernetik.com.au/animancer/api/Animancer/IPlayableWrapper
- ///
- public interface IPlayableWrapper
- {
- /************************************************************************************************************************/
- /// <summary>The object which receives the output of the <see cref="Playable"/>.</summary>
- IPlayableWrapper Parent { get; }
- /// <summary>The current blend weight of this node which determines how much it affects the final output.</summary>
- float Weight { get; }
- /// <summary>The <see cref="UnityEngine.Playables.Playable"/> managed by this object.</summary>
- Playable Playable { get; }
- /// <summary>The number of nodes using this object as their <see cref="Parent"/>.</summary>
- int ChildCount { get; }
- /// <summary>Returns the state connected to the specified `index` as a child of this object.</summary>
- AnimancerNode GetChild(int index);
- /// <summary>
- /// Indicates whether child playables should stay connected to the graph at all times.
- /// <para></para>
- /// If false, playables will be disconnected from the graph while they are at 0 weight to stop it from
- /// evaluating them every frame.
- /// </summary>
- /// <seealso cref="AnimancerPlayable.KeepChildrenConnected"/>
- bool KeepChildrenConnected { get; }
- /// <summary>How fast the <see cref="AnimancerState.Time"/> is advancing every frame.</summary>
- ///
- /// <remarks>
- /// 1 is the normal speed.
- /// <para></para>
- /// A negative value will play the animation backwards.
- /// <para></para>
- /// <em>Animancer Lite does not allow this value to be changed in runtime builds.</em>
- /// </remarks>
- ///
- /// <example><code>
- /// void PlayAnimation(AnimancerComponent animancer, AnimationClip clip)
- /// {
- /// var state = animancer.Play(clip);
- ///
- /// state.Speed = 1;// Normal speed.
- /// state.Speed = 2;// Double speed.
- /// state.Speed = 0.5f;// Half speed.
- /// state.Speed = -1;// Normal speed playing backwards.
- /// }
- /// </code></example>
- float Speed { get; set; }
- /************************************************************************************************************************/
- /// <summary>
- /// Should Unity call <c>OnAnimatorIK</c> on the animated object while this object and its children have any
- /// <see cref="AnimancerNode.Weight"/>?
- /// </summary>
- /// <remarks>
- /// This is equivalent to the "IK Pass" toggle in Animator Controller layers, except that due to limitations in
- /// the Playables API the <c>layerIndex</c> will always be zero.
- /// <para></para>
- /// This value starts false by default, but can be automatically changed by
- /// <see cref="AnimancerNode.CopyIKFlags"/> when the <see cref="Parent"/> is set.
- /// <para></para>
- /// IK only takes effect while at least one <see cref="ClipState"/> has a <see cref="AnimancerNode.Weight"/>
- /// above zero. Other node types either store the value to apply to their children or don't support IK.
- /// <para></para>
- /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/ik#ik-pass">IK Pass</see>
- /// </remarks>
- bool ApplyAnimatorIK { get; set; }
- /************************************************************************************************************************/
- /// <summary>Should this object and its children apply IK to the character's feet?</summary>
- /// <remarks>
- /// This is equivalent to the "Foot IK" toggle in Animator Controller states.
- /// <para></para>
- /// This value starts true by default for <see cref="ClipState"/>s (false for others), but can be automatically
- /// changed by <see cref="AnimancerNode.CopyIKFlags"/> when the <see cref="Parent"/> is set.
- /// <para></para>
- /// IK only takes effect while at least one <see cref="ClipState"/> has a <see cref="AnimancerNode.Weight"/>
- /// above zero. Other node types either store the value to apply to their children or don't support IK.
- /// <para></para>
- /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/ik#foot-ik">Foot IK</see>
- /// </remarks>
- bool ApplyFootIK { get; set; }
- /************************************************************************************************************************/
- }
- }
- /************************************************************************************************************************/
- #if UNITY_EDITOR
- /************************************************************************************************************************/
- namespace Animancer.Editor
- {
- /// https://kybernetik.com.au/animancer/api/Animancer.Editor/AnimancerEditorUtilities
- public static partial class AnimancerEditorUtilities
- {
- /************************************************************************************************************************/
- /// <summary>
- /// Adds functions to show and set <see cref="IPlayableWrapper.ApplyAnimatorIK"/> and
- /// <see cref="IPlayableWrapper.ApplyFootIK"/>.
- /// </summary>
- public static void AddContextMenuIK(UnityEditor.GenericMenu menu, IPlayableWrapper ik)
- {
- menu.AddItem(new GUIContent("Inverse Kinematics/Apply Animator IK ?"),
- ik.ApplyAnimatorIK,
- () => ik.ApplyAnimatorIK = !ik.ApplyAnimatorIK);
- menu.AddItem(new GUIContent("Inverse Kinematics/Apply Foot IK ?"),
- ik.ApplyFootIK,
- () => ik.ApplyFootIK = !ik.ApplyFootIK);
- }
- /************************************************************************************************************************/
- /// <summary>Re-scales the <see cref="AnimancerNode.Weight"/> of all children to add up to 1.</summary>
- public static void NormalizeChildWeights(this IPlayableWrapper parent)
- {
- var totalWeight = 0f;
- var childCount = parent.ChildCount;
- for (int i = 0; i < childCount; i++)
- {
- var child = parent.GetChild(i);
- if (child.IsValid())
- totalWeight += child.Weight;
- }
- if (totalWeight == 0 ||// Can't normalize.
- Mathf.Approximately(totalWeight, 1))// Already normalized.
- return;
- totalWeight = 1f / totalWeight;
- for (int i = 0; i < childCount; i++)
- {
- var child = parent.GetChild(i);
- if (child.IsValid())
- child.Weight *= totalWeight;
- }
- }
- /************************************************************************************************************************/
- }
- }
- /************************************************************************************************************************/
- #endif
- /************************************************************************************************************************/
|