docs(enemy): Boss AI 单轨落地——新增作者指南,清理描述已删除系统的长期文档

新增 Docs/Guides/09_BossAi_Authoring_Guide.md:
定制路径写法([AiDefinition] + AiScript)、建态原语(AiStateFragments +
BossFragments + IBossControl)、阶段=换招池、一招怎么配(EnemyAbilitySO +
EnemyAttackSO + 动画事件)、开战触发、死亡归物理层,
以已落地的 ChaoFengAi 为逐段范例,附 Boss 专属陷阱与已知缺口。
08 号指南加交叉引用。

删除两份整份描述已删除且从未实现的体系的文档:
Docs/Architecture/23_BossSkillModule.md、Docs/Design/47_BossSkillSystem.md。
删前已确认全库无 Markdown 链接残留,索引行与关联文档行改指新指南或 spec。

修订:25_CharacterArchitectureOverview §4 Boss 章节按实际代码重写;
07_EnemyModule 加过时提示、§11 改重定向;02_EventSystem 修正 Boss 事件发送方;
19_BossPatternLibrary 加废止提示(设计意图仍有效,类型名已废);
AssetFolderSpec 删旧 Boss 技能编辑器条目;三处 README/索引同步。
Docs_Dev/ 历史记录保留不动。

spec 标记为已实施,并记录实施期偏差(无 Boss 骨架、Telegraph 枚举保留、
阶段直查不走黑板、BossSkillEvent 一并删除)与八项已知未完成项,
其中 EnemyHurtState 无受击动画永久卡死为最高优先级、且与 Boss 轨无关。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-30 17:14:32 +08:00
co-authored by Claude Opus 5
parent cf0ac60fad
commit 6d3816d7ef
12 changed files with 654 additions and 242 deletions
+4 -4
View File
@@ -53,7 +53,7 @@
| 16 | MapSystem | 15_MapShopModule §1 | ✅ | 完整 | | 16 | MapSystem | 15_MapShopModule §1 | ✅ | 完整 |
| 17 | EquipmentSystem | 09_ProgressionModule | ✅ | 完整 | | 17 | EquipmentSystem | 09_ProgressionModule | ✅ | 完整 |
| 18 | CutsceneSystem | 14_NarrativeModule §7 | ✅ | CutsceneTrigger/CutsceneSO 已定义 | | 18 | CutsceneSystem | 14_NarrativeModule §7 | ✅ | CutsceneTrigger/CutsceneSO 已定义 |
| 19 | BossPatternLibrary | **23_BossSkillModule** | ✅ | BossSkillSO/SkillSequenceSO/WeakPointSystem 全部定义 | | 19 | BossPatternLibrary | **07_EnemyModule** · `Docs/Guides/09_BossAi_Authoring_Guide` | ⚠️ | 旧 Boss 技能轨(BossSkillSO/SkillSequenceSO/WeakPointSystem)已于 2026-07-30 整体退役,Boss 归并到敌人能力轨。Design 19 仍是设计意图文档,实现见作者指南 |
| 20 | AnimationEventSystem | **24_AnimEventModule** | ✅ | PlayerAnimationEvents/EnemyAnimationEvents/AnimationEventBinder 全部定义 | | 20 | AnimationEventSystem | **24_AnimEventModule** | ✅ | PlayerAnimationEvents/EnemyAnimationEvents/AnimationEventBinder 全部定义 |
| 21 | SpellSystem | 09_ProgressionModule | ✅ | 完整 | | 21 | SpellSystem | 09_ProgressionModule | ✅ | 完整 |
| 22 | LocalizationSystem | 16_SupportingModules §1 | ✅ | 完整 | | 22 | LocalizationSystem | 16_SupportingModules §1 | ✅ | 完整 |
@@ -81,7 +81,7 @@
| 44 | LevelDesignGuide | — | 📖 | 关卡设计规范,无需 Architecture | | 44 | LevelDesignGuide | — | 📖 | 关卡设计规范,无需 Architecture |
| 45 | TutorialSystem | **21_LiquidPuzzleModule** §Tutorial | ✅ | TutorialManager/ContextualHintTrigger 已定义 | | 45 | TutorialSystem | **21_LiquidPuzzleModule** §Tutorial | ✅ | TutorialManager/ContextualHintTrigger 已定义 |
| 46 | PlatformIntegration | 16_SupportingModules §3 | ✅ | IPlatformService/SteamPlatformService/NullPlatformServiceServiceLocator 模式)已定义 | | 46 | PlatformIntegration | 16_SupportingModules §3 | ✅ | IPlatformService/SteamPlatformService/NullPlatformServiceServiceLocator 模式)已定义 |
| 47 | BossSkillSystem | **23_BossSkillModule** | ✅ | BossSkillSO/SkillSequenceSO/BossSkillExecutor/WeakPointSystem 全部定义 | | 47 | ~~BossSkillSystem~~ | — | ❌ | 已废止:Design 47 与 Architecture 23 于 2026-07-30 一并删除。Boss 与小怪统一走 `EnemyAbilitySO` + `EnemyAiBrain`,写法见 `Docs/Guides/09_BossAi_Authoring_Guide.md`,设计依据见 `Docs_Dev/superpowers/specs/2026-07-30-boss-ai-single-track-design.md` |
| 48 | EnemyRoster | — | 📖 | 敌人名单(策划),无需 Architecture | | 48 | EnemyRoster | — | 📖 | 敌人名单(策划),无需 Architecture |
| 49 | AntiSoftlockSystem | 16_SupportingModules §5 | ✅ | 完整 | | 49 | AntiSoftlockSystem | 16_SupportingModules §5 | ✅ | 完整 |
| 50 | NarrativeDesignSystem | — | 📖 | 叙事结构设计,无需 Architecture | | 50 | NarrativeDesignSystem | — | 📖 | 叙事结构设计,无需 Architecture |
@@ -130,7 +130,7 @@
| [20_ShieldModule.md](20_ShieldModule.md) | 30 | ShieldComponent、ShieldConfigSO、IShieldable、伤害管道修正 | | [20_ShieldModule.md](20_ShieldModule.md) | 30 | ShieldComponent、ShieldConfigSO、IShieldable、伤害管道修正 |
| [21_LiquidPuzzleModule.md](21_LiquidPuzzleModule.md) | 40、35、36、45 | LiquidZone、SwimState、PuzzleSwitch/Receiver/Wire、WorldMarker、TutorialManager | | [21_LiquidPuzzleModule.md](21_LiquidPuzzleModule.md) | 40、35、36、45 | LiquidZone、SwimState、PuzzleSwitch/Receiver/Wire、WorldMarker、TutorialManager |
| [22_QuestChallengeModule.md](22_QuestChallengeModule.md) | 38、39 | QuestSO、QuestManager、QuestGiver、ChallengeRoomSO、ChallengeRoomManager | | [22_QuestChallengeModule.md](22_QuestChallengeModule.md) | 38、39 | QuestSO、QuestManager、QuestGiver、ChallengeRoomSO、ChallengeRoomManager |
| [23_BossSkillModule.md](23_BossSkillModule.md) | 47、19 | BossSkillSO、SkillSequenceSO、BossSkillExecutor、WeakPointSystem | | ~~23_BossSkillModule.md~~ | — | 已于 2026-07-30 删除(旧 Boss 技能轨退役)。Boss 实现并入 07_EnemyModule 的能力体系,作者指南见 `Docs/Guides/09_BossAi_Authoring_Guide.md` |
| [24_AnimEventModule.md](24_AnimEventModule.md) | 20 | PlayerAnimationEvents、EnemyAnimationEvents、AnimationEventBinder | | [24_AnimEventModule.md](24_AnimEventModule.md) | 20 | PlayerAnimationEvents、EnemyAnimationEvents、AnimationEventBinder |
--- ---
@@ -163,7 +163,7 @@
| [16_SupportingModules.md](16_SupportingModules.md) | **§1.1** LanguageManagerSOSO 单例,PlayerPrefs 持久化,SetLocale/GetCurrentLocaleCode/LoadSavedLocale 三方法);与静态 LocalizationManager 职责对比说明(文本查询 vs 语言切换+持久化) | ✅ 已应用 | | [16_SupportingModules.md](16_SupportingModules.md) | **§1.1** LanguageManagerSOSO 单例,PlayerPrefs 持久化,SetLocale/GetCurrentLocaleCode/LoadSavedLocale 三方法);与静态 LocalizationManager 职责对比说明(文本查询 vs 语言切换+持久化) | ✅ 已应用 |
| [12_SaveModule.md](12_SaveModule.md) | EquipmentSaveData 移除重复工具字段(ToolSlot0/ToolSlot1/OwnedToolIds/ToolStates)——这些字段仅属于 ToolsSaveData(顶层 SaveData.Tools);添加注释说明归属 | ✅ 已应用 | | [12_SaveModule.md](12_SaveModule.md) | EquipmentSaveData 移除重复工具字段(ToolSlot0/ToolSlot1/OwnedToolIds/ToolStates)——这些字段仅属于 ToolsSaveData(顶层 SaveData.Tools);添加注释说明归属 | ✅ 已应用 |
| [09_ProgressionModule.md](09_ProgressionModule.md) | ToolSlotManager.OnSave() 数据写入路径从 `data.Equipment.ToolSlotX` 修正为 `data.Tools.ToolSlotX`OnLoad 注释同步为"从 data.Tools 恢复" | ✅ 已应用 | | [09_ProgressionModule.md](09_ProgressionModule.md) | ToolSlotManager.OnSave() 数据写入路径从 `data.Equipment.ToolSlotX` 修正为 `data.Tools.ToolSlotX`OnLoad 注释同步为"从 data.Tools 恢复" | ✅ 已应用 |
| [23_BossSkillModule.md](23_BossSkillModule.md) | BossSkillSO 补全 `attackPatterns: AttackPatternSO[]``counterResponses: PlayerCounterResponse[]``arenaEvents: ArenaEventTrigger[]``resourceCost: BossResourceCost``buildsRage: bool``poiseWindow: PoiseWindowConfig` 六个缺失字段;新增 §4.1 PlayerCounterResponse + CounterType 枚举、§4.2 ArenaEventTrigger/ArenaEventType/ArenaEventParams/ArenaEventData/IArenaInteractable、§4.3 BossResourceCost + BossResourceConfigSO 定义 | ✅ 已应用 | | `23_BossSkillModule.md`(该文档已于 2026-07-30 删除,本行仅存历史) | BossSkillSO 补全 `attackPatterns: AttackPatternSO[]``counterResponses: PlayerCounterResponse[]``arenaEvents: ArenaEventTrigger[]``resourceCost: BossResourceCost``buildsRage: bool``poiseWindow: PoiseWindowConfig` 六个缺失字段;新增 §4.1 PlayerCounterResponse + CounterType 枚举、§4.2 ArenaEventTrigger/ArenaEventType/ArenaEventParams/ArenaEventData/IArenaInteractable、§4.3 BossResourceCost + BossResourceConfigSO 定义 | ✅ 已应用 |
| [16_SupportingModules.md](16_SupportingModules.md) | §2 AchievementManager 完全重写(对齐 Design/32 SO 策略模式):AchievementDef/AchievementDatabaseSO 替换为 AchievementSO + AchievementType/AchievementTier 枚举 + AchievementCondition 抽象基类(RegisterListeners/UnregisterListeners/IsMet+ 内置 12 种条件类型表 + DefeatedBossCondition 示例 + AchievementManager_allAchievements: AchievementSO[],中继 C# 事件,EvaluateAll/Unlock+ AchievementRuntimeState | ✅ 已应用 | | [16_SupportingModules.md](16_SupportingModules.md) | §2 AchievementManager 完全重写(对齐 Design/32 SO 策略模式):AchievementDef/AchievementDatabaseSO 替换为 AchievementSO + AchievementType/AchievementTier 枚举 + AchievementCondition 抽象基类(RegisterListeners/UnregisterListeners/IsMet+ 内置 12 种条件类型表 + DefeatedBossCondition 示例 + AchievementManager_allAchievements: AchievementSO[],中继 C# 事件,EvaluateAll/Unlock+ AchievementRuntimeState | ✅ 已应用 |
| [24_AnimEventModule.md](24_AnimEventModule.md) | `IAnimEventReceiver` 重命名为 `IAnimationEventHandler`;方法签名 `OnAnimationEvent(type, data)` 改为 `HandleEvent(type, payload)`AnimationEventBinder.Bind() 参数类型、PlayerAnimationEvents/EnemyAnimationEvents 实现声明及方法体内 payload 用法全部同步 | ✅ 已应用 | | [24_AnimEventModule.md](24_AnimEventModule.md) | `IAnimEventReceiver` 重命名为 `IAnimationEventHandler`;方法签名 `OnAnimationEvent(type, data)` 改为 `HandleEvent(type, payload)`AnimationEventBinder.Bind() 参数类型、PlayerAnimationEvents/EnemyAnimationEvents 实现声明及方法体内 payload 用法全部同步 | ✅ 已应用 |
| [16_SupportingModules.md](16_SupportingModules.md) | §5 AntiSoftlockSystem 后新增 §5.1 RoomEscapeInfoSO(设计时房间逃离 SO,含 EscapeRoute 嵌套类,对齐 Design/49 §3+ §5.2 HardAbilityGateAbilityGate 子类,_requirePhysicalValidation + _sequenceBreakRisk,对齐 Design/49 §4.2 | ✅ 已应用 | | [16_SupportingModules.md](16_SupportingModules.md) | §5 AntiSoftlockSystem 后新增 §5.1 RoomEscapeInfoSO(设计时房间逃离 SO,含 EscapeRoute 嵌套类,对齐 Design/49 §3+ §5.2 HardAbilityGateAbilityGate 子类,_requirePhysicalValidation + _sequenceBreakRisk,对齐 Design/49 §4.2 | ✅ 已应用 |
+4 -14
View File
@@ -140,12 +140,6 @@ public class ShopPurchaseEventChannelSO : BaseEventChannelSO<ShopPurchaseEvent>
[CreateAssetMenu(menuName = "Events/DialogueRequest")] [CreateAssetMenu(menuName = "Events/DialogueRequest")]
public class DialogueEventChannelSO : BaseEventChannelSO<DialogueDataSO> { } public class DialogueEventChannelSO : BaseEventChannelSO<DialogueDataSO> { }
// Assets/Scripts/Core/Events/BossSkillEventChannelSO.cs
[System.Serializable]
public struct BossSkillEvent { public string BossId; public string SkillId; }
[CreateAssetMenu(menuName = "Events/BossSkill")]
public class BossSkillEventChannelSO : BaseEventChannelSO<BossSkillEvent> { }
// Assets/Scripts/Core/Events/BossPhaseEventChannelSO.cs // Assets/Scripts/Core/Events/BossPhaseEventChannelSO.cs
[System.Serializable] [System.Serializable]
public struct BossPhaseEvent { public string BossId; public int Phase; } public struct BossPhaseEvent { public string BossId; public int Phase; }
@@ -246,16 +240,12 @@ public class StatusEffectEventChannelSO : BaseEventChannelSO<StatusEffectType> {
| `EVT_EnemyDied` | `TransformEventChannelSO` | `EnemyBase`HP ≤ 0 | `PlayerStats`(击杀点)、`QuestManager` | | `EVT_EnemyDied` | `TransformEventChannelSO` | `EnemyBase`HP ≤ 0 | `PlayerStats`(击杀点)、`QuestManager` |
| `EVT_HitConfirmed` | `HitConfirmedEventChannelSO`HitInfo | `HurtBox.ReceiveDamage` | `HitFXSpawner``AudioManager``PlayerFeedback`(受击方) | | `EVT_HitConfirmed` | `HitConfirmedEventChannelSO`HitInfo | `HurtBox.ReceiveDamage` | `HitFXSpawner``AudioManager``PlayerFeedback`(受击方) |
| `EVT_DamageDealt` | `DamageInfoEventChannelSO` | `HurtBox.ReceiveDamage` | `AnalyticsManager` | | `EVT_DamageDealt` | `DamageInfoEventChannelSO` | `HurtBox.ReceiveDamage` | `AnalyticsManager` |
| `EVT_BossFightStarted` | `StringEventChannelSO`bossId | `BossOrchestrator` | `GameManager`(切换 BossFight 状态)、`AudioManager` | | `EVT_BossFightStarted` | `StringEventChannelSO`bossId | `BossFightTrigger`(玩家进入竞技场触发区) | `GameManager`(切换 BossFight 状态)、`AudioManager` |
| `EVT_BossFightEnded` | `BoolEventChannelSO`胜利/失败) | `BossBase.Die()` | `GameManager``AudioManager``UIManager` | | `EVT_BossFightEnded` | `BoolEventChannelSO`true=开始 / false=结束) | `BossFightTrigger`(开始)、`BossBase.Die()`(结束) | `BossHPBar`(显示/隐藏血条)`AudioManager``UIManager` |
| `EVT_BossFightToggled` | `BoolEventChannelSO`true=开始,false=结束) | `BossOrchestrator`(开始)、`BossBase.Die()`(结束) | `BossHPBar`(显示/隐藏 Boss 血条) |
| `EVT_BossHPChanged` | `IntEventChannelSO` | `BossBase`(受击/回血) | `BossHPBar`HP 进度条更新) | | `EVT_BossHPChanged` | `IntEventChannelSO` | `BossBase`(受击/回血) | `BossHPBar`HP 进度条更新) |
| `EVT_BossNameSet` | `StringEventChannelSO`bossName | `BossOrchestrator`(战斗开始时 | `BossHPBar`(显示 Boss 名称标签) | | `EVT_BossNameSet` | `StringEventChannelSO`bossName | ⚠️ 暂无发送方(旧编排器已删除 | `BossHPBar`(显示 Boss 名称标签) |
| `EVT_BossHPMaxSet` | `IntEventChannelSO` | `BossOrchestrator`(战斗开始时 | `BossHPBar`(初始化满血值) | | `EVT_BossHPMaxSet` | `IntEventChannelSO` | ⚠️ 暂无发送方(旧编排器已删除 | `BossHPBar`(初始化满血值) |
| `EVT_BossPhaseChanged` | `BossPhaseEventChannelSO`bossId, phase | `BossBase.EnterPhase()` | `BossHUD`(相机切换通过 `CameraStateController.Instance` 直接调用,不订阅事件)| | `EVT_BossPhaseChanged` | `BossPhaseEventChannelSO`bossId, phase | `BossBase.EnterPhase()` | `BossHUD`(相机切换通过 `CameraStateController.Instance` 直接调用,不订阅事件)|
| `EVT_BossSkillStarted` | `BossSkillEventChannelSO`bossId, skillId | `BossSkillExecutor` | `BossHUD`(显示技能名)(震动通过 `CameraStateController.Instance.TriggerImpulse()` 直接调用)|
| `EVT_BossSkillEnded` | `BossSkillEventChannelSO`bossId, skillId | `BossSkillExecutor` | `BossOrchestrator`BD 决策推进) |
| `EVT_BossVulnerabilityWindowOpened` | `StringEventChannelSO`bossId | `WeakPointSystem` | `PlayerFeedback`(提示音效)、`HUDController` |
| `EVT_NailClash` | `VoidEventChannelSO` | `ClashResolver`(玩家与敌人 HitBox 对碰) | `VFXSpawner`(拼刀特效)、`AudioManager`(拼刀音效)、`CameraStateController`(轻振动) | | `EVT_NailClash` | `VoidEventChannelSO` | `ClashResolver`(玩家与敌人 HitBox 对碰) | `VFXSpawner`(拼刀特效)、`AudioManager`(拼刀音效)、`CameraStateController`(轻振动) |
| `EVT_StatusEffectApplied` | `StatusEffectEventChannelSO` | `StatusEffectManager.ApplyEffect()` | `HUDController`(状态图标)、`PlayerFeedback`(特效) | | `EVT_StatusEffectApplied` | `StatusEffectEventChannelSO` | `StatusEffectManager.ApplyEffect()` | `HUDController`(状态图标)、`PlayerFeedback`(特效) |
| `EVT_StatusEffectExpired` | `StatusEffectEventChannelSO` | `StatusEffectManager.Tick()` | `HUDController`(移除状态图标) | | `EVT_StatusEffectExpired` | `StatusEffectEventChannelSO` | `StatusEffectManager.Tick()` | `HUDController`(移除状态图标) |
+36 -145
View File
@@ -1,9 +1,30 @@
# 07 · 敌人模块 # 07 · 敌人模块
> **命名空间** `BaseGames.Enemies``BaseGames.Enemies.AI``BaseGames.Enemies.Navigation``BaseGames.Enemies.Boss.Patterns` > **命名空间** `BaseGames.Enemies``BaseGames.Enemies.Abilities``BaseGames.Enemies.Navigation``BaseGames.AI`
> **程序集** 见各 asmdef > **程序集** 见各 asmdef
> **路径** `Assets/Scripts/Enemies/` > **路径** `Assets/_Game/Scripts/Enemies/`
> **依赖** `BaseGames.Combat``Kybernetik.Animancer``BehaviorDesigner.Runtime``PathBerserker2d` > **依赖** `BaseGames.Combat``Kybernetik.Animancer`
---
> ## ⚠️ 本文部分章节已过时(2026-07-30)
>
> 决策层与 Boss 轨已两度重构,以下章节描述的类型**在代码库中已不存在**,保留仅供追溯历史,
> **不要照着它们去找类型或写新代码**
>
> | 章节 | 状态 |
> |---|---|
> | §8 `Behavior Designer 任务类目录` | 第三方行为树插件已移除。决策层现为自研 `BrainGraph``AiScript` / `BrainBuilder` / `AiRuntime` / `EnemyAiBrain` |
> | §10 `BossOrchestrator` | 已删除。开战由 `BossFightTrigger``AiSignal.Engaged`,阶段由 `BossBase.EnterPhase` + `BossPhaseAbilityGate` 承担 |
> | §11 `AttackPatternSO 与 TelegraphSystem` | 整节已删除的类型;预警统一改为动画时间轴上的事件 |
> | §9 `BossBase` 的字段清单 | 已大幅瘦身:技能执行器、预警系统、弹反反制均已移除;新增 `IBossControl` 实现与阶段门引用 |
>
> **当前有效的写法**(这两份是权威):
> - 小怪:[`Docs/Guides/08_EnemyAi_Authoring_Guide.md`](../Guides/08_EnemyAi_Authoring_Guide.md)
> - Boss[`Docs/Guides/09_BossAi_Authoring_Guide.md`](../Guides/09_BossAi_Authoring_Guide.md)
> - 设计依据:`Docs_Dev/superpowers/specs/2026-07-30-boss-ai-single-track-design.md`
>
> 本文其余章节(`EnemyBase` / `EnemyStats` / `EnemyMovement` / 感知 / 掉落 / 池化等)仍然有效。
--- ---
@@ -16,10 +37,10 @@
5. [EnemyNavAgent](#5-enemynavagent) 5. [EnemyNavAgent](#5-enemynavagent)
6. [EnemyStatsSO](#6-enemystatsso) 6. [EnemyStatsSO](#6-enemystatsso)
7. [EnemyAnimationConfigSO](#7-enemyanimationconfigso) 7. [EnemyAnimationConfigSO](#7-enemyanimationconfigso)
8. [Behavior Designer 任务类目录](#8-behavior-designer-任务类目录) 8. ~~[决策层任务类目录](#8-behavior-designer-任务类目录)~~(已过时,见页首提示)
9. [BossBase](#9-bossbase) 9. [BossBase](#9-bossbase)(字段清单已过时)
10. [BossOrchestrator](#10-bossorchestrator) 10. ~~[BossOrchestrator](#10-bossorchestrator)~~(已删除)
11. [AttackPatternSO 与 TelegraphSystem](#11-attackpatternso-与-telegraphsystem) 11. ~~[AttackPatternSO 与 TelegraphSystem](#11-attackpatternso-与-telegraphsystem)~~(已删除)
12. [DeathShade(死亡遗骸)](#12-deathshade) 12. [DeathShade(死亡遗骸)](#12-deathshade)
13. [Enemy Prefab 层级结构](#13-enemy-prefab-层级结构) 13. [Enemy Prefab 层级结构](#13-enemy-prefab-层级结构)
14. [LootTableSO 与 LootResolver](#14-loottableso-与-lootresolver) 14. [LootTableSO 与 LootResolver](#14-loottableso-与-lootresolver)
@@ -551,147 +572,17 @@ public class BossOrchestrator : MonoBehaviour
--- ---
## 11. AttackPatternSO 与 TelegraphSystem ## 11. ~~AttackPatternSO 与 TelegraphSystem~~(已删除)
```csharp 这两个类型连同整套旧 Boss 技能轨已于 2026-07-30 删除。当前等价物:
// 路径: Assets/Scripts/Enemies/Boss/Patterns/AttackPatternSO.cs
[CreateAssetMenu(menuName = "Enemies/Boss/AttackPattern")]
public class AttackPatternSO : ScriptableObject
{
[System.Serializable]
public struct AttackEntry
{
public string AttackId; // BD 任务通过此 ID 触发
public float Weight; // 随机权重(模式随机选择)
public float Cooldown;
public float TelegraphDuration; // 0 = 无预警
public string TelegraphVfxKey; // Addressable 键
public DamageSourceSO DamageSource;
}
public AttackEntry[] Attacks; | 旧类型 | 现在由谁承担 |
public float PhaseSpeedMultiplier = 1f; // 此阶段移速倍率 |---|---|
} | `AttackPatternSO`(攻击条目 + 权重 + 冷却 + 预警时长) | `EnemyAbilitySO`(id / 冷却 / 权重 / 优先级 / 触发范围 / 中断规则)+ `EnemyAttackSO`clip + 归一化时机);选招由 `EnemyAttackSelector` 负责 |
| `AttackPatternEditor`(命中帧可视化 Inspector) | 暂无替代。能力资产的编辑器总览(`EnemyAbilityModule`)是已记录的待办 |
| `TelegraphSystem`(预警 VFX 协程) | 动画时间轴:预警是 clip 的一段,判定 / VFX / 音效 / 无敌帧全部挂动画事件(见 `EnemyAnimationEvents` |
// 路径: Assets/Scripts/Enemies/Boss/Patterns/TelegraphSystem.cs 配招写法见 [`Docs/Guides/09_BossAi_Authoring_Guide.md`](../Guides/09_BossAi_Authoring_Guide.md) §4。
// 攻击预警系统:在攻击前若干帧显示视觉提示
public class TelegraphSystem : MonoBehaviour
{
[SerializeField] private ObjectPoolManager _pool;
// 开始预警(BD_TelegraphAttack 调用)
public IEnumerator ShowTelegraph(string vfxKey, float duration, Vector2 position);
// 1. 从对象池取出预警 VFX
// 2. 等待 duration 秒
// 3. 归还 VFX(攻击开始)
}
```
---
### 11.1 AttackPatternEditor(命中帧可视化 Inspector
> **路径**`Assets/Editor/Enemies/AttackPatternEditor.cs`
> **目标用户**:Boss 战斗设计师(配置攻击权重、预警时长、伤害数值时,无需对照原始 Inspector 多层嵌套)
```csharp
[CustomEditor(typeof(AttackPatternSO))]
public class AttackPatternEditor : UnityEditor.Editor
{
// ── 折叠状态 ─────────────────────────────────────────────────────
private bool[] _foldouts;
public override void OnInspectorGUI()
{
var so = (AttackPatternSO)target;
var prop = serializedObject;
prop.Update();
// ── 整体参数 ─────────────────────────────────────────────────
EditorGUILayout.PropertyField(prop.FindProperty("PhaseSpeedMultiplier"));
EditorGUILayout.Space(6);
// ── 攻击条目列表(可视化条形图 + 折叠面板) ─────────────────
EditorGUILayout.LabelField("AttackEntries", EditorStyles.boldLabel);
var attacks = so.Attacks;
if (attacks == null || attacks.Length == 0)
{
EditorGUILayout.HelpBox("尚无攻击条目。", MessageType.Info);
}
else
{
if (_foldouts == null || _foldouts.Length != attacks.Length)
_foldouts = new bool[attacks.Length];
float totalWeight = 0f;
foreach (var a in attacks) totalWeight += Mathf.Max(a.Weight, 0.001f);
for (int i = 0; i < attacks.Length; i++)
{
var entry = attacks[i];
float ratio = entry.Weight / totalWeight;
// 折叠标题行:「[Bar████░░] AttackId 权重%」
EditorGUILayout.BeginHorizontal();
var barRect = GUILayoutUtility.GetRect(0, 16, GUILayout.Width(80));
EditorGUI.DrawRect(barRect, new Color(0.2f, 0.4f, 0.8f, 0.3f));
EditorGUI.DrawRect(new Rect(barRect.x, barRect.y, barRect.width * ratio, barRect.height),
new Color(0.2f, 0.6f, 1f, 0.8f));
_foldouts[i] = EditorGUILayout.Foldout(_foldouts[i],
$" {entry.AttackId} ({ratio:P0})", true);
EditorGUILayout.EndHorizontal();
if (_foldouts[i])
{
EditorGUI.indentLevel++;
var arrayProp = prop.FindProperty("Attacks").GetArrayElementAtIndex(i);
EditorGUILayout.PropertyField(arrayProp.FindPropertyRelative("AttackId"));
EditorGUILayout.PropertyField(arrayProp.FindPropertyRelative("Weight"));
EditorGUILayout.PropertyField(arrayProp.FindPropertyRelative("Cooldown"));
// 预警时长:0 = 无预警(灰色提示)
float tele = entry.TelegraphDuration;
EditorGUILayout.PropertyField(arrayProp.FindPropertyRelative("TelegraphDuration"));
if (tele <= 0f)
EditorGUILayout.HelpBox("TelegraphDuration = 0:此攻击无预警(即时)", MessageType.None);
EditorGUILayout.PropertyField(arrayProp.FindPropertyRelative("TelegraphVfxKey"));
EditorGUILayout.PropertyField(arrayProp.FindPropertyRelative("DamageSource"));
// 快速展示 DamageSource 摘要(避免策划必须展开嵌套 SO)
if (entry.DamageSource != null)
{
EditorGUI.indentLevel++;
EditorGUILayout.LabelField(
$"伤害预览: {entry.DamageSource.BaseDamage} × {entry.DamageSource.DamageMultiplier:F1} " +
$"= {Mathf.RoundToInt(entry.DamageSource.BaseDamage * entry.DamageSource.DamageMultiplier)} [{entry.DamageSource.Type}]",
EditorStyles.miniLabel);
EditorGUI.indentLevel--;
}
// 一键 Ping 关联 SO
if (entry.DamageSource != null && GUILayout.Button("Ping DamageSourceSO", GUILayout.Height(18)))
EditorGUIUtility.PingObject(entry.DamageSource);
EditorGUI.indentLevel--;
}
}
}
prop.ApplyModifiedProperties();
}
}
```
**提供能力一览**
| 功能 | 收益 |
|------|------|
| 随机权重百分比 + 条形图 | 策划直观感受攻击频率分布 |
| TelegraphDuration=0 警告 | 防止无意做成即时攻击 |
| DamageSource 内联摘要 | 查看伤害值无需展开嵌套 SO |
| Ping 关联 SO 按钮 | 快速定位引用资产 |
--- ---
@@ -1,9 +1,12 @@
# 25 · 角色系统架构全景图 # 25 · 角色系统架构全景图
> **命名空间** `BaseGames.Player``BaseGames.Player.States``BaseGames.Enemies``BaseGames.Enemies.AI``BaseGames.Boss``BaseGames.Combat` > **命名空间** `BaseGames.Player``BaseGames.Player.States``BaseGames.Enemies``BaseGames.Enemies.Abilities``BaseGames.AI``BaseGames.Combat`
> **路径** `Assets/_Game/Scripts/Player/``Assets/_Game/Scripts/Enemies/``Assets/_Game/Scripts/Combat/` > **路径** `Assets/_Game/Scripts/Player/``Assets/_Game/Scripts/Enemies/``Assets/_Game/Scripts/Combat/`
> **关联文档** [05_PlayerModule](05_PlayerModule.md) · [06_CombatModule](06_CombatModule.md) · [07_EnemyModule](07_EnemyModule.md) · [09_ProgressionModule](09_ProgressionModule.md) · [23_BossSkillModule](23_BossSkillModule.md) > **关联文档** [05_PlayerModule](05_PlayerModule.md) · [06_CombatModule](06_CombatModule.md) · [07_EnemyModule](07_EnemyModule.md) · [09_ProgressionModule](09_ProgressionModule.md) · [`Docs/Guides/08_EnemyAi_Authoring_Guide`](../Guides/08_EnemyAi_Authoring_Guide.md) · [`Docs/Guides/09_BossAi_Authoring_Guide`](../Guides/09_BossAi_Authoring_Guide.md)
> **建立日期** 2026-05-17 > **建立日期** 2026-05-17  **§4 Boss 章节重写** 2026-07-30Boss 与小怪单轨统一)
>
> ⚠️ §3.3「AI — Behavior Designer 节点库」仍描述已移除的第三方行为树插件,尚未重写;
> 当前决策层是自研 `BrainGraph`,写法以上方两份作者指南为准。
本文档是跨模块的**角色系统实现全景图**,侧重三类角色(玩家 / 小怪 / Boss)在 Scene 中的节点结构、脚本职责划分、子系统数据流与相互协作关系。各模块深度细节请参阅上方关联文档。 本文档是跨模块的**角色系统实现全景图**,侧重三类角色(玩家 / 小怪 / Boss)在 Scene 中的节点结构、脚本职责划分、子系统数据流与相互协作关系。各模块深度细节请参阅上方关联文档。
@@ -28,7 +31,7 @@
4. [Boss](#4-boss) 4. [Boss](#4-boss)
- 4.1 [继承关系](#41-继承关系) - 4.1 [继承关系](#41-继承关系)
- 4.2 [Scene 节点结构](#42-scene-节点结构) - 4.2 [Scene 节点结构](#42-scene-节点结构)
- 4.3 [技能执行流 BossSkillSO + BossSkillExecutor](#43-技能执行流-bossskillso--bossskillexecutor) - 4.3 [一招的数据流](#43-一招的数据流)
- 4.4 [阶段切换](#44-阶段切换) - 4.4 [阶段切换](#44-阶段切换)
5. [共享战斗层 Combat Module](#5-共享战斗层-combat-module) 5. [共享战斗层 Combat Module](#5-共享战斗层-combat-module)
- 5.1 [核心接口](#51-核心接口) - 5.1 [核心接口](#51-核心接口)
@@ -444,100 +447,110 @@ EnemyBase.TakeDamage(DamageInfo)
``` ```
MonoBehaviour MonoBehaviour
└── EnemyBaseIDamageable / ILOSRequester └── EnemyBaseIDamageable / ILOSRequester
└── BossBase └── BossBase+ BaseGames.AI.IBossControl
├── 阶段切换EnterPhase(int) + BossPhaseEventChannelSO 广播 ├── 阶段:CurrentPhase / EnterPhase(int) + BossPhaseEventChannelSO 广播
├── IsHPBelow(float ratio) → BD_IsHPBelow 轮询条件 ├── 阶段过渡:BeginPhaseTransition(targetPhase, invincibleDuration)
└── override Die() → _onBossFightEnded.Raise(true) │ → IsPhaseTransitioning(期间 IsInvincible 为真)→ EnterPhase
├── IsHPBelow(float ratio):供 AI 图的条件边读取
├── 竞技场锚点:AnchorAt(i) / DistanceToAnchor(i)(转发 BossArenaAnchors
└── override Die() → 中止阶段过渡 + _onBossFightEnded.Raise(true)
└── [具体 Boss 类] └── [具体 Boss 类]
override EnterPhase → 额外过渡逻辑(动画/无敌帧/BD 子树切换) override EnterPhase / OnBeginPhaseTransition → 额外过渡演出
``` ```
**Boss 没有独立的技能体系。** 招式即敌人能力(`EnemyAbilitySO` + `EnemyAbilityBase`),
选招即 `EnemyAttackSelector`,决策即 `EnemyAiBrain` 上的 `AiScript` 图。
Boss 专属的只有 `IBossControl` 这一个决策面加几个旁挂 MonoBehaviour。
--- ---
### 4.2 Scene 节点结构 ### 4.2 Scene 节点结构
``` ```
[Boss_XxxGuardian] [ENM_XxxBoss]
BossBase具体 Boss 脚本继承 BossBase │ 具体 Boss 脚本继承 BossBase,实现 IBossControl
│ ├── EnemyStats / EnemyMovement / EnemyCombat / EnemyFeedback │ ├── EnemyStats / EnemyMovement / EnemyLocomotion / EnemyFeedback
│ ├── BossSkillExecutor 接收 BD/Orchestrator 指令,执行 BossSkillSO 协程 │ ├── GroundNavigator(或 FlyingNavigator
│ ├── WeakPointSystem 弱点激活窗口管理(BossSkillExecutor 技能后开启 │ ├── PhysicsPerceptionSystem 感知(追逐区 / 视野 / 攻击范围
│ ├── TelegraphSystem 攻击预兆提示(激光标线 / 范围高亮 / 地面警示 │ ├── EnemyAiBrain 决策层(_definitionId 指向 [AiDefinition] 的 AiScript
│ ├── BehaviorTree 含 BD_EnterPhase 的行为树资产 │ ├── BossPhaseAbilityGate 阶段 = 换招池:按阶段启停能力组件
│ ├── BossArenaAnchors(可选) 竞技场定点走位的锚点集合
│ ├── EnemyAbilityBase × N 每招一个组件,各自引用一份 EnemyAbilitySO
│ ├── BossResource(可选) 怒气 / 充能;是否已满经 IBossControl.ResourceFull 读取
│ └── AnimancerComponent │ └── AnimancerComponent
├── HurtBox 主体受击盒(Layer=EnemyHurtBox ├── HurtBox 主体受击盒(Layer=EnemyHurtBox
│ └── 弱点受击盒同样是 HurtBox,靠 _damageMultiplier 表达倍率,无独立弱点系统
├── WeakPoint_Head 弱点受击盒 ├── ContactDamageZone 身体接触伤害(常驻,Layer=EnemyHitBox
│ └── HurtBox(弱点专属,WeakPointSystem 控制激活/关闭 ── HitBox_XXX × N 各近战招的判定盒(默认禁用,由动画事件按时机开关
├── XxxMuzzle × N 弹体发射点
── HitBox_Slam 近战攻击 HitBoxLayer=EnemyHitBox ── [场景侧] BossFightTrigger 房间入口触发区:发开战事件 + AiSignal.Engaged
├── HitBox_Sweep 横扫 HitBox(可与 BossSkillSO 绑定)
└── BossArenaBlocker(可选) 竞技场封锁触发器(Boss 战开始时封门)
``` ```
--- ---
### 4.3 技能执行流 BossSkillSO + BossSkillExecutor ### 4.3 一招的数据流
``` ```
BossSkillSOCreateAssetMenu: BaseGames/Boss/BossSkill EnemyAbilitySOCreateAssetMenu: BaseGames/Enemies/Enemy Ability,前缀 ABL_
├── skillId / displayName ├── abilityId / designNote
├── BossSkillType(枚举) ├── attackSequence: EnemyAttackSO[] 一招内的多段
├── AttackPatternSO ├── cooldown 从执行结束起计
│ ├── DamageSourceDamageSourceSO ├── interruptOnHurt / interruptOnStagger 中断规则
│ ├── KnockbackAngle ├── category / weight / priority 选招器用
│ ├── 弹幕参数:ProjectilePrefab / Count / SpreadAngle / Speed ├── rangeRadius / rangeOffset 招式自管的圆形触发范围
│ ├── AoE 参数:Radius / Offset └── requiresGrounded / requiresLineOfSight 选招硬门
│ └── 时序:WindupDuration / ActiveDuration / RecoveryDuration
├── VulnerabilityWindowDuration 技能结束后弱点暴露时长(秒)
└── SkillSequenceSO(可选) 组合技序列(按顺序或随机排列多个 BossSkillSO
BossSkillExecutor.ExecuteSkill(BossSkillSO) EnemyAttackSO(前缀 EATK_)—— 一段动作的时间轴
│ if _isExecuting → return ├── clip: ClipTransitionAnimancer
├── hitBoxSlot / hitBoxEnterT / hitBoxExitT 判定开关的归一化时机
── StartCoroutine(ExecuteSkillCoroutine) ── damageSource: DamageSourceSO
├── _onBossSkillStarted.Raise(BossSkillEvent) ├── projectileConfig / projectileCount / projectileFireT
├── TelegraphSystem.ShowTelegraph(skill.pattern) 预兆提示激活 └── hasPoiseWindow / poiseLevel / poiseStartT / poiseEndT
├── WaitForSeconds(WindupDuration) 前摇等待
├── 激活 HitBox[] / ProjectileManager.Spawn(pattern) 伤害输出
├── WaitForSeconds(ActiveDuration) 活跃帧等待
├── 关闭 HitBox / 清理弹幕
├── WeakPointSystem.OpenWindow(VulnerabilityWindowDuration) 弱点窗口
├── WaitForSeconds(RecoveryDuration) 后摇等待
└── _onBossSkillEnded.Raise(BossSkillEvent)
WaitForSeconds 缓存 执行链
static Dictionary<float, WaitForSeconds> _wfsCache AI 图的攻击态 OnEnter
[RuntimeInitializeOnLoadMethod] ClearWFSCache() └── IAiContext.Combat.UseBestAttack()
→ 避免协程每次 new WaitForSeconds 的 GC 分配 └── EnemyAttackSelector 从 category==Attack 且 CanUse 的能力里选一个
CanUse 含 enabled、冷却、射程、grounded / LOS 硬门;
WeightedRandomAntiRepeat 模式对上次选中的招施加权重折扣)
└── EnemyAbilityBase.Execute():逐段播 clip
判定 / 生成 / 音效 / 无敌帧全部由 clip 上的动画事件驱动
EnemyAnimationEvents.HandleEvent
``` ```
**InterruptCurrentSkill()**:阶段切换时强制停止当前协程并调用 `FinishExecution()`,确保状态一致性。
--- ---
### 4.4 阶段切换 ### 4.4 阶段切换
``` ```
BD_IsHPBelow(每帧轮询 AI 图的条件边(如 x.Vitals.HpBelow(0.5f)
└── BossBase.IsHPBelow(ratio) = CurrentHP / MaxHP < ratio └── 转入阶段过渡态(BossFragments.PhaseTransition
→ true 时 BD 子树激活 BD_EnterPhase OnEnterLocomotion.Stop() + Combat.InterruptAbilities()
+ IBossControl.BeginPhaseTransition(targetPhase, invincibleDuration)
BD_EnterPhase → BossBase.EnterPhase(phase) BossBase.BeginPhaseTransition
├── _currentPhase = phase ├── IsPhaseTransitioning = true → IsInvincible 随之为真
├── BossPhaseEventChannelSO _onBossPhaseChanged.Raise(BossPhaseEvent{BossId, Phase}) ├── OnBeginPhaseTransition(targetPhase) [子类重写:浮空 / 过渡动画]
│ → Boss HP 条分段动画(UI) ├── 等待 invincibleDuration
│ → 音乐系统切换 BGM 段落 ├── EnterPhase(targetPhase)
→ VFX 场景效果触发 ├── _currentPhase = phase
└── [子类重写 EnterPhase] │ ├── BossPhaseAbilityGate.ApplyPhase(phase)
├── BossSkillExecutor.InterruptCurrentSkill() 打断当前技能 │ │ → 按阶段表设置各能力组件的 enabled
├── 切换 BD 行为树活跃子树(换招式库) │ │ → 被禁用的能力 CanUse 为 false,自动从选招器候选消失
── 播放阶段过渡动画(Animancer ── _onBossPhaseChanged.Raise(BossPhaseEvent{BossId, Phase})
└── 短暂无敌帧(保护阶段切换不被秒杀) │ → Boss HP 条分段动画 / BGM 段落切换 / 场景 VFX
└── IsPhaseTransitioning = false
→ AI 图上 .To(下一态).When(x => !x.Boss.IsPhaseTransitioning) 放行
``` ```
**阶段不是 SO 上的字段,也不是选招器里的过滤条件——阶段就是"哪些能力组件当前启用"。**
`BossBase.OnSpawn``ApplyPhase(0)`,保证对象池复用时回到初始招池。
作者写法详见 [`Docs/Guides/09_BossAi_Authoring_Guide.md`](../Guides/09_BossAi_Authoring_Guide.md)。
--- ---
## 5. 共享战斗层 Combat Module ## 5. 共享战斗层 Combat Module
@@ -613,10 +626,10 @@ StatusEffectEventChannelSO 广播效果开始/结束(UI 状态图标)
| `ProjectileConfigSO` | `BaseGames.Combat` | 投射物速度/碰撞层/生命时长/弹幕参数 | | `ProjectileConfigSO` | `BaseGames.Combat` | 投射物速度/碰撞层/生命时长/弹幕参数 |
| `EnemyStatsSO` | `BaseGames.Enemies` | 敌人 HP/Defense/速度/攻击冷却 | | `EnemyStatsSO` | `BaseGames.Enemies` | 敌人 HP/Defense/速度/攻击冷却 |
| `EnemyAnimationConfigSO` | `BaseGames.Enemies` | 敌人动画 Clip 集合 | | `EnemyAnimationConfigSO` | `BaseGames.Enemies` | 敌人动画 Clip 集合 |
| `AttackPatternSO` | `BaseGames.Enemies`(Boss) | 攻击图案:伤害/弹幕/AoE/时序 | | `EnemyAbilitySO` | `BaseGames.Enemies.Abilities` | 一招的全量配置(id/冷却/权重/射程/中断规则);小怪与 Boss 共用 |
| `BossSkillSO` | `BaseGames.Enemies`Boss | Boss 技能全量配置 | | `EnemyAttackSO` | `BaseGames.Enemies.Abilities` | 一段动作的时间轴(clip + 判定/弹体/霸体的归一化时机) |
| `SkillSequenceSO` | `BaseGames.Enemies`Boss) | Boss 组合技序列(有序/随机) | | `AiRecipeSO` | `BaseGames.Enemies` | 小怪 AI 配方(未发现层 + 交战层两个可插拔模块)。Boss 不用配方,走 `[AiDefinition]` 定制图 |
| `BossResourceConfigSO` | `BaseGames.Enemies`Boss | Boss 阶段资源(HP 阈值/技能池) | | `BossResourceConfigSO` | `BaseGames.Enemies`Boss | Boss 资源(怒气/充能)配置 |
**设计原则**:所有运行时组件在 `Awake` 中通过 `Initialize(SO)` 接收配置,与数据资产完全解耦,支持 Inspector 热替换和难度 A/B 测试,无需修改脚本代码。 **设计原则**:所有运行时组件在 `Awake` 中通过 `Initialize(SO)` 接收配置,与数据资产完全解耦,支持 Inspector 热替换和难度 A/B 测试,无需修改脚本代码。
+1 -1
View File
@@ -32,7 +32,7 @@
| [20](./20_ShieldModule.md) | 护盾模块 | ShieldComponent、ShieldConfigSO、IShieldable、护盾破碎/恢复管道 | 05、13 | | [20](./20_ShieldModule.md) | 护盾模块 | ShieldComponent、ShieldConfigSO、IShieldable、护盾破碎/恢复管道 | 05、13 |
| [21](./21_LiquidPuzzleModule.md) | 液体谜题模块 | LiquidZone、LiquidPhysicsConfigSO、SwimState、PuzzleSwitch/PuzzleReceiver、WorldMarker | 08、41 | | [21](./21_LiquidPuzzleModule.md) | 液体谜题模块 | LiquidZone、LiquidPhysicsConfigSO、SwimState、PuzzleSwitch/PuzzleReceiver、WorldMarker | 08、41 |
| [22](./22_QuestChallengeModule.md) | 任务与挑战模块 | QuestManager、QuestSO、QuestObjectiveSO、ChallengeRoom、QuestEventChannelSO | 37、38、39 | | [22](./22_QuestChallengeModule.md) | 任务与挑战模块 | QuestManager、QuestSO、QuestObjectiveSO、ChallengeRoom、QuestEventChannelSO | 37、38、39 |
| [23](./23_BossSkillModule.md) | Boss 技能模块 | BossSkillSOBossSkillExecutorSkillSequenceSO、VulnerabilityWindow、WeakPointSystem | 19、47、48 | | ~~23~~ | ~~Boss 技能模块~~ | **已于 2026-07-30 删除。** 旧 Boss 技能轨(`BossSkillSO` / `BossSkillExecutor` / `SkillSequenceSO` / `WeakPointSystem`)整体退役,Boss 与小怪统一走 `EnemyAbilitySO` + `EnemyAiBrain`。实现见 07;写法见 [`Docs/Guides/09_BossAi_Authoring_Guide.md`](../Guides/09_BossAi_Authoring_Guide.md) | 07 |
| [24](./24_AnimEventModule.md) | 动画事件模块 | PlayerAnimationEvents、EnemyAnimationEvents、AnimEventBridge、Animancer 事件回调 | 03 | | [24](./24_AnimEventModule.md) | 动画事件模块 | PlayerAnimationEvents、EnemyAnimationEvents、AnimEventBridge、Animancer 事件回调 | 03 |
--- ---
+20 -2
View File
@@ -1,8 +1,26 @@
# 19 · Boss 攻击模式库(Boss Pattern Library # 19 · Boss 攻击模式库(Boss Pattern Library
> **命名空间** `BaseGames.Enemies.Boss.Patterns`
> **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md) > **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md)
> **依赖** `BaseGames.Enemies` · `BaseGames.Combat` · `BaseGames.Feedback` · `BaseGames.Core.Events` · BehaviorDesigner · Animancer > **文档性质** 设计意图文档
---
> ## ⚠️ 本文描述的实现方案已废止(2026-07-30)
>
> 文中的 `AttackPatternSO` / `BossOrchestrator` / `TelegraphSystem` 三个类型**从未落地**
> 并已随旧 Boss 技能轨一并退役。当前实现:
>
> | 本文提出的 | 实际由谁承担 |
> |---|---|
> | `AttackPatternSO`(攻击模式数据层) | `EnemyAbilitySO` + `EnemyAttackSO`(小怪与 Boss 共用一套) |
> | `BossOrchestrator`(运行时编排器) | `EnemyAiBrain` 上的 `AiScript` 定制图;选招归 `EnemyAttackSelector` |
> | `TelegraphSystem`(预警系统) | 动画时间轴:预警是 clip 的一段,判定/VFX/音效/无敌帧全挂动画事件 |
> | 阶段切换换招池 | `BossPhaseAbilityGate`(按阶段启停能力组件) |
>
> **本文的设计意图(攻击模式的节奏分层、预警的可读性、阶段递进的学习曲线)仍然有效**
> 但类型名与代码结构一律以下列文档为准:
> - [`Docs/Guides/09_BossAi_Authoring_Guide.md`](../Guides/09_BossAi_Authoring_Guide.md)(作者指南)
> - `Docs_Dev/superpowers/specs/2026-07-30-boss-ai-single-track-design.md`(设计依据)
--- ---
+1 -1
View File
@@ -1,7 +1,7 @@
# 69 · Boss 设计圣经(Boss Design Bible # 69 · Boss 设计圣经(Boss Design Bible
> **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md) > **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md)
> **关联文档** 19_BossPatternLibrary · 47_BossSkillSystem · 60_Lore_WorldBible · 63_AudioCreativeDirection · 48_EnemyRoster > **关联文档** 19_BossPatternLibrary · 60_Lore_WorldBible · 63_AudioCreativeDirection · 48_EnemyRoster · 实现写法见 [`Docs/Guides/09_BossAi_Authoring_Guide.md`](../Guides/09_BossAi_Authoring_Guide.md)(原 47_BossSkillSystem 已于 2026-07-30 废止)
> **文档性质** 每个 Boss 的独立设计规格。包含攻击序列、阶段结构、学习曲线、叙事角色、死亡设计。19_BossPatternLibrary 是工具,本文档是作品。 > **文档性质** 每个 Boss 的独立设计规格。包含攻击序列、阶段结构、学习曲线、叙事角色、死亡设计。19_BossPatternLibrary 是工具,本文档是作品。
--- ---
+1 -1
View File
@@ -57,7 +57,7 @@
| 44 | [关卡设计指南](./44_LevelDesignGuide.md) | 房间尺寸规范、难度曲线与节奏、敌人布置原则、危险物规范、收集品与秘密房间设计、平台路径参数、房间连通性、视觉叙事、Tilemap SOP、关卡验收清单 | | 44 | [关卡设计指南](./44_LevelDesignGuide.md) | 房间尺寸规范、难度曲线与节奏、敌人布置原则、危险物规范、收集品与秘密房间设计、平台路径参数、房间连通性、视觉叙事、Tilemap SOP、关卡验收清单 |
| 45 | [教程与情境提示系统](./45_TutorialSystem.md) | ContextualHintTrigger、AbilityTutorialSequence、InGameHintPanel、TooltipPopup、TutorialManager、SaveData 集成(seenHints[])、多语言支持 | | 45 | [教程与情境提示系统](./45_TutorialSystem.md) | ContextualHintTrigger、AbilityTutorialSequence、InGameHintPanel、TooltipPopup、TutorialManager、SaveData 集成(seenHints[])、多语言支持 |
| 46 | [平台发布集成指南](./46_PlatformIntegration.md) | IPlatformService 抽象接口、Steam PC/Deck 集成、Steamworks.NET 成就桥接、Steam Cloud 存档同步、Steam Rich Presence、多平台手柄振动适配、构建配置、发布验收清单 | | 46 | [平台发布集成指南](./46_PlatformIntegration.md) | IPlatformService 抽象接口、Steam PC/Deck 集成、Steamworks.NET 成就桥接、Steam Cloud 存档同步、Steam Rich Presence、多平台手柄振动适配、构建配置、发布验收清单 |
| 47 | [Boss 技能系统框架](./47_BossSkillSystem.md) | BossSkillSO 数据层、技能分类体系(BossSkillCategory + InteractionTag)、脆弱窗口系统、玩家反制接口(PlayerCounterResponse)、技能序列系统(SkillSequenceSO)、Boss 资源/愤怒系统、场景联动接口(ArenaEventBus)、平衡数据模板、编辑器工作流 | | ~~47~~ | ~~Boss 技能系统框架~~ | **已于 2026-07-30 删除。** 该框架从未实现,且已被"Boss 与小怪单轨统一"取代:招式即能力(`EnemyAbilitySO`),阶段即招池(`BossPhaseAbilityGate`),决策即 AI 图(`EnemyAiBrain`)。作者指南见 [`Docs/Guides/09_BossAi_Authoring_Guide.md`](../Guides/09_BossAi_Authoring_Guide.md) |
| 48 | [敌人图鉴](./48_EnemyRoster.md) | 5 区域 × 6-7 只普通敌人 + 5 只区域精英怪完整设计、AI 复杂度分级(T1-T4)、弹反标记、掉落表、房间编队配置建议 | | 48 | [敌人图鉴](./48_EnemyRoster.md) | 5 区域 × 6-7 只普通敌人 + 5 只区域精英怪完整设计、AI 复杂度分级(T1-T4)、弹反标记、掉落表、房间编队配置建议 |
| 49 | [防软锁系统](./49_AntiSoftlockSystem.md) | SoftlockDetector45s 无移动检测)、EscapeTeleporter(安全传送回存档点)、RoomEscapeInfoSO(每间房逃生路线)、HardAbilityGate(高风险门扩展)、EscapeGuaranteeValidatorBFS 可达性编辑器工具)| | 49 | [防软锁系统](./49_AntiSoftlockSystem.md) | SoftlockDetector45s 无移动检测)、EscapeTeleporter(安全传送回存档点)、RoomEscapeInfoSO(每间房逃生路线)、HardAbilityGate(高风险门扩展)、EscapeGuaranteeValidatorBFS 可达性编辑器工具)|
| 50 | [叙事设计系统](./50_NarrativeDesignSystem.md) | NarrativeNodeSO 故事节点、WorldStateRegistry 全局状态标志、NarrativeNPC+DialogueVersion 世界状态对话版本、NPCMigrationConfigSO、LoreItemSO(题记/遗物/回忆/回响碎片)、EndingGate 结局评估、5阶段叙事弧线、NPC 迁移路线表 | | 50 | [叙事设计系统](./50_NarrativeDesignSystem.md) | NarrativeNodeSO 故事节点、WorldStateRegistry 全局状态标志、NarrativeNPC+DialogueVersion 世界状态对话版本、NPCMigrationConfigSO、LoreItemSO(题记/遗物/回忆/回响碎片)、EndingGate 结局评估、5阶段叙事弧线、NPC 迁移路线表 |
+5 -1
View File
@@ -7,6 +7,10 @@
其中约 95% 只需建一个配方资产、两个下拉选一选,零代码零编译。读完本文档应该能在 5 分钟内判断 其中约 95% 只需建一个配方资产、两个下拉选一选,零代码零编译。读完本文档应该能在 5 分钟内判断
「我这个敌人该走哪条路径」,并在动手前看到已知的坑。 「我这个敌人该走哪条路径」,并在动手前看到已知的坑。
> **要写的是 Boss** Boss 与小怪跑同一条轨(同一套能力、同一个选招器、同一个 `EnemyAiBrain`),
> 但一律走定制脚本路径,另有阶段门与竞技场锚点等专属件。
> 先读完本文的 §2 / §6,再看 [09_BossAi_Authoring_Guide](09_BossAi_Authoring_Guide.md)。
--- ---
## 目录 ## 目录
@@ -141,7 +145,7 @@ Build(b):
### E004 蛭母 —— 定制脚本路径(Boss,多技能轮转 + 出场演出) ### E004 蛭母 —— 定制脚本路径(Boss,多技能轮转 + 出场演出)
出场剧情 → 三技能轮转(撕咬/头槌连段/酸液远程,按距离和 CD/权重选择)→ 死亡分两阶段(挣扎前摇 → 爆体)。技能选择逻辑(按距离分层、CD 轮转)比 `ApproachAttackEngagement` 复杂得多,且需要「玩家绕后触发 Flip、但技能执行中不检测」这类与感知骨架无关的定制转换,属于"完全定制"的判据(与范式无关的独门机制)。Boss 是否要接入 `PerceptionSkeleton` 视具体实现取舍:若拆出"未发现(几乎不存在,出场即战斗)→ 交战(技能轮转视为一个大号 `Attack` 态)"两层意义不大,直接写定制脚本更直接。死亡链遵循 [§6](#6-常见陷阱) 的死亡规则,`Death_Pre`/`Death` 完全交给物理层(`EnemyDeathSequence` 演出 + `EnemyBase.PerformDeath`),AI 图里只需要一个 `Death` 终态兜住全局边。 出场剧情 → 三技能轮转(撕咬/头槌连段/酸液远程,按距离和 CD/权重选择)→ 死亡分两阶段(挣扎前摇 → 爆体)。技能选择逻辑(按距离分层、CD 轮转)比 `ApproachAttackEngagement` 复杂得多,且需要「玩家绕后触发 Flip、但技能执行中不检测」这类与感知骨架无关的定制转换,属于"完全定制"的判据(与范式无关的独门机制)。Boss 是否要接入 `PerceptionSkeleton` 视具体实现取舍:若拆出"未发现(几乎不存在,出场即战斗)→ 交战(技能轮转视为一个大号 `Attack` 态)"两层意义不大,直接写定制脚本更直接。死亡链遵循 [§6](#6-常见陷阱) 的死亡规则,`Death_Pre`/`Death` 完全交给物理层(`EnemyDeathSequence` 演出 + `EnemyBase.PerformDeath`),AI 图里只需要一个 `Death` 终态兜住全局边。Boss 图的写法(建态原语、阶段门、开战触发)见 [09_BossAi_Authoring_Guide](09_BossAi_Authoring_Guide.md),已落地的 `ChaoFengAi` 是完整范例。
### E005 肥蛭 —— 配方路径(精英怪,攻击选择器覆盖远近两招) ### E005 肥蛭 —— 配方路径(精英怪,攻击选择器覆盖远近两招)
+424
View File
@@ -0,0 +1,424 @@
# Boss AI 作者指南
> 文件位置:`Docs/Guides/09_BossAi_Authoring_Guide.md`
> 版本:1.0 · 适用项目:zeling_v2
> 前置阅读:[08_EnemyAi_Authoring_Guide](08_EnemyAi_Authoring_Guide.md)(术语、建态原语、常见陷阱在那边讲过,本文不重复)
本文面向**给项目新增一个 Boss 的人**。核心结论只有一句:
> **Boss 与小怪跑的是同一条轨。** 同一套能力(`EnemyAbilitySO` + `EnemyAbilityBase`)、同一个选招器
> `EnemyAttackSelector`)、同一套建态原语(`AiStateFragments`)、同一个决策层组件(`EnemyAiBrain`)。
> Boss 独有的只有三样:**手写的 `AiScript` 图**、**一个 `IBossControl` 决策面(阶段 + 竞技场锚点)**、
> 以及几个旁挂的 MonoBehaviour(阶段门 / 锚点 / 开战触发)。
不存在"Boss 技能系统"这种独立体系。招式就是能力,阶段就是招池,没有第二套数据模型。
---
## 目录
1. [Boss 走定制路径](#1-boss-走定制路径)
2. [可用的建态原语](#2-可用的建态原语)
3. [阶段 = 换招池](#3-阶段--换招池)
4. [一招怎么配](#4-一招怎么配)
5. [开战怎么触发](#5-开战怎么触发)
6. [死亡不在 AI 层](#6-死亡不在-ai-层)
7. [完整范例:嘲风](#7-完整范例嘲风)
8. [Boss 专属陷阱](#8-boss-专属陷阱)
9. [创建链路与自检](#9-创建链路与自检)
---
## 1. Boss 走定制路径
小怪有三条作者路径(配方 / 配方+前置态 / 定制脚本,见 08 号指南 §1)。**Boss 一律走第三条:定制脚本。**
理由不是"Boss 更高级",而是数量与形状:Boss 只有个位数,彼此差异极大(有的浮空、有的分身、有的换竞技场),
把这些差异塞进可插拔模块的下拉里,只会产生一堆各用一次的模块类。手写图更直接、可读性更好,
且改一个 Boss 不会波及另一个。
写法:
```csharp
using BaseGames.AI;
namespace BaseGames.Enemies
{
[AiDefinition("<BossId>")] // ← id 字符串,全项目唯一
public sealed class XxxAi : AiScript
{
protected override void Build(BrainBuilder b) { /* 整张图写在这里 */ }
}
}
```
放在 `Assets/_Game/Scripts/Enemies/AIBrain/Ai/` 下。
接线:Boss 物体上的 `EnemyAiBrain` 组件,**`_definitionId` 填上面那个 id`_recipe` 留空**。
两者是二选一,`EnemyAiBrain.Awake` 做互斥校验——两个都配或都不配会 `Debug.LogError` 并禁用组件。
id 由 `AiDefinitionRegistry` 反射收集所有 `[AiDefinition]``AiScript` 子类解析,重复 id 在进入 Play 时直接抛异常。
`AiGraph` 按 id 共享缓存:同一个 `AiScript` 只建一次图,所有实例共用。
**直接后果:`Build()` 里的 lambda 绝对不能闭包捕获具体实例**(组件、Transform、Boss 引用一概不行),
一切实例数据只能经 `IAiContext x` 参数取。第 8 节还会再提一次,因为这是 Boss 图最容易踩的坑。
---
## 2. 可用的建态原语
建态原语是静态方法,不是可插拔模块——不需要 `[Serializable]`、不进 Inspector 下拉,直接调用。
### 2.1 通用原语 `AiStateFragments`
`Assets/_Game/Scripts/Enemies/AIBrain/Modules/AiStateFragments.cs`
| 方法 | 语义 | 用在哪 |
|---|---|---|
| `Locomotion(b, state, mode)` | 进入 / 每帧声明移动意图,离开时停。`mode``LocomotionMode.Idle` / `Face` / `Patrol` / `Pursue`。 | 静置等待、悬停朝向玩家、走位 |
| `Ability(b, state, abilityId)` | 每帧 `EnsureAbility`:能力被受击打断后,下一帧自动重新触发。 | "只要还在这个态就该一直在做"的持续态(冲锋、追击) |
| `AbilityOnce(b, state, abilityId)` | 只在 `OnEnter` 触发一次,不每帧重触发。 | 一次性演出(入场、变身),**用 `Ability` 会无限重播** |
| `Terminal(b, state)` | 无行为终态。 | 死亡态 |
| `LostAllZones`(字段) | 共享条件:脱离全部感知区。 | 小怪脱战边;**Boss 一般不用**(见 §8) |
### 2.2 Boss 原语 `BossFragments`
`Assets/_Game/Scripts/Enemies/AIBrain/Modules/BossFragments.cs`
| 方法 | 语义 |
|---|---|
| `PhaseTransition(b, state, targetPhase, invincibleDuration)` | 阶段过渡态:`OnEnter` 停移动 + 中断能力 + 调 `IBossControl.BeginPhaseTransition`。**刻意不带出边**——调用方必须自己挂 `.To(下一态).When(x => !x.Boss.IsPhaseTransitioning)`,忘了挂 Boss 会永久锁死。`targetPhase < 0``invincibleDuration <= 0` 在建图期抛异常。 |
| `ApproachAttack(b, approach, attack, rest)` | 一组「寻路逼近 ↔ 到射程选招攻击」。转发到 `ApproachAttackEngagement.Declare` 的**同一份实现**,所以小怪的交战模块与 Boss 图行为永远一致。返回**逼近态**的 builder,可继续挂阶段过渡等出边。 |
| `MoveToAnchor(b, state, index)` | 移动到第 `index` 个竞技场锚点(`BossArenaAnchors`),到位后由调用方挂出边。 |
| `AtAnchor(index, tolerance = 0.2f)` | 共享条件:已到达第 `index` 个锚点。配合上一条用。 |
### 2.3 Boss 决策面 `IBossControl`
`Assets/_Game/Scripts/AI/IBossControl.cs`。图里经 `x.Boss` 访问,由 `BossBase` 实现。
| 成员 | 用途 |
|---|---|
| `CurrentPhase` | 当前阶段索引(出生为 0 |
| `IsPhaseTransitioning` | 是否处于阶段过渡(无敌 + 演出)期间 |
| `ResourceFull` | Boss 资源(怒气 / 充能)是否已满。未挂资源组件时**抛异常**——图问了资源却没配组件是配置错误,不静默返回 false |
| `BeginPhaseTransition(targetPhase, invincibleDuration)` | 发起阶段过渡。过渡中重复调用会被忽略并告警,所以只能放 `OnEnter`,不能放 `Tick` |
| `AnchorAt(index)` / `DistanceToAnchor(index)` | 竞技场锚点坐标 / 距离。漏配组件或下标越界即抛 |
**非 Boss 敌人访问 `x.Boss` 会抛异常**`EnemyBrainContext` 里显式失败),这是有意的——
在小怪图里误用 Boss 语义应当立刻炸掉,而不是拿到一个假的默认值。
---
## 3. 阶段 = 换招池
阶段不是 SO 上的一个字段,也不是选招器里的一个过滤条件。**阶段就是"哪些能力组件当前是启用的"。**
承载它的是 `BossPhaseAbilityGate``Assets/_Game/Scripts/Enemies/Boss/BossPhaseAbilityGate.cs`),
挂在 Boss 根节点上,Inspector 里配一张表:
| 列 | 含义 |
|---|---|
| `ability` | 受阶段管控的能力组件(`EnemyAbilityBase` |
| `phases` | 该能力可用的阶段索引数组;**留空 = 全阶段可用** |
`ApplyPhase(phase)` 把该阶段的启用集刷到所有登记的能力上:`ability.enabled = 该阶段是否放行`
这条链之所以成立,是因为 `EnemyAbilityBase.CanUse``enabled` 纳入了判据——
被禁用的能力自动从 `EnemyAttackSelector` 的候选里消失。**阶段门不需要碰选招器,选招器也不知道阶段的存在。**
调用时机由 `BossBase` 直接驱动(不订阅事件频道,保证与阶段切换严格同序):
- `BossBase.OnSpawn()``ApplyPhase(0)`(对象池复用时回到初始招池)
- `BossBase.EnterPhase(phase)``ApplyPhase(phase)`
**不要在 `EnemyAbilitySO` 上写阶段字段。** SO 描述的是"这一招是什么",不是"什么时候能用"。
未登记在阶段表里的能力不受阶段门影响,保持自身启用状态——入场演出、位移类能力通常就这么放着。
表里某行漏配能力组件会在 `OnValidate``Debug.LogError` 点名行号。
---
## 4. 一招怎么配
一招 = 一个 `EnemyAbilitySO` 资产 + 一个挂在 Boss 上的 `EnemyAbilityBase` 子类组件(+ 若干 `EnemyAttackSO`)。
与小怪完全一致,没有 Boss 专用的招式资产类型。
### 4.1 `EnemyAbilitySO``ABL_` 前缀)
`CreateAssetMenu: BaseGames/Enemies/Enemy Ability`
| 字段 | 说明 |
|---|---|
| `abilityId` | 全小写英文 + 下划线,图里 `x.Combat.IsAbilityRunning("...")` 按它匹配 |
| `designNote` | 设计备注,只给编辑器看,不影响运行 |
| `attackSequence` | `EnemyAttackSO[]`,一招内的多段(如三连挥扇 = 3 个) |
| `cooldown` | 冷却(秒),从**执行结束**开始计 |
| `interruptOnHurt` / `interruptOnStagger` | 中断规则;`interruptOnHurt = false` 即该招自带霸体 |
| `category` | `AbilityCategory.Attack` 的才进选招器候选 |
| `weight` / `priority` | 选招权重与优先级 |
| `rangeRadius` / `rangeOffset` | **招式自管的圆形触发范围**`category == Attack` 时必须 `> 0`,否则永远够不着(`Awake` 报错) |
| `requiresGrounded` | 选招器的**硬门**。Boss 浮空阶段 `IsGrounded` 恒为 false,空中招留默认 `true` 会永远选不中 |
| `requiresLineOfSight` | 同上,视线硬门 |
| `exclusionGroup` | 互斥组,同组能力不能同时执行 |
需要额外可配参数(动画 / 数值 / LayerMask)的招,建 `EnemyAbilitySO` 的**类型化子类**
由能力组件的 `ResolveConfig<T>()` 解析;类型不符显式报错,不做兜底。场景引用(发射点 Transform 等)留在组件上,不进 SO。
### 4.2 `EnemyAttackSO``EATK_` 前缀)
一段动作的时间轴描述。**判定 / 生成 / 音效 / 无敌帧全部挂在动画 clip 的归一化时机上,不写在代码里。**
| 字段 | 说明 |
|---|---|
| `clip` | Animancer `ClipTransition`。**留空则该段瞬间完成**(见 §8 与 §9 的已知缺口) |
| `fallbackDuration` | 无 clip 时的兜底时长 |
| `hitBoxSlot` / `hitBoxEnterT` / `hitBoxExitT` | 命中框开关的归一化时机(0–1) |
| `damageSource` | `DamageSourceSO` |
| `projectileConfig` / `projectileCount` / `spreadAngleDeg` / `projectileFireT` | 弹体招的发射参数与时机 |
| `hasPoiseWindow` / `poiseLevel` / `poiseStartT` / `poiseEndT` | 霸体窗口 |
| `lockMovement` / `postDelay` | 收招锁移动 / 后摇 |
### 4.3 动画事件
`EnemyAnimationEvents.HandleEvent(AnimationEventType, string payload)` 支持:
`EnableHitBox` / `DisableHitBox` / `EnableIFrame` / `DisableIFrame` / `SpawnProjectile` /
`RoarStart` / `RoarEnd` / `PhaseTwoStart` / `TriggerFeedback` / `PlaySFX` / `AnimationComplete`
弹体招的判定跟着 `SpawnProjectile` 生成的弹体走,**Boss 身上不留对应 HitBox**——
留一个无人引用的 HitBox 会让下一个作者误以为该招判定挂在 Boss 身上。
### 4.4 防重复选招
`EnemyAttackSelector` 新增了 `AttackSelectionMode.WeightedRandomAntiRepeat`
`WeightedRandom`,但对上一次选中的招施加权重折扣,压低连续重复。
折扣系数配在 `EnemyStatsSO.attackAntiRepeatFactor`(0–1)。Boss 招池小、重复感明显,建议开启。
---
## 5. 开战怎么触发
Boss 出生停在静置态(`LocomotionMode.Idle`),**不巡逻、不搜敌**——等玩家进场。
把它叫醒的是 `BossFightTrigger``Assets/_Game/Scripts/Enemies/Boss/BossFightTrigger.cs`),
放在 Boss 房间入口的触发区上(`Collider2D` + `isTrigger`),只触发一次。
玩家进入时它做三件事:
```
_onBossFightStarted.Raise(bossId) // EVT_BossFightStarted:全局状态机 / 后处理 / HUD
_onBossFightToggled.Raise(true) // EVT_BossFightEnded(布尔开关):血条与 BGM
_bossBrain.Send(AiSignal.Engaged) // ← 决策层从静置态进战
```
图里对应的边:
```csharp
AiStateFragments.Locomotion(b, Wait, LocomotionMode.Idle)
.To(Intro).OnEvent(AiSignal.Engaged);
```
`AiSignal` 现有两个值:`Died``Engaged`。受击 / 硬直**不进 AI 图**(见 08 号指南 §6 第 5 条)。
漏配处理:`BossFightTrigger.Awake` 逐条点名报错(触发器未勾 Is Trigger、未指定 Brain、未填 bossId、
两个频道、玩家层掩码为空),任一缺失就整体禁用组件——不做"缺谁跳过谁"的部分执行,
因为半开的战斗(有 BGM 没血条、Boss 不动)比彻底不开更难查。
---
## 6. 死亡不在 AI 层
与小怪同一条规则,原因见 08 号指南 §6 第 3 条:`EnemyBase.PerformDeath``ForceState(Dead)`
之后 `IsControllable` 永久为假,`AiRuntime.Tick` 在让位门处直接 `return`
**任何条件边都不会再被求值**。所以死亡链一条条件边都不能放。
图里只需要两行:
```csharp
AiStateFragments.Terminal(b, Death);
b.Global().To(Death).OnEvent(AiSignal.Died);
```
演出全部归物理层:`EnemyDeathSequence`(前摇演出,`_stopDecisionLayer` 勾上则调 `EnemyBase.NotifyDecisionStop()`)、
`EnemyBase.PerformDeath`(关碰撞体、对象池归还)、具体 Boss 的击败序列(如 `ChaoFengBoss` 里的 `NotifyDecisionStop()`)。
`BossBase` 在死亡时会立即中止阶段过渡(`IsPhaseTransitioning = false`),
防止该标志永久锁死影响对象池复用。
---
## 7. 完整范例:嘲风
`Assets/_Game/Scripts/Enemies/AIBrain/Ai/ChaoFengAi.cs` —— 整张图 30 行,逐段拆解。
### 7.1 态与常量
```csharp
[AiDefinition("ChaoFeng")]
public sealed class ChaoFengAi : AiScript
{
public const string Wait = "Wait", Intro = "Intro";
public const string Ground = "Ground", GroundAttack = "GroundAttack";
public const string PhaseTx = "PhaseTransition";
public const string Air = "Air", AirAttack = "AirAttack";
public const string Death = "Death";
public const string IntroAbility = "chaofeng_intro"; // 与 ABL_ChaoFeng_Intro.abilityId 一致
private const float AirPhaseHpRatio = 0.5f; // 50% 血进空中阶段
private const int AirPhaseIndex = 1;
private const float PhaseTxInvincible = 2f; // 须 ≥ 浮空上升时长 + 缓冲
```
态名用 `public const string` 而不是字面量,是为了让 EditMode 测试(`ChaoFengAiTests`)能断言状态序列
而不靠拼字符串。态名本身只是 trace 标签,不驱动动画。
### 7.2 静置 → 入场
```csharp
b.Entry(Wait);
AiStateFragments.Locomotion(b, Wait, LocomotionMode.Idle)
.To(Intro).OnEvent(AiSignal.Engaged); // ← BossFightTrigger 发的信号
AiStateFragments.AbilityOnce(b, Intro, IntroAbility)
.To(Ground).When(x => !x.Combat.IsAbilityRunning(IntroAbility), "introDone");
```
入场用 `AbilityOnce` 而非 `Ability`:入场是一次性演出,用 `Ability` 会被每帧 `Tick` 无限重播、永远退不出去。
### 7.3 阶段 0(地面):逼近 ↔ 选招
```csharp
BossFragments.ApproachAttack(b, Ground, GroundAttack, rest: Ground)
.To(PhaseTx).When(x => x.Vitals.HpBelow(AirPhaseHpRatio), "hp<50%");
```
一行建两个态:`Ground``Locomotion.Pursue` 逼近)与 `GroundAttack``Combat.UseBestAttack()` 出招)。
`rest: Ground` 指回自身——**Boss 不脱战**,玩家跑出感知区 Boss 也不回静置态。
`ApproachAttack` 返回的是**逼近态**的 builder,所以后面 `.To(PhaseTx)` 挂在 `Ground` 上:
血量掉到 50% 时从逼近态切阶段。攻击态不挂这条边,是为了"起手就打完"(见 7.6)。
选哪一招不在图里——`Combat.UseBestAttack()` 交给 `EnemyAttackSelector`
射程 / 冷却 / 权重全在各能力自己的 `EnemyAbilitySO` 上。
### 7.4 阶段过渡
```csharp
BossFragments.PhaseTransition(b, PhaseTx, AirPhaseIndex, PhaseTxInvincible)
.To(Air).When(x => !x.Boss.IsPhaseTransitioning, "txDone");
```
`PhaseTransition` 片段**故意不自带出边**,这条 `txDone` 就是它唯一的出口——**删了 Boss 会永久锁死**
`BrainBuilder.Build()` 目前不校验"非终态是否有出边",见 §8)。
过渡期间的无敌与浮空演出由 Boss 侧承担:`BossBase.BeginPhaseTransition``IsPhaseTransitioning = true`
`IsInvincible` 随之为真),走完 `invincibleDuration` 后调 `EnterPhase(1)``BossPhaseAbilityGate.ApplyPhase(1)`
→ 地面四招被禁用、风石招被放行,最后清 `IsPhaseTransitioning`,图上这条边才放行。
### 7.5 阶段 1(空中):悬停 ↔ 选招
```csharp
AiStateFragments.Locomotion(b, Air, LocomotionMode.Face)
.To(AirAttack).When(x => x.Combat.HasEligibleAttack(), "attackInRange");
b.DeclareState(AirAttack)
.OnEnter(x => { x.Locomotion.Stop(); x.Combat.UseBestAttack(); })
.OnExit (x => x.Combat.InterruptAbilities())
.To(Air).When(x => !x.Combat.IsAbilityRunning(), "attackDone");
```
空中阶段不需要寻路逼近(浮空 + 远程招),所以不用 `ApproachAttack`,改成 `Face`(原地朝向玩家)+ 手写攻击态。
攻击态的形状与 `ApproachAttack` 生成的完全一致,只是逼近换成了悬停。
**刻意没有回地面阶段的边**——阶段单向推进,血量回升也不退阶段(招池已经换了)。
### 7.6 死亡
```csharp
AiStateFragments.Terminal(b, Death);
b.Global().To(Death).OnEvent(AiSignal.Died);
```
### 7.7 三条刻意的形状(改图时别顺手抹掉)
1. **Boss 不脱战** —— 逼近态的 `rest` 指回自身。
2. **阶段单向推进** —— 空中阶段没有回地面阶段的边。
3. **起手就打完** —— 攻击态不挂脱战边、不挂阶段边,前摇中玩家跑开仍完整打完。
观感上比"起手到一半凭空收招"合理,也避免了在能力执行途中切阶段导致的状态撕裂。
这三条在源码注释里也写了一遍,因为它们看起来都像"漏挂了一条边"。
---
## 8. Boss 专属陷阱
08 号指南 §6 的七条陷阱**全部适用**,以下是 Boss 图额外的。
1. **`Build()` 的 lambda 不能闭包捕获实例。**
`AiGraph``[AiDefinition]` id 共享缓存,一张图被所有实例共用。捕获了某个具体 Boss 的组件引用,
第二个实例就会去驱动第一个实例。锚点坐标要经 `x.Boss.AnchorAt(i)` 取,不能捕获 `Transform`——
`BossFragments.MoveToAnchor` 存在的理由正是这个。
2. **`PhaseTransition` 不带出边,必须自己挂。**
`BrainBuilder.Build()` 只校验"边指向的态是否已声明",**不校验"已声明的非终态是否有出边"**。
一个没有出边的非终态会让 Boss 永久卡住且**零报错**。阶段过渡态是这类风险的头号候选。
(补上这项校验是已记录的待办,见 §9。)
3. **浮空阶段的招不能留 `requiresGrounded = true`。**
Boss 浮空时 `IsGrounded` 恒为 false,该字段是选招器的硬门,留默认值会让整个空中招池永远选不中——
表现为"Boss 悬停着什么都不做",且没有任何报错。
4. **阶段过渡的无敌时长必须覆盖演出。**
`PhaseTxInvincible` 须 ≥ 浮空上升时长 + 缓冲。配短了 Boss 会在还没升到位时就恢复可受击并进入下一阶段。
`invincibleDuration <= 0` 在建图期就抛异常(0 意味着过渡演出期间可被打断,那不是阶段过渡的语义)。
5. **`BeginPhaseTransition` 只能在 `OnEnter` 调,不能在 `Tick`。**
过渡进行中重复调用会被忽略并告警。`BossFragments.PhaseTransition` 已经把它放在 `OnEnter`
手写阶段态时别照抄成 `Tick`
6. **Boss 的脱战语义与小怪相反。**
小怪模块默认挂 `LostAllZones` 脱战边,Boss 一般不挂。别因为"小怪都这么写"就顺手加上。
7. **`x.Boss` 在非 Boss 上会抛异常。**
这是设计如此。把 Boss 原语复制到小怪图里时会立刻炸掉,而不是拿到假数据。
---
## 9. 创建链路与自检
**不要裸建**CLAUDE.md 第 2 条)。两条脚手架已经按新轨重建:
| 目的 | 入口 |
|---|---|
| 建 Boss 的 SO 资产(`EnemyStatsSO` / `EnemyAnimationConfigSO` / 各 `EnemyAbilitySO` | 菜单 `BaseGames/Data/Character Wizard`**Boss** 标签页 |
| 在场景里放 Boss 完整组件树 | 菜单 `BaseGames/Scene/Place/Boss 嘲风 (ChaoFeng)``SceneObjectPlacerTool.PlaceChaoFeng` |
| 放开战触发区 | 菜单 `BaseGames/Scene/Place/Boss 开战触发区 (嘲风)``SceneObjectPlacerTool.PlaceBossFightTrigger(bossId)` |
| 存成预制体 | 菜单 `BaseGames/Scene/Save Prefab/Boss 嘲风 (ChaoFeng)` |
放置器产出的组件树(嘲风为例):`ChaoFengBoss`(继承 `BossBase`) + `EnemyStats` + `EnemyFeedback` +
`EnemyMovement` + `GroundNavigator` + `EnemyLocomotion` + `EnemyAiBrain` + `BossPhaseAbilityGate` +
`PhysicsPerceptionSystem` + 演出组件 + `HurtBox` / `ContactDamageZone` / 各招 `HitBox` / 弹体发射点。
> `EnemyLocomotion` 是必需的:AI 图的全部移动意图靠它落地。缺了它 `AiStateFragments` 建态时 NRE、
> `AiRuntime` 构造失败,Boss 完全不动。
新增一个 Boss 时,把上述放置器复制一份改名,**不要**在场景里手工 `AddComponent` 拼——
脚手架保证了层、命名、事件频道绑定符合规范。
建完跑三项自检(CLAUDE.md 第 3 条):
```
菜单栏 → BaseGames → Tools → Validation → Validate All ScriptableObjects
菜单栏 → BaseGames → Addressables → Validate Address Keys
菜单栏 → BaseGames → Tools → Maintenance → Physics2D Layer Matrix → Check
```
### 已知缺口(写 Boss 时会碰到)
| 缺口 | 影响 |
|---|---|
| **动画 clip 尚未接入** | `EnemyAttackSO.clip` 留空时该段瞬间完成。目前 Boss 的招"能选中、能跑完、能回到逼近态",但**判定时机、伤害、手感一律未经验证**。clip 到位后必须重新校时序 |
| **`EnemyHurtState` 无受击动画时永久卡死** | `Enter``AnimConfig.Hurt` 为空时提前返回且不安排回到 `Controlled`,敌人被打一次就永久停在 `Hurt``IsControllable` 恒假、AI 永久停摆。当前美术未接入 = 大部分敌人一挨打就废。**优先级最高的已知缺陷** |
| **池化敌人复活带着上一条命的冷却** | `EnemyBase.OnSpawn` 的中断调用注释写着"重置能力冷却"但实际没重置 |
| **`BrainBuilder.Build()` 不校验"非终态有无出边"** | 见 §8 第 2 条 |
| **`EnemyBase.ReceiveParry` 无调用方** | 伤害管线不带攻击者引用,"谁被弹反谁硬直"暂时接不上。旧的 Boss 侧弹反反制已删除(它的行为是"玩家弹反任意敌人都会让 Boss 硬直",是错的),属于**有意的移除且暂无替代** |
| **能力资产没有编辑器总览视图** | 需要一个 `EnemyAbilityModule` 编辑器窗口,尚未编写 |
| **没有 `AiDefinitionValidator`** | 能力引用漏配 / 拼错目前只能在 Play Mode 里靠肉眼排查 |
-1
View File
@@ -857,7 +857,6 @@ var (prefab, _) = await AssetLoader.LoadAsync<GameObject>(AddressKeys.PrefabPlay
| **Character Wizard** | `BaseGames/Data/Character Wizard` | 角色 SO(玩家形态 / Minion / Boss 通用入口) | 统一入口,自动在正确路径创建所有配套 SO,内含快捷跳转按钮 | | **Character Wizard** | `BaseGames/Data/Character Wizard` | 角色 SO(玩家形态 / Minion / Boss 通用入口) | 统一入口,自动在正确路径创建所有配套 SO,内含快捷跳转按钮 |
| **Form Editor** | `BaseGames/Data/Form Editor` | 玩家三魂形态(FormSO) | 三栏可视化网格,自动绑定武器/技能引用,支持 TianHun / DiHun / MingHun | | **Form Editor** | `BaseGames/Data/Form Editor` | 玩家三魂形态(FormSO) | 三栏可视化网格,自动绑定武器/技能引用,支持 TianHun / DiHun / MingHun |
| **Enemy Data Manager** | `BaseGames/Data/Enemy Data Manager` | 敌人配置 SO`ENM_*_Stats.asset`)+ 掉落表 | 双面板列表编辑,左栏搜索 + [New],右栏 Stats/Loot 标签 | | **Enemy Data Manager** | `BaseGames/Data/Enemy Data Manager` | 敌人配置 SO`ENM_*_Stats.asset`)+ 掉落表 | 双面板列表编辑,左栏搜索 + [New],右栏 Stats/Loot 标签 |
| **Boss Skill Sequence** | `BaseGames/Data/Boss Skill Sequence` | Boss 技能阶段(BossSkillSO / SkillSequenceSO | Gantt 时间轴可视化,Windup / Active / Recovery 三段颜色标记 |
| **Skill Editor** | `BaseGames/Data/Skill Editor` | 技能配置 SO`SKL_*_Data.asset` | 按 SkillEffectType 分组筛选,右栏含 HitBox 验证 + 资源费预览 | | **Skill Editor** | `BaseGames/Data/Skill Editor` | 技能配置 SO`SKL_*_Data.asset` | 按 SkillEffectType 分组筛选,右栏含 HitBox 验证 + 资源费预览 |
| **Weapon Editor** | `BaseGames/Data/Weapon Editor` | 武器配置 SO`WPN_*_Data.asset`) | 双面板列表,右栏全属性 + HitBox Prefab 验证 + 快捷操作 | | **Weapon Editor** | `BaseGames/Data/Weapon Editor` | 武器配置 SO`WPN_*_Data.asset`) | 双面板列表,右栏全属性 + HitBox Prefab 验证 + 快捷操作 |
| **Weapon HitBox Wizard** | `BaseGames/Create/Weapon HitBox Prefab` | 武器 HitBox Prefab4 方向 Ground/Up/Down/Air | 自动生成 `WPN_{ID}_HitBox.prefab`,支持各方向碰撞体形状配置 | | **Weapon HitBox Wizard** | `BaseGames/Create/Weapon HitBox Prefab` | 武器 HitBox Prefab4 方向 Ground/Up/Down/Air | 自动生成 `WPN_{ID}_HitBox.prefab`,支持各方向碰撞体形状配置 |
@@ -1,6 +1,7 @@
# Boss AI 双轨统一:决策层与执行层一并归并到小怪轨 # Boss AI 双轨统一:决策层与执行层一并归并到小怪轨
> 日期:2026-07-30  状态:设计已确认,待实施 > 日期:2026-07-30  状态:**已实施**(阶段一 Task 115、阶段二 Task 1621
> 实施期偏差与仍为待办的项见 [§13 注记](#13-注记)。作者指南:`Docs/Guides/09_BossAi_Authoring_Guide.md`
> 背景:小怪走 `EnemyAiBrain`BrainGraph+ 组合式模块 + `EnemyAbilityBase`/`EnemyAbilitySO` > 背景:小怪走 `EnemyAiBrain`BrainGraph+ 组合式模块 + `EnemyAbilityBase`/`EnemyAbilitySO`
> Boss 走 `BossBase` + `BossSkillExecutor` + `BossSkillSO`。2026-07-27 的抽取决策记录把终态定为 > Boss 走 `BossBase` + `BossSkillExecutor` + `BossSkillSO`。2026-07-27 的抽取决策记录把终态定为
> 「决策层统一 BrainGraph + 执行层按复杂度分层(Boss 保留 `BossSkillExecutor` 富编排)」。 > 「决策层统一 BrainGraph + 执行层按复杂度分层(Boss 保留 `BossSkillExecutor` 富编排)」。
@@ -567,3 +568,75 @@ C# 单继承直接堵死。
本次确认 E004 归精英怪,`ApproachAttackEngagement` 的投入不作废,反而被 Boss 图复用(§4.2)。 本次确认 E004 归精英怪,`ApproachAttackEngagement` 的投入不作废,反而被 Boss 图复用(§4.2)。
- 竞品调研于 2026-07-30 完成,调研对象与来源链接见对应会话记录;本文档按 CLAUDE.md 第 4 条 - 竞品调研于 2026-07-30 完成,调研对象与来源链接见对应会话记录;本文档按 CLAUDE.md 第 4 条
只保留功能性描述,不写入具体作品与角色名。 只保留功能性描述,不写入具体作品与角色名。
---
### 13.1 实施期偏差(Task 21 收尾时记录)
按实际落地情况修正设计文档中与最终代码不一致之处:
| 设计原文 | 实际落地 | 原因 |
|---|---|---|
| Boss 图共享一个「Boss 骨架」 | **没有骨架,每个 Boss 手写整张 `AiScript` 图**;重复形状抽成 `BossFragments` 的静态建态原语 | Boss 只有个位数且形状差异大,骨架会退化成只服务单个 Boss 的一堆参数 |
| `AbilityRunState.Telegraph` 随预警系统一并删除 | **保留**。它现在是 `BlinkStrikeAbility` 的一个执行阶段(现身前的闪光),与已删除的 `TelegraphSystem` 无关 | 该枚举值描述的是能力自身的执行阶段,不是旧预警组件的一部分 |
| 阶段信息写入黑板供图读取 | 未引入黑板写入,阶段经 `IAiContext.Boss``IBossControl`)**直接查询** | 少一层同步,且非 Boss 访问 `x.Boss` 抛异常这条显式失败更有价值 |
| `BossSkillEvent` 事件频道保留 | **随旧轨一并删除**`BossSkillEventChannelSO` + `BossEvents.BossSkillEvent` + `EVT_BossSkill.asset`) | Task 21 复核确认:全项目零发送方、零订阅方、无任何场景/预制体/Addressables 引用 |
### 13.2 已知未完成项(本计划范围内确认,但**未做**)
按严重度排列。这些不是遗漏,是明确记录下来的缺口。
1. **⚠️ `EnemyHurtState.Enter` 无受击动画时永久卡死(最严重,且与 Boss 轨无关)。**
`AnimConfig.Hurt` 为空时提前返回,且**不安排回到 `Controlled`**。任何没有受击动画的敌人被打一次
就永久停在 `Hurt` 态:`IsControllable` 恒假、`AiRuntime` 永久挂起、AI 完全停摆。
当前美术未接入 ⇒ **大部分敌人一挨打就废**。典型的 CLAUDE.md 第 6 条静默提前返回。
Task 15 进 Play 验证时发现。应尽快单独立项。
2. **战斗本身未经验证。** 动画 clip 尚未接入,`EnemyAttackSO.clip` 留空则该段瞬间完成。
已验证的是「能开战、能追击、能选招、能跑完招式、50% 血能换阶段、能悬停、零报错」这条**流程**;
**判定时机、伤害数值、手感一律未验证**。clip 到位后必须重新校时序与预警节奏。
3. **`EnemyBase.ReceiveParry` 无调用方。** 方法本身正确,但 `DamageInfo` 不携带攻击者引用,
"谁被弹反谁硬直"接不上。旧的 Boss 侧弹反反制已在 Task 16 删除——它的实际行为是
"玩家弹反**任意**敌人都会让 Boss 硬直",是错的,所以这是**有意的移除且暂无替代**。
接线需要在 Combat 层补攻击者引用(见 §6.2)。
4. **池化敌人复活时带着上一条命的能力冷却。** `EnemyBase.OnSpawn`
`_abilities.InterruptAll(InterruptReason.Dead)` 的注释写着「重置能力冷却」,但
`EnemyAbilityBase.Interrupt``!_isRunning` 时提前返回,真跑到时又是**设置**
`_cooldownEndTime = Time.time + cooldown * 0.5f` 而非清零。冷却从未被重置。
修法:加 `EnemyAbilityBase.ResetCooldown()``OnSpawn` 遍历调用。影响全体池化敌人。
5. **`BrainBuilder.Build()` 不校验「非终态是否有出边」。** 只校验正向(边指向的态是否已声明)。
一个已声明却没有任何出边的非终态会让敌人永久卡住且**零报错**。
`BossFragments.PhaseTransition` 按设计不自带出边,正是这类风险的头号候选
`ChaoFengAi``txDone` 边就是它唯一出口,删了 Boss 永久锁死)。
做法:给 `AiStateFragments.Terminal` 加显式终态标记,`Build()` 对「非终态且无出边」抛异常。
6. **`EnemyAbilityModule` 编辑器总览未写。** 旧的 `BossSkillModule` 编辑器视图随旧轨删除,
能力资产目前没有编辑器总览。
7. **`AiDefinitionValidator` 未写。** 能力引用漏配 / id 拼错目前只能在 Play Mode 里靠肉眼排查。
优先级高于第 6 项。
8. **`BossFragments.MoveToAnchor` 只在 `OnEnter` 采样锚点。** 锚点 Transform 若会移动则不重新取点。
与「锚点是固定点」的设定一致,但这是个隐含假设。
### 13.3 文档处理与残留(Task 21
- **删除**`Docs/Architecture/23_BossSkillModule.md``Docs/Design/47_BossSkillSystem.md`
(整份描述已删除且从未实现的体系)。删除前已确认全库无 Markdown 链接残留,
索引行与关联文档行均已改指本 spec 或新的作者指南。
- **修订**`Docs/Architecture/00_CoverageIndex.md``README.md``02_EventSystem.md`
`07_EnemyModule.md`(加过时提示 + §11 改为重定向)、`25_CharacterArchitectureOverview.md`
(§4 Boss 章节按实际代码重写)、`Docs/Design/README.md``19_BossPatternLibrary.md`(加废止提示)、
`69_BossDesignBible.md``Docs/Standards/AssetFolderSpec.md`(删旧 Boss 技能编辑器条目)。
- **保留不动**`Docs_Dev/` 下的历史计划与验证清单——那是开发过程记录,反映当时状态,改了反而失真。
- **仍有残留、超出本次范围**`Docs/` 里还有约十余处提到 `BossOrchestrator` / `AttackPatternSO` /
`TelegraphSystem` 的单行残留(`03_CoreModule` / `10_UIModule` / `11_AudioModule` /
`14_NarrativeModule` / `16_SupportingModules` / `01_ProjectStructure` / `Design/00_Overview` /
`Design/54_PoiseSystem` / `DesignSpec/07_EnemySystem` / `EditorTools/00_EditorToolsPlan`
/ `Architecture_Review.md`)。这些多是跨模块事件表与目录树里的顺带提及,
属于更大范围的「文档与代码一致性」清理,应单独立项,不在本计划内假装做完。
最关键的两份入口文档(`07_EnemyModule` / `25_CharacterArchitectureOverview`)已加显式过时提示,
不会把读者引向不存在的类型。