docs(ai): 敌人执行层统一 + AI/动画/属性瘦身 设计文档

通篇审查敌人架构(movement/stats/state/AI+abilities)后的重构方案:
引入统一 EnemyLocomotion(Idle/Patrol/Face/Approach 模式 + Wander/Pace/
Waypoints 策略)取代 7 种巡逻/4 套移动/IMover/三个协程能力;删 AiPhase
影子层(动画改由 locomotion 驱动);清 EnemyStatsSO ~11 个死字段。范围
E001 样板+框架,E002-E06/Boss 定落地范式后续实现。P1(死代码清除)已完成。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@
This commit is contained in:
2026-07-10 11:39:26 +08:00
parent e894a9dd27
commit ab8f61d2d9
@@ -0,0 +1,139 @@
# 敌人执行层统一 + AI/动画/属性瘦身 —— 设计文档
- 日期:2026-07-10
- 分支:`feat/braingraph-enemy-integration`
- 范围:**E001 样板 + 可复用框架**E002-E006/Boss 的 AI 落地范式在本文件定义、后续逐个实现。
- 关联:[[braingraph_ai_framework]]、[[ai_decision_only_delegates_abilities]]、[[enemy_nav_movement_architecture]]spec `2026-07-03-enemy-ai-framework-design.md`
## 1. 背景与问题
敌人 AI 已从三方 Behavior Designer 迁到自研 BrainGraph。四个子系统(movement / stats / state / AI+abilities)通篇审查后暴露三类问题:
1. **两套 AI 并存**~50 个 `BD_*` Behavior Designer 任务 + `BaseGames.Enemies.AI` asmdef + 三个 Opsive 包,运行期全死,只靠 `GRAPH_DESIGNER` 宏还在编译。→ **已在 P1 删除(本文件写作前完成)**
2. **"同一概念多实现"**
- **7 种巡逻**`PatrolAbility`(nav 随机) / `IMover.WalkRandom`(nav 随机, 仅测试) / `BD_WalkRandom` / `BD_InvestigateLastKnown` 子步 / `BD_Patrol`(速度踱步, 撞墙翻向) / `BD_PatrolWaypoints`(路点) / `FlyingDirectNavigator.WalkToRandom`(MovePosition)。既有 4 份"nav 随机游走"重复,又把有玩法差异的"踱步/路点"在迁移中弄丢。
- **4 套移动执行**`EnemyMovement` 直设 velocity / `PendingInput` 信号 / `FlyingEnemy` 直设 velocity / `FlyingDirectNavigator` MovePosition。nav 与 AI 会在同一 FixedUpdate 写同一批 `PendingInput` 字段互相覆盖。
- "朝向"4 入口、"停"4 入口、"设速度"跨 `EnemyStatsSO`/`TBM.movementSpeed`/`MoveInput` 三处。
- `IMover`(含 `UseChaseSpeed/UsePatrolSpeed/LookAround/WalkRandom`)零生产调用,被能力直调 `EnemyBase` 架空。
3. **冗余状态层**`AiPhase`(Idle/Patrol/Alert/Chase/Combat/Investigate/ReturnHome) 与 BrainGraph 状态严格 1:1,只用来选动画、AI 从不回读;`Combat/Investigate/ReturnHome` 是死枚举值。
4. **Model A 过度设计**`IdleAbility`/`PatrolAbility`/`AlertAbility``while(true) yield` 常驻协程,唯一作用是占住 `IsRunning``EnsureAbility` 空转——为琐碎行为各付出「协程+注册项+SO 资产」,且借用了本为攻击设计的 `EnemyAbilitySO``attackSequence/telegraph/range/LOS/priority` 全是死字段)。
5. **属性冗余**`EnemyStatsSO` 约 11/26 字段死或与 sensor 槽 / `DamageSourceSO` 重复;速度配在 3 处;玩家/敌人难度缩放逻辑重复。
**现状要点**:只有 **E001** 有可用 AI`[AiDefinition("E001")]` + `EnemyAiBrain`)。E002/E003/E006/Boss 完全无 AIE004/E005 prefab 里的 "BehaviorTree" 只是 `_stopBehaviorTree` bool 字段,非 Opsive 组件。→ 整套 AI/能力设计只在 1 个敌人上验证过,是重构的最佳时机。
## 2. 设计原则(不变)
- **AI 只决策,不 actuate**AI 决定"进哪个状态 / 转换条件 / 触发哪个能力 / 声明哪个移动意图";移动/朝向/停/速度/动画的**实现**不在 AI。见 [[ai_decision_only_delegates_abilities]]。
- **根因修复,不下游兜底**:删除多余抽象本身(而非留着不调用),让"AI 无法 actuate"在类型层成立。见 CLAUDE.md §6。
- **"能力"一词收回给战斗**:带冷却/预警/HitBox/接触伤害才叫 ability;纯移动/朝向归 locomotion。
## 3. 目标架构
三条正交轴,各自单一职责:
| 轴 | 组件 | 职责 | 谁改它 |
|---|---|---|---|
| 反应态 | `EnemyStateType` FSMControlled/Hurt/Stagger/KnockUp/Dead | 受击/硬直/死亡生命周期;当 AI 的门(`IsControllable`) | 伤害/招架/死亡 |
| 决策 | BrainGraph`AiRuntime`/`PerceptionStateMachine`/`AiScript`) | 感知→状态;声明移动意图 + 触发攻击能力 | 感知查询 |
| 执行 | **`EnemyLocomotion`(新)** + `EnemyAbilityBase`(攻击) | 移动/朝向/步态动画;攻击 | AI 声明意图;能力协程 |
### 3.1 核心组件 `EnemyLocomotion`(统一移动执行器)
单一移动入口,取代 4 套移动模型 + `IMover` + 三个协程能力 + `EnemyBase` 上散落的移动方法。
```csharp
namespace BaseGames.Enemies
{
public enum LocomotionMode { Idle, Patrol, Face, Approach }
public enum PatrolStrategy { Wander, Pace, Waypoints }
// 对外只暴露"声明意图"的 APIAI/能力调用),执行在 FixedUpdate 内部完成
public interface IEnemyLocomotion
{
void SetMode(LocomotionMode mode); // Idle(停)/ Patrol(按配置策略游走)
void Approach(Transform target); // 持续跟随(Chase 能力 / 调查用),派生 RunSpeed
void MoveTo(Vector2 point); // 一次性目标点
void Face(Vector2 lookAt); // 停 + 朝向(Alert 用)
void Stop();
LocomotionMode CurrentMode { get; }
bool IsMoving { get; }
}
}
```
- **内部后端不变**:地面怪用 `EnemyNavAgent`(PathBerserker2d)、飞行怪用 `FlyingDirectNavigator`,作为可替换的 `IPathAgent``EnemyLocomotion` 是它们之上的唯一门面。物理原生架构(寻路只给方向、velocity 执行、碰撞体底部对齐 y=0)保持,见 [[enemy_nav_movement_architecture]]。
- **巡逻 = `Patrol` 模式 + 每敌人序列化 `PatrolStrategy` + 参数**:一个组件三种玩法(Wander 随机 / Pace 撞墙翻向踱步 / Waypoints 路点序列),消灭 7 份实现并找回踱步/路点。
- **速度单一来源**:由模式派生(Patrol→`WalkSpeed`、Approach→`RunSpeed`,读 `EnemyStatsSO`)。删除 `EnemyMovement``EnemyStatsSO` 的二次直读接线(`EnemyMovement._config`),删除经 `TBM.movementSpeed` 的速度中转重复。
- **`Approach` 不改追击语义**`ContactChaseAbility` 保留为能力;仅把内部 `_enemy.MoveTo(player)` 换成 `Locomotion.Approach(player)`;接触伤害(战斗语义)仍在能力里。
### 3.2 AI 决策层用法(仍"只决策")
`PerceptionStateMachine` 状态不再绑"能力 id",改绑 **locomotion 意图 + 可选攻击能力 id**
```
Idle_Disguise : OnEnter → Locomotion.SetMode(Idle)
Move_Patrol : OnEnter → Locomotion.SetMode(Patrol)
Alert : OnEnter/Tick → Locomotion.Face(player)
Chase : OnEnter → Combat.UseAbility("e001_chase") // 能力内部 Approach(player)
Death : 终态(死亡演出走反应态 FSM)
```
- `SetMode/Face/Approach` 是**声明**(与原 `SetAiPhase` 同性质),执行在 `EnemyLocomotion`——AI 仍不碰 velocity/朝向实现。
- **删除** `IdleAbility`/`PatrolAbility`/`AlertAbility` 三协程能力、`ABL_E001_Idle`/`ABL_E001_Patrol`/`ABL_E001_Alert` 三 SO、`IMover` 接口及其在 `EnemyBrainContext` 的实现。
- `IAiContext` 增加 `IEnemyLocomotion Locomotion { get; }`(替换 `IMover Mover`)。`ICombatant.UseAbility/IsAbilityRunning/InterruptAbilities` 保留(攻击/Chase 用)。
- `PerceptionStateMachine.Config` 改为每状态填 `LocomotionIntent`(模式 + 可选 target 来源)+ 可选 `abilityId``AddAbilityState` 换成 `AddLocomotionState`
### 3.3 动画(删 `AiPhase`
- `EnemyLocomotion` 按当前模式/实际速度驱动步态 clip:静止→`Idle`、Patrol 移动→`Walk`、Approach→`Run`、Face→`Alert`。映射表 = 原 `AiPhase→AnimConfig` switch,改 **key 在 `LocomotionMode`** 上(放 `EnemyLocomotion` 或一个轻量 `EnemyAnimationDriver`)。
- 反应态(Hurt/Stagger/KnockUp/Dead)与攻击/出现能力**照旧各自播 clip**,覆盖在步态之上。
- **删除** `AiPhase` 枚举、`EnemyBase.SetAiPhase`/`CurrentAiPhase`/`OnAiPhaseChanged`,及所有能力里的 `SetAiPhase(...)``ReceiveAlert` 里用 `AiPhase` 做的"已交战不降级"判断改读 AI 当前状态名或一个 `bool IsEngaged`
### 3.4 属性清理(`EnemyStatsSO`
删除死/重复字段:`AttackDamage``AttackRange``DetectRange``DetectAngleDeg``EyeOffset``LOSBlockingMask`(感知全归 sensor 槽 `PhysicsPerceptionSystem`)、`AlertDuration``InvestigateDuration``KnockbackForce``HitStunDuration`(击退归 `DamageSourceSO`)、`HitTierConfig.heavyHitThreshold`(硬直由 Poise `Break` vs `PoiseLevel` 决定)。
- 速度单一来源(删 `EnemyMovement._config` 直读,改经 `EnemyLocomotion``Stats`)。
- (低优先,可选)玩家/敌人难度缩放抽共享 `ScalableVitals` helper(当前两边近乎逐行重复)。
## 4. E002-E006 / Boss 的 AI 落地范式(本文件定义,后续实现)
每个敌人 = **一个 `[AiDefinition("Exxx")]` `AiScript` 子类**,内容仅为:
1. 复用 `PerceptionStateMachine`(或 Boss 专用图),填状态名 + 每状态的 **locomotion 意图** + **攻击能力 id**
2. 攻击行为写成 `EnemyAbilityBase` 子类(已有一批:Melee/Projectile/Leap/Charge/CeilingDrop/…),配 `EnemyAbilitySO`(真攻击才需 cooldown/telegraph/HitBox)。
3. 巡逻/待机/警觉/追击**不写能力**,只在状态里声明 locomotion 意图(含选 `PatrolStrategy`)。
4. 脚手架 `SceneObjectPlacerTool.PlaceExxx``EnemyAiBrain(_definitionId)` + `EnemyLocomotion` + 攻击能力子节点。
近重复能力(后续合并,不阻塞本次):`CeilingDropAbility` vs `AnimatedCeilingDropAbility`(后者注释已声明取代前者);`AppearAbility` = `PlayClipAbility` + 一行 `SetAiPhase``FacePlayerAbility``AlertAbility` 的"朝向"原语;多个攻击能力里手抄的 HitBox 窗口 + `IsGrounded` 射线。
## 5. 分期实施(每期独立可提交、可回滚)
- **P1 死代码清除** — ✅ **已完成**commit `e894a9d`):删 `BD_*` + `BaseGames.Enemies.AI` asmdef + `GRAPH_DESIGNER` 宏 + 三个 `com.opsive.*` 包;恢复编译(0 错误)。
- **P2 引入 `EnemyLocomotion`** — 建组件 + 接入 Nav/Flying 后端;先与旧 API 并存,E001 切过去 PlayMode 跑通四态 + de-escalation。
- **P3 AI 改绑 locomotion 意图** — 删三协程能力/三 SO/`IMover``PerceptionStateMachine``AddLocomotionState``E001CaoZhiAi` 改声明意图;`ContactChaseAbility` 内部改 `Approach`。E001 验证。
- **P4 删 `AiPhase`** — 动画改由 locomotion 驱动;迁移 `SetAiPhase` 全部调用点;`ReceiveAlert` 改判据。
- **P5 Stats 清理** — 删死字段 + 速度单一来源(+ 可选难度缩放 helper)。
- **P6 巡逻策略补全** — 实现 `PatrolStrategy.Pace/Waypoints`(找回丢失玩法)。
- **文档产物** — 本文件即 E002-E06/Boss AI 落地范式;各敌人后续按范式逐个实现(独立任务)。
## 6. 测试
- **EditMode**BrainGraph 现有测试(`Assets/Tests/EditMode/AI/`)保留;`IMover` 相关用例改用 `IEnemyLocomotion` spy 或 `ICombatant` spy 验证状态机 Enter/Tick/Exit 机制。
- **PlayModeTestRoomAE001**:每期验 待机(伪装)→巡逻→警觉(朝向)→追击(接触伤害)→死亡 全链 + 脱离感知 de-escalation;断言 AI 脚本零 `velocity/朝向` 实现、动画随 locomotion 模式切换、console 0 报错。
- **自检**`Validate All ScriptableObjects` / `Validate Address Keys` / `Physics2D Layer Matrix Check`CLAUDE.md §3)。
## 7. 风险与缓解
- **飞行怪双模型**`FlyingEnemy`/`FlyingDirectNavigator``MovePosition`,需在 `EnemyLocomotion` 内以 `IPathAgent` 后端形式收编,避免又留一套并行执行。P2 明确覆盖飞行分支。
- **物理原生易回归**nav 只给方向、velocity 执行、`TBM.SegmentMovement` 关、碰撞体底部 y=0——重构中必须保留,见 [[enemy_nav_movement_architecture]]。
- **动画覆盖顺序**:反应态/攻击 clip 必须能压过步态 clip;P4 需验证受击/攻击时步态不抢播。
- **`AiPhase` 删除波及面**`SetAiPhase` 有多处调用点(能力、`ReceiveAlert`、gizmo/overlay);P4 逐点迁移并保留调试可视化(改读状态名)。
- **范围克制**:本次只在 E001 落地并验证;E002-E006/Boss 仅定范式,避免一次性大改多敌人放大回归面。
## 8. 成功判据
- 编译 0 错误;E001 PlayMode 行为与重构前一致(四态 + de-escalation + 接触伤害)。
- 代码库中"巡逻"实现 1 个(`EnemyLocomotion` + 策略)、"移动执行"入口 1 个、无 `AiPhase`、无 `IMover`、无 Idle/Patrol/Alert 协程能力与其 SO。
- `EnemyStatsSO` 无死字段;速度单一来源。
- E002-E006/Boss 有明确、可照抄的 AI 落地范式文档。