yyl
2025-07-21 5bc2cc9a3e007b96a0de96e70e87f25bc5a254a2
Main/System/Battle/Motion/MotionBase.cs
@@ -10,47 +10,19 @@
/// </summary>
public class MotionBase
{
    public class WaitingTask
    public static List<string> AttackMotionList = new List<string>
    {
        public List<int> triggerFrame;
        public MotionName motionName;
        public int currentFrame;
        public Action<MotionName, int> callback;
        MotionName.attack.ToString(),
        MotionName.angerSkill.ToString(),
        MotionName.passiveSkill.ToString(),
    };
        public WaitingTask(List<int> triggerFrame, MotionName motionName, Action<MotionName, int> _callback)
        {
            this.triggerFrame = new List<int>(triggerFrame);
            this.motionName = motionName;
            this.currentFrame = 0;
            this.callback = _callback;
        }
        public bool IsFinished()
        {
            return triggerFrame.Count <= 0;
        }
        public void Run()
        {
            if (triggerFrame.Count > 0)
            {
                currentFrame ++;
                if (currentFrame >= triggerFrame[0])
                {
                    int frame = triggerFrame[0];
                    triggerFrame.RemoveAt(0);
                    callback?.Invoke(motionName, frame);
                }
            }
        }
    }
    private Dictionary<Spine.TrackEntry, Action> trackEntryCompleteDict = new Dictionary<Spine.TrackEntry, Action>();
    // 动画事件
    public Action OnAttackAnimationComplete;
    public Action OnHitAnimationComplete;
    public Action<MotionName> OnOtherAnimationComplete;
    public Action<int> OnAttackHitEvent; //trigger index
    public Action<MotionName> onAnimationComplete;
    #region 组件引用
    
@@ -66,9 +38,6 @@
    protected float defaultMixDuration = 0f;
    
    #endregion
    protected List<WaitingTask> waitingTaskList = new List<WaitingTask>();
    protected List<WaitingTask> removeList = new List<WaitingTask>();
    private Spine.TrackEntry currentTrackEntry;
@@ -117,11 +86,8 @@
        skeletonGraphic = null;
        skeleton = null;
        currentTrackEntry = null;
        waitingTaskList.Clear();
        removeList.Clear();
    }
    #endregion
    #region 动画控制
@@ -131,15 +97,35 @@
    /// </summary>
    /// <param name="motionName">动画枚举</param>
    /// <param name="loop">是否循环</param>
    /// <param name="_onComplete">动画播放完成回调</param>
    /// <returns>动画轨道条目</returns>
    public virtual Spine.TrackEntry PlayAnimation(MotionName motionName, bool loop)
    public virtual Spine.TrackEntry PlayAnimation(MotionName motionName, bool loop, Action _onComplete = null)
    {
        if (spineAnimationState == null) return null;
        // 如果当前动画未完成
        if (currentTrackEntry != null && !currentTrackEntry.IsComplete)
        {
            if (trackEntryCompleteDict.TryGetValue(currentTrackEntry, out var __onComplete))
            {
                __onComplete?.Invoke();
                trackEntryCompleteDict.Remove(currentTrackEntry);
            }
            currentTrackEntry = null;
        }
        // 直接使用 ToString() 而不是调用 GetAnimationName
        currentTrackEntry = spineAnimationState.SetAnimation(0, motionName.ToString(), loop);
        // 绑定回调
        if (_onComplete != null && currentTrackEntry != null)
        {
            trackEntryCompleteDict[currentTrackEntry] = _onComplete;
        }
        return currentTrackEntry;
    }
    
    /// <summary>
    /// 设置动画事件监听
@@ -147,84 +133,44 @@
    protected virtual void SetupAnimationHandlers()
    {
        if (spineAnimationState == null) return;
        // 监听动画完成事件
        spineAnimationState.Complete += OnAnimationComplete;
    }
    /// <summary>
    /// 动画完成事件处理
    /// </summary>
    protected virtual void OnAnimationComplete(Spine.TrackEntry trackEntry)
    {
        string animation = trackEntry.Animation.Name;
        // 攻击动画完成后恢复到待机状态
        if (animation == MotionName.attack.ToString() ||
            animation == MotionName.angerSkill.ToString())
        if (AttackMotionList.Contains(animation))
        {
            OnAttackAnimationComplete?.Invoke();
            PlayAnimation(MotionName.idle, true);
        }
        // 受伤动画完成后恢复到待机状态
        // 受伤动画完成后恢复到待机状态 可能触发多次 因为有多段攻击的存在
        else if (animation == MotionName.hit.ToString())
        {
            OnHitAnimationComplete?.Invoke();
            PlayAnimation(MotionName.idle, true);
        }
        else
        onAnimationComplete?.Invoke((MotionName)Enum.Parse(typeof(MotionName), animation));
        // 只调用本次TrackEntry的回调
        if (trackEntryCompleteDict.TryGetValue(trackEntry, out var cb))
        {
            OnOtherAnimationComplete?.Invoke((MotionName)Enum.Parse(typeof(MotionName), animation));
            cb?.Invoke();
            trackEntryCompleteDict.Remove(trackEntry);
        }
    }
    
    /// <summary>
    /// 动画事件处理
    /// </summary>
    protected virtual void OnTriggerHitEvent(MotionName motionName, int hitIndex)
    {
        OnAttackHitEvent?.Invoke(hitIndex);
    }
    //  拓展了播放动画方法,添加了触发帧的功能,在攻击动画中多段攻击的触发帧
    //  例如:攻击动画有三段,第一段攻击在第1帧触发,第二段攻击在第10帧触发,第三段攻击在第20帧触发
    //  那么triggerFrame就应该是[1, 10, 20]
    public virtual void PlayAnimationEx(MotionName motionName, bool loop, List<int> triggerFrame = null)
    {
        PlayAnimation(motionName, loop);
        if (triggerFrame != null && triggerFrame.Count >= 0)
        {
            AddWaitingTask(triggerFrame, motionName);
        }
    }
    protected void AddWaitingTask(List<int> triggerFrame, MotionName motionName)
    {
        if (triggerFrame != null && triggerFrame.Count > 0)
        {
            WaitingTask waitingTask = new WaitingTask(triggerFrame, motionName, OnTriggerHitEvent);
            waitingTaskList.Add(waitingTask);
        }
    }
    public virtual void Run()
    {
        foreach (WaitingTask waitingTask in waitingTaskList)
        {
            waitingTask.Run();
            if (waitingTask.IsFinished())
            {
                removeList.Add(waitingTask);
            }
        }
        foreach (WaitingTask waitingTask in removeList)
        {
            waitingTaskList.Remove(waitingTask);
        }
        removeList.Clear();
    }
    public virtual void Pause()