351 lines
14 KiB
Markdown
351 lines
14 KiB
Markdown
# 手动测试 09 · 世界与场景系统
|
||
|
||
> **测试类型**:Unity Editor 手动测试(Play Mode)
|
||
> **覆盖模块**:`BaseGames.World`、`BaseGames.World.Map`
|
||
> **依赖组件**:`RoomController`、`RoomTransition`、`SavePoint`、`DeathShade`、`WorldStateRegistry`
|
||
> **场景要求**:含多房间连接(至少 2 个 Room Scene),AbilityGate,MovingPlatform,SavePoint
|
||
|
||
---
|
||
|
||
## 快速工具
|
||
|
||
| 工具 | 用途 | 菜单路径 |
|
||
|------|------|----------|
|
||
| **Place Save Point** | 放置带 SavePoint 组件和 BoxCollider2D(TriggerZone) 的存档点 | `BaseGames → Scene → Place → Save Point` |
|
||
| **Place Camera Trigger Zone** | 放置带 CameraTriggerZone 和 BoxCollider2D(TriggerZone) 的摄像机触发区 | `BaseGames → Scene → Place → Camera Trigger Zone` |
|
||
| **Place Room Camera** | 放置带 Cinemachine + RoomCamera + CinemachineConfiner2D 的房间摄像机 | `BaseGames → Scene → Place → Room Camera` |
|
||
| **Place Ground Platform** | 放置地面平台(Layer=Ground) | `BaseGames → Scene → Place → Ground Platform` |
|
||
| **Place Tilemap Ground** | 放置 Grid + Tilemap + CompositeCollider2D(Layer=Ground) | `BaseGames → Scene → Place → Tilemap Ground` |
|
||
| **Scaffold Room Scene** | 一键生成完整房间场景结构 | `BaseGames → Tools → Scaffold Room Scene` |
|
||
|
||
> **注意**:PlayModeDebugOverlay 已移除。Run Mode 存档调试请直接通过交互键触发存档点,或在 Inspector 中手动调用 `ISaveService.QuickSave()`。
|
||
> 房间过渡对象、移动平台、可破坏平台、能力门等复杂对象请参照下方各节的**手动步骤**手工创建。
|
||
|
||
**典型工作流**:
|
||
1. `MT-WORLD-01` 房间过渡:手动创建 `RoomTransition` GameObject,添加 BoxCollider2D Trigger,配置 `_targetSceneAddress`,两端各一个出口(参考下方手动步骤)。
|
||
2. `MT-WORLD-02` 存档:`Place → Save Point` 放置存档点,Play Mode 交互键激活;确认文件写入通过文件浏览器查看 `Application.persistentDataPath`。
|
||
3. `MT-WORLD-05` 移动平台 / `MT-WORLD-06` 能力门:手动创建对象,参照各节步骤配置组件(无专用菜单命令)。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [场景结构检查](#1-场景结构检查)
|
||
2. [MT-WORLD-01:房间过渡(RoomTransition)](#mt-world-01房间过渡roomtransition)
|
||
3. [MT-WORLD-02:存档点交互](#mt-world-02存档点交互)
|
||
4. [MT-WORLD-03:死亡阴影(DeathShade)](#mt-world-03死亡阴影deathshade)
|
||
5. [MT-WORLD-04:世界状态持久化(WorldStateRegistry)](#mt-world-04世界状态持久化worldstateregistry)
|
||
6. [MT-WORLD-05:可破坏平台与移动平台](#mt-world-05可破坏平台与移动平台)
|
||
7. [MT-WORLD-06:能力门(AbilityGate)](#mt-world-06能力门abilitygate)
|
||
8. [MT-WORLD-07:可收集物(Collectibles)](#mt-world-07可收集物collectibles)
|
||
9. [MT-WORLD-08:世界地图显示](#mt-world-08世界地图显示)
|
||
|
||
---
|
||
|
||
## 1. 场景结构检查
|
||
|
||
| 元素 | 说明 | ✓ |
|
||
|------|------|---|
|
||
| RoomController | 每个 Room Scene 挂有 `RoomController`,`roomId` 唯一 | ☐ |
|
||
| RoomTransition | 房间出入口各有 `RoomTransition`,`targetSceneName` 和 `targetTransitionId` 已配置 | ☐ |
|
||
| SavePoint | 测试场景含至少 1 个 `SavePoint`,挂有 `SavePointSO` 资产 | ☐ |
|
||
| WorldStateRegistry | 场景挂有 `WorldStateRegistrar` 或 GlobalObject 上有 `WorldStateRegistry` | ☐ |
|
||
|
||
> **🔧 一键搭建世界测试场景**
|
||
>
|
||
> | 需求 | 工具 | 操作 |
|
||
> |------|------|------|
|
||
> | 基础场景(地面 + 玩家) | `BaseGames → Scene → Place → Player` + `Place → Ground Platform` | 分别放置玩家和地面 |
|
||
> | 需要存档点(MT-WORLD-02) | `BaseGames → Scene → Place → Save Point` | 放置 SavePoint + 手动绑定事件频道 |
|
||
> | 需要 2 个 Room 场景(MT-WORLD-01) | 手动创建场景(见下方 MT-WORLD-01 步骤) | 注册到 Build Settings + Addressables |
|
||
> | 需要死亡阴影(MT-WORLD-03) | 手动创建 `DeathShade` GameObject | 挂 `DeathShade` 组件,设置 `_geoAmount = 50` |
|
||
> | 需要过渡触发器 | 手动创建 `RoomTransition` GameObject | 挂 BoxCollider2D Trigger + `RoomTransition` 组件 |
|
||
>
|
||
> **完整世界测试场景搭建顺序**:
|
||
> 1. `Place → Player` + `Place → Ground Platform`(地面 + 玩家)
|
||
> 2. 手动创建 Room_A / Room_B 并注册(仅 MT-WORLD-01 需要)
|
||
> 3. `Place → Save Point` + 手动创建 DeathShade
|
||
> 4. 手动创建 RoomTransition 对(若在当前单一场景内测试)
|
||
> 5. Addressable Batch Tool → 注册 Room_A / Room_B 场景
|
||
|
||
---
|
||
|
||
## MT-WORLD-01:房间过渡(RoomTransition)
|
||
|
||
**目的**:验证 `SceneLoader` + `RoomTransition` 的场景加载/卸载流程(Addressables 异步加载)。
|
||
|
||
> **🔧 资源准备**
|
||
>
|
||
> 1. 手动创建两个测试场景:`File → New Scene → Empty`,保存为 `Assets/_Game/Scenes/Room_A.unity` 和 `Room_B.unity`,添加地面、`RoomController`、出生点、`RoomTransition` 触发器(左右各一),然后 `File → Build Settings → Add Open Scenes` 注册。
|
||
> 2. 用 **Addressable Batch Tool** 将 `Room_A.unity` / `Room_B.unity` 注册,Key 建议 = `Room_A` / `Room_B`
|
||
> 3. 在两个场景中分别打开对应的 `RoomTransition` GameObject,填写 `_targetSceneAddress`:
|
||
> - `Room_A` 场景的右侧 Transition:`_targetSceneAddress = "Room_B"`
|
||
> - `Room_B` 场景的左侧 Transition:`_targetSceneAddress = "Room_A"`
|
||
> 4. 也可在**单一测试场景**中测试(手动创建 RoomTransition 对),但此方案无法测试实际场景卸载/加载
|
||
|
||
### 步骤
|
||
|
||
1. 进入 Play Mode
|
||
2. 玩家走入场景边缘 `RoomTransition` 触发区域
|
||
|
||
**预期(过渡动画开始)**:
|
||
- `ScreenFader` 黑幕淡入(淡出当前场景)
|
||
- Console 出现 `[SceneLoader] Loading: RoomB` 类似日志
|
||
- `EVT_RoomTransitionStart` 触发(EventBusMonitor)
|
||
|
||
**预期(新场景加载完成)**:
|
||
- 新场景画面淡入
|
||
- 玩家出现在目标 `RoomTransition` 的 `spawnPoint` 位置
|
||
- `EVT_RoomTransitionEnd` 触发
|
||
|
||
3. 立即再次走回上一个 `RoomTransition`
|
||
|
||
**预期**:可无缝往返,无加载错误,HP 和状态保持不变。
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 黑幕过渡 | 进出场景时有黑幕淡入淡出 | ☐ |
|
||
| 玩家出现位置 | 出现在目标过渡点的 spawnPoint | ☐ |
|
||
| 无加载错误 | Console 无 `InvalidKeyException` 或 `NullReferenceException` | ☐ |
|
||
| 往返正常 | 多次房间切换无内存泄漏或重复 | ☐ |
|
||
|
||
---
|
||
|
||
## MT-WORLD-02:存档点交互
|
||
|
||
**目的**:端到端验证 `SavePoint` 激活→存档→读取全流程。
|
||
|
||
> **🔧 资源准备(一键)**
|
||
>
|
||
> 使用 `BaseGames → Scene → Place → Save Point` 在场景中快速放置存档点,或手动创建(见下方手动步骤)。
|
||
>
|
||
> **手动步骤**:
|
||
> 1. 创建空 GameObject,挂 `SavePoint`、`CapsuleCollider2D`(isTrigger=true)
|
||
> 2. 设置 `_savePointId`(唯一字符串,如 `"testroom_SP_01"`)
|
||
> 3. 将 `EVT_SavePointActivated`(StringEventChannelSO)拖入 `_onSavePointActivated`
|
||
>
|
||
> **触发存档**:进入 Play Mode → 走到存档点 → 按 **E 键**(或配置的 Interact 键)激活
|
||
> **快速确认**:存档后打开文件浏览器查看 `Application.persistentDataPath` 目录,确认存档文件已生成
|
||
|
||
### 步骤
|
||
|
||
1. 走到 `SavePoint`(场景中有 `SavePoint.cs` 的 GameObject)
|
||
2. 按**交互键**(默认 E 或 F)
|
||
|
||
**预期**:
|
||
- `SavePoint` 播放激活动画/粒子
|
||
- `EVT_SavePointActivated` 触发
|
||
- `SaveManager.Save()` 被调用
|
||
- Console 出现 `[SaveManager] 存档成功` 日志
|
||
- 灵泉次数恢复满值(`SpringCount = MaxSpringCount`)
|
||
|
||
3. 打开存档文件位置验证(`%AppData%\..\LocalLow\[CompanyName]\[AppName]\save.dat`)
|
||
|
||
**预期**:存档文件修改时间与测试时间一致。
|
||
|
||
4. 退出 Play Mode,再进入 Play Mode(模拟游戏重启)
|
||
5. 验证是否从存档点位置开始
|
||
|
||
**预期**:玩家出现在存档点坐标,HP 保持存档时的值。
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 激活动画 | SavePoint 激活 VFX/动画播放 | ☐ |
|
||
| 存档文件更新 | 存档文件时间戳更新 | ☐ |
|
||
| 灵泉恢复 | SpringCount = MaxSpringCount | ☐ |
|
||
| 读档位置 | 重启后从存档点出生 | ☐ |
|
||
|
||
---
|
||
|
||
## MT-WORLD-03:死亡阴影(DeathShade)
|
||
|
||
**目的**:验证 `DeathShade` 在死亡位置生成、Geo 附着、回收互动。
|
||
|
||
> **🔧 资源准备**
|
||
>
|
||
> **全流程测试(推荐)**:
|
||
> 1. 确保场景已有存档点(`BaseGames → Scene → Place → Save Point`)
|
||
> 2. 正常游戏中让玩家死亡 → DeathShade 自动由 `DeathRespawnService` 在死亡位置创建
|
||
>
|
||
> **快速单元测试(无需真实死亡)**:
|
||
> - 手动创建 `DeathShade` GameObject,挂 `DeathShade` 组件,设置 `_geoAmount = 50`,放置在场景 x=5 位置
|
||
> - 进入 Play Mode → 玩家走到 DeathShade 位置 → 观察 Geo 回收交互
|
||
> - ⚠ 此为手动占位;完整流程(覆盖测试项 DeathShade 生成位置/第二次死亡覆盖)仍需通过真实死亡触发
|
||
|
||
### 步骤
|
||
|
||
1. 确认玩家携带 **Geo > 0**,存档(与存档点交互)
|
||
2. 让玩家**在存档点之外的区域死亡**(HP 归零)
|
||
3. 在死亡屏幕选择重试(复活在存档点)
|
||
|
||
**预期(复活后)**:
|
||
- 玩家出现在存档点
|
||
- 死亡位置(Room B 某坐标)出现 `DeathShade` 对象
|
||
- `DeathShade` 持有死亡时的 Geo 数量
|
||
|
||
4. 走到 `DeathShade` 位置,与其交互(进入触发区域)
|
||
|
||
**预期**:
|
||
- Geo 被回收,玩家 `CurrentGeo` 增加
|
||
- `DeathShade` 消失(`Destroy` 或 `SetActive(false)`)
|
||
|
||
5. 不回收 DeathShade,再次死亡
|
||
|
||
**预期**:旧 `DeathShade` 被新的取代(只保留最新一次),旧 Geo 丢失。
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| DeathShade 生成位置 | 出现在死亡坐标 | ☐ |
|
||
| Geo 附着 | 显示正确的 Geo 数量 | ☐ |
|
||
| 回收 | 交互后 Geo 增加,DeathShade 消失 | ☐ |
|
||
| 第二次死亡覆盖 | 只保留最新 DeathShade | ☐ |
|
||
|
||
---
|
||
|
||
## MT-WORLD-04:世界状态持久化(WorldStateRegistry)
|
||
|
||
**目的**:验证 `WorldStateRegistry` 中场景状态(门开关、敌人死亡、机关激活)在房间切换后正确持久化。
|
||
|
||
### 步骤
|
||
|
||
1. 找到场景中一个可**一次性触发**的机关(如需要击打的开关、某只 One-Shot 敌人)
|
||
2. 激活该机关(或击杀该敌人)
|
||
3. 记录其 `stateId`(Inspector 可查)
|
||
4. 离开本房间,进入另一个房间,再返回本房间
|
||
|
||
**预期**:
|
||
- 机关仍处于已激活状态(门仍开启)
|
||
- One-Shot 敌人不重新生成
|
||
- `WorldStateRegistry.GetState(stateId)` 返回 `true`
|
||
|
||
5. 退出 Play Mode,再进入 Play Mode(读取存档)
|
||
|
||
**预期**:状态仍持久化(`SaveData.WorldStates` 中有对应 `stateId`)。
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 房间返回后状态 | 机关/敌人状态不重置 | ☐ |
|
||
| 读档后状态 | 重新进入 Play Mode 后状态仍持久 | ☐ |
|
||
|
||
---
|
||
|
||
## MT-WORLD-05:可破坏平台与移动平台
|
||
|
||
**目的**:验证 `CrumblePlatform`(踩后掉落)和 `MovingPlatform`(循环移动)物理行为。
|
||
|
||
### CrumblePlatform(碎裂平台)
|
||
|
||
1. 站在 `CrumblePlatform` 上
|
||
|
||
**预期**:
|
||
- 约 `crumbleDelay` 秒后平台开始抖动
|
||
- 抖动后平台消失(Deactivate/Destroy)
|
||
- 玩家正常下落
|
||
|
||
2. 等待 `resetTime` 秒
|
||
|
||
**预期**:平台重新出现(`SetActive(true)` 或重置到初始位置)。
|
||
|
||
### MovingPlatform(移动平台)
|
||
|
||
1. 站在 `MovingPlatform` 上
|
||
|
||
**预期**:
|
||
- 平台在两个 waypoint 之间来回循环移动
|
||
- 玩家随平台移动(玩家相对平台位置不变,通过 `transform.SetParent` 或速度叠加实现)
|
||
|
||
2. 从移动平台跳跃
|
||
|
||
**预期**:跳跃方向和高度正确(平台速度叠加到跳跃速度)。
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| CrumblePlatform 掉落 | 站上后 crumbleDelay 后消失 | ☐ |
|
||
| CrumblePlatform 重置 | resetTime 后平台重新出现 | ☐ |
|
||
| MovingPlatform 携带玩家 | 站上平台随之移动 | ☐ |
|
||
| 平台跳跃 | 速度叠加正确 | ☐ |
|
||
|
||
---
|
||
|
||
## MT-WORLD-06:能力门(AbilityGate)
|
||
|
||
**目的**:验证 `AbilityGate` 根据玩家已解锁能力决定是否通行。
|
||
|
||
### 步骤
|
||
|
||
**步骤 A:无对应能力时**
|
||
|
||
1. 确保玩家**未解锁** `AbilityGate` 要求的能力(如 DoubleJump)
|
||
2. 走到 `AbilityGate`
|
||
|
||
**预期**:门保持关闭(碰撞体阻挡玩家),显示所需能力提示。
|
||
|
||
**步骤 B:解锁能力后**
|
||
|
||
1. 通过调试工具或正常流程解锁所需能力
|
||
2. 再次走到 `AbilityGate`
|
||
|
||
**预期**:门开启(碰撞体禁用或动画播放),玩家可通过。
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 无能力 | 门阻挡通行 | ☐ |
|
||
| 有能力 | 门开启可通行 | ☐ |
|
||
|
||
---
|
||
|
||
## MT-WORLD-07:可收集物(Collectibles)
|
||
|
||
**目的**:验证地图中固定位置收集物(Geo 堆、道具)的拾取与持久化。
|
||
|
||
### 步骤
|
||
|
||
1. 找到场景中一个 `Collectible` 物品(如固定 Geo 堆)
|
||
2. 玩家走过拾取
|
||
|
||
**预期**:
|
||
- 拾取动画/音效播放
|
||
- 玩家 CurrentGeo 增加
|
||
- `Collectible.stateId` 写入 `WorldStateRegistry`
|
||
|
||
3. 离开房间再返回
|
||
|
||
**预期**:该收集物不再出现(One-Shot 语义)。
|
||
|
||
4. 读取存档重进
|
||
|
||
**预期**:该收集物仍不出现(状态持久化)。
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 拾取效果 | 动画/音效 + Geo 增加 | ☐ |
|
||
| 房间返回 | 不再出现 | ☐ |
|
||
| 读档后 | 仍不出现(持久化) | ☐ |
|
||
|
||
---
|
||
|
||
## MT-WORLD-08:世界地图显示
|
||
|
||
**目的**:验证 `WorldMap` UI 正确显示已探索房间和玩家当前位置。
|
||
|
||
### 步骤
|
||
|
||
1. 在多个房间之间来回切换(探索新房间)
|
||
2. 打开世界地图 UI(默认 Tab 键)
|
||
|
||
**预期**:
|
||
- 已探索的房间在地图上显示(灰色/彩色)
|
||
- 未探索的房间不显示(或显示为迷雾)
|
||
- 玩家当前位置有图标标识
|
||
|
||
3. 找到并激活 `MapPin`(地图标记物,如 Boss 房间标记)
|
||
|
||
**预期**:地图上对应位置出现 `MapPin` 图标(存档后重进仍存在)。
|
||
|
||
| 检查点 | 期望 | ✓ |
|
||
|--------|------|---|
|
||
| 已探索房间显示 | 地图正确显示探索过的房间 | ☐ |
|
||
| 未探索房间 | 未探索区域显示迷雾或不显示 | ☐ |
|
||
| 玩家位置标记 | 玩家图标在正确房间 | ☐ |
|
||
| MapPin 持久化 | 存档后 MapPin 仍存在 | ☐ |
|