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