@
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:
@@ -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 完全无 AI;E004/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` FSM(Controlled/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 }
|
||||
|
||||
// 对外只暴露"声明意图"的 API(AI/能力调用),执行在 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 机制。
|
||||
- **PlayMode(TestRoomA,E001)**:每期验 待机(伪装)→巡逻→警觉(朝向)→追击(接触伤害)→死亡 全链 + 脱离感知 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 落地范式文档。
|
||||
Reference in New Issue
Block a user