| | |
| | | protected Spine.Skeleton skeleton; |
| | | protected float defaultMixDuration = 0f; |
| | | private Spine.TrackEntry currentTrack; |
| | | private Dictionary<int, Spine.TrackEntry> activeSkillTracks = new Dictionary<int, Spine.TrackEntry>(); // 改为字典:trackIndex -> TrackEntry |
| | | private Dictionary<int, Spine.TrackEntry> activeSkillTracks = new Dictionary<int, Spine.TrackEntry>(); |
| | | |
| | | // 子技能轨道池管理(在Init中初始化,不要在这里初始化) |
| | | private Queue<int> availableSubTracks; |
| | | private Dictionary<SkillBase, int> subSkillTrackMap = new Dictionary<SkillBase, int>(); |
| | | |
| | | private SkeletonIllusionShadow illusionShadow; |
| | | private bool playingSkillAnim = false; |
| | | |
| | |
| | | if (animState != null) |
| | | animState.Data.DefaultMix = defaultMixDuration; |
| | | |
| | | // 初始化子技能轨道池 |
| | | availableSubTracks = new Queue<int>(); |
| | | for (int i = 1; i <= 8; i++) |
| | | availableSubTracks.Enqueue(i); |
| | | |
| | | PlayAnimation(MotionName.idle, true); |
| | | SetupAnimationHandlers(); |
| | | |
| | |
| | | { |
| | | trackEntryCallbacks.Clear(); |
| | | activeSkillTracks.Clear(); |
| | | availableSubTracks?.Clear(); |
| | | subSkillTrackMap.Clear(); |
| | | if (animState != null) |
| | | { |
| | | animState.Complete -= OnAnimationComplete; |
| | |
| | | return null; |
| | | } |
| | | |
| | | // 子技能强制使用无动画模式,或者如果没有动画名称 |
| | | if (isSubSkill || string.IsNullOrEmpty(skillConfig.SkillMotionName)) |
| | | // 如果没有动画名称,使用无动画模式 |
| | | if (string.IsNullOrEmpty(skillConfig.SkillMotionName)) |
| | | { |
| | | PlaySkillNoAnim(skillConfig, skillBase, onComplete, isSubSkill); |
| | | return null; |
| | |
| | | int frameCount = activeFrames.Length; |
| | | float recoveryFrame = skillConfig.RecoveryFrames; |
| | | |
| | | // 主技能用 track 0,子技能用 track 1 |
| | | int trackIndex = isSubSkill ? 1 : 0; |
| | | // 轨道分配策略:主技能用 track 0,子技能从轨道池分配 |
| | | int trackIndex = 0; |
| | | if (isSubSkill) |
| | | { |
| | | if (availableSubTracks != null && availableSubTracks.Count > 0) |
| | | { |
| | | trackIndex = availableSubTracks.Dequeue(); |
| | | subSkillTrackMap[skillBase] = trackIndex; |
| | | } |
| | | else |
| | | { |
| | | // 轨道池耗尽或未初始化,回退到无动画模式 |
| | | Debug.LogWarning($"子技能轨道池已满或未初始化,技能{skillConfig.SkillID}使用无动画模式"); |
| | | PlaySkillNoAnim(skillConfig, skillBase, onComplete, isSubSkill); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | Spine.TrackEntry skillTrack = null; |
| | | |
| | | if (hasAnim) |
| | | { |
| | | skillTrack = animState.SetAnimation(trackIndex, targetAnim, false); |
| | | if (null == skillTrack) |
| | | { |
| | | Debug.LogError($"技能 {skillConfig.SkillID} 动画设置失败"); |
| | | // 如果是子技能且分配了轨道,需要回收 |
| | | if (isSubSkill && subSkillTrackMap.ContainsKey(skillBase)) |
| | | { |
| | | if (availableSubTracks != null) |
| | | availableSubTracks.Enqueue(subSkillTrackMap[skillBase]); |
| | | subSkillTrackMap.Remove(skillBase); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | // 只有主技能才更新 currentTrack |
| | | if (!isSubSkill) |
| | |
| | | { |
| | | if (activeSkillTracks[trackIndex] == skillTrack) |
| | | activeSkillTracks.Remove(trackIndex); |
| | | } |
| | | |
| | | // 回收子技能轨道 |
| | | if (isSubSkill && subSkillTrackMap.ContainsKey(skillBase)) |
| | | { |
| | | if (availableSubTracks != null) |
| | | availableSubTracks.Enqueue(subSkillTrackMap[skillBase]); |
| | | subSkillTrackMap.Remove(skillBase); |
| | | } |
| | | |
| | | // 只有当没有其他活跃技能时才复位 playingSkillAnim |
| | |
| | | |
| | | // 清理并确保状态复位 |
| | | RemoveAction(frameHandler); |
| | | |
| | | // 回收子技能轨道 |
| | | if (isSubSkill && subSkillTrackMap.ContainsKey(skillBase)) |
| | | { |
| | | if (availableSubTracks != null) |
| | | availableSubTracks.Enqueue(subSkillTrackMap[skillBase]); |
| | | subSkillTrackMap.Remove(skillBase); |
| | | } |
| | | |
| | | if (activeSkillTracks.Count == 0) |
| | | playingSkillAnim = false; |
| | | return; |
| | |
| | | RemoveAction(frameHandler); |
| | | if (activeSkillTracks.ContainsKey(trackIndex)) |
| | | activeSkillTracks.Remove(trackIndex); |
| | | |
| | | // 回收子技能轨道 |
| | | if (isSubSkill && subSkillTrackMap.ContainsKey(skillBase)) |
| | | { |
| | | if (availableSubTracks != null) |
| | | availableSubTracks.Enqueue(subSkillTrackMap[skillBase]); |
| | | subSkillTrackMap.Remove(skillBase); |
| | | } |
| | | |
| | | if (activeSkillTracks.Count == 0) |
| | | playingSkillAnim = false; |
| | | return; |
| | |
| | | { |
| | | if (activeSkillTracks[trackIndex] == skillTrack) |
| | | activeSkillTracks.Remove(trackIndex); |
| | | } |
| | | |
| | | // 回收子技能轨道 |
| | | if (isSubSkill && subSkillTrackMap.ContainsKey(skillBase)) |
| | | { |
| | | if (availableSubTracks != null) |
| | | availableSubTracks.Enqueue(subSkillTrackMap[skillBase]); |
| | | subSkillTrackMap.Remove(skillBase); |
| | | } |
| | | |
| | | // 只有当没有其他活跃技能时才复位 playingSkillAnim |
| | |
| | | trackEntryCallbacks.Clear(); |
| | | runningActions.Clear(); |
| | | activeSkillTracks.Clear(); |
| | | |
| | | // 重置子技能轨道池 |
| | | if (availableSubTracks == null) |
| | | availableSubTracks = new Queue<int>(); |
| | | else |
| | | availableSubTracks.Clear(); |
| | | |
| | | subSkillTrackMap.Clear(); |
| | | for (int i = 1; i <= 8; i++) |
| | | availableSubTracks.Enqueue(i); |
| | | |
| | | playingSkillAnim = false; |
| | | PlayAnimation(MotionName.idle, true); |
| | | } |