From dc7922d80c1d133b6261b8af1d521567d2c0a35d Mon Sep 17 00:00:00 2001
From: hch <305670599@qq.com>
Date: 星期四, 30 十月 2025 16:51:39 +0800
Subject: [PATCH] Merge branch 'master' of http://mobile.secondworld.net.cn:10010/r/Project_SG_scripts
---
Main/System/Battle/Motion/MotionBase.cs | 481 +++++++++++++++++++++++++++-------------------------
1 files changed, 248 insertions(+), 233 deletions(-)
diff --git a/Main/System/Battle/Motion/MotionBase.cs b/Main/System/Battle/Motion/MotionBase.cs
index 7a35dd2..5a29950 100644
--- a/Main/System/Battle/Motion/MotionBase.cs
+++ b/Main/System/Battle/Motion/MotionBase.cs
@@ -1,17 +1,11 @@
using System;
-using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Spine.Unity;
-using Cysharp.Threading.Tasks;
-/// <summary>
-/// 瑙掕壊鍔ㄧ敾鍩虹被锛屽鐞嗘墍鏈変笌鍔ㄧ敾鐩稿叧鐨勫姛鑳�
-/// </summary>
public class MotionBase
{
- public static float MotionTimeScale = 1f;
-
+ public float MotionTimeScale = 1f;
public static List<string> AttackMotionList = new List<string>
{
MotionName.attack.ToString().ToLower(),
@@ -19,360 +13,381 @@
MotionName.passiveSkill.ToString().ToLower(),
};
- private Dictionary<Spine.TrackEntry, Action> trackEntryCompleteDict = new Dictionary<Spine.TrackEntry, Action>();
-
- // 鍔ㄧ敾浜嬩欢
+ private Dictionary<Spine.TrackEntry, Action> trackEntryCallbacks = new Dictionary<Spine.TrackEntry, Action>();
public Action OnAttackAnimationComplete;
public Action OnHitAnimationComplete;
- public Action<string> onAnimationComplete;
-
- private List<Action> runActionList = new List<Action>();
+ private List<Action> runningActions = new List<Action>();
- #region 缁勪欢寮曠敤
-
- protected SkeletonGraphic skeletonGraphic;
- protected Spine.AnimationState spineAnimationState;
+ public SkeletonAnimation skeletonAnim;
+ protected Spine.AnimationState animState;
protected Spine.Skeleton skeleton;
-
- #endregion
-
- #region 鍔ㄧ敾璁剧疆
-
- // 鍔ㄧ敾娣峰悎鏃堕棿
protected float defaultMixDuration = 0f;
-
- #endregion
+ private Spine.TrackEntry currentTrack;
+ private SkeletonIllusionShadow illusionShadow;
+ private bool playingSkillAnim = false;
- private Spine.TrackEntry currentTrackEntry;
-
+ private bool isUnderControl = false;
- #region 鍒濆鍖栨柟娉�
+ private float pauseTime = 0f;
- /// <summary>
- /// 鍒濆鍖栧姩鐢荤粍浠�
- /// </summary>
- /// <param name="skeletonGraphic">楠ㄩ鍔ㄧ敾缁勪欢</param>
- public virtual void Init(SkeletonGraphic skeletonGraphic)
+ private float resumeTime = 0f;
+
+ public virtual void Init(SkeletonAnimation skelAnim)
{
- this.skeletonGraphic = skeletonGraphic;
-
- if (skeletonGraphic != null)
- {
- spineAnimationState = skeletonGraphic.AnimationState;
- spineAnimationState.TimeScale = MotionTimeScale;
- skeletonGraphic.timeScale = MotionTimeScale;
-
- skeleton = skeletonGraphic.Skeleton;
-
- // 璁剧疆鍔ㄧ敾娣峰悎鏃堕棿
- if (spineAnimationState != null)
- {
- spineAnimationState.Data.DefaultMix = defaultMixDuration;
- }
-
- // 鎾斁榛樿鍔ㄧ敾
- PlayAnimation(MotionName.idle, true);
-
- // 璁剧疆鍔ㄧ敾浜嬩欢鐩戝惉
- SetupAnimationHandlers();
- }
- else
+ skeletonAnim = skelAnim;
+ if (skeletonAnim == null)
{
BattleDebug.LogError("缂哄皯SkeletonGraphic缁勪欢!");
+ return;
}
-
+ animState = skeletonAnim.AnimationState;
+ skeletonAnim.timeScale = MotionTimeScale;
+ skeleton = skeletonAnim.Skeleton;
+
+ if (animState != null)
+ animState.Data.DefaultMix = defaultMixDuration;
+
+ PlayAnimation(MotionName.idle, true);
+ SetupAnimationHandlers();
+
+ if (skelAnim.gameObject != null)
+ illusionShadow = skelAnim.gameObject.AddMissingComponent<SkeletonIllusionShadow>();
}
public virtual void Release()
{
- trackEntryCompleteDict.Clear();
- if (spineAnimationState != null)
+ trackEntryCallbacks.Clear();
+ if (animState != null)
{
- spineAnimationState.Complete -= OnAnimationComplete;
- spineAnimationState.ClearTracks();
- spineAnimationState = null;
+ animState.Complete -= OnAnimationComplete;
+ animState.ClearTracks();
+ animState = null;
}
-
- skeletonGraphic = null;
+ skeletonAnim = null;
skeleton = null;
- currentTrackEntry = null;
+ currentTrack = null;
+ playingSkillAnim = false;
}
- #endregion
-
- #region 鍔ㄧ敾鎺у埗
-
- /// <summary>
- /// 鎾斁鎸囧畾鍔ㄧ敾
- /// </summary>
- /// <param name="motionName">鍔ㄧ敾鏋氫妇</param>
- /// <param name="loop">鏄惁寰幆</param>
- /// <param name="_onComplete">鍔ㄧ敾鎾斁瀹屾垚鍥炶皟</param>
- /// <returns>鍔ㄧ敾杞ㄩ亾鏉$洰</returns>
- public virtual Spine.TrackEntry PlayAnimation(MotionName motionName, bool loop, Action _onComplete = null)
+ public virtual Spine.TrackEntry PlayAnimation(MotionName motionName, bool loop, Action onComplete = null)
{
- if (spineAnimationState == null) return null;
+ if (playingSkillAnim || animState == null) return null;
- // 濡傛灉褰撳墠鍔ㄧ敾鏈畬鎴�
- if (currentTrackEntry != null && !currentTrackEntry.IsComplete)
+ if (currentTrack != null && !currentTrack.IsComplete && trackEntryCallbacks.TryGetValue(currentTrack, out var prevCallback))
{
- if (trackEntryCompleteDict.TryGetValue(currentTrackEntry, out var __onComplete))
- {
- __onComplete?.Invoke();
- trackEntryCompleteDict.Remove(currentTrackEntry);
- }
- currentTrackEntry = null;
+ trackEntryCallbacks.Remove(currentTrack);
+ prevCallback?.Invoke();
+ currentTrack = null;
}
- // 鐩存帴浣跨敤 ToString() 鑰屼笉鏄皟鐢� GetAnimationName
- currentTrackEntry = spineAnimationState.SetAnimation(0, motionName.ToString(), loop);
+ currentTrack = animState.SetAnimation(0, motionName.ToString(), loop);
+ if (onComplete != null && currentTrack != null)
+ trackEntryCallbacks[currentTrack] = onComplete;
- // 缁戝畾鍥炶皟
- if (_onComplete != null && currentTrackEntry != null)
- {
- trackEntryCompleteDict[currentTrackEntry] = _onComplete;
- }
-
- return currentTrackEntry;
+ return currentTrack;
}
- private void RunAction(Action _action)
- {
- runActionList.Add(_action);
- }
+ private void AddAction(Action action) => runningActions.Add(action);
+ private void RemoveAction(Action action) => runningActions.Remove(action);
- private void RemoveRunAction(Action _action)
+ public Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, SkillBase skillBase, bool isSubSkill, Action onComplete = null)
{
- runActionList.Remove(_action);
- }
-
- public Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, SkillBase skillBase, Action _onComplete = null)
- {
- // 鍙傛暟鏍¢獙
if (skillConfig == null)
{
- BattleDebug.LogError("鎶�鑳介厤缃负绌猴紝鏃犳硶鎾斁鎶�鑳藉姩鐢�");
+ Debug.LogError("鎶�鑳介厤缃负绌猴紝鏃犳硶鎾斁鎶�鑳藉姩鐢�");
return null;
}
- if (spineAnimationState == null || skeleton == null)
+ if (animState == null || skeleton == null)
{
- BattleDebug.LogError("SkeletonGraphic鎴朅nimationState鏈垵濮嬪寲锛屾棤娉曟挱鏀炬妧鑳藉姩鐢�");
+ Debug.LogError("SkeletonGraphic鎴朅nimationState鏈垵濮嬪寲锛屾棤娉曟挱鏀炬妧鑳藉姩鐢�");
return null;
}
-
- Spine.Animation anim = skeleton.Data.FindAnimation(skillConfig.SkillMotionName);
-
- if (null == anim)
+ if (string.IsNullOrEmpty(skillConfig.SkillMotionName))
{
- for (int i = 0; i < skeleton.Data.Animations.Count; i++)
- {
- var skeletonAnim = skeleton.Data.Animations.Items[i];
- if (skeletonAnim.Name.ToLower() == skillConfig.SkillMotionName.ToLower())
- {
- anim = skeletonAnim;
- // 鎵惧埌鍔ㄧ敾
- break;
- }
- }
- }
-
- // 鑾峰彇鍔ㄧ敾
- if (anim == null)
- {
- BattleDebug.LogError($"鎵句笉鍒板姩鐢�: {skillConfig.SkillMotionName}");
- _onComplete?.Invoke();
+ PlaySkillNoAnim(skillConfig, skillBase, onComplete, isSubSkill);
return null;
}
- // 鍏抽敭甯у弬鏁�
+ Spine.Animation targetAnim = FindAnim(skillConfig.SkillMotionName);
+ if (targetAnim == null)
+ {
+ skillBase.ForceFinished();
+ return null;
+ }
+
+ return ExecuteSkillAnim(skillConfig, skillBase, onComplete, targetAnim, true, isSubSkill);
+ }
+
+ private Spine.TrackEntry ExecuteSkillAnim(SkillConfig skillConfig, SkillBase skillBase, Action onComplete,
+ Spine.Animation targetAnim, bool hasAnim, bool isSubSkill)
+ {
+ bool isPangdeSkill = 1003020 == skillConfig.SkillID;
+
int loopCount = skillConfig.LoopCount;
- int[] activeFrames = skillConfig.ActiveFrames;
- int activeFrameCount = activeFrames.Length;
+ int[] activeFrames = skillConfig.ActiveFrames ?? new int[0];
+ int frameCount = activeFrames.Length;
float recoveryFrame = skillConfig.RecoveryFrames;
- // 鎾斁鍔ㄧ敾
- var skillTrackEntry = spineAnimationState.SetAnimation(0, anim, false);
- currentTrackEntry = skillTrackEntry;
+ Spine.TrackEntry skillTrack = null;
+ if (hasAnim)
+ {
+ skillTrack = animState.SetAnimation(0, targetAnim, false);
+ currentTrack = skillTrack;
+ }
+
+ playingSkillAnim = true;
- // 浜嬩欢鐘舵��
- int curLoop = 0;
- bool isFinish = false;
- bool beginPhaseTriggered = false;
- bool finalFrameStarted = false;
- bool finalFrameEnded = false;
- bool middleFrameStarted = false;
- bool[] triggeredActiveFrame = new bool[activeFrameCount];
+ int currentLoop = 0, triggerCount = 0, failCount = 0;
+ bool beginTriggered = false, finalStarted = false, finalEnded = false, middleStarted = false;
+ bool[] triggeredFrames = new bool[frameCount];
+ float startTime = hasAnim ? 0 : Time.time;
- // 鎶�鑳藉紑濮�
skillBase.OnSkillStart();
- // 鍔ㄧ敾甯ф洿鏂板鐞�
- int triggerMFEndCount = 0;
- Action updateLocalHandler = null;
- updateLocalHandler = () =>
+ Action frameHandler = null;
+ frameHandler = () =>
{
- if (isFinish) return;
-
- float frame = (skillTrackEntry.TrackTime * (float)BattleConst.skillMotionFps);
-
- // 鍓嶆憞缁撴潫锛堝彧瑙﹀彂涓�娆★級
- if (!beginPhaseTriggered && frame >= skillConfig.StartupFrames && curLoop == 0)
+ if (skillBase.IsFinished())
{
- beginPhaseTriggered = true;
+ playingSkillAnim = false;
+ RemoveAction(frameHandler);
+ return;
+ }
+
+ float trackTime = 0f; //hasAnim ? skillTrack.TrackTime * skillTrack.TimeScale : (Time.time - startTime) * MotionTimeScale;
+
+ if (hasAnim)
+ {
+ trackTime = skillTrack.TrackTime;
+ }
+ else
+ {
+ float adjustedTime = Time.time;
+ if (pauseTime > 0f && resumeTime > pauseTime)
+ {
+ startTime = startTime + (resumeTime - pauseTime);
+ pauseTime = 0f;
+ resumeTime = 0f;
+ }
+ trackTime = (adjustedTime - startTime) * MotionTimeScale;
+ }
+
+ float currentFrame = trackTime * BattleConst.skillMotionFps;
+
+ if (hasAnim)
+ {
+ if (currentTrack != skillTrack)
+ {
+ Debug.LogError("鎶�鑳藉姩鐢昏鎵撴柇锛屽己鍒剁粨鏉� " + skillConfig.SkillID);
+ skillBase.ForceFinished();
+ RemoveAction(frameHandler);
+ playingSkillAnim = false;
+ return;
+ }
+
+ if (skillTrack.TrackTime == 0) failCount++;
+ if (failCount > 100)
+ {
+ Debug.LogError("鎶�鑳藉姩鐢绘挱鏀惧け璐ワ紝寮哄埗缁撴潫 " + skillConfig.SkillID);
+ skillBase.ForceFinished();
+ RemoveAction(frameHandler);
+ playingSkillAnim = false;
+ return;
+ }
+ }
+
+ if (!beginTriggered && currentFrame >= skillConfig.StartupFrames && currentLoop == 0)
+ {
+ beginTriggered = true;
skillBase.OnStartSkillFrameEnd();
}
- // 涓憞寮�濮嬶紙姣忚疆loop鐨勫紑濮嬶紝鍙Е鍙戜竴娆★級
- if (!middleFrameStarted && frame >= skillConfig.StartupFrames && curLoop <= loopCount)
+ if (!middleStarted && currentFrame >= skillConfig.StartupFrames && currentLoop <= loopCount)
{
- middleFrameStarted = true;
- skillBase.OnMiddleFrameStart(curLoop);
+ middleStarted = true;
+ skillBase.OnMiddleFrameStart(currentLoop);
}
- // 澶氭鏀诲嚮甯цЕ鍙�
- for (int hitIndex = 0; hitIndex < activeFrameCount; hitIndex++)
+ for (int i = 0; i < frameCount && i < triggeredFrames.Length; i++)
{
- float activeFrame = activeFrames[hitIndex];
- if (!triggeredActiveFrame[hitIndex] && frame >= activeFrame)
+ if (!triggeredFrames[i] && currentFrame >= activeFrames[i])
{
- skillBase.OnMiddleFrameEnd(curLoop, triggerMFEndCount++);
- triggeredActiveFrame[hitIndex] = true;
+ skillBase.OnMiddleFrameEnd(currentLoop, triggerCount++);
+ triggeredFrames[i] = true;
}
}
- // 鍒ゆ柇鏄惁鎵�鏈塧ctiveFrame閮藉凡瑙﹀彂锛屽噯澶囪繘鍏ヤ笅涓�杞甽oop
- bool allTriggered = true;
- for (int i = 0; i < activeFrameCount; i++)
- {
- if (!triggeredActiveFrame[i])
- {
- allTriggered = false;
- break;
- }
- }
+ bool allTriggered = Array.TrueForAll(triggeredFrames, x => x);
- // 杩涘叆涓嬩竴杞甽oop
- if (allTriggered && curLoop < loopCount)
+ if (allTriggered && currentLoop < loopCount)
{
- curLoop++;
- Array.Clear(triggeredActiveFrame, 0, activeFrameCount);
- middleFrameStarted = false;
+ currentLoop++;
+ Array.Clear(triggeredFrames, 0, frameCount);
+ middleStarted = false;
- if (curLoop < loopCount)
+ if (currentLoop < loopCount)
{
- // 閲嶆柊璁剧疆鍒扮涓�娆$殑涓憞鏃堕棿
- skillTrackEntry.TrackTime = skillConfig.StartupFrames / BattleConst.skillMotionFps;
- beginPhaseTriggered = false;
+ if (BattleConst.skillMotionFps > 0)
+ {
+ if (hasAnim)
+ skillTrack.TrackTime = skillConfig.StartupFrames / BattleConst.skillMotionFps;
+ else
+ startTime = Time.time - (skillConfig.StartupFrames / BattleConst.skillMotionFps);
+ }
+ beginTriggered = false;
}
else
{
- finalFrameStarted = false;
- finalFrameEnded = false;
- // 鏀跺熬闃舵鐢卞悗缁�昏緫澶勭悊
+ finalStarted = false;
+ finalEnded = false;
}
}
- // 鏀跺熬闃舵锛歄nFinalFrameStart 鍜� OnFinalFrameEnd
- if (curLoop >= loopCount)
+ if (currentLoop >= loopCount)
{
- if (!finalFrameStarted && frame >= recoveryFrame)
+ if (!finalStarted && currentFrame >= recoveryFrame)
{
- finalFrameStarted = true;
+ finalStarted = true;
skillBase.OnFinalFrameStart();
}
- if (finalFrameStarted && !finalFrameEnded && frame >= recoveryFrame)
+ if (finalStarted && !finalEnded && currentFrame >= recoveryFrame)
{
- finalFrameEnded = true;
+ finalEnded = true;
+ if (!isSubSkill)
+ {
+ playingSkillAnim = false;
+ }
+ RemoveAction(frameHandler);
+ onComplete?.Invoke();
skillBase.OnFinalFrameEnd();
- RemoveRunAction(updateLocalHandler);
- isFinish = true;
}
}
};
- if (_onComplete != null && currentTrackEntry != null)
+ AddAction(frameHandler);
+ return skillTrack;
+ }
+
+ private Spine.Animation FindAnim(string animName)
+ {
+ if (string.IsNullOrEmpty(animName)) return null;
+
+ Spine.Animation targetAnim = skeleton.Data.FindAnimation(animName);
+ if (targetAnim == null && skeleton.Data.Animations != null)
{
- trackEntryCompleteDict[currentTrackEntry] = _onComplete;
+ for (int i = 0; i < skeleton.Data.Animations.Count; i++)
+ {
+ var anim = skeleton.Data.Animations.Items[i];
+ if (anim?.Name != null && anim.Name.ToLower() == animName.ToLower())
+ {
+ targetAnim = anim;
+ break;
+ }
+ }
}
- RunAction(updateLocalHandler);
+ if (targetAnim == null)
+ Debug.LogError($"鎵句笉鍒板姩鐢�: {animName}");
- return skillTrackEntry;
+ return targetAnim;
}
-
- /// <summary>
- /// 璁剧疆鍔ㄧ敾浜嬩欢鐩戝惉
- /// </summary>
+ private void PlaySkillNoAnim(SkillConfig skillConfig, SkillBase skillBase, Action onComplete, bool isSubSkill) =>
+ ExecuteSkillAnim(skillConfig, skillBase, onComplete, null, false, isSubSkill);
+
protected virtual void SetupAnimationHandlers()
{
- if (spineAnimationState == null) return;
-
- // 鐩戝惉鍔ㄧ敾瀹屾垚浜嬩欢
- spineAnimationState.Complete += OnAnimationComplete;
+ if (animState != null)
+ animState.Complete += OnAnimationComplete;
}
- /// <summary>
- /// 鍔ㄧ敾瀹屾垚浜嬩欢澶勭悊
- /// </summary>
protected virtual void OnAnimationComplete(Spine.TrackEntry trackEntry)
{
- string animation = trackEntry.Animation.Name.ToLower();
+ if (trackEntry?.Animation?.Name == null) return;
- // 鏀诲嚮鍔ㄧ敾瀹屾垚鍚庢仮澶嶅埌寰呮満鐘舵��
- if (AttackMotionList.Contains(animation))
+ string animName = trackEntry.Animation.Name.ToLower();
+
+ if (AttackMotionList.Contains(animName))
{
OnAttackAnimationComplete?.Invoke();
PlayAnimation(MotionName.idle, true);
}
- // 鍙椾激鍔ㄧ敾瀹屾垚鍚庢仮澶嶅埌寰呮満鐘舵�� 鍙兘瑙﹀彂澶氭 鍥犱负鏈夊娈垫敾鍑荤殑瀛樺湪
- else if (animation == MotionName.hit.ToString().ToLower())
+ else if (animName == MotionName.hit.ToString().ToLower())
{
OnHitAnimationComplete?.Invoke();
PlayAnimation(MotionName.idle, true);
}
- onAnimationComplete?.Invoke(animation);
-
- // 鍙皟鐢ㄦ湰娆rackEntry鐨勫洖璋�
- if (trackEntryCompleteDict.TryGetValue(trackEntry, out var cb))
+ if (trackEntryCallbacks.TryGetValue(trackEntry, out var callback))
{
- cb?.Invoke();
- trackEntryCompleteDict.Remove(trackEntry);
+ trackEntryCallbacks.Remove(trackEntry);
+ callback?.Invoke();
}
}
+ public void SetControledAnimation()
+ {
+ // 鍙楀埌纭帶鐨勬椂鍊欙紝淇濇寔鍙楀嚮鍔ㄧ敾鐨勭涓夊抚锛岀洿鍒版帶鍒剁粨鏉� 鎴栬�呮渶鍚庝竴鍑绘浜★紝绉婚櫎鎺у埗鏁堟灉鍚庯紝鎭㈠鍒板緟鏈虹姸鎬佹垨鑰呮挱鏀炬浜″姩鐢�
+ // 杩欓噷鏄彈鍒扮‖鎺ф椂鍊� 闇�瑕佽〃鐜扮殑鍔ㄧ敾
+ var entry = PlayAnimation(MotionName.hit, false);
+ float threeFrameTrackTime = 3f / BattleConst.skillMotionFps;
+ entry.TrackTime = threeFrameTrackTime;
+ entry.TimeScale = 0;
+
+ isUnderControl = true;
+
+ }
+
+ public void CancelControledAnimation()
+ {
+ // 纭帶缁撴潫锛屾仮澶嶅姩鐢绘挱鏀�
+ isUnderControl = false;
+ PlayAnimation(MotionName.idle, true);
+ }
public virtual void Run()
{
- for (int i = runActionList.Count - 1; i >= 0; i--)
- {
- runActionList[i]?.Invoke();
- }
+ for (int i = runningActions.Count - 1; i >= 0; i--)
+ runningActions[i]?.Invoke();
+
+ illusionShadow?.Run();
}
public virtual void Pause()
{
- spineAnimationState.TimeScale = 0f;
- skeletonGraphic.timeScale = 0f;
+ if (skeletonAnim != null) skeletonAnim.timeScale = 0f;
+ pauseTime = Time.time;
}
public virtual void Resume()
{
- spineAnimationState.TimeScale = MotionTimeScale;
- skeletonGraphic.timeScale = MotionTimeScale;
+ if (skeletonAnim != null) skeletonAnim.timeScale = MotionTimeScale;
+ resumeTime = Time.time;
}
public void HaveRest()
{
- trackEntryCompleteDict.Clear();
- runActionList.Clear();
+ trackEntryCallbacks.Clear();
+ runningActions.Clear();
+ playingSkillAnim = false;
PlayAnimation(MotionName.idle, true);
}
- #endregion
+ public void SetSpeedRatio(float ratio)
+ {
+ MotionTimeScale = ratio;
+ if (skeletonAnim != null) skeletonAnim.timeScale = ratio;
+ }
+ public void ShowIllusionShadow(bool isVisible, Color color = default)
+ {
+ if (illusionShadow != null)
+ {
+ illusionShadow.SetSkeletonAnimation(skeletonAnim);
+ illusionShadow.Show(isVisible, color);
+ }
+ }
}
\ No newline at end of file
--
Gitblit v1.8.0