diff --git a/Assets/_Game/Scripts/Editor/Enemies/BossSkillSequenceWindow.cs b/Assets/_Game/Scripts/Editor/Enemies/BossSkillSequenceWindow.cs
deleted file mode 100644
index 70b5fe72..00000000
--- a/Assets/_Game/Scripts/Editor/Enemies/BossSkillSequenceWindow.cs
+++ /dev/null
@@ -1,306 +0,0 @@
-using System.Collections.Generic;
-using UnityEditor;
-using UnityEngine;
-using BaseGames.Boss;
-
-namespace BaseGames.Editor
-{
- ///
- /// Boss 技能序列甘特图可视化窗口(架构 23_BossSkillModule §12)。
- /// 菜单:BaseGames/Tools/Boss Skill Sequence Viewer
- ///
- /// 功能:
- /// - 拖放 BossSkillSO 或 SkillSequenceSO 资产加载
- /// - 甘特图:Windup(黄色)→ Active(红色)→ Recovery(灰色)各阶段时序条
- /// - VulnerabilityWindow 绿色覆盖层(TriggerDelay 偏移 + Duration 宽度)
- /// - DurationNormalized < 0.1 时阶段条变红警告
- /// - 点击阶段条高亮对应 AttackPatternSO(EditorGUIUtility.PingObject)
- ///
- public class BossSkillSequenceWindow : EditorWindow
- {
- // ── State ──────────────────────────────────────────────────────────
- private BossSkillSO _loadedSkill;
- private SkillSequenceSO _loadedSequence;
- private Vector2 _scrollPos;
-
- // ── Layout ─────────────────────────────────────────────────────────
- private const float HeaderH = 24f;
- private const float RowH = 28f;
- private const float LabelW = 180f;
- private const float MinBarWidth = 6f;
- // 时间轴宽度随窗口宽度动态调整,最小 300px
- private float TimelineW => Mathf.Max(300f, position.width - LabelW - 30f);
-
- // ── Colors ─────────────────────────────────────────────────────────
- private static readonly Color ColWindup = new Color(0.95f, 0.80f, 0.10f, 0.85f);
- private static readonly Color ColActive = new Color(0.90f, 0.20f, 0.15f, 0.85f);
- private static readonly Color ColRecovery = new Color(0.50f, 0.50f, 0.55f, 0.70f);
- private static readonly Color ColVuln = new Color(0.10f, 0.90f, 0.30f, 0.45f);
- private static readonly Color ColDelay = new Color(0.25f, 0.25f, 0.30f, 0.50f);
- private static readonly Color ColWarn = new Color(0.95f, 0.10f, 0.10f, 0.85f);
-
- [MenuItem("BaseGames/Data/Boss Skill Sequence", priority = 110)]
- public static void OpenWindow()
- {
- var win = GetWindow("Boss Skill Sequence");
- win.minSize = new Vector2(900, 400);
- win.Show();
- }
-
- // ── GUI ────────────────────────────────────────────────────────────
-
- private void OnGUI()
- {
- DrawToolbar();
-
- if (_loadedSkill == null && _loadedSequence == null)
- {
- EditorGUILayout.HelpBox(
- "将 BossSkillSO 或 SkillSequenceSO 资产拖放到此处,或使用上方字段加载。",
- MessageType.Info);
- HandleDragDrop();
- return;
- }
-
- _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos);
-
- if (_loadedSkill != null)
- DrawSkillTimeline(_loadedSkill);
- else if (_loadedSequence != null)
- DrawSequenceTimeline(_loadedSequence);
-
- EditorGUILayout.EndScrollView();
- }
-
- // ── Toolbar ───────────────────────────────────────────────────────
-
- private void DrawToolbar()
- {
- EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
-
- EditorGUILayout.LabelField("技能:", GUILayout.Width(36));
- var newSkill = (BossSkillSO)EditorGUILayout.ObjectField(
- _loadedSkill, typeof(BossSkillSO), false, GUILayout.Width(200));
- if (newSkill != _loadedSkill)
- {
- _loadedSkill = newSkill;
- _loadedSequence = null;
- }
-
- GUILayout.Space(12);
- EditorGUILayout.LabelField("序列:", GUILayout.Width(36));
- var newSeq = (SkillSequenceSO)EditorGUILayout.ObjectField(
- _loadedSequence, typeof(SkillSequenceSO), false, GUILayout.Width(200));
- if (newSeq != _loadedSequence)
- {
- _loadedSequence = newSeq;
- _loadedSkill = null;
- }
-
- GUILayout.FlexibleSpace();
-
- if (GUILayout.Button("清除", EditorStyles.toolbarButton, GUILayout.Width(50)))
- {
- _loadedSkill = null;
- _loadedSequence = null;
- }
-
- EditorGUILayout.EndHorizontal();
- }
-
- // ── BossSkillSO 时间轴 ────────────────────────────────────────────
-
- private void DrawSkillTimeline(BossSkillSO skill)
- {
- EditorGUILayout.LabelField($"技能:{skill.displayName} [{skill.skillId}]",
- EditorStyles.boldLabel);
- EditorGUILayout.Space(4);
-
- if (skill.attackPatterns == null || skill.attackPatterns.Length == 0)
- {
- EditorGUILayout.HelpBox("此技能没有 AttackPattern。", MessageType.Warning);
- return;
- }
-
- // 计算总时长
- float totalDuration = 0f;
- foreach (var p in skill.attackPatterns)
- if (p != null) totalDuration += p.WindupDuration + p.ActiveDuration + p.RecoveryDuration;
-
- if (totalDuration <= 0f) totalDuration = 1f;
-
- DrawTimelineHeader(totalDuration);
-
- float cursor = 0f;
- for (int i = 0; i < skill.attackPatterns.Length; i++)
- {
- var pattern = skill.attackPatterns[i];
- if (pattern == null) continue;
- DrawPatternRow($"[{i}] {pattern.name}", pattern, ref cursor, totalDuration);
- }
-
- // 绘制 VulnerabilityWindows
- if (skill.vulnerabilityWindows != null && skill.vulnerabilityWindows.Length > 0)
- {
- EditorGUILayout.Space(4);
- EditorGUILayout.LabelField("弱点窗口(Vulnerability Windows)", EditorStyles.miniBoldLabel);
- foreach (var vw in skill.vulnerabilityWindows)
- DrawVulnWindowRow(vw, totalDuration);
- }
- }
-
- // ── SkillSequenceSO 时间轴 ────────────────────────────────────────
-
- private void DrawSequenceTimeline(SkillSequenceSO sequence)
- {
- EditorGUILayout.LabelField($"序列:{sequence.name}", EditorStyles.boldLabel);
- EditorGUILayout.Space(4);
-
- if (sequence.steps == null || sequence.steps.Length == 0)
- {
- EditorGUILayout.HelpBox("此序列没有步骤。", MessageType.Warning);
- return;
- }
-
- // 计算总时长
- float totalDuration = 0f;
- foreach (var step in sequence.steps)
- {
- totalDuration += step.delayBeforeStep;
- if (step.pattern != null)
- totalDuration += step.pattern.WindupDuration + step.pattern.ActiveDuration + step.pattern.RecoveryDuration;
- }
- if (totalDuration <= 0f) totalDuration = 1f;
-
- DrawTimelineHeader(totalDuration);
-
- float cursor = 0f;
- for (int i = 0; i < sequence.steps.Length; i++)
- {
- var step = sequence.steps[i];
-
- // 延迟条
- if (step.delayBeforeStep > 0f)
- {
- DrawBar($"延迟 {step.delayBeforeStep:F2}s", cursor, step.delayBeforeStep,
- totalDuration, ColDelay, null);
- cursor += step.delayBeforeStep;
- }
-
- if (step.pattern != null)
- DrawPatternRow($"[{i}] {step.pattern.name}", step.pattern, ref cursor, totalDuration);
- }
- }
-
- // ── 共用绘制方法 ──────────────────────────────────────────────────
-
- private void DrawTimelineHeader(float totalDuration)
- {
- Rect headerRect = EditorGUILayout.GetControlRect(false, HeaderH);
- headerRect.x += LabelW;
- headerRect.width -= LabelW;
-
- EditorGUI.DrawRect(headerRect, new Color(0.18f, 0.18f, 0.20f));
-
- // 刻度线(每 0.5s 一条)
- float step = 0.5f;
- for (float t = 0; t <= totalDuration + 0.001f; t += step)
- {
- float x = headerRect.x + (t / totalDuration) * headerRect.width;
- EditorGUI.DrawRect(new Rect(x, headerRect.y, 1f, HeaderH * 0.6f), Color.gray);
- EditorGUI.LabelField(new Rect(x + 2f, headerRect.y, 40f, HeaderH),
- $"{t:F1}s", new GUIStyle(EditorStyles.miniLabel) { normal = { textColor = Color.gray } });
- }
- }
-
- private void DrawPatternRow(string label, AttackPatternSO pattern, ref float cursor, float totalDuration)
- {
- float windupDur = pattern.WindupDuration;
- float activeDur = pattern.ActiveDuration;
- float recoveryDur = pattern.RecoveryDuration;
-
- float rowStart = cursor;
- EditorGUILayout.BeginHorizontal(GUILayout.Height(RowH));
-
- // 标签 + Ping
- if (GUILayout.Button(label, EditorStyles.miniLabel, GUILayout.Width(LabelW), GUILayout.Height(RowH)))
- EditorGUIUtility.PingObject(pattern);
-
- Rect timelineRect = EditorGUILayout.GetControlRect(false, RowH,
- GUILayout.Width(TimelineW));
-
- // Windup
- if (windupDur > 0f)
- DrawBarInRect(timelineRect, cursor, windupDur, totalDuration,
- windupDur / (windupDur + activeDur + recoveryDur) < 0.1f ? ColWarn : ColWindup);
- cursor += windupDur;
-
- // Active
- if (activeDur > 0f)
- DrawBarInRect(timelineRect, cursor, activeDur, totalDuration,
- activeDur / (windupDur + activeDur + recoveryDur) < 0.1f ? ColWarn : ColActive);
- cursor += activeDur;
-
- // Recovery
- if (recoveryDur > 0f)
- DrawBarInRect(timelineRect, cursor, recoveryDur, totalDuration,
- recoveryDur / (windupDur + activeDur + recoveryDur) < 0.1f ? ColWarn : ColRecovery);
- cursor += recoveryDur;
-
- _ = rowStart; // suppress unused warning
- EditorGUILayout.EndHorizontal();
- }
-
- private void DrawVulnWindowRow(VulnerabilityWindow vw, float totalDuration)
- {
- string label = $"弱点:{vw.TriggerType} +{vw.TriggerDelay:F2}s / {vw.Duration:F2}s";
- DrawBar(label, vw.TriggerDelay, vw.Duration, totalDuration, ColVuln, null);
- }
-
- private void DrawBar(string label, float start, float duration, float totalDuration,
- Color color, AttackPatternSO pingTarget)
- {
- EditorGUILayout.BeginHorizontal(GUILayout.Height(RowH));
-
- if (GUILayout.Button(label, EditorStyles.miniLabel, GUILayout.Width(LabelW), GUILayout.Height(RowH)))
- {
- if (pingTarget != null) EditorGUIUtility.PingObject(pingTarget);
- }
-
- Rect timelineRect = EditorGUILayout.GetControlRect(false, RowH, GUILayout.Width(TimelineW));
- DrawBarInRect(timelineRect, start, duration, totalDuration, color);
-
- EditorGUILayout.EndHorizontal();
- }
-
- private static void DrawBarInRect(Rect timeline, float start, float duration,
- float totalDuration, Color color)
- {
- float x = timeline.x + (start / totalDuration) * timeline.width;
- float w = Mathf.Max(MinBarWidth, (duration / totalDuration) * timeline.width);
- EditorGUI.DrawRect(new Rect(x, timeline.y + 2f, w, timeline.height - 4f), color);
- }
-
- // ── Drag & Drop ───────────────────────────────────────────────────
-
- private void HandleDragDrop()
- {
- var evt = Event.current;
- if (evt.type != EventType.DragUpdated && evt.type != EventType.DragPerform) return;
-
- DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
-
- if (evt.type == EventType.DragPerform)
- {
- DragAndDrop.AcceptDrag();
- foreach (var obj in DragAndDrop.objectReferences)
- {
- if (obj is BossSkillSO skill) { _loadedSkill = skill; _loadedSequence = null; break; }
- if (obj is SkillSequenceSO seq) { _loadedSequence = seq; _loadedSkill = null; break; }
- }
- Repaint();
- }
- evt.Use();
- }
- }
-}
diff --git a/Assets/_Game/Scripts/Editor/Enemies/BossSkillSequenceWindow.cs.meta b/Assets/_Game/Scripts/Editor/Enemies/BossSkillSequenceWindow.cs.meta
deleted file mode 100644
index 397db5f6..00000000
--- a/Assets/_Game/Scripts/Editor/Enemies/BossSkillSequenceWindow.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: d47145d394333184eb3ff822e3c4aa4d
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/_Game/Scripts/Editor/Modules/BossSkillModule.cs b/Assets/_Game/Scripts/Editor/Modules/BossSkillModule.cs
deleted file mode 100644
index efca1016..00000000
--- a/Assets/_Game/Scripts/Editor/Modules/BossSkillModule.cs
+++ /dev/null
@@ -1,209 +0,0 @@
-using System;
-using UnityEditor;
-using UnityEditor.UIElements;
-using UnityEngine;
-using UnityEngine.UIElements;
-using BaseGames.Boss;
-
-namespace BaseGames.Editor.Modules
-{
- ///
- /// DataHub Boss技能模块 —— Tab 切换管理 BossSkillSO 和 SkillSequenceSO。
- ///
- public class BossSkillModule : IDataModule, IDataModuleOrdered
- {
- private const string SkillFolder = "Assets/_Game/Data/Boss/Skills";
- private const string SeqFolder = "Assets/_Game/Data/Boss/Sequences";
-
- public string ModuleId => "boss";
- public string DisplayName => "Boss技能";
- public string IconName => null;
- public int DisplayOrder => 50;
-
- private int _activeTab = 0;
-
- private SoListPane _skillPane;
- private SoListPane _seqPane;
- private Action _onSelected;
-
- private DetailHeader _header;
- private BossSkillSO _selectedSkill;
- private SkillSequenceSO _selectedSeq;
-
- public void Initialize()
- {
- _skillPane = new SoListPane(
- SkillFolder, "ABL_Boss_",
- s => s.category.ToString());
- _skillPane.SelectionChanged = s => { _selectedSkill = s; _onSelected?.Invoke(s); };
-
- _seqPane = new SoListPane(SeqFolder, "ABL_Seq_");
- _seqPane.SelectionChanged = s => { _selectedSeq = s; _onSelected?.Invoke(s); };
- }
-
- public void BuildListPane(VisualElement container, Action onSelected)
- {
- _onSelected = onSelected;
- container.style.flexDirection = FlexDirection.Column;
-
- // Tab bar
- var tabBar = new VisualElement();
- tabBar.style.flexDirection = FlexDirection.Row;
- tabBar.style.borderBottomWidth = 1;
- tabBar.style.borderBottomColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.3f));
- container.Add(tabBar);
-
- var btnSkill = BuildTabBtn("技能 (Skill)", 0, tabBar);
- var btnSeq = BuildTabBtn("序列 (Seq)", 1, tabBar);
-
- var listArea = new VisualElement();
- listArea.style.flexGrow = 1;
- container.Add(listArea);
-
- ShowTab(0, listArea, new[] { btnSkill, btnSeq });
- btnSkill.clicked += () => ShowTab(0, listArea, new[] { btnSkill, btnSeq });
- btnSeq.clicked += () => ShowTab(1, listArea, new[] { btnSkill, btnSeq });
-
- _skillPane.Refresh();
- _seqPane.Refresh();
- }
-
- public void BuildDetailPane(VisualElement container, UnityEngine.Object selected)
- {
- _header = new DetailHeader();
- _header.SetAsset(selected);
- _header.RenameRequested += name => OnRenameRequested(selected, name);
- container.Add(_header);
-
- if (selected == null) return;
-
- if (selected is BossSkillSO skill)
- {
- container.Add(BuildSkillCard(skill));
- container.Add(BuildActionBar(skill, SkillFolder, _skillPane));
- container.Add(SkillModule.MakeDivider());
- var insp = new InspectorElement(skill); container.Add(insp);
- }
- else if (selected is SkillSequenceSO seq)
- {
- container.Add(BuildSeqCard(seq));
- container.Add(BuildActionBar(seq, SeqFolder, _seqPane));
- container.Add(SkillModule.MakeDivider());
- var insp = new InspectorElement(seq); container.Add(insp);
- }
- }
-
- public void OnActivated()
- {
- _skillPane?.Refresh();
- _seqPane?.Refresh();
- }
-
- // ── 内部 ─────────────────────────────────────────────────────────────
-
- private Button BuildTabBtn(string text, int tabIdx, VisualElement bar)
- {
- var btn = new Button { text = text };
- btn.style.flexGrow = 1;
- btn.style.paddingTop = 5;
- btn.style.paddingBottom = 5;
- btn.style.borderTopLeftRadius = 0;
- btn.style.borderTopRightRadius = 0;
- btn.style.borderBottomLeftRadius = 0;
- btn.style.borderBottomRightRadius = 0;
- btn.style.borderLeftWidth = 0;
- btn.style.borderRightWidth = 0;
- btn.style.borderTopWidth = 0;
- btn.style.borderBottomWidth = 0;
- btn.style.backgroundColor = new StyleColor(Color.clear);
- btn.userData = tabIdx;
- bar.Add(btn);
- return btn;
- }
-
- private void ShowTab(int tab, VisualElement area, Button[] tabBtns)
- {
- _activeTab = tab;
- area.Clear();
-
- for (int i = 0; i < tabBtns.Length; i++)
- {
- if (i == tab)
- {
- tabBtns[i].style.borderBottomWidth = 2;
- tabBtns[i].style.borderBottomColor = new StyleColor(new Color(0.4f, 0.65f, 1f, 1f));
- tabBtns[i].style.opacity = 1f;
- }
- else
- {
- tabBtns[i].style.borderBottomWidth = 0;
- tabBtns[i].style.opacity = 0.65f;
- }
- }
-
- if (tab == 0) { _skillPane.style.flexGrow = 1; area.Add(_skillPane); }
- else { _seqPane.style.flexGrow = 1; area.Add(_seqPane); }
- }
-
- private void OnRenameRequested(UnityEngine.Object asset, string newName)
- {
- var (ok, err) = AssetOperations.Rename(asset, newName);
- if (!ok) EditorUtility.DisplayDialog("重命名失败", err, "确定");
- else
- {
- _header.SetAsset(asset);
- if (_activeTab == 0) _skillPane.Invalidate();
- else _seqPane.Invalidate();
- }
- }
-
- private static VisualElement BuildSkillCard(BossSkillSO s)
- {
- var card = SkillModule.MakeCard();
- SkillModule.AddChip(card, "分类", s.category.ToString());
- SkillModule.AddChip(card, "类型", s.skillType.ToString());
- SkillModule.AddChip(card, "模式数", (s.attackPatterns?.Length ?? 0).ToString());
- SkillModule.AddChip(card, "弱点窗口", (s.vulnerabilityWindows?.Length ?? 0).ToString());
- if (!string.IsNullOrEmpty(s.skillId))
- SkillModule.AddChip(card, "ID", s.skillId);
- return card;
- }
-
- private static VisualElement BuildSeqCard(SkillSequenceSO s)
- {
- var card = SkillModule.MakeCard();
- SkillModule.AddChip(card, "步骤数", (s.steps?.Length ?? 0).ToString());
- SkillModule.AddChip(card, "循环", s.RepeatIfPlayerInRange ? "是" : "否");
- SkillModule.AddChip(card, "最大循环次数", s.MaxRepeatCount.ToString());
- return card;
- }
-
- private VisualElement BuildActionBar(T asset, string folder, SoListPane pane)
- where T : ScriptableObject
- {
- var bar = SkillModule.MakeActionBar();
- new Button(() => { EditorGUIUtility.PingObject(asset); Selection.activeObject = asset; })
- { text = "定位" }.AlsoAddTo(bar);
- new Button(() =>
- {
- var c = AssetOperations.Clone(asset, folder);
- if (c != null) pane.Refresh(c);
- }) { text = "克隆..." }.AlsoAddTo(bar);
- var del = new Button(() =>
- {
- if (AssetOperations.Delete(asset)) pane.Refresh(null);
- }) { text = "删除" };
- del.style.borderLeftColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
- del.style.borderRightColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
- del.style.borderTopColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
- del.style.borderBottomColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
- del.style.borderLeftWidth = 1;
- del.style.borderRightWidth = 1;
- del.style.borderTopWidth = 1;
- del.style.borderBottomWidth = 1;
- del.style.marginLeft = 8;
- del.AlsoAddTo(bar);
- return bar;
- }
- }
-}
diff --git a/Assets/_Game/Scripts/Editor/Modules/BossSkillModule.cs.meta b/Assets/_Game/Scripts/Editor/Modules/BossSkillModule.cs.meta
deleted file mode 100644
index 3f77eaa3..00000000
--- a/Assets/_Game/Scripts/Editor/Modules/BossSkillModule.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: f0d0425e529293e469da3762fe3bf8f0
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/_Game/Scripts/Editor/Shared/EditorScaffoldUtils.cs b/Assets/_Game/Scripts/Editor/Shared/EditorScaffoldUtils.cs
index 7c627512..b380af19 100644
--- a/Assets/_Game/Scripts/Editor/Shared/EditorScaffoldUtils.cs
+++ b/Assets/_Game/Scripts/Editor/Shared/EditorScaffoldUtils.cs
@@ -18,8 +18,6 @@ namespace BaseGames.Editor
{
{ "WeaponSO", ("WPN_", "WPN_{ID},例:WPN_SkyBlade") },
{ "FormSkillSO", ("SKL_", "SKL_{Name},例:SKL_SoulBlade") },
- { "BossSkillSO", ("SKL_", "SKL_{Name},例:SKL_BossRage") },
- { "SkillSequenceSO", ("SKL_", "SKL_Seq_{Name},例:SKL_Seq_RageCombo") },
{ "EnemyStatsSO", ("ENM_", "ENM_E{ID}_Stats,例:ENM_E001_Stats") },
{ "LootTableSO", ("ENM_", "ENM_E{ID}_Loot,例:ENM_E001_Loot") },
{ "FormConfigSO", ("PLY_", "PLY_{FormID},例:PLY_Player01") },
diff --git a/Assets/_Game/Scripts/Enemies/Boss/AttackPatternSO.cs b/Assets/_Game/Scripts/Enemies/Boss/AttackPatternSO.cs
deleted file mode 100644
index ee62b7ab..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/AttackPatternSO.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-using UnityEngine;
-using UnityEngine.AddressableAssets;
-using BaseGames.Combat;
-
-namespace BaseGames.Boss
-{
- ///
- /// 单个攻击图案的数据。伤害参数只写在此处,BossSkillSO 不存参数。
- ///
- [CreateAssetMenu(menuName = "BaseGames/Boss/AttackPattern")]
- public class AttackPatternSO : ScriptableObject
- {
- [Header("输出")]
- public DamageSourceSO DamageSource;
- public float KnockbackAngle;
-
- [Header("弹幕(若为弹幕类型)")]
- public AssetReferenceGameObject ProjectilePrefab;
- public int ProjectileCount = 1;
- public float SpreadAngle = 0f;
- public float ProjectileSpeed = 8f;
-
- [Header("范围攻击(若为 AoE 类型)")]
- public float AoERadius;
- public Vector2 AoEOffset;
-
- [Header("时序")]
- [Min(0f)] public float WindupDuration;
- [Min(0f)] public float ActiveDuration;
- [Min(0f)] public float RecoveryDuration;
- }
-}
diff --git a/Assets/_Game/Scripts/Enemies/Boss/AttackPatternSO.cs.meta b/Assets/_Game/Scripts/Enemies/Boss/AttackPatternSO.cs.meta
deleted file mode 100644
index 6e0a41d7..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/AttackPatternSO.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 81f89b6e2f8f2774ab7cedbe45dcb810
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/_Game/Scripts/Enemies/Boss/BossSkillExecutor.cs b/Assets/_Game/Scripts/Enemies/Boss/BossSkillExecutor.cs
deleted file mode 100644
index 9be6312a..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/BossSkillExecutor.cs
+++ /dev/null
@@ -1,359 +0,0 @@
-using System.Collections;
-using System.Collections.Generic;
-using UnityEngine;
-using Animancer;
-using BaseGames.Combat;
-using BaseGames.Core.Events;
-
-namespace BaseGames.Boss
-{
- ///
- /// 挂在 Boss GameObject 上,接收 BossOrchestrator 的指令执行指定 BossSkillSO。
- /// 管理 VulnerabilityWindow 计时和 WeakPointSystem 激活。
- ///
- public class BossSkillExecutor : MonoBehaviour
- {
- [SerializeField] private HitBox[] _hitBoxes;
- [SerializeField] private WeakPointSystem _weakPointSystem;
- [SerializeField] private AnimancerComponent _animancer;
- [SerializeField] private string _bossId;
- [SerializeField] private BossSkillEventChannelSO _onBossSkillStarted;
- [SerializeField] private BossSkillEventChannelSO _onBossSkillEnded;
- /// PlayerController 无 Instance(架构 05 §2),由 Inspector 指定。
- [SerializeField] private Transform _playerTransform;
-
- [SerializeField] private BossSkillSO[] _skills;
-
- [Header("技能重复检测范围")]
- [Tooltip("SkillSequence RepeatIfPlayerInRange 的检测半径(m)")]
- [SerializeField, Min(1f)] private float _repeatRangeCheck = 8f;
-
- private BossSkillSO _currentSkill;
- private bool _isExecuting;
- private Coroutine _activeCoroutine;
- private Coroutine _vulnCoroutine; // 弱点窗口协程(中断时需同步停止)
- private bool _patternHitConfirmed; // 本次技能执行期间是否有 HitBox 命中
-
- // 技能冷却:skillId → 冷却结束的 Time.time 时刻
- private readonly Dictionary _skillCooldownEndTimes = new();
-
- public bool IsExecuting => _isExecuting;
-
- /// 检查指定技能是否冷却就绪(无冷却记录或已过冷却时间)。
- public bool CanUseSkill(string skillId)
- {
- if (string.IsNullOrEmpty(skillId)) return false;
- if (_skillCooldownEndTimes.TryGetValue(skillId, out float endTime))
- return Time.time >= endTime;
- return true;
- }
-
- /// 强制重置指定技能的冷却(阶段切换、复活等场景使用)。
- public void ResetSkillCooldown(string skillId)
- {
- _skillCooldownEndTimes.Remove(skillId);
- }
-
- /// 重置所有技能冷却。
- public void ResetAllCooldowns() => _skillCooldownEndTimes.Clear();
-
- private void Awake()
- {
-#if UNITY_EDITOR
- ValidateSkillConfig();
-#endif
- }
-
-#if UNITY_EDITOR
- private void OnValidate() => ValidateSkillConfig();
-
- private void ValidateSkillConfig()
- {
- if (_skills == null || _skills.Length == 0)
- {
- Debug.LogError($"[BossSkillExecutor] Boss '{_bossId}' ({gameObject.name}) 未配置任何技能 SO。", this);
- return;
- }
- foreach (var skill in _skills)
- {
- if (skill == null)
- Debug.LogError($"[BossSkillExecutor] Boss '{_bossId}' ({gameObject.name}) _skills 数组含 null 元素。", this);
- else if (string.IsNullOrEmpty(skill.skillId))
- Debug.LogError($"[BossSkillExecutor] Boss '{_bossId}' ({gameObject.name}) 技能 '{skill.name}' 缺少 skillId。", this);
- }
- }
-#endif
-
- ///
- /// 按 float 值复用 WaitForSeconds 实例,消除协程中每次 new WaitForSeconds 的 GC 分配。
- /// Domain Reload 禁用时静态缓存跨 PlayMode 会话保留,但 WaitForSeconds 是幂等值对象,
- /// 不会引发功能错误;[RuntimeInitializeOnLoadMethod] 确保每次进入 Play 时清空。
- ///
- private static readonly Dictionary _wfsCache = new();
-
- [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
- private static void ClearWFSCache() => _wfsCache.Clear();
-
- private const int MaxWFSCacheSize = 64;
-
- private static WaitForSeconds GetWFS(float t)
- {
- if (!_wfsCache.TryGetValue(t, out var wfs))
- {
- if (_wfsCache.Count < MaxWFSCacheSize)
- _wfsCache[t] = wfs = new WaitForSeconds(t);
- else
- return new WaitForSeconds(t);
- }
- return wfs;
- }
-
- // ── 公共 API ───────────────────────────────────────────────────────────
-
- ///
- /// 按 skillId 查找已在 Inspector 注册的技能 SO。未找到返回 null。
- ///
- public BossSkillSO FindSkill(string skillId)
- {
- if (_skills == null) return null;
- foreach (var s in _skills)
- if (s != null && s.skillId == skillId) return s;
- return null;
- }
-
- /// 返回当前正在执行的技能 SO,未执行时返回 null。
- public BossSkillSO FindCurrentSkill() => _isExecuting ? _currentSkill : null;
-
- /// Inspector 中注册的全部技能 SO(只读)。
- public BossSkillSO[] Skills => _skills;
-
- ///
- /// 执行一个 Boss 技能。若当前正在执行或技能冷却未就绪则返回。
- ///
- public void ExecuteSkill(BossSkillSO skill)
- {
- if (_isExecuting || skill == null) return;
- if (!CanUseSkill(skill.skillId))
- {
- Debug.Log($"[BossSkillExecutor] 技能 '{skill.skillId}' 冷却中,无法执行。", this);
- return;
- }
- // 提前订阅,确保 InterruptCurrentSkill() 中断时 FinishExecution() 能正常取消
- SubscribeHitCallbacks();
- _activeCoroutine = StartCoroutine(ExecuteSkillCoroutine(skill));
- }
-
- ///
- /// 立即打断正在执行的技能(阶段切换时调用)。
- ///
- public void InterruptCurrentSkill()
- {
- // 同步停止弱点窗口协程,防止中断后继续激活 WeakPointSystem
- if (_vulnCoroutine != null)
- {
- StopCoroutine(_vulnCoroutine);
- _vulnCoroutine = null;
- }
- if (_activeCoroutine != null)
- {
- StopCoroutine(_activeCoroutine);
- _activeCoroutine = null;
- }
- FinishExecution();
- }
-
- // 等待事件触发的 VulnWindow(事件驱动类型,存储后由 NotifyVulnTrigger 逐个激活)
- private readonly List _pendingEventWindows = new();
-
- ///
- /// 通知执行器某一外部事件已发生(如格挡成功、反制命中等),
- /// 激活所有注册该触发类型的弱点窗口。
- /// 由 BossBase.HandleParrySuccess / ApplyCounterResponse 等调用。
- ///
- public void NotifyVulnTrigger(VulnTriggerType triggerType)
- {
- for (int i = _pendingEventWindows.Count - 1; i >= 0; i--)
- {
- var w = _pendingEventWindows[i];
- if (w.TriggerType == triggerType)
- {
- _pendingEventWindows.RemoveAt(i);
- StartCoroutine(OpenWindowCoroutine(w));
- }
- }
- }
-
- private void OnHitConfirmedCallback(DamageInfo _) => _patternHitConfirmed = true;
-
- private void SubscribeHitCallbacks()
- {
- if (_hitBoxes == null) return;
- foreach (var hb in _hitBoxes) if (hb != null) hb.OnHitConfirmed += OnHitConfirmedCallback;
- }
-
- private void UnsubscribeHitCallbacks()
- {
- if (_hitBoxes == null) return;
- foreach (var hb in _hitBoxes) if (hb != null) hb.OnHitConfirmed -= OnHitConfirmedCallback;
- }
-
- private IEnumerator ExecuteSkillCoroutine(BossSkillSO skill)
- {
- _isExecuting = true;
- _currentSkill = skill;
- _patternHitConfirmed = false;
-
- // HitBox 订阅已在 ExecuteSkill() 入口完成(确保 Interrupt 中断时能在 FinishExecution 取消)
-
- _onBossSkillStarted?.Raise(new BossSkillEvent { BossId = _bossId, SkillId = skill.skillId });
-
- // 播放技能动画
- if (skill.skillAnimation != null)
- _animancer.Play(skill.skillAnimation);
-
- // 启动 VulnerabilityWindow 协程(与主序列并行)
- _vulnCoroutine = null;
- if (skill.vulnerabilityWindows != null && skill.vulnerabilityWindows.Length > 0)
- _vulnCoroutine = StartCoroutine(ActivateVulnerabilityWindowsCoroutine(skill));
-
- // 执行主攻击序列(始终执行 sequenceOnMiss;sequenceOnHit 是命中后的追加序列)
- if (skill.sequenceOnMiss != null)
- yield return ExecuteSequenceCoroutine(skill.sequenceOnMiss);
-
- // 若本次有命中确认且配置了 sequenceOnHit,执行追加序列(连段、击倒追击等)
- if (_patternHitConfirmed && skill.sequenceOnHit != null)
- yield return ExecuteSequenceCoroutine(skill.sequenceOnHit);
-
- // 若弱点协程还在运行则等待其结束(避免孤立协程)
- if (_vulnCoroutine != null)
- yield return _vulnCoroutine;
-
- FinishExecution();
- }
-
- private void FinishExecution()
- {
- UnsubscribeHitCallbacks(); // 无论正常结束还是被 Interrupt,均在此取消订阅
- _pendingEventWindows.Clear(); // 清除未触发的事件驱动弱点窗口,防止跨技能积压
- _vulnCoroutine = null; // 正常结束时已自然结束,仅清除引用
- _isExecuting = false;
- if (_currentSkill != null)
- {
- // 记录冷却结束时刻
- if (_currentSkill.cooldown > 0f)
- _skillCooldownEndTimes[_currentSkill.skillId] = Time.time + _currentSkill.cooldown;
-
- _onBossSkillEnded?.Raise(new BossSkillEvent { BossId = _bossId, SkillId = _currentSkill.skillId });
- _currentSkill = null;
- }
- }
-
- // ── 序列协程 ────────────────────────────────────────────────────────────
-
- private IEnumerator ExecuteSequenceCoroutine(SkillSequenceSO seq)
- {
- int repeatCount = 0;
- do
- {
- foreach (var step in seq.steps)
- {
- if (step.delayBeforeStep > 0f)
- yield return GetWFS(step.delayBeforeStep);
-
- if (step.pattern != null)
- yield return ExecutePatternCoroutine(step.pattern);
- }
-
- repeatCount++;
-
- if (seq.RepeatIfPlayerInRange && seq.RepeatDelay > 0f)
- yield return GetWFS(seq.RepeatDelay);
- }
- while (seq.RepeatIfPlayerInRange
- && (seq.MaxRepeatCount == 0 || repeatCount < seq.MaxRepeatCount)
- && IsPlayerInRange());
- }
-
- private IEnumerator ExecutePatternCoroutine(AttackPatternSO pattern)
- {
- // 预备
- if (pattern.WindupDuration > 0f)
- yield return GetWFS(pattern.WindupDuration);
-
- // 激活 HitBox(架构 06 §4:Activate(DamageSourceSO, Transform))
- if (_hitBoxes != null && _hitBoxes.Length > 0)
- foreach (var hb in _hitBoxes)
- if (hb != null) hb.Activate(pattern.DamageSource, transform);
-
- if (pattern.ActiveDuration > 0f)
- yield return GetWFS(pattern.ActiveDuration);
-
- // 关闭 HitBox
- if (_hitBoxes != null && _hitBoxes.Length > 0)
- foreach (var hb in _hitBoxes)
- if (hb != null) hb.Deactivate();
-
- // 后摇
- if (pattern.RecoveryDuration > 0f)
- yield return GetWFS(pattern.RecoveryDuration);
- }
-
- // ── VulnerabilityWindow 协程 ─────────────────────────────────────────────
-
- private IEnumerator ActivateVulnerabilityWindowsCoroutine(BossSkillSO skill)
- {
- _pendingEventWindows.Clear();
-
- foreach (var window in skill.vulnerabilityWindows)
- {
- if (window.TriggerType == VulnTriggerType.OnAttackRecovery)
- {
- // 时间驱动:按 TriggerDelay 延迟后自动激活
- if (window.TriggerDelay > 0f)
- yield return GetWFS(window.TriggerDelay);
- StartCoroutine(OpenWindowCoroutine(window));
- }
- else
- {
- // 事件驱动(OnParriedSuccess / Manual 等):注册到待触发列表
- _pendingEventWindows.Add(window);
- }
- }
- }
-
- /// 实际开启并持续弱点窗口,支持独立并行运行。
- private IEnumerator OpenWindowCoroutine(VulnerabilityWindow window)
- {
- bool activateSpecific = window.ActivateWeakPointHurtBox;
- _weakPointSystem?.SetActive(true, window.DamageMultiplier, activateSpecific);
- window.OpenFeedback?.Play();
-
- yield return GetWFS(window.Duration);
-
- _weakPointSystem?.SetActive(false, 1f, activateSpecific);
- window.CloseFeedback?.Play();
- }
-
- // ── 工具 ───────────────────────────────────────────────────────────────
-
- ///
- /// 在指定时长内开启弱点窗口(格挡/闪避反制时调用,独立于技能 VulnerabilityWindow 序列)。
- ///
- public void OpenVulnerabilityWindow(float duration, float damageMultiplier)
- {
- if (_weakPointSystem == null || duration <= 0f) return;
- StartCoroutine(VulnWindowOverride(duration, damageMultiplier));
- }
-
- private IEnumerator VulnWindowOverride(float duration, float multiplier)
- {
- _weakPointSystem.SetActive(true, multiplier, false);
- yield return GetWFS(duration);
- _weakPointSystem.SetActive(false, 1f, false);
- }
-
- private bool IsPlayerInRange() =>
- _playerTransform != null &&
- Vector2.Distance(transform.position, _playerTransform.position) < _repeatRangeCheck;
- }
-}
diff --git a/Assets/_Game/Scripts/Enemies/Boss/BossSkillExecutor.cs.meta b/Assets/_Game/Scripts/Enemies/Boss/BossSkillExecutor.cs.meta
deleted file mode 100644
index cce54276..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/BossSkillExecutor.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 4dfa1c525eaca5640b3cfe945626a466
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/_Game/Scripts/Enemies/Boss/BossSkillSO.cs b/Assets/_Game/Scripts/Enemies/Boss/BossSkillSO.cs
deleted file mode 100644
index 4c67271b..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/BossSkillSO.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using System;
-using UnityEngine;
-using Animancer;
-using BaseGames.Combat;
-
-namespace BaseGames.Boss
-{
- ///
- /// Boss 单个技能的所有数据,包括攻击模式、弱点窗口、互动标签等。
- ///
- [CreateAssetMenu(menuName = "BaseGames/Boss/BossSkill")]
- public class BossSkillSO : ScriptableObject
- {
- [Header("元信息")]
- [Tooltip("技能唯一标识符(全小写英文 + 下划线,如 'slash_combo'、'phase_dash')。BD_UseBossSkill 通过此 Id 引用")]
- public string skillId;
- [Tooltip("编辑器中显示的可读名称,不影响运行逻辑")]
- public string displayName;
- [TextArea(1, 4)]
- [Tooltip("设计备注(仅供编辑器参考,不影响运行)")]
- public string designNote;
-
- [Header("技能分类")]
- public BossSkillCategory category;
- public BossSkillType skillType;
-
- [Header("阶段可用性")]
- [Tooltip("空数组 = 全阶段可用")]
- public int[] availablePhaseIndices;
-
- [Header("核心攻击动作引用")]
- public AttackPatternSO[] attackPatterns;
-
- [Header("弱点窗口(至少 1 个)")]
- public VulnerabilityWindow[] vulnerabilityWindows;
-
- [Header("互动标签")]
- public InteractionTag interactionTags;
-
- [Header("连段")]
- public SkillSequenceSO sequenceOnHit;
- public SkillSequenceSO sequenceOnMiss;
-
- [Header("玩家反制接口")]
- public PlayerCounterResponse[] counterResponses;
-
- [Header("场景联动")]
- public ArenaEventTrigger[] arenaEvents;
-
- [Header("Boss 资源")]
- public BossResourceCost resourceCost;
- public bool buildsRage;
-
- [Header("霸体配置")]
- public PoiseWindowConfig poiseWindow;
-
- [Header("动画")]
- public ClipTransition skillAnimation;
-
- [Header("冷却")]
- [Min(0f)]
- public float cooldown;
-
- [Header("权重随机(UseBossSkillWeighted 使用)")]
- [Tooltip("相对权重,数值越大被随机选中的概率越高;0 = 禁用随机选择")]
- [Min(0f)]
- public float weight = 1f;
- }
-}
diff --git a/Assets/_Game/Scripts/Enemies/Boss/BossSkillSO.cs.meta b/Assets/_Game/Scripts/Enemies/Boss/BossSkillSO.cs.meta
deleted file mode 100644
index aaceeee8..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/BossSkillSO.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: de92221c7c3fb4a42a7cd122a8f97632
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/_Game/Scripts/Enemies/Boss/BossSkillTypes.cs b/Assets/_Game/Scripts/Enemies/Boss/BossSkillTypes.cs
deleted file mode 100644
index a612f79a..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/BossSkillTypes.cs
+++ /dev/null
@@ -1,184 +0,0 @@
-using System;
-using UnityEngine;
-using BaseGames.Feedback;
-
-namespace BaseGames.Boss
-{
- // ── 分类枚举 ───────────────────────────────────────────────────────────────
-
- public enum BossSkillCategory
- {
- Melee, Ranged, Charge, AoE, Environmental, Summon,
- Buff, Debuff, Phase, Passive, Reactive
- }
-
- public enum BossSkillType
- {
- MeleeSlash,
- ChargeAttack,
- LeapSlam,
- ProjectileVolley,
- LaserBeam,
- PhaseTransition,
- SummonMinion,
- ArenaTrap,
- SpeedBurst,
- DefensiveShell,
- }
-
- [Flags]
- public enum InteractionTag
- {
- None = 0,
- Parryable = 1 << 0,
- PerfectParryOnly = 1 << 1,
- DodgeWindow = 1 << 2,
- Unblockable = 1 << 3,
- CanBeReflected = 1 << 4,
- ExposesWeakPoint = 1 << 5,
- GrantsPlayerReso = 1 << 6,
- ArenaHazard = 1 << 7,
- PhaseGate = 1 << 8,
- }
-
- // ── VulnerabilityWindow ────────────────────────────────────────────────────
-
- public enum VulnTriggerType
- {
- OnAttackRecovery,
- OnParriedSuccess,
- OnCounterSkillHit,
- OnPhaseTransition,
- OnHazardBackfire,
- OnSummonDefeated,
- Manual,
- }
-
- public enum WeakPointType
- {
- FullBody,
- HeadOnly,
- BackOnly,
- CoreExposed,
- CustomPoint,
- }
-
- [Serializable]
- public struct VulnerabilityWindow
- {
- [Tooltip("弱点触发方式")]
- public VulnTriggerType TriggerType;
-
- [Tooltip("触发后延迟出现(秒)")]
- [Min(0f)]
- public float TriggerDelay;
-
- [Tooltip("弱点持续时长(秒)")]
- [Min(0.1f)]
- public float Duration;
-
- public WeakPointType WeakPointType;
-
- [Tooltip("弱点激活时 Boss 受击乘数")]
- [Min(0.1f)]
- public float DamageMultiplier;
-
- public bool ForceStagger;
-
- [Min(0f)]
- public float StaggerDuration;
-
- public SceneFeedback OpenFeedback;
- public SceneFeedback CloseFeedback;
- public Color HighlightColor;
-
- public bool ActivateWeakPointHurtBox => WeakPointType != WeakPointType.FullBody;
- }
-
- // ── PlayerCounterResponse ─────────────────────────────────────────────────
-
- public enum CounterType
- {
- Parry,
- PerfectParry,
- DodgeThrough,
- SpecificSkill,
- WeakPointHit,
- HazardBackfire,
- SummonKill,
- }
-
- [Serializable]
- public struct PlayerCounterResponse
- {
- [Header("反制条件")]
- public CounterType counterType;
- public string requiredSkillId;
-
- [Header("反制效果(对 Boss)")]
- public float bossStaggerDuration;
- public float bossDamageBonus;
- public bool openVulnWindow;
- public bool interruptSkill;
-
- [Header("反制收益(对玩家)")]
- public int soulPowerGrant;
- public int spiritPowerGrant;
- public SceneFeedback counterFeedback;
- }
-
- // ── ArenaEvent ────────────────────────────────────────────────────────────
-
- public enum ArenaEventType
- {
- DestroyPlatform,
- ActivateHazard,
- DeactivateHazard,
- SpawnHazardArea,
- ShakeArena,
- ToggleLighting,
- SpawnPlatform,
- TriggerCutscene,
- }
-
- [Serializable]
- public struct ArenaEventParams
- {
- public float duration;
- public float intensity;
- public bool revertsOnPhaseEnd;
- }
-
- [Serializable]
- public struct ArenaEventTrigger
- {
- public string targetArenaObjectId;
- public ArenaEventType eventType;
- public float delay;
- public ArenaEventParams parameters;
- }
-
- [Serializable]
- public struct ArenaEventData
- {
- public ArenaEventType type;
- public ArenaEventParams parameters;
- public string sourceSkillId;
- }
-
- public interface IArenaInteractable
- {
- string ArenaObjectId { get; }
- void OnBossArenaEvent(ArenaEventData data);
- }
-
- // ── BossResourceCost ──────────────────────────────────────────────────────
-
- [Serializable]
- public struct BossResourceCost
- {
- public string resourceId;
- public float cost;
- public float minRequired;
- }
-}
diff --git a/Assets/_Game/Scripts/Enemies/Boss/BossSkillTypes.cs.meta b/Assets/_Game/Scripts/Enemies/Boss/BossSkillTypes.cs.meta
deleted file mode 100644
index 2f8a3962..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/BossSkillTypes.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: a1beb8f8f7958b84c9ab60abe5f8c4ed
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/_Game/Scripts/Enemies/Boss/ChaoFengKnockdownCounter.cs b/Assets/_Game/Scripts/Enemies/Boss/ChaoFengKnockdownCounter.cs
index 9ed20228..69f9f910 100644
--- a/Assets/_Game/Scripts/Enemies/Boss/ChaoFengKnockdownCounter.cs
+++ b/Assets/_Game/Scripts/Enemies/Boss/ChaoFengKnockdownCounter.cs
@@ -2,6 +2,7 @@ using System.Collections;
using Animancer;
using BaseGames.Boss;
using BaseGames.Combat;
+using BaseGames.Enemies.Abilities;
using UnityEngine;
namespace BaseGames.Enemies.Boss
@@ -79,7 +80,8 @@ namespace BaseGames.Enemies.Boss
{
_inKnockdown = true;
- _boss.GetComponentInChildren()?.InterruptCurrentSkill();
+ // 击落打断当前正在执行的所有能力(招式统一由能力注册表管理)
+ _boss.Abilities.InterruptAll(InterruptReason.ExternalRequest);
if (_knockdownHitClip.Clip != null)
_boss.Animancer.Play(_knockdownHitClip);
diff --git a/Assets/_Game/Scripts/Enemies/Boss/Patterns.meta b/Assets/_Game/Scripts/Enemies/Boss/Patterns.meta
deleted file mode 100644
index a881eff4..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/Patterns.meta
+++ /dev/null
@@ -1,8 +0,0 @@
-fileFormatVersion: 2
-guid: 6d8f5f23ee1dde046b1a7361ac1b6386
-folderAsset: yes
-DefaultImporter:
- externalObjects: {}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/_Game/Scripts/Enemies/Boss/Patterns/BaseGames.Enemies.Boss.Patterns.asmdef b/Assets/_Game/Scripts/Enemies/Boss/Patterns/BaseGames.Enemies.Boss.Patterns.asmdef
deleted file mode 100644
index 757971ee..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/Patterns/BaseGames.Enemies.Boss.Patterns.asmdef
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "excludePlatforms": [],
- "allowUnsafeCode": false,
- "precompiledReferences": [],
- "name": "BaseGames.Enemies.Boss.Patterns",
- "defineConstraints": [],
- "noEngineReferences": false,
- "versionDefines": [],
- "rootNamespace": "BaseGames.Enemies.Boss.Patterns",
- "references": [
- "BaseGames.Core",
- "BaseGames.Core.Events",
- "BaseGames.Enemies",
- "BaseGames.Combat"
- ],
- "autoReferenced": true,
- "overrideReferences": false,
- "includePlatforms": []
-}
diff --git a/Assets/_Game/Scripts/Enemies/Boss/Patterns/BaseGames.Enemies.Boss.Patterns.asmdef.meta b/Assets/_Game/Scripts/Enemies/Boss/Patterns/BaseGames.Enemies.Boss.Patterns.asmdef.meta
deleted file mode 100644
index 0bab4b52..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/Patterns/BaseGames.Enemies.Boss.Patterns.asmdef.meta
+++ /dev/null
@@ -1,7 +0,0 @@
-fileFormatVersion: 2
-guid: 8bc3529e552a34a45998814c7cd056e6
-AssemblyDefinitionImporter:
- externalObjects: {}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/_Game/Scripts/Enemies/Boss/Patterns/TelegraphSystem.cs b/Assets/_Game/Scripts/Enemies/Boss/Patterns/TelegraphSystem.cs
deleted file mode 100644
index 64e2991c..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/Patterns/TelegraphSystem.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System.Collections;
-using UnityEngine;
-using BaseGames.Core;
-using BaseGames.Core.Pool;
-
-namespace BaseGames.Enemies.Boss.Patterns
-{
- ///
- /// 攻击预警系统(架构 07_EnemyModule §11)。
- /// 在攻击前若干帧显示视觉提示(VFX 从对象池取出,到期归还)。
- /// 由 BD_TelegraphAttack 通过协程调用 ShowTelegraph。
- ///
- public class TelegraphSystem : MonoBehaviour
- {
- ///
- /// 开始预警:从对象池取出 vfxKey 对应预警 VFX,等待 duration 秒后归还。
- /// 由 BD_TelegraphAttack.OnStart 通过 StartCoroutine 调用。
- ///
- public IEnumerator ShowTelegraph(string vfxKey, float duration, Vector2 position)
- {
- if (string.IsNullOrEmpty(vfxKey) || duration <= 0f)
- {
- yield return null;
- yield break;
- }
-
- GameObject vfx = null;
- var pool = ServiceLocator.GetOrDefault();
- if (pool != null)
- vfx = pool.Spawn(vfxKey, new Vector3(position.x, position.y, 0f), Quaternion.identity);
- else
- Debug.LogWarning($"[TelegraphSystem] IObjectPoolService 未就绪,预警 VFX '{vfxKey}' 无法显示。");
-
- yield return new WaitForSeconds(duration);
-
- if (vfx != null && pool != null)
- {
- var po = vfx.GetComponent();
- if (po != null) po.ReturnToPool();
- else vfx.SetActive(false);
- }
- }
-
- /// 立即隐藏所有活跃预警 VFX(技能被打断时调用)。
- public void CancelTelegraph()
- {
- StopAllCoroutines();
- }
- }
-}
diff --git a/Assets/_Game/Scripts/Enemies/Boss/Patterns/TelegraphSystem.cs.meta b/Assets/_Game/Scripts/Enemies/Boss/Patterns/TelegraphSystem.cs.meta
deleted file mode 100644
index 7c15784a..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/Patterns/TelegraphSystem.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: e6f4987894dfe1648909b6863c003c31
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/_Game/Scripts/Enemies/Boss/SkillSequenceSO.cs b/Assets/_Game/Scripts/Enemies/Boss/SkillSequenceSO.cs
deleted file mode 100644
index 978598e4..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/SkillSequenceSO.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using UnityEngine;
-
-namespace BaseGames.Boss
-{
- ///
- /// 有序攻击序列(一个技能内的多段连段)。
- ///
- [CreateAssetMenu(menuName = "BaseGames/Boss/SkillSequence")]
- public class SkillSequenceSO : ScriptableObject
- {
- [Serializable]
- public struct SequenceStep
- {
- public AttackPatternSO pattern;
- [Min(0f)] public float delayBeforeStep;
- }
-
- public SequenceStep[] steps;
-
- [Header("序列完成后的行为")]
- public bool RepeatIfPlayerInRange;
- [Min(0f)] public float RepeatDelay;
- [Range(0, 10)] public int MaxRepeatCount;
- }
-}
diff --git a/Assets/_Game/Scripts/Enemies/Boss/SkillSequenceSO.cs.meta b/Assets/_Game/Scripts/Enemies/Boss/SkillSequenceSO.cs.meta
deleted file mode 100644
index 8a1169fc..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/SkillSequenceSO.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: ab2ec01e225283d4face08cef0d72c87
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/_Game/Scripts/Enemies/Boss/WeakPointSystem.cs b/Assets/_Game/Scripts/Enemies/Boss/WeakPointSystem.cs
deleted file mode 100644
index d89df133..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/WeakPointSystem.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using UnityEngine;
-using BaseGames.Combat;
-using BaseGames.Core.Events;
-
-namespace BaseGames.Boss
-{
- ///
- /// 管理 Boss 的专属弱点 HurtBox(如核心、眼睛等)。
- /// 弱点激活期间受到的伤害会乘以 DamageMultiplier。
- ///
- public class WeakPointSystem : MonoBehaviour
- {
- [System.Serializable]
- public struct WeakPoint
- {
- public HurtBox hurtBox;
- public GameObject visualIndicator;
- }
-
- [SerializeField] private WeakPoint[] _weakPoints;
- [SerializeField] private string _bossId;
- [SerializeField] private StringEventChannelSO _onVulnerabilityWindowOpened;
-
- private float _damageMultiplier = 1f;
-
- /// 激活或关闭弱点 HurtBox 及视觉指示器。
- /// 是否激活。
- /// 激活时的受击伤害乘数。
- /// true = 仅激活弱点专属 HurtBox;false = 全身视为弱点(不改变 HurtBox 状态)。
- public void SetActive(bool active, float multiplier = 1f, bool activateSpecific = false)
- {
- _damageMultiplier = active ? multiplier : 1f;
-
- if (activateSpecific)
- {
- foreach (var wp in _weakPoints)
- {
- wp.hurtBox.gameObject.SetActive(active);
- if (wp.visualIndicator != null)
- wp.visualIndicator.SetActive(active);
- }
- }
-
- if (active)
- _onVulnerabilityWindowOpened?.Raise(_bossId);
- }
-
- /// 弱点 HurtBox 受击时,由 BossStats 调用此方法获取最终伤害系数。
- public float GetDamageMultiplier() => _damageMultiplier;
- }
-}
diff --git a/Assets/_Game/Scripts/Enemies/Boss/WeakPointSystem.cs.meta b/Assets/_Game/Scripts/Enemies/Boss/WeakPointSystem.cs.meta
deleted file mode 100644
index 2c79579d..00000000
--- a/Assets/_Game/Scripts/Enemies/Boss/WeakPointSystem.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 96ffe91642a6ccc4ea4c6076d80f5e27
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/zeling_v2.sln b/zeling_v2.sln
index 4f8bc59e..09257a25 100644
--- a/zeling_v2.sln
+++ b/zeling_v2.sln
@@ -23,14 +23,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Combat", "BaseGam
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Dialogue", "BaseGames.Dialogue.csproj", "{4595E198-DE11-AAF7-3388-915563EBFE41}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Enemies", "BaseGames.Enemies.csproj", "{5E00F025-ED00-233A-3B2F-BAFF76D883F0}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.VFX", "BaseGames.VFX.csproj", "{31DBC108-839C-1442-F9AC-A39596C9E06A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.UI", "BaseGames.UI.csproj", "{7D3E9996-D17C-52A7-538D-3AEBAAF35DF3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Micosmo.SensorToolkit.Editor", "Micosmo.SensorToolkit.Editor.csproj", "{DF93C827-75A1-E6E4-D7D2-206550211A63}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Enemies", "BaseGames.Enemies.csproj", "{5E00F025-ED00-233A-3B2F-BAFF76D883F0}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.World.Map", "BaseGames.World.Map.csproj", "{16BB97E7-3EA9-4707-2D93-441D9C908404}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Tests.EditMode", "BaseGames.Tests.EditMode.csproj", "{0CFAE763-03B9-0921-E4ED-03289E7D499F}"
@@ -93,8 +93,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Spells", "BaseGam
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.World.Streaming", "BaseGames.World.Streaming.csproj", "{8FA0AF4D-7EF6-D3CD-F2A1-9C291AA06F3C}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Enemies.Boss.Patterns", "BaseGames.Enemies.Boss.Patterns.csproj", "{FABE4470-F5D8-FF10-6CF9-C03E9D2A8DBD}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Tutorial", "BaseGames.Tutorial.csproj", "{0A1566C3-6032-C8A1-D015-8EF75B3F7099}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.World.Shop", "BaseGames.World.Shop.csproj", "{3022C488-D174-AD8B-A390-675C8CB13DEF}"
@@ -157,10 +155,6 @@ Global
{4595E198-DE11-AAF7-3388-915563EBFE41}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4595E198-DE11-AAF7-3388-915563EBFE41}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4595E198-DE11-AAF7-3388-915563EBFE41}.Release|Any CPU.Build.0 = Release|Any CPU
- {5E00F025-ED00-233A-3B2F-BAFF76D883F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5E00F025-ED00-233A-3B2F-BAFF76D883F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5E00F025-ED00-233A-3B2F-BAFF76D883F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5E00F025-ED00-233A-3B2F-BAFF76D883F0}.Release|Any CPU.Build.0 = Release|Any CPU
{31DBC108-839C-1442-F9AC-A39596C9E06A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{31DBC108-839C-1442-F9AC-A39596C9E06A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31DBC108-839C-1442-F9AC-A39596C9E06A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -173,6 +167,10 @@ Global
{DF93C827-75A1-E6E4-D7D2-206550211A63}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF93C827-75A1-E6E4-D7D2-206550211A63}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DF93C827-75A1-E6E4-D7D2-206550211A63}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5E00F025-ED00-233A-3B2F-BAFF76D883F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5E00F025-ED00-233A-3B2F-BAFF76D883F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5E00F025-ED00-233A-3B2F-BAFF76D883F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5E00F025-ED00-233A-3B2F-BAFF76D883F0}.Release|Any CPU.Build.0 = Release|Any CPU
{16BB97E7-3EA9-4707-2D93-441D9C908404}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{16BB97E7-3EA9-4707-2D93-441D9C908404}.Debug|Any CPU.Build.0 = Debug|Any CPU
{16BB97E7-3EA9-4707-2D93-441D9C908404}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -297,10 +295,6 @@ Global
{8FA0AF4D-7EF6-D3CD-F2A1-9C291AA06F3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FA0AF4D-7EF6-D3CD-F2A1-9C291AA06F3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FA0AF4D-7EF6-D3CD-F2A1-9C291AA06F3C}.Release|Any CPU.Build.0 = Release|Any CPU
- {FABE4470-F5D8-FF10-6CF9-C03E9D2A8DBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FABE4470-F5D8-FF10-6CF9-C03E9D2A8DBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FABE4470-F5D8-FF10-6CF9-C03E9D2A8DBD}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {FABE4470-F5D8-FF10-6CF9-C03E9D2A8DBD}.Release|Any CPU.Build.0 = Release|Any CPU
{0A1566C3-6032-C8A1-D015-8EF75B3F7099}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A1566C3-6032-C8A1-D015-8EF75B3F7099}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A1566C3-6032-C8A1-D015-8EF75B3F7099}.Release|Any CPU.ActiveCfg = Release|Any CPU