// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2023 Kybernetik // using UnityEngine; using UnityEngine.Playables; namespace Animancer { /// Interface for objects that manage a . /// https://kybernetik.com.au/animancer/api/Animancer/IPlayableWrapper /// public interface IPlayableWrapper { /************************************************************************************************************************/ /// The object which receives the output of the . IPlayableWrapper Parent { get; } /// The current blend weight of this node which determines how much it affects the final output. float Weight { get; } /// The managed by this object. Playable Playable { get; } /// The number of nodes using this object as their . int ChildCount { get; } /// Returns the state connected to the specified `index` as a child of this object. AnimancerNode GetChild(int index); /// /// Indicates whether child playables should stay connected to the graph at all times. /// /// If false, playables will be disconnected from the graph while they are at 0 weight to stop it from /// evaluating them every frame. /// /// bool KeepChildrenConnected { get; } /// How fast the is advancing every frame. /// /// /// 1 is the normal speed. /// /// A negative value will play the animation backwards. /// /// Animancer Lite does not allow this value to be changed in runtime builds. /// /// /// /// 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. /// } /// float Speed { get; set; } /************************************************************************************************************************/ /// /// Should Unity call OnAnimatorIK on the animated object while this object and its children have any /// ? /// /// /// This is equivalent to the "IK Pass" toggle in Animator Controller layers, except that due to limitations in /// the Playables API the layerIndex will always be zero. /// /// This value starts false by default, but can be automatically changed by /// when the is set. /// /// IK only takes effect while at least one has a /// above zero. Other node types either store the value to apply to their children or don't support IK. /// /// Documentation: IK Pass /// bool ApplyAnimatorIK { get; set; } /************************************************************************************************************************/ /// Should this object and its children apply IK to the character's feet? /// /// This is equivalent to the "Foot IK" toggle in Animator Controller states. /// /// This value starts true by default for s (false for others), but can be automatically /// changed by when the is set. /// /// IK only takes effect while at least one has a /// above zero. Other node types either store the value to apply to their children or don't support IK. /// /// Documentation: Foot IK /// bool ApplyFootIK { get; set; } /************************************************************************************************************************/ } } /************************************************************************************************************************/ #if UNITY_EDITOR /************************************************************************************************************************/ namespace Animancer.Editor { /// https://kybernetik.com.au/animancer/api/Animancer.Editor/AnimancerEditorUtilities public static partial class AnimancerEditorUtilities { /************************************************************************************************************************/ /// /// Adds functions to show and set and /// . /// 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); } /************************************************************************************************************************/ /// Re-scales the of all children to add up to 1. 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 /************************************************************************************************************************/