| | |
| | | /// </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 组件引用 |
| | | |
| | |
| | | protected float defaultMixDuration = 0f; |
| | | |
| | | #endregion |
| | | |
| | | protected List<WaitingTask> waitingTaskList = new List<WaitingTask>(); |
| | | protected List<WaitingTask> removeList = new List<WaitingTask>(); |
| | | |
| | | private Spine.TrackEntry currentTrackEntry; |
| | | |
| | |
| | | skeletonGraphic = null; |
| | | skeleton = null; |
| | | currentTrackEntry = null; |
| | | |
| | | waitingTaskList.Clear(); |
| | | removeList.Clear(); |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | |
| | | #region 动画控制 |
| | |
| | | /// </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> |
| | | /// 设置动画事件监听 |
| | |
| | | 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() |