com.alicizax.unity.animatio.../Runtime/AnimationFlow.cs
2025-03-12 20:58:49 +08:00

280 lines
7.3 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Cysharp.Threading.Tasks;
using Sirenix.OdinInspector;
using UnityEngine;
namespace AlicizaX.AnimationFlow.Runtime
{
[DisallowMultipleComponent]
public class AnimationFlow : MonoBehaviour
{
#region Editor相关
#if UNITY_EDITOR
public List<string> GetAllAnimationClips
{
get
{
List<string> keys = new();
foreach (EntryNode root in AnimationNodes)
{
if (!string.IsNullOrEmpty(root.Name))
{
keys.Add(root.Name);
}
}
keys.Insert(0, "None");
return keys;
}
}
[Button("节点编辑器", ButtonSizes.Large), GUIColor(0, 1, 0)]
private void OpenGraphWindow()
{
UnityEditor.EditorApplication.ExecuteMenuItem("Window/AnimationGraph");
}
#endif
#endregion
[HideInInspector] [SerializeReference] public List<EntryNode> AnimationNodes = new List<EntryNode>();
[LabelText("动画片段")] [BoxGroup("基础设置", true)] [ValueDropdown("GetAllAnimationClips", ExpandAllMenuItems = true)] [SerializeField]
private string _defaultPlayName = "None";
[LabelText("自动播放")] [BoxGroup("基础设置", true)] [SerializeField]
private bool _enableAutoPlay;
private List<ActionNode> _runningNodes = new List<ActionNode>();
private List<ActionNode> _resetNodes = new List<ActionNode>();
private ActionNode _curEntryNode;
private int _loopCount = 0;
/// <summary>
/// 节点播放回调
/// </summary>
private Action _playFinishEvent;
/// <summary>
/// 时间缩放系数 受Time.deltatime影响
/// </summary>
private float _timeScale = 1f;
public float TimeScale
{
get => _timeScale;
set => _timeScale = value;
}
/// <summary>
/// 当前节点状态
/// </summary>
private EAnimationFlowPlayebleType _playebleType = EAnimationFlowPlayebleType.Stop;
public EAnimationFlowPlayebleType AnimationFlowPlayebleType
{
get => _playebleType;
set => _playebleType = value;
}
/// <summary>
/// 是否播放中
/// </summary>
public bool InPlaying => _playebleType == EAnimationFlowPlayebleType.Play;
/// <summary>
/// 是否暂停中
/// </summary>
public bool InPause => _playebleType == EAnimationFlowPlayebleType.Pause;
private void Start()
{
if (_enableAutoPlay)
{
Play(_defaultPlayName);
}
}
private void Update()
{
if (_playebleType == EAnimationFlowPlayebleType.Play)
{
Tick(Time.deltaTime * _timeScale);
}
}
public void Tick(float deltaTime)
{
List<ActionNode> runNodes = _runningNodes;
int runCount = runNodes.Count;
if (runCount == 0)
{
if (_loopCount > 0)
{
_loopCount--;
ResetNode();
PushNode(_curEntryNode);
}
else
{
StopFlow();
}
}
if (runCount > 0)
{
for (int i = runCount - 1; i >= 0; i--)
{
ActionNode node = _runningNodes[i];
if (node.Condition())
{
PopNode(node);
}
else
{
node.elapsedTime = Mathf.Min(node.elapsedTime + deltaTime, node.Duration());
node.OnUpdate(deltaTime);
node.State = EState.Running;
}
}
}
}
public void ResetNode()
{
for (int i = _resetNodes.Count - 1; i >= 0; i--)
{
ActionNode node = _resetNodes[i];
node.Reset();
node.OnReset();
}
_resetNodes.Clear();
}
private void StopFlow(bool isInterrupt = false)
{
_playebleType = EAnimationFlowPlayebleType.Stop;
_curEntryNode = null;
_loopCount = 0;
for (int i = _resetNodes.Count - 1; i >= 0; i--)
{
ActionNode node = _resetNodes[i];
if (!Application.isPlaying)
{
node.OnReset();
}
node.Reset();
}
if (isInterrupt)
{
for (int i = _runningNodes.Count - 1; i >= 0; i--)
{
ActionNode node = _runningNodes[i];
node.OnInterrupt();
}
}
if (_playFinishEvent != null) _playFinishEvent();
_resetNodes.Clear();
_runningNodes.Clear();
}
private void PopNode(ActionNode node)
{
node.OnExit();
node.State = EState.Exit;
_runningNodes.Remove(node);
PushChildNode(node);
}
private void PushChildNode(ActionNode node)
{
List<ActionNode> childNode = node.Childs;
if (childNode.Count > 0)
{
foreach (var child in childNode)
{
PushNode(child);
}
}
}
private void PushNode(ActionNode node)
{
node.OnInit();
node.OnEnter();
node.State = EState.Enter;
_runningNodes.Add(node);
_resetNodes.Add(node);
}
public UniTask PlayAsync(string clipName)
{
var tcs = new UniTaskCompletionSource();
Action asyncCallBack = () => tcs.TrySetResult();
Play(clipName, asyncCallBack);
return tcs.Task;
}
public void Play(string clipName = "", Action actionComplete = null)
{
if (string.IsNullOrEmpty(clipName) || clipName == "None")
{
Debug.LogWarning($"animation name is empty!");
return;
}
if (_playebleType == EAnimationFlowPlayebleType.Play)
{
Debug.LogWarning($"animation flow is playing!");
StopFlow(true);
}
_playFinishEvent = actionComplete;
EntryNode entryNode = AnimationNodes.Find(a => a.Name == clipName);
if (entryNode == null)
{
Debug.LogWarning($"Can not find this Clip {clipName}");
return;
}
_loopCount = entryNode.LoopCount;
_curEntryNode = entryNode;
_playebleType = EAnimationFlowPlayebleType.Play;
}
public void Stop()
{
if (_playebleType == EAnimationFlowPlayebleType.Play)
{
StopFlow(true);
}
}
}
}