Files
zeling_v2/Docs/Verification/12_Manual_CameraSystem.md
2026-05-17 07:56:12 +08:00

24 KiB
Raw Permalink Blame History

手动测试 12 · 区域相机系统

测试类型Unity Editor 手动测试Play Mode
覆盖模块CameraAreaCameraTriggerZoneCameraStateControllerCinemachineConfiner2DCameraBlendProfileSO
前置文档Phase1_Verification_Guide.md §1验证前准备


快速工具

工具 用途 菜单路径
Camera Area Setup窗口 扫描场景中所有 CameraArea/TriggerZone/Controller显示绑定状态提供一键修复 BaseGames → Camera → Camera Area Setup
Place Camera Area 生成 CameraArea 节点(含 PolygonCollider2D 限位边界) BaseGames → Scene → Place → Camera Area
Place Camera Trigger Zone 生成 CameraTriggerZone + BoxCollider2D Trigger BaseGames → Scene → Place → Camera Trigger Zone

典型工作流

  1. 在 Persistent 场景中放置两台全局虚拟相机(VCamA / VCamB),绑定到 CameraStateController._vcamA/_vcamB
  2. 在关卡场景中使用 Place Camera Area 为每个相机区域放置 CameraArea 数据节点(一个房间可放多个)。
  3. 选中 CameraArea,在 Scene 视图中拖拽黄色可视区域的边 Handle 调整可见范围,然后点击 Inspector 底部 「从可视区域更新限位区域(透视)」 自动换算限位多边形。
  4. 使用 Place Camera Trigger Zone 在区域入口放置触发器,并将目标 CameraArea 拖入 _targetArea
  5. 打开 Camera Area Setup 窗口,点击 为全局 VCam 赋值 Follow 目标(会自动在 Player 下创建或复用 CameraFollowTarget 子节点并绑定)。
  6. 所有条目显示绿色 ● → 进入 Play Mode 验证。

目录

  1. 系统架构说明
  2. Persistent 场景配置CameraStateController
  3. 关卡场景配置CameraArea + CameraTriggerZone
  4. ScriptableObject 资产说明
  5. Camera Area Setup 工具详解
  6. 验收测试用例
  7. 常见问题排查

1. 系统架构说明

Persistent.unity
└── [Camera]
    └── CameraStateController          ExecutionOrder = -100
          组件: CameraStateController
          │     _vcamA   → VCamA全局虚拟相机 A
          │     _vcamB   → VCamB全局虚拟相机 B
          │     _lookSystem → CameraLookSystem 节点
          组件: CinemachineBrain        ← 实际渲染相机(随 Main Camera 放置)
          组件: CinemachineImpulseSource ← 屏幕抖动信号源
    ├── CameraLookSystem               ← 运行时由 SetFollowTarget() 赋值基准目标
    │     组件: CameraLookSystem        双轴窥视偏移 + 速度门控;输出 VirtualTarget
    ├── VCamA
    │     组件: CinemachineCamera       Follow = CameraLookSystem.VirtualTarget运行时自动赋值
    │     组件: CinemachinePositionComposer    Body 跟随组件;初始值与 CameraArea 默认值对齐
    │     组件: CinemachineConfiner2D   ← 由 CameraStateController 动态更新 BoundingShape2D
    │     组件: CameraAxisLockExtension       锁定 X 或 Y 轴(竖井 / 走廊场景)
    │     组件: CameraAsymmetricDampingExtension  非对称 Y 阻尼(下落快恢复,起跳慢追赶)
    │     组件: CameraAdaptiveLookaheadExtension   速度自适应 Lookahead移动快 → 预见更多)
    └── VCamB
          组件: CinemachineCamera       Follow = CameraLookSystem.VirtualTarget运行时自动赋值
          组件: CinemachinePositionComposer    同 VCamA
          组件: CinemachineConfiner2D   ← 由 CameraStateController 动态更新 BoundingShape2D
          组件: CameraAxisLockExtension
          组件: CameraAsymmetricDampingExtension
          组件: CameraAdaptiveLookaheadExtension

