# 手动测试 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(); > 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 个 | ☐ |