using System; using UnityEngine; using UnityEngine.Animations; using UnityEngine.Assertions; using UnityEngine.Playables; using Logger = RebootKit.Engine.Foundation.Logger; // @TODO: // - avoid boxing values // - think about refactoring in order to reduce gc allocs namespace RebootKit.Engine.Animations { public interface IReAnimatorNode { string Name { get; } void Tick(float deltaTime); IPlayable Build(PlayableGraph graph); bool TryFindChild(string name, out IReAnimatorNode node); } public enum ReAnimatorTickMode { Update, Fixed, Manual } [DefaultExecutionOrder(-100)] public class ReAnimator : MonoBehaviour { static readonly Logger s_Logger = new Logger(nameof(ReAnimator)); [SerializeField] Animator m_Animator; [SerializeField] LayerMixerNode m_Root; public PlayableGraph Graph { get; private set; } AnimationPlayableOutput m_Output; void Awake() { Assert.IsNotNull(m_Animator, "Animator is not set"); m_Animator.runtimeAnimatorController = null; Graph = PlayableGraph.Create(name); m_Output = AnimationPlayableOutput.Create(Graph, "Animation Output", m_Animator); if (m_Root.Build(Graph) is AnimationLayerMixerPlayable layerMixer) { m_Output.SetSourcePlayable(layerMixer, 0); } Graph.Play(); } void OnDestroy() { if (Graph.IsValid()) { Graph.Destroy(); } } void Update() { float dt = Time.deltaTime; m_Root.Tick(dt); Graph.Evaluate(dt); } public void SetLayerWeight(int layer, float weight) { m_Root.SetLayerWeight(layer, weight); } public IReAnimatorNode FindNode(string nodeName) { if (m_Root.TryFindChild(nodeName, out IReAnimatorNode node)) { return node; } s_Logger.Error($"Couldn't find node with name: {nodeName}"); return null; } public TNode FindNode(string nodeName) where TNode : class, IReAnimatorNode { IReAnimatorNode node = FindNode(nodeName); if (node is TNode tnode) { return tnode; } s_Logger.Error($"Couldn't find node with name: {nodeName} of type {typeof(TNode).Name}"); return null; } } }