359 lines
13 KiB
Markdown
359 lines
13 KiB
Markdown
# 手动测试 07 · 战斗系统
|
||
|
||
> **测试类型**:Unity Editor 手动测试(Play Mode)
|
||
> **覆盖模块**:`BaseGames.Combat`、`BaseGames.Parry`、`BaseGames.Combat.StatusEffects`
|
||
> **依赖组件**:`HitBox`、`HurtBox`、`ShieldComponent`、`ParrySystem`、`StatusEffectManager`
|
||
> **场景要求**:测试场景含玩家 + 至少一只敌人,Physics2D Layer 矩阵已配置
|
||
|
||
---
|
||
|
||
## 快速工具
|
||
|
||
| 工具 | 用途 | 菜单路径 |
|
||
|------|------|----------|
|
||
| **Check Physics2D Layer Matrix** | 一键检查层碰撞矩阵配置,输出 ✅/❌ 报告 | `BaseGames → Tools → Physics2D Layer Matrix → Check` |
|
||
| **Auto Fix Physics2D Layer Matrix** | 对所有错误层对自动调用 `Physics2D.IgnoreLayerCollision()` 并持久化 | `BaseGames → Tools → Physics2D Layer Matrix → Auto Fix` |
|
||
| **Place Enemy (Basic)** | 放置带 HurtBox、HitBox_Body 和 EnemyStats 的基础敌人(护盾测试需手动再添加 ShieldComponent) | `BaseGames → Scene → Place → Enemy (Basic)` |
|
||
| **Place Obstacle (Static)** | 放置静止障碍物(投射物测试挡墙) | `BaseGames → Scene → Place → Obstacle (Static)` |
|
||
|
||
> **注意**:PlayModeDebugOverlay 已移除。Play Mode 运行时调试请利用 Inspector 直接修改字段,或通过代码调用施加状态效果(见方式 C)。
|
||
|
||
**典型工作流**:
|
||
1. 测试前:`BaseGames → Tools → Physics2D Layer Matrix → Check` 一键确认矩阵,若有红项立即 **Auto Fix**,无需手动翻 Project Settings。
|
||
2. `MT-COMBAT-04` 护盾:`Place → Enemy (Basic)` 放置敌人,Inspector 中手动添加 `ShieldComponent`,进入 Play Mode 直接攻击。
|
||
3. `MT-COMBAT-06` 状态效果:通过代码或配置有状态效果的敌人攻击触发(见下方方式 A/B/C)。
|
||
4. `MT-COMBAT-07` 投射物:`Place → Obstacle (Static)` 放置挡墙,观察投射物命中效果。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [Physics2D 配置检查](#1-physics2d-配置检查)
|
||
2. [MT-COMBAT-01:战斗管道基础](#mt-combat-01战斗管道基础)
|
||
3. [MT-COMBAT-02:HitBox 激活时序](#mt-combat-02hitbox-激活时序)
|
||
4. [MT-COMBAT-03:弹反系统](#mt-combat-03弹反系统)
|
||
5. [MT-COMBAT-04:护盾系统](#mt-combat-04护盾系统)
|
||
6. [MT-COMBAT-05:霸体(Poise)系统](#mt-combat-05霸体poise系统)
|
||
7. [MT-COMBAT-06:状态效果集成](#mt-combat-06状态效果集成)
|
||
8. [MT-COMBAT-07:投射物系统](#mt-combat-07投射物系统)
|
||
9. [MT-COMBAT-08:碰撞冲突(Clash)系统](#mt-combat-08碰撞冲突clash系统)
|
||
|
||
---
|
||
|
||
## 1. Physics2D 配置检查
|
||
|
||
在开始战斗测试前,必须确认 Layer 碰撞矩阵:
|
||
|
||
**路径**:`Edit → Project Settings → Physics 2D → Layer Collision Matrix`
|
||
|
||
| Layer A | Layer B | 应开启碰撞 |
|
||
|---------|---------|---------|
|
||
| `PlayerHitBox` | `EnemyHurtBox` | ✅ 开启 |
|
||
| `EnemyHitBox` | `PlayerHurtBox` | ✅ 开启 |
|
||
| `Player` | `Ground` | ✅ 开启 |
|
||
| `Enemy` | `Ground` | ✅ 开启 |
|
||
| `Projectile` | `EnemyHurtBox` | ✅ 开启 |
|
||
| `Projectile` | `PlayerHurtBox` | ✅ 开启 |
|
||
| `PlayerHitBox` | `PlayerHurtBox` | ❌ 关闭(不自伤) |
|
||
| `EnemyHitBox` | `EnemyHurtBox` | ❌ 关闭(不自伤) |
|
||
|
||
---
|
||
|
||
## MT-COMBAT-01:战斗管道基础
|
||
|
||
**目的**:验证完整攻击链路:玩家攻击 → HitBox 触发 → DamageInfo 计算 → 敌人 HP 扣减。
|
||
|
||
> **🔧 资源准备**
|
||
>
|
||
> 此测试需要场景中同时存在玩家和至少一只敌人:
|
||
>
|
||
> 1. `BaseGames → Scene → Place → Player` 生成玩家;`Place → Ground Platform` 生成地面(若尚未搭建)
|
||
> 2. `BaseGames → Scene → Place → Enemy (Basic)` 放置带 HurtBox 的基础敌人
|
||
> 3. `BaseGames → Tools → Physics2D Layer Matrix → Check` 检查并按需 **Auto Fix** 层碰撞矩阵
|
||
>
|
||
> **最小手动步骤**:场景中必须有 Layer=`EnemyHurtBox` 的触发碰撞体(挂 `HurtBox`),以及 Layer=`PlayerHitBox` 的攻击碰撞体(挂 `HitBox`)。
|
||
|
||
### 步骤
|
||
|
||
1. 进入 Play Mode
|
||
2. 走到敌人附近(攻击范围内)
|
||
3. 按攻击键(Z/J)
|
||
|
||
**预期**:
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 伤害数字弹出 | 屏幕出现伤害数字 FloatingText | ☐ |
|
||
| 敌人 HP 减少 | Inspector 中 `EnemyStats.CurrentHP` 减少 | ☐ |
|
||
| HitStop 停顿 | 命中瞬间短暂帧停顿(约 0.05-0.1s),有命中质感 | ☐ |
|
||
| HitFX 播放 | 命中点产生对应类型的击中特效(斩击/钝击等) | ☐ |
|
||
| EVT_HitConfirmed 触发 | EventBusMonitor 显示 `EVT_HitConfirmed` 频道触发 | ☐ |
|
||
| Console 无 Error | 0 个红色 Error | ☐ |
|
||
|
||
4. 让敌人攻击玩家
|
||
|
||
**预期**:
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 玩家 HP 减少 | HUD HP 条正确减少 | ☐ |
|
||
| HurtState 触发 | 玩家进入受击硬直 | ☐ |
|
||
| 受击闪白 | 玩家 Sprite 短暂白色(HurtFlash) | ☐ |
|
||
|
||
---
|
||
|
||
## MT-COMBAT-02:HitBox 激活时序
|
||
|
||
**目的**:验证 `HitBox` 只在攻击动画关键帧期间处于 Active 状态,防止持续判定。
|
||
|
||
### 步骤
|
||
|
||
1. 打开 `Window → Analysis → Physics Debugger`(Unity 内置)
|
||
2. 勾选 `Show Colliders`,并设置 Active Colliders 的颜色(绿色)
|
||
3. 进入 Play Mode,放慢时间(在 Console 输入 `Time.timeScale = 0.1f` 或使用调试菜单)
|
||
4. 执行攻击动作,在 Scene 视图观察 HitBox Collider
|
||
|
||
**预期**:
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 攻击帧前 HitBox | `HitBox.gameObject.activeSelf == false` | ☐ |
|
||
| 攻击关键帧 HitBox | HitBox 变为 Active(绿色 Collider 出现) | ☐ |
|
||
| 攻击帧后 HitBox | HitBox 重新 Deactive | ☐ |
|
||
|
||
**Console 验证方式(替代方案)**:
|
||
|
||
在 `HitBox.cs` 的 `OnTriggerEnter2D` 中已有调试日志,观察 Console 中 HitBox 触发时序是否仅在攻击帧。
|
||
|
||
---
|
||
|
||
## MT-COMBAT-03:弹反系统
|
||
|
||
**目的**:验证 `ParrySystem` 的弹反窗口判定、成功/失败反馈。
|
||
|
||
### 步骤
|
||
|
||
**步骤 A:弹反成功**
|
||
|
||
1. 等待敌人发动攻击
|
||
2. 在攻击**命中前 `parryWindow` 秒内**按弹反键(默认 Q)
|
||
|
||
**预期**:
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 玩家不扣血 | HP 保持不变 | ☐ |
|
||
| 敌人硬直 | 敌人进入 `parriedStunDuration` 秒硬直 | ☐ |
|
||
| ParryFlash VFX | 命中点产生弹反特效 | ☐ |
|
||
| `EVT_ParrySuccess` 触发 | EventBusMonitor 显示触发 | ☐ |
|
||
| Stats.ParryCount +1 | 调试窗口或 Inspector 中 ParryCount 增加 | ☐ |
|
||
|
||
**步骤 B:弹反窗口外(过早)**
|
||
|
||
1. 提前 1 秒按弹反键,等待敌人攻击到来
|
||
|
||
**预期**:弹反失败,玩家正常受击扣血,无弹反 VFX。
|
||
|
||
**步骤 C:弹反窗口外(过晚)**
|
||
|
||
1. 等待敌人攻击已命中后再按弹反键
|
||
|
||
**预期**:弹反无效(已受伤),无弹反 VFX。
|
||
|
||
**步骤 D:不可弹反攻击(Unblockable)**
|
||
|
||
1. 找到标记为 `Unblockable`(`InteractionTag`)的敌人攻击
|
||
2. 在弹反窗口内按弹反键
|
||
|
||
**预期**:弹反无效,玩家正常受击,无弹反 VFX。
|
||
|
||
**步骤 E:弹反冷却**
|
||
|
||
1. 成功弹反后立即再次按弹反键
|
||
|
||
**预期**:冷却期间(`parryCooldown`)弹反无效。
|
||
|
||
| 弹反结果 | 预期现象 | ✓ |
|
||
|---------|---------|---|
|
||
| 成功(窗口内) | 不扣血 + 敌人硬直 + ParryFlash | ☐ |
|
||
| 失败(过早) | 正常受击扣血,无特效 | ☐ |
|
||
| 失败(过晚) | 正常受击扣血,无特效 | ☐ |
|
||
| Unblockable 攻击 | 弹反无效 | ☐ |
|
||
| 冷却期 | 再次按弹反无反应 | ☐ |
|
||
|
||
---
|
||
|
||
## MT-COMBAT-04:护盾系统
|
||
|
||
**目的**:验证 `ShieldComponent` 护盾先吸收伤害,耗尽后 HP 才减少,护盾恢复计时。
|
||
|
||
### 前提条件
|
||
|
||
- 玩家装备含护盾护符(`ShieldComponent` 初始化,`ShieldHP > 0`)
|
||
|
||
### 步骤
|
||
|
||
1. 确认 Inspector 中 `ShieldComponent.CurrentShieldHP` 为满值
|
||
2. 让敌人攻击玩家(伤害小于护盾值)
|
||
|
||
**预期**:护盾 HP 减少,玩家 HP 不变。
|
||
|
||
3. 继续承受伤害直到护盾耗尽
|
||
|
||
**预期**:护盾耗尽(`ShieldHP == 0`),护盾破碎 VFX/音效播放,后续攻击直接扣 HP。
|
||
|
||
4. 停止受击,等待 `shieldRecoveryDelay` 秒
|
||
|
||
**预期**:护盾开始恢复,逐步回满。
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 护盾先吸收伤害 | 护盾耗尽前 HP 不减少 | ☐ |
|
||
| 护盾耗尽 | ShieldHP == 0,ShieldIsBroken == true | ☐ |
|
||
| 耗尽后正常受伤 | 护盾破碎后攻击直接扣 HP | ☐ |
|
||
| 护盾恢复 | 停止受击后护盾逐步回满 | ☐ |
|
||
|
||
---
|
||
|
||
## MT-COMBAT-05:霸体(Poise)系统
|
||
|
||
**目的**:验证 `PoiseComponent` 防止低优先级攻击打断高优先级动作。
|
||
|
||
### 步骤
|
||
|
||
**步骤 A:普通攻击不打断霸体**
|
||
|
||
1. 进入攻击动作(Attack3 动画)
|
||
2. 此时让霸体值足够(`currentPoise >= breakLevel of attack`)的敌人攻击玩家
|
||
|
||
**预期**:攻击动作**不被打断**,`HurtState` 未触发(霸体值保护)。
|
||
|
||
**步骤 B:重攻击打断霸体**
|
||
|
||
1. 找到攻击 `BreakLevel` 高于玩家 `Poise` 的敌人(Boss 重击或特殊攻击)
|
||
2. 让其攻击玩家
|
||
|
||
**预期**:`HurtState` 触发,攻击动作被打断,霸体值减少。
|
||
|
||
**步骤 C:霸体恢复**
|
||
|
||
1. 玩家停止受击(不再被攻击),等待 `poiseRecoveryRate` 恢复
|
||
|
||
**预期**:Inspector 中 `PoiseComponent.CurrentPoise` 逐步恢复至 `maxPoise`。
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 普通攻击不打断 | 霸体充足时动作不中断 | ☐ |
|
||
| 重攻击打断 | BreakLevel > Poise 时触发 HurtState | ☐ |
|
||
| 霸体恢复 | 停止受击后逐步回满 | ☐ |
|
||
|
||
---
|
||
|
||
## MT-COMBAT-06:状态效果集成
|
||
|
||
**目的**:在 Play Mode 中验证 StatusEffect 与 MonoBehaviour 的集成(Tick 逻辑、VFX 显示)。
|
||
|
||
> **🔧 触发状态效果(三种方式)**
|
||
>
|
||
> **方式 A — 带状态效果的敌人攻击**
|
||
>
|
||
> 在敌人的攻击 `HitBox` 上配置 `_applyStatusEffect`(`StatusEffectSO` 引用 FireEffect / PoisonEffect),让敌人打到玩家后自动施加
|
||
>
|
||
> **方式 C — 代码直接调用**
|
||
>
|
||
> ```csharp
|
||
> // 在场景内任意 MonoBehaviour 中调用(Play Mode)
|
||
> var sem = FindFirstObjectByType<StatusEffectManager>();
|
||
> sem?.Apply(poisonEffectSO, 3); // 施加 3 层 Poison
|
||
> ```
|
||
|
||
### 步骤(通过配置敌人或代码触发效果)
|
||
|
||
**Poison(中毒)测试**:
|
||
|
||
1. 使玩家或敌人受到 Poison 状态效果(配置带毒敌人攻击,或代码调用 `sem?.Apply(poisonEffectSO, 3)`)
|
||
2. 观察绿色粒子特效
|
||
|
||
**预期**:
|
||
- 每 `tickInterval` 秒扣减 `tickDamage` HP
|
||
- 绿色 VFX 粒子持续显示
|
||
- `duration` 秒后效果自动移除,VFX 消失
|
||
|
||
**Fire(燃烧)测试**:
|
||
|
||
1. 施加 Fire 效果,再施加 Freeze 效果
|
||
|
||
**预期**:
|
||
- Fire 被 Freeze 互斥移除(`MutualExclusions` 生效)
|
||
- Console 无 NullReferenceException
|
||
|
||
**Stagger(硬直)测试**:
|
||
|
||
1. 对敌人施加 Stagger 效果
|
||
|
||
**预期**:
|
||
- 敌人进入硬直动画,`staggerDuration` 秒内无法移动/攻击
|
||
|
||
| 效果 | 检查点 | ✓ |
|
||
|------|--------|---|
|
||
| Poison | 定期 Tick 扣血 + 绿色粒子 + 到期自动移除 | ☐ |
|
||
| Fire | 施加 Freeze 后 Fire 自动移除 | ☐ |
|
||
| Stagger | 敌人硬直期间无法行动 | ☐ |
|
||
|
||
---
|
||
|
||
## MT-COMBAT-07:投射物系统
|
||
|
||
**目的**:验证 `LinearProjectile`、`HomingProjectile`、`ArcProjectile` 三种投射物类型。
|
||
|
||
### 步骤
|
||
|
||
**LinearProjectile(直线子弹)**:
|
||
|
||
1. 让远程敌人向玩家发射直线子弹
|
||
2. 观察子弹轨迹
|
||
|
||
**预期**:子弹沿直线运动,命中玩家扣血,命中地面消失(归还对象池)。
|
||
|
||
**HomingProjectile(追踪子弹)**:
|
||
|
||
1. 触发追踪子弹(若场景有此类敌人)
|
||
2. 移动玩家改变位置
|
||
|
||
**预期**:子弹自动转向追踪玩家(`turnSpeed` 控制转向速率)。
|
||
|
||
**ParryableProjectile(可弹反子弹)**:
|
||
|
||
1. 在子弹飞来时的弹反窗口内按弹反键
|
||
|
||
**预期**:子弹反向飞回,命中发射者并造成伤害。
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| Linear 直线运动 | 子弹直线飞行到目标或边界 | ☐ |
|
||
| Homing 追踪 | 子弹追踪玩家运动 | ☐ |
|
||
| 命中后归还对象池 | Hierarchy 中子弹 `SetActive(false)` | ☐ |
|
||
| Parryable 弹反 | 弹反后子弹反向 | ☐ |
|
||
|
||
---
|
||
|
||
## MT-COMBAT-08:碰撞冲突(Clash)系统
|
||
|
||
**目的**:验证当玩家攻击与敌人投射物同时碰撞时,`ClashResolver` 正确处理冲突。
|
||
|
||
### 步骤
|
||
|
||
1. 在敌人发射子弹的同时,玩家攻击命中子弹(HitBox 与子弹 Collider 重叠)
|
||
2. 观察双方结果
|
||
|
||
**预期**:
|
||
- 若玩家攻击力 >= 子弹 ClashBreakValue:子弹被消除,玩家无伤
|
||
- 若玩家攻击力 < 子弹 ClashBreakValue:双方均受到部分伤害(根据 `ClashConfigSO` 设置)
|
||
- Console 无 NullReferenceException
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 攻击胜出 | 子弹消除,玩家无伤 | ☐ |
|
||
| 攻击失败 | 双方受伤,无 Error | ☐ |
|
||
| Console 无 Error | 0 个 | ☐ |
|