using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using Spine.Unity; using Cysharp.Threading.Tasks; /// /// 角色动画基类,处理所有与动画相关的功能 /// public class MotionBase { public static List AttackMotionList = new List { MotionName.attack.ToString(), MotionName.angerSkill.ToString(), MotionName.passiveSkill.ToString(), }; private Dictionary trackEntryCompleteDict = new Dictionary(); // 动画事件 public Action OnAttackAnimationComplete; public Action OnHitAnimationComplete; public Action onAnimationComplete; #region 组件引用 protected SkeletonGraphic skeletonGraphic; protected Spine.AnimationState spineAnimationState; protected Spine.Skeleton skeleton; #endregion #region 动画设置 // 动画混合时间 protected float defaultMixDuration = 0f; #endregion private Spine.TrackEntry currentTrackEntry; #region 初始化方法 /// /// 初始化动画组件 /// /// 骨骼动画组件 public virtual void Init(SkeletonGraphic skeletonGraphic) { this.skeletonGraphic = skeletonGraphic; if (skeletonGraphic != null) { spineAnimationState = skeletonGraphic.AnimationState; skeleton = skeletonGraphic.Skeleton; // 设置动画混合时间 if (spineAnimationState != null) { spineAnimationState.Data.DefaultMix = defaultMixDuration; } // 播放默认动画 PlayAnimation(MotionName.idle, true); // 设置动画事件监听 SetupAnimationHandlers(); } else { Debug.LogError("缺少SkeletonGraphic组件!"); } } public virtual void Release() { if (spineAnimationState != null) { spineAnimationState.Complete -= OnAnimationComplete; spineAnimationState.ClearTracks(); spineAnimationState = null; } skeletonGraphic = null; skeleton = null; currentTrackEntry = null; } #endregion #region 动画控制 /// /// 播放指定动画 /// /// 动画枚举 /// 是否循环 /// 动画播放完成回调 /// 动画轨道条目 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; } /// /// 设置动画事件监听 /// protected virtual void SetupAnimationHandlers() { if (spineAnimationState == null) return; // 监听动画完成事件 spineAnimationState.Complete += OnAnimationComplete; } /// /// 动画完成事件处理 /// protected virtual void OnAnimationComplete(Spine.TrackEntry trackEntry) { string animation = trackEntry.Animation.Name; // 攻击动画完成后恢复到待机状态 if (AttackMotionList.Contains(animation)) { OnAttackAnimationComplete?.Invoke(); PlayAnimation(MotionName.idle, true); } // 受伤动画完成后恢复到待机状态 可能触发多次 因为有多段攻击的存在 else if (animation == MotionName.hit.ToString()) { OnHitAnimationComplete?.Invoke(); PlayAnimation(MotionName.idle, true); } onAnimationComplete?.Invoke((MotionName)Enum.Parse(typeof(MotionName), animation)); // 只调用本次TrackEntry的回调 if (trackEntryCompleteDict.TryGetValue(trackEntry, out var cb)) { cb?.Invoke(); trackEntryCompleteDict.Remove(trackEntry); } } public virtual void Run() { } public virtual void Pause() { if (currentTrackEntry != null) currentTrackEntry.TimeScale = 0f; } public virtual void Resume() { if (currentTrackEntry != null) currentTrackEntry.TimeScale = 1f; } #endregion }