// 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
/************************************************************************************************************************/