Level_01.unity
├── [CameraAreas]
│   ├── CameraArea_A                   区域 A可在同一房间内放置多个
│   │   组件: CameraArea               _confinerCollider → PolygonCollider2D
│   │   │                             _visibleBounds可视矩形
│   │   │                             _blendProfile → CameraBlendProfileSO可选
│   │   │                             _dedicatedCamera专有 VCam可选priority > 全局)
│   │   └── PolygonCollider2D         定义该区域的相机限位边界
│   │
│   └── CameraArea_B                   区域 B
│       ...(同上)
│
└── [Triggers]
    ├── CameraTriggerZone_AB           区域 A→B 入口
    │   组件: CameraTriggerZone         _targetArea = CameraArea_B
    │   组件: BoxCollider2D             isTrigger = true
    └── CameraTriggerZone_BA           区域 B→A 入口
        组件: CameraTriggerZone         _targetArea = CameraArea_A
        组件: BoxCollider2D             isTrigger = true

核心流程

  1. 玩家进入 CameraTriggerZoneOnTriggerEnter2D 调用 ICameraService.SwitchArea(targetArea)
  2. CameraStateController.SwitchArea → 应用 BlendProfileCinemachineBrain.DefaultBlend
    • 无专有 VCam:配置非活跃全局 VCam 的 CinemachineConfiner2D.BoundingShape2D → 提升其优先级至 10 → 降低旧 VCam 优先级至 0ping-pongCinemachine Brain 自动触发混合过渡
    • 有专有 VCam:提升 _dedicatedCamera 优先级至 _dedicatedPriority(默认 20高于全局 VCamCinemachine 自动切换

2. Persistent 场景配置CameraStateController

2.1 组件放置

在 Persistent 场景的 [Camera] 下建立以下节点结构:

GameObject 挂载组件 说明
[CameraController] CameraStateControllerCinemachineBrainCinemachineImpulseSource ExecutionOrder = -100
CameraLookSystem CameraLookSystem 双轴窥视偏移(垂直+水平)+ 速度门控;输出 VirtualTarget 供 VCam 跟随;拖入 CameraStateController._lookSystem
VCamA CinemachineCameraCinemachinePositionComposerCinemachineConfiner2DCameraAxisLockExtensionCameraAsymmetricDampingExtensionCameraAdaptiveLookaheadExtension 全局虚拟相机 APositionComposer 是 Body 组件,必须存在;拖入 CameraStateController._vcamA
VCamB CinemachineCameraCinemachinePositionComposerCinemachineConfiner2DCameraAxisLockExtensionCameraAsymmetricDampingExtensionCameraAdaptiveLookaheadExtension 全局虚拟相机 B同 VCamA拖入 CameraStateController._vcamB

注意CinemachineBrain 须挂在附有 Camera 组件Main Camera的 GameObject 上, 否则 Cinemachine 无法驱动视口渲染。两台全局 VCam 初始优先级均为 0CameraStateController 在运行时动态管理。

2.2 字段绑定清单

打开 Camera Area Setup 窗口(BaseGames → Camera → Camera Area SetupCameraStateController 区域确认以下项目全为绿色 ●:

字段 期望状态
_vcamA (CinemachineCamera) ● 已绑定
_vcamB (CinemachineCamera) ● 已绑定
_brain (CinemachineBrain) ● 已绑定
_lookSystem (CameraLookSystem) ● 已绑定
_impulseSource (CinemachineImpulseSource) ◌ 可选;用于屏幕抖动
_defaultBlendProfile (CameraBlendProfileSO) ◌ 可选;未设置则无混合过渡

3. 关卡场景配置CameraArea + CameraTriggerZone

3.1 添加 CameraArea

方式 A使用快速放置工具(推荐)

  1. 菜单 BaseGames → Scene → Place → Camera Area
  2. 工具自动创建以下节点结构:
    CameraArea
    ├── CameraArea组件_confinerCollider 已绑定)
    └── PolygonCollider2D默认矩形 24×12isTrigger = true定义限位区域
    
  3. 打开 Camera Area Setup 窗口,点击 为全局 VCam 赋值 Follow 目标 (工具会自动在 Player 下查找或创建 CameraFollowTarget 子节点,绑定到两台全局 VCam
  4. 手动调整子节点 PolygonCollider2D 顶点定义限位范围。

方式 B手动创建

  1. 新建空 GameObject命名如 CameraArea_A
  2. 挂载 CameraAreaBaseGames.Camera
  3. 在同一 GameObject 或子对象上创建 PolygonCollider2D
  4. PolygonCollider2D 拖入 CameraArea._confinerCollider
  5. (可选)如需专有相机参数,新建独立 VCam GameObject挂载 CinemachineCamera,拖入 CameraArea._dedicatedCamera

一个房间可放置多个 CameraArea,如大厅区域与 Boss 区域分别使用不同的限位和混合配置。

3.2 调整限位区域PolygonCollider2D

CameraArea 上(或子节点)的 PolygonCollider2D 定义了相机在该区域内的移动边界。

  • 编辑顶点:选中 CameraArea 节点 → Inspector 中 PolygonCollider2D → 点击 Edit Collider 图标,在 Scene 视图拖动顶点
  • 自动修复:打开 Camera Area Setup 窗口,对应条目点击 修复:绑定子节点 PolygonCollider2D

最佳实践:限位区域应比实际可见范围大一格以上(约 1 unit避免相机卡在边缘。

3.3 添加 CameraTriggerZone

使用快速放置工具(推荐)

  1. 菜单 BaseGames → Scene → Place → Camera Trigger Zone
  2. 工具生成:
    CameraTriggerZone
    ├── CameraTriggerZone组件_playerTag = "Player"
    └── BoxCollider2DisTrigger = true默认 2×2
    
  3. 在 Inspector 中将目标 CameraArea 拖入 CameraTriggerZone._targetArea
  4. 调整 BoxCollider2D 大小至覆盖整个区域过渡走廊宽度(通常 2×3 或 2×4

典型布局

[区域 A]  ‖  [走廊]  ‖  [区域 B]
            ←← TriggerZone_A→B (_targetArea = CameraArea_B)
            TriggerZone_B→A (_targetArea = CameraArea_A) →→

双向过渡需要两个 TriggerZone 分别放置在走廊两端,各自指向对应区域的 CameraArea

3.4 全局 VCam Follow 绑定

Persistent 场景中两台全局 VCam 的 CinemachineCamera.Follow 不直接指向 Player 而是指向 CameraLookSystem 组件在运行时生成的 [CameraLookTarget] 虚拟目标节点
该节点由 CameraStateController.SetFollowTarget(Transform) 在玩家注册时自动创建并赋值, 其世界位置 = Player 基准目标位置 + 当前窥视偏移(CameraLookSystem 的双轴输出)。

不要在 Inspector 中手动把 VCam.Follow 拖到 Player 本身或 Player/CameraFollowTarget。
SetFollowTarget 会在运行时覆盖,且直接指向 Player 会绕过窥视偏移计算。

工具支持
Camera Area Setup 窗口 → 为全局 VCam 赋值 Follow 目标 按钮
→ 该按钮仅用于调试回退(绕过 LookSystem直指 Player/CameraFollowTarget
正式流程请通过 ICameraService.SetFollowTarget(playerTransform) 注册,由系统自动处理。


3.5 编辑可视区域(透视相机)

CameraArea 支持在 Scene 视图中直接定义摄像机的最大可视范围,并自动换算为限位 PolygonCollider2D 的顶点坐标。

Inspector 字段

字段 说明
_visibleBounds 摄像机应显示的最大可视矩形世界坐标Scene 视图选中时显示为黄色矩形
_cameraDepth 摄像机到场景平面Z = 0的垂直距离0 则自动读取 |transform.position.z|

Scene 视图拖拽编辑

选中 CameraArea GameObject 后Scene 视图出现:

  • 黄色矩形:可视区域(玩家在此区域内的最大可见范围)
  • 蓝色多边形:当前 PolygonCollider2D 限位边界(参考用)

矩形四条边各有一个滑动 Handle拖拽即可调整

  • 左 / 右边 Handle沿 X 轴滑动
  • 上 / 下边 Handle沿 Y 轴滑动

同步到限位区域

调整好可视区域后,在 Inspector 底部点击 「从可视区域更新限位区域(透视)」,工具根据以下公式换算限位多边形:

halfH   = depth × tan(vFOV / 2)
halfW   = halfH × aspectRatio
confiner = visibleBounds 向内收缩 (halfW, halfH)

含义相机视口边缘恰好与可视区域边框对齐。若区域小于单屏inset 后为负),限位收缩为中心点,相机固定居中。

Inspector 参数预览区实时显示 FOV来源专有 VCam → 全局 VCamA → Camera.main → 60°、深度、视口半宽 / 半高的计算值。

3.6 专有 VCam特殊区域

需要独特相机参数(如 Boss 区域特写 FOV的区域可在 CameraArea._dedicatedCamera 中指定一台独立的 CinemachineCamera

  1. 在关卡场景中新建空 GameObject挂载 CinemachineCamera(设置好 Lens、Follow、Noise 等参数)
  2. 将其拖入该 CameraArea._dedicatedCamera
  3. _dedicatedPriority(默认 20须高于全局 VCam 的激活优先级10

进入该区域时,CameraStateController 自动提升专有 VCam 优先级Cinemachine 混合切换;离开时优先级归零,全局 VCam 重新接管。


4. ScriptableObject 资产说明

4.1 CameraBlendProfileSO

创建路径Assets → Create → BaseGames → Camera → BlendProfile

字段 说明 典型值
Style 混合曲线类型EaseInOut / Linear / Cut / Custom EaseInOut
BlendTime 混合持续时间(秒) 0.5
CustomCurve Style = Custom 时使用

使用

  • 全局默认:拖入 CameraStateController._defaultBlendProfile
  • 单独区域:拖入对应 CameraArea._blendProfile(覆盖全局默认)

4.2 CameraConfigSO

Legacy / 已废弃CameraConfigSO 是早期相机系统的配置资产,现已不再被 CameraStateController 读取或应用。
当前架构直接通过 CameraArea 字段(ScreenPositionDeadZoneSizeLookaheadTimeDampingDownDampingUp 等)在 ConfigureSlot 时写入 Cinemachine 组件,无需此 SO。
若项目中仍存在 CameraConfigSO 资产,可安全忽略或删除。

创建路径Assets → Create → BaseGames → Camera → CameraConfig

字段 说明 典型值
FollowDamping 跟随阻尼
LookAheadTime 朝向预见时间
DeadZoneSize 死区尺寸
SoftZoneSize 软区尺寸
LookDownOffset 俯视偏移
LookUpOffset 仰视偏移
DefaultImpulseStrength 默认震屏强度

CameraConfigSO 的配置值须由运行时的 CameraStateController 或相机系统读取并写入 Cinemachine 组件,具体写入逻辑取决于 CameraStateController.ApplyConfig() 的实现(如有扩展)。


5. Camera Area Setup 工具详解

菜单:BaseGames → Camera → Camera Area Setup

5.1 界面区域说明

工具栏

  • ↻ 刷新:手动重新扫描当前已加载场景
  • Place Camera Area:快捷调用 BaseGames → Scene → Place → Camera Area
  • Place Trigger Zone:快捷调用 BaseGames → Scene → Place → Camera Trigger Zone

CameraStateController 区域
显示控制器组件绑定状态。若显示"未找到"提示,说明 Persistent 场景未加载(属正常)。

图标 含义
(绿) 项目已正确配置
(红) 缺失必填项
(黄) 可选项未设置

检查项:_vcamA_vcamB(必填)、_brain(必填)、_lookSystem(必填)、_impulseSource(可选)、_defaultBlendProfile(可选)

底部按钮:为全局 VCam 赋值 Follow 目标 → 查找 Player/CameraFollowTarget 并写入两台 VCam 的 Follow 字段。

Camera Areas 区域
为每个 CameraArea 显示一行,检查项:

字段 状态
_confinerCollider (PolygonCollider2D) 必填
_dedicatedCamera(专有 VCam 可选
_blendProfile 可选

每行可点击 修复:绑定子节点 PolygonCollider2D 自动修复 _confinerCollider 未绑定的情况。

Camera Trigger Zones 区域
列出所有 CameraTriggerZone,高亮显示 _targetArea 未绑定的项目(红色 ✗)。

5.2 典型使用流程

1. 打开窗口 BaseGames → Camera → Camera Area Setup
2. (仅首次)加载 Persistent 场景,确认 _vcamA/_vcamB/_brain 全绿
3. 在关卡场景中使用 Place Camera Area × N一个房间可放多个
4. 选中每个 CameraArea在 Scene 视图拖拽黄色可视区域边 Handle点击 [从可视区域更新限位区域(透视)]
5. 点击 [为全局 VCam 赋值 Follow 目标](自动创建 Player/CameraFollowTarget 并绑定)
6. 使用 Place Trigger Zone 添加 N 个触发器,手动绑定 _targetArea
7. 所有条目绿色 ● → 进入 Play Mode 验证

6. 验收测试用例

测试前检查清单

# 检查项 操作
1 Console 无红色 Error Window → General → Console
2 Camera Area Setup 窗口所有必填项为绿色 ● BaseGames → Camera → Camera Area Setup
3 Player 已在场景中tag = Player Hierarchy
4 Physics2D Layer 矩阵已配置 BaseGames → Tools → Validate Physics2D Layer Matrix

MT-CAM-01全局 VCam 正常跟随

目的:验证全局 VCam 激活后 CinemachineCamera 跟随玩家移动。

步骤:

  1. Persistent 场景中放置 VCamA/VCamBFollow = Player/CameraFollowTarget
  2. 关卡场景中放置一个 CameraArea,通过 CameraTriggerZoneRoomController 触发 SwitchArea
  3. Play,在 Scene 视图和 Game 视图同时观察
  4. 用 WASD/方向键移动 Player

预期结果:

检查点 期望
Game 视图相机跟随 Player 移动 玩家靠近边缘时相机平滑跟进
相机不会越出 CameraArea 的限位范围 玩家走到边角时相机贴边停止
无跳变(平滑)跟随 无抖动、跳帧

MT-CAM-02区域相机切换CameraTriggerZone

目的:验证玩家穿越触发器后全局 VCam ping-pong 平滑过渡到目标区域。

步骤:

  1. 场景中放置两个 CameraAreaA、B各有独立 PolygonCollider2D 限位
  2. 在两区域之间放置两个 CameraTriggerZone(各自 _targetArea 互指)
  3. Play,引导 Player 穿越触发区进入区域 B

预期结果:

检查点 期望
穿越触发器后 Game 视图开始混合过渡 相机平滑从 A 过渡到 B非切割
过渡时长约等于 CameraBlendProfileSO.BlendTime 与 SO 设置一致(默认 0.5s
过渡后相机限位在 CameraArea_B 的边界内 玩家无法把相机带出 B 的限位范围
反向穿越触发器后相机切回 A 同上,反向过渡

MT-CAM-03CinemachineConfiner2D 边界限位

目的:验证 CinemachineConfiner2D 正确将相机限制在 CameraArea 限位范围内。

步骤:

  1. 打开关卡场景,确认 CameraArea._confinerCollider 已绑定,且 CameraStateController 已调用 SwitchArea
  2. Play,将 Player 移动到房间的各个角落和边缘

预期结果:

检查点 期望
相机在所有方向均不超出 PolygonCollider2D 多边形范围 无越界
小房间(相机视口 > 房间)时相机居中,不晃动 稳定居中

常见失败原因

  • CameraArea._confinerCollider 未绑定 → 打开 Camera Area Setup 点击修复
  • PolygonCollider2D 顶点数量少于 3 → 确认 _confinerCollider 路径顶点完整

MT-CAM-04屏幕抖动CinemachineImpulseSource

目的:验证调用 ICameraService.TriggerImpulse 时 Game 视图画面抖动。

步骤:

  1. 确认 CameraStateController._impulseSource 已绑定
  2. Play
  3. 在 Console 执行(或通过游戏内事件触发):
    ServiceLocator.Get<ICameraService>().TriggerImpulse(0.5f);
    
    或让玩家受到一次伤害(若伤害系统已接入抖动调用)

预期结果:

检查点 期望
Game 视图画面发生轻微抖动后恢复稳定 抖动时长约 0.20.4s,幅度可见
无 Console 错误 无 NullReferenceException

MT-CAM-05初始场景无 CameraStateController 时安全降级

目的:验证场景中未加载 Persistent 场景时,CameraTriggerZone 不崩溃。

步骤:

  1. 单独打开关卡场景(不加载 Persistent.unity
  2. Play,移动 Player 穿越 CameraTriggerZone

预期结果:

检查点 期望
无 NullReferenceException ServiceLocator.GetOrDefault<ICameraService>() 返回 null 时跳过
Console 可能有黄色 Warning服务未注册 无红色 Error

MT-CAM-06多场景加载时相机状态正确恢复

目的:验证通过 SceneLoader 加载新场景时,CameraStateController 正确切换到新场景首个 CameraArea

步骤:

  1. 以 Persistent + Level_01 双场景启动
  2. Play,触发场景加载切换到 Level_02
  3. Level_02 加载完成后观察相机

预期结果:

检查点 期望
Level_02 的 RoomController 调用 SwitchArea 后相机切换正确 无黑屏、无旧场景相机残影
旧场景 CameraArea 随场景卸载,全局 VCam 状态不受干扰 无相机混合错误

注意:全局 VCam 常驻 Persistent 场景,CinemachineConfiner2D.BoundingShape2DSwitchArea 时动态更新, 旧场景卸载后引用会变为 null须确保 SwitchArea 在新场景 CameraArea 可用后再调用。


7. 常见问题排查

现象 原因 解决
Game 视图相机不动(黑屏或固定位置) 全局 VCam Follow 未绑定 ICameraService.SetFollowTarget(player) 注册玩家;或 Camera Area Setup → 为全局 VCam 赋值 Follow 目标
相机追赶卡顿/震颤 CinemachineConfiner2D.BoundingShape2D 未绑定或碰撞体顶点有误 确认 CameraArea._confinerCollider 已绑定PolygonCollider2D 顶点数 ≥ 3
进入区域后限位未更新(仍在旧区域限位内) CameraArea._confinerCollider 为空,ConfigureSlot 跳过了更新 打开 Camera Area Setup 修复 _confinerCollider 绑定
场景中有多个 CinemachineBrain Persistent 场景外又添加了含 Camera 组件的对象 仅 Main Camera 上保留一个 Brain
过渡时画面闪切而非混合 CameraBlendProfileSO.BlendTime = 0 或 Style = Cut 检查 BlendProfile 并将 BlendTime 设置为 > 0
CameraStateController 未找到Console 错误) Persistent 场景未加载 确认 Build Settings 中 Persistent.unity 第一位;开发测试用 SceneManager.LoadScene("Persistent", Additive)
触发器无响应(玩家穿越后相机不切) CameraTriggerZone._targetArea 未绑定,或 _playerTag 不匹配 检查 _targetArea 是否已拖入 CameraArea;确认 Player Tag = "Player"
Camera Area Setup 窗口列表为空 场景未保存或 DomainReload 后未刷新 点击窗口内 ↻ 刷新 按钮
专有 VCam 不切换 _dedicatedPriority ≤ 全局激活优先级(默认 10 _dedicatedPriority 设置为 > 10默认 20 已满足)
Camera Area Setup 中 _lookSystem 红色 ✗ CameraStateController._lookSystem 未绑定 将 Persistent 场景 [Camera]/CameraLookSystem 节点拖入该字段;或重新运行 SceneScaffoldTools
按住方向键相机偏移不出现(窥视无效) CameraLookSystem._baseTarget 未设置 确认 ICameraService.SetFollowTarget(player) 在玩家 Awake/Start 后调用
下落时相机跟随过慢(非对称阻尼异常) CameraAsymmetricDampingExtension 未挂到 VCamA/VCamBDampingDown 未被 ConfigureSlot 写入 确认两台 VCam 已挂载该扩展;检查 CameraArea._dampingDown > 0
高速移动时 Lookahead 不变化 CameraAdaptiveLookaheadExtension 未挂到 VCamA/VCamBSetConfiguredMax 未被调用 确认两台 VCam 已挂载该扩展;检查 ConfigureSlot 代码路径正常执行