Files
zeling_v2/Docs/Verification/08_Manual_EnemySystem.md

325 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 手动测试 08 · 敌人系统
> **测试类型**Unity Editor 手动测试Play Mode
> **覆盖模块**`BaseGames.Enemies`、`BaseGames.Enemies.AI`、`BaseGames.Enemies.Navigation`
> **依赖组件**`EnemyBase`、`EnemyCombat`、`EnemyMovement`、`BehaviorDesigner`、`PathBerserker2d`
> **场景要求**:已烘焙 NavSurface至少包含近战/远程/飞行三种敌人各一只
---
## 快速工具
| 工具 | 用途 | 菜单路径 |
|------|------|----------|
| **Place Enemy (Basic)** | 放置带 EnemyBase、EnemyStats、HurtBox、HitBox_Body 的基础敌人;多次调用可摆放多种变体,然后手动调整组件 | `BaseGames → Scene → Place → Enemy (Basic)` |
| **Place Nav Surface** | 在场景中放置 PathBerserker2d NavSurface 对象 | `BaseGames → Scene → Place → Nav Surface` |
| **Place Ground Platform** | 放置地面平台Layer=Ground | `BaseGames → Scene → Place → Ground Platform` |
> **NavSurface 烘焙**:在 Inspector 中找到 `NavSurface` 组件,点击 **Bake** 按钮(无对应菜单命令)。
> **注意**PlayModeDebugOverlay 已移除。运行时状态效果测试请通过配置带效果的敌人攻击,或代码调用 `StatusEffectManager.Apply()`。
**典型工作流**
1. 测试前:`Place → Ground Platform` 生成地面 + `Place → Enemy (Basic)` 放置近战 / 远程 / 飞行三种敌人(多次调用,手动调整组件和配置)。
2. **Add Enemy Variants**`Place → Enemy (Basic)` 多次,分别调整 `EnemyStats` 和行为树为远程 / 飞行变体。
3. Inspector NavSurface → **Bake** 烘焙寻路数据(相比手动查找 Inspector 更直接)。
4. 状态效果测试(`MT-ENEMY-04`):配置带毒/燃烧效果的敌人攻击,或通过代码调用;观察 VFX 变化和 Console 事件。
---
## 目录
1. [NavSurface 烘焙检查](#1-navsurface-烘焙检查)
2. [MT-ENEMY-01近战敌人 AI 基础行为](#mt-enemy-01近战敌人-ai-基础行为)
3. [MT-ENEMY-02远程敌人RangedEnemy](#mt-enemy-02远程敌人rangedenemy)
4. [MT-ENEMY-03飞行敌人FlyingEnemy](#mt-enemy-03飞行敌人flyingenemy)
5. [MT-ENEMY-04敌人霸体与击退](#mt-enemy-04敌人霸体与击退)
6. [MT-ENEMY-05敌人死亡与掉落](#mt-enemy-05敌人死亡与掉落)
7. [MT-ENEMY-06敌人配额管理](#mt-enemy-06敌人配额管理)
8. [MT-ENEMY-07Boss 战切换流程](#mt-enemy-07boss-战切换流程)
---
## 1. NavSurface 烘焙检查
PathBerserker2d 的寻路**完全依赖烘焙数据**,未烘焙时敌人原地站立无响应。
> **🔧 敌人场景快速搭建**
>
> 1. `BaseGames → Scene → Place → Ground Platform` 生成地面 + `Place → Player` 放置玩家(若尚未搭建)
> 2. `BaseGames → Scene → Place → Enemy (Basic)` 多次调用,放置近战 / 远程 / 飞行三种敌人:
> - **MeleeEnemy**保持默认配置EnemyBase + EnemyStats + EnemyMovement + HurtBox
> - **RangedEnemy**:手动添加 `ShootPoint` 子 GameObject调整 EnemyStats 为远程变体 SO
> - **FlyingEnemy**:手动修改 Rigidbody2D → Kinematic`gravityScale = 0`
>
> 三只敌人均需在 Inspector 中绑定 Behavior Designer 行为树资产(`BehaviorTree._externalBehavior` 字段)
> 3. Inspector NavSurface 组件 → 点击 **Bake** 烘焙近战 + 远程敌人的寻路数据
>
> **注意**`FlyingEnemy` 无需 NavSurface 寻路;`RangedEnemy` 需要 NavSurface 才能进行保距移动。
**检查步骤**
1. 在测试场景中选中挂有 `NavSurface` 组件的 GameObject
2. Inspector 中找到 `NavSurface` 组件,点击 **Bake**
3. Scene 视图中地面显示**蓝绿色半透明网格** → 烘焙成功
**提示**:若 Gizmo 不可见,点击 Scene 视图右上角 `Gizmos` → 确认 PathBerserker2d 相关项已勾选。
---
## MT-ENEMY-01近战敌人 AI 基础行为
**目的**:验证近战敌人的巡逻 → 追击 → 攻击 → 返回 Behavior Designer 行为树。
> **🔧 前置检查**
> - `Place → Enemy (Basic)` 已放置 `MeleeEnemy` 并挂载所有必要组件
> - Inspector 中 `BehaviorTree._externalBehavior` 字段已绑定行为树资产(手动拖入)
> - NavSurface 已烘焙Inspector → Bake 按钮)
### 步骤
**步骤 A巡逻行为**
1. 进入 Play Mode
2. 玩家保持在敌人**视野范围外**(超过 `detectionRange`
3. 观察敌人
**预期**
- 敌人在巡逻点之间来回移动
- 播放 `Walk`/`Patrol` 动画
- Console 无 PathBerserker2d 寻路错误
**步骤 B追击行为**
1. 玩家进入敌人视野(`detectionRange` 内且无遮挡物)
2. 观察敌人反应
**预期**
- 敌人停止巡逻,转向玩家方向
- 播放 `Run`/`Chase` 动画
- 以最优路径追击玩家PathBerserker2d 动态路径)
**步骤 C攻击行为**
1. 玩家进入敌人攻击范围(`attackRange` 内)
2. 观察敌人攻击
**预期**
- 播放攻击动画Behavior Designer 行为树触发攻击节点)
- `EnemyCombat.HitBox` 激活,若玩家在判定范围内触发伤害
- 攻击后进入冷却(`attackCooldown`
**步骤 D掉失目标后返回**
1. 玩家跑出敌人追击范围(`chaseRange` 外)
2. 观察敌人
**预期**
- 敌人停止追击,返回初始位置或巡逻路径
- 返回后恢复巡逻动画
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 巡逻动画 | 视野外敌人来回巡逻 | ☐ |
| 追击切换 | 玩家进入视野后立即追击 | ☐ |
| 攻击命中 | 攻击范围内玩家 HP 减少 | ☐ |
| 返回巡逻 | 丢失目标后返回初始位置 | ☐ |
| 无寻路错误 | Console 无 PathBerserker2d 相关 Error | ☐ |
---
## MT-ENEMY-02远程敌人RangedEnemy
**目的**:验证 `RangedEnemy` 的投射物发射、移动闪避、最优射击位置。
> **🔧 前置检查**
> - `BaseGames → Scene → Place → Enemy (Basic)` 已放置 `RangedEnemy`(调整 EnemyStats 为远程变体,位置 x=8
> - Inspector 中为 `RangedEnemy` 配置行为树资产(保距 + LOS 检测 + 发射节点)
> - `RangedEnemy._shootPoint` 子 Transform 已手动添加
> - 场景有静止障碍物(`Place → Obstacle (Static)`)以便观察子弹碰撞
### 步骤
1. 确认测试场景中有 `RangedEnemy` 实例(挂有 `EnemyCombat` 组件)
2. 进入 Play Mode玩家接近远程敌人
**步骤 A保持距离**
**预期**:远程敌人尝试保持在 `preferredDistance` 附近,玩家靠近时后退。
**步骤 B发射投射物**
**预期**
-`shootRange` 内发射投射物(`LinearProjectile``ArcProjectile`
- 投射物从 `_shootPoint` Transform 位置发出
- 命中玩家触发伤害
**步骤 CLOS视线检测**
1. 让玩家躲在墙壁后面(无视线)
2. 观察远程敌人是否仍然发射
**预期**无视线时敌人停止发射LOS 检测生效)。
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 保持距离 | 玩家靠近时后退 | ☐ |
| 发射投射物 | 视线内发射子弹命中玩家 | ☐ |
| LOS 遮挡 | 墙后无视线时停止发射 | ☐ |
---
## MT-ENEMY-03飞行敌人FlyingEnemy
**目的**:验证 `FlyingEnemy` 的空中移动、俯冲攻击、不受地面 NavSurface 约束。
> **🔧 前置检查**
> - `BaseGames → Scene → Place → Enemy (Basic)` 已放置 `FlyingEnemy`(位置 (3,5,0)
> - `Rigidbody2D.gravityScale = 0``bodyType = Kinematic`(手动在 Inspector 设置)
> - 配置行为树资产(直线追击 + 俯冲攻击,无需 NavSurface
### 步骤
1. 确认场景有 `FlyingEnemy` 实例Kinematic RBgravityScale=0
2. 进入 Play Mode
**步骤 A空中悬停/巡逻**
**预期**
- 飞行敌人在空中自由移动,不受地形限制
- 可以穿越平台上下(不像地面敌人需要寻路绕路)
**步骤 B俯冲攻击**
**预期**
- 锁定玩家后俯冲攻击
- 攻击后飞回起始高度,继续攻击循环
**步骤 C不被地面碰撞阻挡**
1. 让飞行敌人在追击路径中有地形障碍
**预期**:飞行敌人从障碍物上方飞过(不被地面碰撞体阻挡)。
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 空中自由移动 | 不受地面寻路限制 | ☐ |
| 俯冲攻击 | 正确识别玩家位置并俯冲 | ☐ |
| 绕过地形 | 从障碍上方飞过 | ☐ |
---
## MT-ENEMY-04敌人霸体与击退
**目的**:验证 `EnemyPoiseComponent` 在普通攻击下保持动画,重攻击才打断。
### 步骤
**步骤 A普通连击不打断**
1. 对有较高霸体的敌人进行连击
**预期**:若连击伤害低于霸体 `breakLevel`,敌人动画**不被打断**,继续执行 AI 行为。
**步骤 B重攻击打断**
1. 对同一敌人使用 `BreakLevel` 高的攻击(如下劈 `DownAttack` 或特殊技能)
**预期**敌人进入受击硬直AI 行为树暂停。
**步骤 C击退效果**
1. 攻击有击退(`knockbackForce > 0`)的攻击
**预期**:敌人被击退一定距离(`knockbackForce` 方向与大小),不会穿墙。
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 普通攻击不打断 | 霸体保护时 AI 行为继续 | ☐ |
| 重攻击打断 | BreakLevel > Poise 时触发硬直 | ☐ |
| 击退物理 | 被击退后不穿越地形 | ☐ |
---
## MT-ENEMY-05敌人死亡与掉落
**目的**:验证敌人 HP 归零后的死亡流程、Geo 掉落、`LootResolver`
### 步骤
1. 将敌人 HP 降至 0
**预期**
- 死亡动画播放
- 死亡动画结束后 GameObject 从场景移除(或 `SetActive(false)` 归还对象池)
- `LootTableSO` 根据权重随机掉落 Geo 或其他物品
2. 在掉落的 Geo 上移动玩家
**预期**Geo 被拾取,玩家 `CurrentGeo` 增加HUD Geo 数量更新。
3. 重新进入场景(房间切换后返回)
**预期**:根据 `WorldStateRegistry` 配置,死亡敌人是否重生(可配置的一次性/可重生区别)。
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 死亡动画 | HP 归零后播放死亡动画 | ☐ |
| 清理 | 动画结束后 GameObject 消失或归池 | ☐ |
| Geo 掉落 | 掉落 Geo 可拾取HUD 更新 | ☐ |
| LootTable | 掉落物符合权重概率 | ☐ |
---
## MT-ENEMY-06敌人配额管理
**目的**:验证 `EnemyQuotaManager` 限制同屏激活敌人数量,防止性能劣化。
### 步骤
1. 打开 Inspector找到场景中的 `EnemyQuotaManager`
2. 记录当前 `maxActiveEnemies` 配置值(如 8
3. 进入 Play Mode触发大量敌人通过多个 EnemySpawner
**预期**
- 同屏激活的敌人不超过 `maxActiveEnemies`
- 超出配额的敌人保持待机Deactivate 或等待)
- 当已激活敌人死亡后,待机敌人激活补充
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 不超过配额 | 激活敌人数量 ≤ maxActiveEnemies | ☐ |
| 死亡后补充 | 敌人死亡后待机敌人激活 | ☐ |
---
## MT-ENEMY-07Boss 战切换流程
**目的**:验证 Boss 战触发的 GameState 切换Gameplay → BossFight、Boss 血条 UI 显示。
### 步骤
1. 进入有 Boss 触发器的场景或房间
2. 玩家进入 Boss 房间触发器
**预期**
- `EVT_BossFightStarted` 事件触发EventBusMonitor 可见)
- `GameManager` 状态切换到 `BossFight`
- Boss HP 血条 UI 出现(大型 HP 条 + Boss 名称文字)
- 背景音乐切换为 Boss 战曲目
3. 将 Boss HP 降至 0
**预期**
- `EVT_BossFightEnded` 事件触发(`victory = true`
- GameManager 切回 `Gameplay` 状态
- Boss 血条 UI 隐藏
- 胜利 VFX/音效播放
| 检查点 | 期望 | ✓ |
|--------|------|---|
| Boss 战触发 | 进入触发器后 GameState = BossFight | ☐ |
| Boss HP 条 | Boss 血条 UI 正确显示 | ☐ |
| BGM 切换 | 战斗音乐正确播放 | ☐ |
| Boss 死亡 | 胜利后状态恢复 Gameplay | ☐ |
| BossProgressTracker | Console 中 Boss 击败状态记录 | ☐ |