266 lines
7.0 KiB
C#
266 lines
7.0 KiB
C#
![]() |
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);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|