摄像机区域的架构改动
This commit is contained in:
196
Docs/Practices/World_Region_Room_CameraZone.md
Normal file
196
Docs/Practices/World_Region_Room_CameraZone.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# 世界层级划分规范:大地图区域 / 房间 / 摄像机区域
|
||||
|
||||
> **适用范围**:`BaseGames.World`、`BaseGames.Camera`、`BaseGames.World.Map`
|
||||
> **关联代码**:`RoomController`、`RoomTransition`、`MapRoomDataSO`、`MapDatabaseSO`、`RoomCamera`、`CameraTriggerZone`、`CameraStateController`
|
||||
|
||||
---
|
||||
|
||||
## 一、三层结构总览
|
||||
|
||||
```
|
||||
大地图区域(Region) ← 纯分类标签,无独立 Scene
|
||||
└── 房间(Room) ← 一个 Addressable Unity 场景,加载/卸载的最小单元
|
||||
└── 摄像机区域(Camera Zone) ← Room 内部的视野子区域
|
||||
```
|
||||
|
||||
这三层粒度**严格单向包含**,不允许跨层引用(如 CameraZone 不应直接引用 Region 数据)。
|
||||
|
||||
---
|
||||
|
||||
## 二、大地图区域(Region)
|
||||
|
||||
### 定义
|
||||
|
||||
Region 在代码中仅体现为 `MapRoomDataSO.RegionId`(`string` 字段),**没有独立的 Scene 或 GameObject**。
|
||||
它是一个纯粹的分类标签,由各子系统按需读取。
|
||||
|
||||
### 命名约定
|
||||
|
||||
```
|
||||
Forest、Ruins、Underground、Castle、Abyss ...
|
||||
```
|
||||
|
||||
使用 PascalCase 英文单词,与 `MapRoomDataSO` 资产文件路径保持一致:
|
||||
```
|
||||
Assets/ScriptableObjects/Map/Room_Forest_01.asset → RegionId = "Forest"
|
||||
Assets/ScriptableObjects/Map/Room_Ruins_03.asset → RegionId = "Ruins"
|
||||
```
|
||||
|
||||
### 各系统对 RegionId 的用途
|
||||
|
||||
| 系统 | 行为 |
|
||||
|------|------|
|
||||
| `MapPanel` | 按 `RegionId` 分组格子,可染不同底色 |
|
||||
| `BGMController` | 监听 `EVT_RoomEntered`,比较前后 `RegionId` 决定是否淡入淡出新 BGM |
|
||||
| `DifficultyScalerSO` | 可按 Region 配置不同难度曲线 |
|
||||
|
||||
### 跨区域事件(已实现)
|
||||
|
||||
`MapManager.OnRoomEntered` 每次进房时比较 `RegionId`,区域变化时广播 `_onRegionChanged`(`StringEventChannelSO`,建议资产命名 `EVT_RegionChanged`)。在 Inspector 中将对应的 `StringEventChannelSO` 资产拖入 `_onRegionChanged` 槽位即可启用。
|
||||
|
||||
订阅示例:
|
||||
```csharp
|
||||
// BGMController — 区域切换时淡入新 BGM
|
||||
_onRegionChanged?.Subscribe(regionId => PlayBGMForRegion(regionId)).AddTo(_subs);
|
||||
|
||||
// MapPanel — 可选:高亮当前区域格子
|
||||
_onRegionChanged?.Subscribe(_ => RefreshRegionHighlight()).AddTo(_subs);
|
||||
```
|
||||
|
||||
也可通过接口直接查询当前区域(无需订阅事件):
|
||||
```csharp
|
||||
var region = ServiceLocator.Get<IMapService>().CurrentRegionId;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、房间(Room)
|
||||
|
||||
### 定义
|
||||
|
||||
Room = **一个 Addressable Unity 场景**,通过 `SceneLoader` 以 Additive 模式加载,是地图加载/卸载的最小单元。
|
||||
|
||||
每个 Room 场景必须包含:
|
||||
- `RoomController`(挂在 `[RoomRoot]` 下):持有 `_roomId`、`_spawnPoints[]`、`_roomCamera`
|
||||
- 至少一个 `PlayerSpawnPoint`(`TransitionId` 与上游 `RoomTransition._targetTransitionId` 对应)
|
||||
- 对应的 `MapRoomDataSO` 资产(`RoomId` 与 `_roomId` 一致)
|
||||
|
||||
### 划分原则
|
||||
|
||||
**应该单独成一个 Room 的情况:**
|
||||
|
||||
| 情况 | 原因 |
|
||||
|------|------|
|
||||
| 地形拓扑彻底断开(门、竖井、地下入口) | 自然的 Additive 场景边界 |
|
||||
| 有独立存档点(`SavePoint`) | 复活逻辑依赖 `roomId` 定位存档点 |
|
||||
| Boss 竞技场 | `IsBossRoom = true`,`GameManager` 监听 `EVT_BossFightStarted` |
|
||||
| 商店 / 特殊 NPC 房间 | `IsShop = true`,地图图标独立标记 |
|
||||
| 独立 BGM 区域 | `RegionId` 变化或同区域内 BGM 不同 |
|
||||
| 地图格子单元(`GridPosition` 有意义的独立位置) | `MapPanel` 以格为单位渲染 |
|
||||
|
||||
**不要过度切分的情况:**
|
||||
|
||||
| 情况 | 建议 |
|
||||
|------|------|
|
||||
| 无地图意义的短走廊 | 合并到相邻功能房间,避免触发无意义的 Additive 加载/卸载 |
|
||||
| 同一视野无特殊逻辑的连续平台 | 合并,减少 `RoomTransition` 触发频率 |
|
||||
|
||||
### 命名约定
|
||||
|
||||
```
|
||||
Room_{RegionId}_{序号两位}
|
||||
示例:Room_Forest_01、Room_Ruins_03、Room_Boss_Forest_01
|
||||
```
|
||||
|
||||
Addressable Key 与场景名保持一致,`MapRoomDataSO.RoomId` 与两者均一致。
|
||||
|
||||
---
|
||||
|
||||
## 四、摄像机区域(Camera Zone)
|
||||
|
||||
### 定义
|
||||
|
||||
Camera Zone = Room 内部的**视野子区域**,由以下组件组合定义:
|
||||
|
||||
| 组件 | 职责 |
|
||||
|------|------|
|
||||
| `RoomCamera` | 包装 `CinemachineCamera`,持有该区域的 `RoomVisibleArea`、偏移、混合配置 |
|
||||
| `RoomVisibleArea` | `PolygonCollider2D`,作为 Cinemachine Confiner2D 的限位边界 |
|
||||
| `CameraTriggerZone` | `BoxCollider2D` 触发器,玩家进入时调用 `ICameraService.SwitchRoom(targetCamera)` |
|
||||
|
||||
`CameraStateController` 同时只激活一个 `RoomCamera`,切换时旧相机 `Priority = 0`(停用),新相机 `Priority = 15`(激活)。
|
||||
|
||||
### 划分原则
|
||||
|
||||
**需要新建 Camera Zone 的情况:**
|
||||
|
||||
| 情况 | 配置方式 |
|
||||
|------|---------|
|
||||
| 房间内有高低落差或宽窄通道 | 各区域放独立 `CameraTriggerZone` + `RoomCamera`(独立 `RoomVisibleArea`) |
|
||||
| Boss 竞技场入场锁定视野 | 进入 Arena 触发器切换到关闭 Follow 的固定 `RoomCamera` |
|
||||
| 可选路径(上路/下路)视野不同 | 每条路各放 1 个触发器 |
|
||||
|
||||
**不需要额外 Camera Zone 的情况:**
|
||||
|
||||
| 情况 | 配置方式 |
|
||||
|------|---------|
|
||||
| 房间完全平坦无特殊视野需求 | 仅 `RoomController._roomCamera` 1 个,无需 `CameraTriggerZone` |
|
||||
|
||||
### Room 内 Camera Zone 的标准层级结构
|
||||
|
||||
```
|
||||
[Room_Forest_01]
|
||||
├── RoomController (_roomCamera → Cam_Main)
|
||||
├── Cameras/
|
||||
│ ├── Cam_Main (RoomCamera + RoomVisibleArea) ← 入口默认视野
|
||||
│ ├── Cam_Narrow (RoomCamera + RoomVisibleArea) ← 密道区
|
||||
│ └── Cam_Arena (RoomCamera + RoomVisibleArea) ← Boss 场
|
||||
├── Triggers/
|
||||
│ ├── Trigger_Narrow (CameraTriggerZone → Cam_Narrow)
|
||||
│ └── Trigger_Arena (CameraTriggerZone → Cam_Arena)
|
||||
├── SpawnPoints/
|
||||
│ ├── SpawnPoint_Entry (transitionId: "entry_main")
|
||||
│ └── SpawnPoint_Arena (transitionId: "entry_arena")
|
||||
└── [GameplayObjects] ...
|
||||
```
|
||||
|
||||
### 混合配置复用
|
||||
|
||||
不同 Camera Zone 切换时的过渡动画通过 `CameraBlendProfileSO` 配置:
|
||||
```
|
||||
Assets/ScriptableObjects/Camera/Blend_Default.asset → EaseInOut 0.5s(大多数房间切换)
|
||||
Assets/ScriptableObjects/Camera/Blend_BossArena.asset → Cut 0s(Boss 入场瞬切)
|
||||
Assets/ScriptableObjects/Camera/Blend_Slow.asset → EaseInOut 1.5s(过场/剧情用)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、完整示例
|
||||
|
||||
```
|
||||
Region: Forest(森林区域)
|
||||
│
|
||||
├── Room: Room_Forest_01(入口区)
|
||||
│ RoomCamera: 1个,无子区域
|
||||
│ RoomTransition → Room_Forest_02(右侧出口)
|
||||
│ RoomTransition → Room_Ruins_01(跨区域出口,需钥匙)
|
||||
│
|
||||
├── Room: Room_Forest_02(主干道 + 密道)
|
||||
│ RoomCamera: Cam_Main(平台区宽视野)
|
||||
│ RoomCamera: Cam_Narrow(树干夹缝,窄限位)
|
||||
│ CameraTriggerZone → Cam_Narrow(进入密道触发)
|
||||
│ RoomTransition → Room_Forest_Boss_01
|
||||
│
|
||||
└── Room: Room_Forest_Boss_01(Boss 竞技场)
|
||||
RoomCamera: Cam_Entrance(进门走廊)
|
||||
RoomCamera: Cam_Arena(Boss战,固定锁定视野)
|
||||
CameraTriggerZone → Cam_Arena(进入竞技场触发)
|
||||
IsBossRoom = true → GameManager 监听 EVT_BossFightStarted
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、编辑器工具
|
||||
|
||||
- **`BaseGames → Camera → Room Camera Setup`**:扫描当前场景所有 `RoomCamera` / `CameraTriggerZone`,显示绑定状态并提供一键修复。新建 Room 后务必用此工具检查是否存在未绑定的 Camera Zone。
|
||||
- **`MapDatabaseSO.GetRoom(roomId)`**:已内置懒加载字典索引(O(1) 查找),无需手动维护索引。
|
||||
Reference in New Issue
Block a user