Net.Like.Xue.Tokyo/Assets/Plugins/Animancer/Internal/Interfaces/IPlayableWrapper.cs

162 lines
7.5 KiB
C#

// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2023 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
/************************************************************************************************************************/