com.alicizax.unity.animatio.../Runtime/AnimationFlow.cs

280 lines
7.3 KiB
C#
Raw Normal View History

2025-02-07 16:05:13 +08:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
2025-03-12 20:58:49 +08:00
using Cysharp.Threading.Tasks;
2025-02-07 16:05:13 +08:00
using Sirenix.OdinInspector;
using UnityEngine;
namespace AlicizaX.AnimationFlow.Runtime
{
2025-03-12 20:58:49 +08:00
[DisallowMultipleComponent]
2025-02-07 16:05:13 +08:00
public class AnimationFlow : MonoBehaviour
{
#region Editor相关
#if UNITY_EDITOR
2025-03-12 20:58:49 +08:00
public List<string> GetAllAnimationClips
2025-02-07 16:05:13 +08:00
{
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()
{
2025-03-12 20:58:49 +08:00
UnityEditor.EditorApplication.ExecuteMenuItem("Window/AnimationGraph");
2025-02-07 16:05:13 +08:00
}
#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);
}
2025-03-12 20:58:49 +08:00
public UniTask PlayAsync(string clipName)
{
var tcs = new UniTaskCompletionSource();
Action asyncCallBack = () => tcs.TrySetResult();
Play(clipName, asyncCallBack);
return tcs.Task;
}
2025-02-07 16:05:13 +08:00
public void Play(string clipName = "", Action actionComplete = null)
{
if (string.IsNullOrEmpty(clipName) || clipName == "None")
{
Debug.LogWarning($"animation name is empty!");
return;
}
2025-03-12 20:58:49 +08:00
if (_playebleType == EAnimationFlowPlayebleType.Play)
{
Debug.LogWarning($"animation flow is playing!");
StopFlow(true);
}
2025-02-07 16:05:13 +08:00
_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);
}
}
}
}