using System; using UnityEngine; using UnityEngine.Animations; using UnityEngine.Playables; namespace RebootKit.Engine.Animations { [Serializable] public class MixerNode : IReAnimatorNode { [Serializable] struct InputState { [SerializeReference] public IReAnimatorNode node; [Range(0.0f, 1.0f)] public float targetWeight; [NonSerialized] public float CurrentWeight; } [field: SerializeField] public string Name { get; private set; } AnimationMixerPlayable m_Mixer; [SerializeField] float m_TransitionSpeed = 5.0f; [SerializeField] InputState[] m_Inputs; public void Tick(float deltaTime) { for (int i = 0; i < m_Inputs.Length; ++i){ if (m_TransitionSpeed > 0.0f) { m_Inputs[i].CurrentWeight = Mathf.MoveTowards(m_Inputs[i].CurrentWeight, m_Inputs[i].targetWeight, m_TransitionSpeed * deltaTime); } else { m_Inputs[i].CurrentWeight = m_Inputs[i].targetWeight; } m_Mixer.SetInputWeight(i, m_Inputs[i].CurrentWeight); m_Inputs[i].node.Tick(deltaTime); } } public IPlayable Build(PlayableGraph graph) { m_Mixer = AnimationMixerPlayable.Create(graph, m_Inputs.Length); for (int i = 0; i < m_Inputs.Length; ++i) { IPlayable playable = m_Inputs[i].node.Build(graph); if (playable is AnimationMixerPlayable mixerPlayable) { m_Mixer.ConnectInput(i, mixerPlayable, 0, m_Inputs[i].targetWeight); } else if (playable is AnimationClipPlayable clipPlayable) { m_Mixer.ConnectInput(i, clipPlayable, 0, m_Inputs[i].targetWeight); } } return m_Mixer; } public bool TryFindChild(string name, out IReAnimatorNode node) { for (int i = 0; i < m_Inputs.Length; i++) { if (m_Inputs[i].node.Name.Equals(name, StringComparison.Ordinal)) { node = m_Inputs[i].node; return true; } if (m_Inputs[i].node.TryFindChild(name, out IReAnimatorNode childNode)) { node = childNode; return true; } } node = null; return false; } public void SetInputWeight(int index, float weight) { m_Inputs[index].targetWeight = weight; } } }