7.5 KiB
世界层级划分规范:大地图区域 / 房间 / 摄像机区域
适用范围:
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 槽位即可启用。
订阅示例:
// BGMController — 区域切换时淡入新 BGM
_onRegionChanged?.Subscribe(regionId => PlayBGMForRegion(regionId)).AddTo(_subs);
// MapPanel — 可选:高亮当前区域格子
_onRegionChanged?.Subscribe(_ => RefreshRegionHighlight()).AddTo(_subs);
也可通过接口直接查询当前区域(无需订阅事件):
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) 查找),无需手动维护索引。