com.alicizax.unity.animatio.../Runtime/AnimationFlow.cs
陈思海 11e5744b46 init
2025-02-07 16:05:13 +08:00

266 lines
7.0 KiB
C#
Raw 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 Sirenix.OdinInspector;
using UnityEngine;
namespace AlicizaX.AnimationFlow.Runtime
{
public class AnimationFlow : MonoBehaviour
{
#region Editor相关
#if UNITY_EDITOR
IEnumerable 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("AlicizaFramework/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 void Play(string clipName = "", Action actionComplete = null)
{
if (_playebleType == EAnimationFlowPlayebleType.Play)
{
Debug.LogWarning($"animation flow is playing!");
return;
}
if (string.IsNullOrEmpty(clipName) || clipName == "None")
{
Debug.LogWarning($"animation name is empty!");
return;
}
_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);
}
}
}
}