Files
zeling_v2/Docs/Verification/09_Manual_WorldSystem.md

351 lines
14 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.
# 手动测试 09 · 世界与场景系统
> **测试类型**Unity Editor 手动测试Play Mode
> **覆盖模块**`BaseGames.World`、`BaseGames.World.Map`
> **依赖组件**`RoomController`、`RoomTransition`、`SavePoint`、`DeathShade`、`WorldStateRegistry`
> **场景要求**:含多房间连接(至少 2 个 Room SceneAbilityGateMovingPlatformSavePoint
---
## 快速工具
| 工具 | 用途 | 菜单路径 |
|------|------|----------|
| **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 + CompositeCollider2DLayer=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 仍存在 | ☐ |