26 KiB
02 · 镜头系统
命名空间
BaseGames.Camera
所属文档集 ← 返回索引 · 总览
依赖 Cinemachine 3 ·BaseGames.Core.Events
目录
- 设计目标
- Cinemachine 3 核心组件
- 虚拟相机架构
- 3.1 全局双机(Global A/B)
- 3.2 房间专用相机(可选)
- 3.3 特殊状态相机
- CameraStateController
- 可视区域与触发区域
- 5.1 可视区域(RoomVisibleArea)
- 5.2 切换触发区域(CameraTriggerZone)
- 过渡效果:CameraBlendProfileSO
- 镜头震动:CinemachineImpulse
- 像素对齐:Pixel Perfect 集成
- CameraConfigSO — 配置资产
- 场景搭建规范
- 编辑器友好设计
- 大房间相机处理
- 12.1 竖向/横向无缝滚动房间
- 12.2 子区域相机分段
- 12.3 滚动限制模式
1. 设计目标
- 镜头行为完全由 Cinemachine 3 驱动,不手动操作
Camera.transform - 全局 A/B 双机交替复用:切换房间时将 inactive 的全局相机预设好新边界再切过去,彻底消除 Confiner 跳变
- 房间专用相机(可选):每个房间可配置专属
VCam_Room,存在时自动优先使用;不配置则回退到全局双机 - 触发区域驱动切换:
CameraTriggerZoneTrigger Collider 控制镜头切换时机,可在 Scene 视图中可视化编辑 - 可视区域独立编辑:
RoomVisibleArea的PolygonCollider2D在 Scene 视图可直接拖拽顶点,Gizmo 实时预览视野 - 过渡效果可配置:
CameraBlendProfileSO资产,可逐触发区域覆盖全局默认混合风格与时长 - 镜头震动通过
CinemachineImpulseSource发布,与 Feel 的MMF_CinemachineImpulse集成 - 像素艺术风格保持亚像素锁定,防止渲染模糊
2. Cinemachine 3 核心组件
| 组件 | 挂载位置 | 说明 |
|---|---|---|
CinemachineBrain |
Main Camera | 统一调度所有虚拟相机,同一时刻激活优先级最高者 |
CinemachineCamera |
虚拟相机 GO | Cinemachine 3 的虚拟相机基础组件(取代旧版 CinemachineVirtualCamera) |
CinemachinePositionComposer |
虚拟相机组件 | 控制跟随目标偏移与阻尼(探索镜头用) |
CinemachineOrbitalFollow |
虚拟相机组件 | Boss 战镜头围绕目标(可选) |
CinemachineConfiner2D |
虚拟相机组件 | 房间边界约束(每个房间设置独立 Collider2D) |
CinemachineImpulseSource |
虚拟相机 GO | 发布震动冲量(与 Feel 集成) |
CinemachineImpulseListener |
虚拟相机组件 | 接收并响应冲量(震屏强度系数) |
CinemachinePixelPerfect |
虚拟相机组件 | 与 PixelPerfectCamera 协同,消除亚像素抖动 |
3. 虚拟相机架构
3.1 全局双机(Global A/B)
Persistent 场景中预置两台全局虚拟相机,同一时刻仅一台处于"热"优先级。切换房间时将 inactive 机预配置好新 Confiner,再升高其优先级触发 Blend,Blend 结束后互换角色。
| 虚拟相机 | 默认 Priority | 说明 |
|---|---|---|
VCam_Global_A |
10 | 初始活跃,跟踪玩家 |
VCam_Global_B |
9 | 待机,切换时接管 |
房间切换时序(无房间专用相机):
玩家穿过 CameraTriggerZone
│
▼
CameraStateController.SwitchRoom(data)
│
├─ 1. 更新 inactive 机(如 VCam_B)
│ · BoundingShape2D ← 新房间 RoomVisibleArea.Collider2D
│ · FollowTarget ← 玩家 Transform(不变)
│ · PositionOffset ← data.cameraOffset
│
├─ 2. 将 data.blendProfile 写入 CinemachineBrain.DefaultBlend
│
├─ 3. inactiveCam.Priority = activeCam.Priority + 1
│ → CinemachineBrain 自动开始 Blend
│
└─ 4. Blend 结束(CinemachineBrain.BlendFinished 回调)
activeCam.Priority = 9
swap _activeCam / _inactiveCam 引用
3.2 房间专用相机(可选)
每个房间场景可以放置一个带 RoomCamera 组件的虚拟相机。若存在,则优先级高于全局双机;全局双机继续在后台保持配置,以便专用相机卸载时无缝接管。
| 情况 | 使用相机 | Priority |
|---|---|---|
| 房间无专用相机 | 全局 A/B 中的 active 方 | 10 |
房间有 RoomCamera |
房间专用虚拟相机 | 15 |
// RoomCamera.cs — 挂在房间场景的 VCam_Room_XXX 上
public class RoomCamera : MonoBehaviour
{
[SerializeField] CinemachineCamera _vcam;
[SerializeField] RoomVisibleArea _visibleArea; // 本房间可视区域
[SerializeField] CameraBlendProfileSO _enterBlend; // 进入时的过渡(可留空)
void OnEnable() => CameraStateController.Instance.RegisterRoomCamera(this);
void OnDisable() => CameraStateController.Instance.UnregisterRoomCamera(this);
public CinemachineCamera Vcam => _vcam;
public RoomVisibleArea VisibleArea => _visibleArea;
public CameraBlendProfileSO EnterBlend => _enterBlend;
}
房间专用相机注册时,
CameraStateController同步将全局双机的 Confiner 也设置为同一区域,确保专用相机卸载后全局机能无缝接管。
3.3 特殊状态相机
以下相机覆盖所有普通相机,由 CameraStateController 响应事件频道激活:
| 虚拟相机 | Priority | 激活条件 | 默认 Blend |
|---|---|---|---|
VCam_Boss |
30 | OnBossFightToggled.Raise(true) |
0.8 s EaseIn |
VCam_Cutscene |
40 | OnCutsceneStarted |
0.0 s Cut |
VCam_Death |
50 | OnPlayerDied |
1.0 s EaseIn |
4. CameraStateController
CameraStateController(MonoBehaviour,挂在 CameraRig GO 上,DefaultExecutionOrder(-200))负责维护全局双机状态、响应事件频道、协调房间专用相机:
public class CameraStateController : MonoBehaviour
{
public static CameraStateController Instance { get; private set; }
[Header("全局双机")]
[SerializeField] CinemachineCamera _globalA;
[SerializeField] CinemachineCamera _globalB;
[Header("特殊状态机")]
[SerializeField] CinemachineCamera _vcamBoss;
[SerializeField] CinemachineCamera _vcamCutscene;
[SerializeField] CinemachineCamera _vcamDeath;
[Header("默认过渡效果")]
[SerializeField] CameraBlendProfileSO _defaultRoomBlend;
[Header("事件频道")]
[SerializeField] BoolEventChannelSO _onBossFightToggled;
[SerializeField] VoidEventChannelSO _onPlayerDied;
[SerializeField] VoidEventChannelSO _onCutsceneStarted;
[SerializeField] VoidEventChannelSO _onCutsceneEnded;
CinemachineCamera _activeCam; // 当前"热"全局机
CinemachineCamera _inactiveCam; // 待机全局机
RoomCamera _currentRoomCam;
// 切换到新房间(由 CameraTriggerZone 调用)
public void SwitchRoom(CameraTriggerZone.SwitchData data) { ... }
// 房间专用相机注册/反注册(由 RoomCamera.OnEnable/OnDisable 调用)
public void RegisterRoomCamera(RoomCamera cam) { ... }
public void UnregisterRoomCamera(RoomCamera cam) { ... }
}
默认 Blend 查找顺序(优先级从高到低):
触发区域 CameraTriggerZone._blendOverride (最高优先)
↓ 为空时
目标房间 RoomCamera._enterBlend
↓ 为空时
CameraStateController._defaultRoomBlend (全局兜底)
特殊状态 Blend(固定值,不受 BlendProfile 影响):
| 切换 | 时长 | 风格 | 说明 |
|---|---|---|---|
| 任意 → Boss | 0.8 s | EaseIn | 慢推入强调 Boss 出场 |
| Boss → 探索 | 0.5 s | EaseOut | 退场恢复 |
| 任意 → Death | 1.0 s | EaseIn | 慢推营造悲剧感 |
| 任意 → Cutscene | 0.0 s | Cut | 过场硬切 |
| Cutscene → 探索 | 0.3 s | EaseOut | 过场结束柔和恢复 |
5. 可视区域与触发区域
5.1 可视区域(RoomVisibleArea)
定义该房间允许相机移动的边界,驱动 CinemachineConfiner2D。每个房间场景(或同房间不同区段)放置一个:
Scene: Room_Forest_01
└── [VisibleArea_Main] (GameObject)
├── PolygonCollider2D (IsTrigger = false) ← Confiner 要求非 Trigger
└── RoomVisibleArea.cs
├── [SerializeField] string areaId // 唯一 ID("Room_Forest_01_Main")
├── [SerializeField] Vector2 cameraOffset // 此区域相机跟随偏移
└── [SerializeField] bool hideOnPlay // 运行时隐藏 Gizmo
重要:
CinemachineConfiner2D要求PolygonCollider2D.IsTrigger = false。如需同一位置同时做触发检测,在子 GO 上另挂一个 Trigger Collider(CameraTriggerZone使用独立 GO)。
边界约束参数(CameraConfigSO):
| 参数 | 推荐值 | 说明 |
|---|---|---|
ConfinerDamping |
0.0 | 到达边界时的阻尼(0 = 硬停止) |
SlowingDistance |
0.5 | 靠近边界时开始减速的距离 |
一个大房间可以配置多个 RoomVisibleArea(如上下层、分支路线),由不同的 CameraTriggerZone 分别引用。
5.2 切换触发区域(CameraTriggerZone)
CameraTriggerZone 是驱动相机切换的入口,通过 Trigger Collider 检测玩家进入:
Scene: Room_Forest_01
└── [CameraTrigger_Entry] (GameObject)
├── BoxCollider2D (IsTrigger = true) ← 放在入口门洞处,可视化编辑
└── CameraTriggerZone.cs
├── [SerializeField] RoomVisibleArea _targetVisibleArea // 切换到哪个可视区域
├── [SerializeField] RoomCamera _targetRoomCamera // 可留空(使用全局双机)
├── [SerializeField] CameraBlendProfileSO _blendOverride // 可留空(使用全局默认)
├── [SerializeField] Vector2 _cameraOffset // 可覆盖 VisibleArea 的偏移
└── [SerializeField] bool _triggerOnce // true = 仅触发一次
public class CameraTriggerZone : MonoBehaviour
{
public struct SwitchData
{
public RoomVisibleArea visibleArea;
public RoomCamera roomCamera; // null = 使用全局双机
public CameraBlendProfileSO blendProfile; // null = 查找上级默认
public Vector2 cameraOffset;
}
void OnTriggerEnter2D(Collider2D other)
{
if (!other.CompareTag("Player")) return;
if (_triggerOnce && _triggered) return;
_triggered = true;
CameraStateController.Instance.SwitchRoom(new SwitchData
{
visibleArea = _targetVisibleArea,
roomCamera = _targetRoomCamera,
blendProfile = _blendOverride,
cameraOffset = _cameraOffset != Vector2.zero
? _cameraOffset
: _targetVisibleArea.CameraOffset
});
}
bool _triggered;
}
典型放置方式:在房间入口门洞处放置细长 BoxCollider2D(宽约 0.5 单位,高覆盖整个通道),确保玩家穿越时必然触发。_triggerOnce = false 时,玩家来回穿越可双向切换(适合同一大房间内的区段分割线)。
6. 过渡效果:CameraBlendProfileSO
CameraBlendProfileSO 是一个轻量配置资产,封装 CinemachineBlendDefinition,可在 Inspector 中独立编辑并在多个触发区域之间复用:
[CreateAssetMenu(menuName = "Camera/BlendProfile")]
public class CameraBlendProfileSO : ScriptableObject
{
[Tooltip("过渡风格:Cut / EaseInOut / EaseIn / EaseOut / HardIn / HardOut / Linear")]
public CinemachineBlendDefinition.Styles style = CinemachineBlendDefinition.Styles.EaseInOut;
[Range(0f, 3f)]
public float duration = 0.4f;
public CinemachineBlendDefinition ToBlendDefinition()
=> new CinemachineBlendDefinition(style, duration);
}
资产存放路径:Assets/ScriptableObjects/Config/Camera/Blends/
预置资产(建议创建):
| 资产名 | Style | Duration | 典型用途 |
|---|---|---|---|
Blend_Room_Default.asset |
EaseInOut | 0.4 s | 普通房间切换(全局兜底) |
Blend_Room_Snap.asset |
Cut | 0.0 s | 重生/传送等硬切 |
Blend_Room_Slow.asset |
EaseIn | 0.8 s | 进入特殊区域(如 Boss 前厅) |
Blend_Room_Fast.asset |
Linear | 0.15 s | 快速连续的密集小房间 |
7. 镜头震动:CinemachineImpulse
震动类型设计
| 类型 | 触发来源 | 强度 | 时长 | 说明 |
|---|---|---|---|---|
Light |
玩家攻击命中普通敌人 | 0.2 | 0.1s | 轻微点击感 |
Medium |
玩家受击 | 0.5 | 0.25s | 明显震动 |
Heavy |
玩家死亡 / Boss 重击 | 1.0 | 0.4s | 强烈震动 |
Parry |
弹反成功 | 0.7 | 0.2s | 带方向性(从敌人方向弹开) |
Landing |
高空落地 | 0.3 | 0.15s | 垂直向下震动 |
震动集成方式
Feel 的 MMF_CinemachineImpulse Feedback 内部持有 CinemachineImpulseSource:
- 命中时由
PlayerFeedback/EnemyFeedback中的MMF_Player触发 CinemachineImpulseListener(挂在虚拟相机上)响应冲量,配置强度缩放系数
CinemachineImpulseSource 配置(Inspector):
| 参数 | 推荐值 | 说明 |
|---|---|---|
ImpulseDefinition.ImpulseType |
Uniform |
各方向均匀(普通)/ Directional(带方向性震动) |
ImpulseDefinition.ImpulseShape |
自定义曲线 | 快速衰减曲线(前 20% 满强度,后 80% 指数衰减) |
DefaultVelocity |
(0.5, -0.5, 0) | 默认震动方向(右斜下) |
8. 像素对齐:Pixel Perfect 集成
像素艺术游戏要求相机位置锁定到整数像素,否则 Sprite 会出现模糊/闪烁:
组件配置链
Main Camera
├── PixelPerfectCamera (com.unity.2d.pixel-perfect)
│ ├── Assets Pixels Per Unit: 32
│ ├── Reference Resolution: 480 × 270 (16:9 基准)
│ ├── Crop Frame X/Y: 关闭(允许缩放而非裁剪)
│ └── Upscale Render Texture: 开启(低分辨率渲染再放大)
│
└── CinemachineBrain
└── Update Method: Fixed Update(与物理帧同步,消除抖动)
虚拟相机配置
每个虚拟相机上添加 CinemachinePixelPerfect Extension:
- 此 Extension 自动将相机位置对齐到像素网格
- 与
PixelPerfectCamera配合,确保最终渲染无亚像素误差
Orthographic Size 计算
\text{Orthographic Size} = \frac{\text{Reference Resolution Height}}{2 \times \text{PPU}} = \frac{270}{2 \times 32} = 4.21875
使用
PixelPerfectCamera时,Orthographic Size 由组件自动管理,勿手动设置。
9. CameraConfigSO — 配置资产
CameraConfigSO 集中管理所有可调节的镜头参数,存放于:
Assets/ScriptableObjects/Config/Camera/CameraConfigSO.asset
探索镜头参数
| 参数 | 类型 | 推荐值 | 说明 |
|---|---|---|---|
ExploreFollowDamping |
Vector2 |
(0.2, 0.2) | XY 轴跟随阻尼 |
ExploreAheadDistance |
float |
2.0 | 朝移动方向的前瞻偏移量 |
ExploreAheadSmoothing |
float |
0.5 | 前瞻平滑时间 |
ExploreLookUpOffset |
float |
1.5 | 长按上看时的额外 Y 偏移 |
ExploreLookDownOffset |
float |
-1.0 | 长按下看时的额外 Y 偏移 |
ExploreFOV |
float |
4.22 | Orthographic Size(像素对齐) |
战斗镜头参数
| 参数 | 类型 | 推荐值 | 说明 |
|---|---|---|---|
CombatZoomOut |
float |
+0.5 | 战斗时 Orthographic Size 增量(拉远) |
CombatForwardOffset |
float |
1.0 | 朝敌人方向额外偏移 |
CombatFollowDamping |
Vector2 |
(0.3, 0.3) | 战斗时更高阻尼(稳定) |
Boss 镜头参数
| 参数 | 类型 | 推荐值 | 说明 |
|---|---|---|---|
BossRoomCenter |
Vector2 |
由 Boss 房间配置 | Boss 房间固定镜头中心 |
BossZoomLevel |
float |
6.0 | Boss 战 Orthographic Size |
10. 场景搭建规范
Persistent 场景:CameraRig 层级结构
[CameraRig] (Prefab — DontDestroyOnLoad,放入 Persistent 场景)
│
├── Main Camera
│ ├── PixelPerfectCamera
│ └── CinemachineBrain
│ └── DefaultBlend ← 运行时由 CameraStateController 动态写入
│
├── [GlobalCameras] ← 全局双机,永远存在
│ ├── VCam_Global_A (CinemachineCamera, Priority 10)
│ │ ├── CinemachinePositionComposer (Follow = Player)
│ │ ├── CinemachineConfiner2D ← BoundingShape2D 运行时设置
│ │ ├── CinemachineImpulseListener
│ │ └── CinemachinePixelPerfect
│ └── VCam_Global_B (CinemachineCamera, Priority 9)
│ ├── CinemachinePositionComposer (Follow = Player)
│ ├── CinemachineConfiner2D
│ ├── CinemachineImpulseListener
│ └── CinemachinePixelPerfect
│
├── [SpecialCameras] ← 特殊状态机,默认 Priority 0
│ ├── VCam_Boss (CinemachineCamera)
│ │ ├── CinemachineConfiner2D ← Boss 房间专属 Confiner(运行时设置)
│ │ └── CinemachinePixelPerfect
│ ├── VCam_Death (CinemachineCamera)
│ │ └── CinemachinePixelPerfect
│ └── VCam_Cutscene (CinemachineCamera)
│ └── CinemachinePixelPerfect
│
├── [ImpulseSources]
│ ├── ImpulseSource_Light
│ ├── ImpulseSource_Medium
│ ├── ImpulseSource_Heavy
│ ├── ImpulseSource_Parry
│ └── ImpulseSource_Landing
│
└── CameraStateController.cs
房间场景中的标准配置
Room_XXX (Scene)
│
├── [VisibleArea_Main] (GameObject) ← 必须,定义主可视区域
│ ├── PolygonCollider2D (IsTrigger = false)
│ └── RoomVisibleArea.cs
│ └── areaId = "Room_XXX_Main"
│
├── [VisibleArea_Sub] (GameObject) ← 可选,房间有多段时使用
│ ├── PolygonCollider2D (IsTrigger = false)
│ └── RoomVisibleArea.cs
│
├── [CameraTrigger_Entry] (GameObject) ← 房间入口触发器
│ ├── BoxCollider2D (IsTrigger = true) ← 放在入口门洞处
│ └── CameraTriggerZone.cs
│ ├── _targetVisibleArea = VisibleArea_Main
│ ├── _targetRoomCamera = (留空→使用全局双机)
│ └── _blendOverride = (留空→全局默认)
│
└── [VCam_Room_XXX] (GameObject) ← 可选,房间专用相机
├── CinemachineCamera (Priority 15)
│ ├── CinemachinePositionComposer
│ ├── CinemachineConfiner2D
│ └── CinemachinePixelPerfect
└── RoomCamera.cs
├── _visibleArea = VisibleArea_Main
└── _enterBlend = Blend_Room_Slow (可选)
11. 编辑器友好设计
RoomVisibleArea — Scene 视图
PolygonCollider2D内置Edit Collider 按钮,可直接在 Scene 视图拖拽顶点编辑边界形状RoomVisibleArea始终绘制 青色轮廓线 + 半透明青色填充,表示 Confiner 边界- 叠加绘制 白色虚线矩形 表示当前 Orthographic Size 对应的实际视野范围,方便确认边界是否足够
- Inspector 中自动检测:若 PolygonCollider2D 包围盒小于摄像机视野,显示红色警告:
⚠ 可视区域小于摄像机视野,镜头将无法移动!
CameraTriggerZone — Scene 视图
- 触发区域 Collider2D 始终绘制 黄色轮廓(即使未选中 GO)
- 选中时:绘制从触发区域中心指向
_targetVisibleArea中心的 橙色箭头,直观显示切换目标 - 若
_targetRoomCamera不为空,额外绘制 紫色细线 指向专用相机位置 - Inspector 中
_blendOverride字段旁显示当前生效的 Blend 描述(含回退链说明):生效 Blend: [触发区域覆盖] EaseIn 0.8s 或 生效 Blend: [全局兜底] EaseInOut 0.4s
CameraStateController — 运行时监控
Play Mode 下 Inspector 显示:
┌─ CameraStateController ──────────────────────────────────────────┐
│ Active Global : VCam_Global_A (Priority 10) │
│ Inactive Global: VCam_Global_B (Priority 9) │
│ Room Camera : VCam_Room_Forest01 (Priority 15) │
│ Blend Progress : ████████████░░░░ 75% │
│ Current Area : Room_Forest_01_Main │
│ ─────────────────────────────────────────────────────────────── │
│ [触发房间切换] [触发 Boss] [触发死亡] [强制 Snap] │
└──────────────────────────────────────────────────────────────────┘
Scene 视图 Gizmos 汇总
| 组件 | Gizmo 颜色 | 内容 |
|---|---|---|
RoomVisibleArea |
青色 | Confiner 边界轮廓 + 当前视野矩形 |
CameraTriggerZone |
黄色 | 触发 Collider 轮廓 |
CameraTriggerZone(选中) |
橙色箭头 | 指向目标 VisibleArea |
RoomCamera |
紫色 | VCam 视锥(Frustum)轮廓 |
CinemachineImpulseSource |
红色箭头 | 震动方向,长度表示强度 |
LargeRoomBoundary |
绿色粗线框 | 大房间整体边界 |
SubRegionTrigger(选中) |
青绿箭头 | 指向该子区域激活的 VCam |
12. 大房间相机处理
银河恶魔城中存在若干大型房间(Boss 房、竖井、长廊),单个 Confiner 配合全局相机会导致视野移动范围过大、失去房间感。本节说明三种处理策略。
12.1 竖向/横向无缝滚动房间
适用:长廊(横向滚动)、竖井(纵向滚动)、Boss 前庭。
做法:创建宽/高尺寸匹配房间的 RoomVisibleArea(PolygonCollider2D),全局相机的 Confiner 直接限制在这块大 Confiner 里自由滑动。
房间宽度 60 单位、高度 12 单位(横向长廊):
RoomVisibleArea:
PolygonCollider2D 顶点: (-30,-6), (30,-6), (30,6), (-30,6)
全局相机 Confiner2D → 绑定这个 Collider
结果: 镜头可以横向自由跟随,纵向锁死在房间高度内
锁轴配置(在 RoomVisibleArea 上附加 CameraAxisLock):
public class CameraAxisLock : MonoBehaviour
{
public enum LockMode { None, LockX, LockY }
[SerializeField] LockMode _lock = LockMode.None;
[SerializeField] float _lockedValue; // LockX 时为固定 X 坐标,LockY 时为固定 Y 坐标
// CameraStateController 在读取 RoomVisibleArea 时检查是否挂载了此组件
// 若存在,则在 LateUpdate 中强制修正相机位置
public void ApplyLock(CinemachineBrain brain)
{
var pos = brain.transform.position;
switch (_lock)
{
case LockMode.LockX: brain.transform.position = new Vector3(_lockedValue, pos.y, pos.z); break;
case LockMode.LockY: brain.transform.position = new Vector3(pos.x, _lockedValue, pos.z); break;
}
}
}
12.2 子区域相机分段
适用:Boss 房(进入 Boss 房后锁定在 Boss 战视角)、多功能大厅(不同区域有不同镜头高度)。
策略:在大房间内放置若干 SubRegionTrigger,每个子区域激活专属 RoomCamera(更高 Priority):
大房间层级:
├── LargeRoom_BossArena
│ ├── RoomVisibleArea_Global ← 整体边界(兜底 Confiner)
│ ├── SubRegionTrigger_Entrance ← 入口区,激活 VCam_Entrance(低焦)
│ ├── SubRegionTrigger_Arena ← 战斗区,激活 VCam_Arena(剧院视角)
│ └── SubRegionTrigger_Exit ← 出口区,激活 VCam_Exit(低焦)
/// <summary>
/// 挂载在子区域触发 Collider 上,玩家进入时激活指定 RoomCamera,离开时还原。
/// 可与 §3.2 RoomCamera 逻辑复用,SubRegionTrigger 本质是 CameraTriggerZone 的轻量别名。
/// </summary>
[RequireComponent(typeof(Collider2D))]
public class SubRegionTrigger : MonoBehaviour
{
[SerializeField] CinemachineCamera _subCamera; // 子区域专用 VCam
[SerializeField] CameraBlendProfileSO _blendIn; // 进入时的 Blend
[SerializeField] CameraBlendProfileSO _blendOut; // 离开时的 Blend(可为 null,用全局兜底)
void OnTriggerEnter2D(Collider2D other)
{
if (!other.CompareTag("Player")) return;
CameraStateController.Instance.ActivateSubRegion(_subCamera, _blendIn);
}
void OnTriggerExit2D(Collider2D other)
{
if (!other.CompareTag("Player")) return;
CameraStateController.Instance.DeactivateSubRegion(_subCamera, _blendOut);
}
}
CameraStateController 新增方法:
public void ActivateSubRegion(CinemachineCamera subCam, CameraBlendProfileSO blend)
{
if (blend != null)
ApplyBlendOverride(subCam, blend);
subCam.Priority = _roomCameraBasePriority + 5; // 高于普通房间相机
}
public void DeactivateSubRegion(CinemachineCamera subCam, CameraBlendProfileSO blend)
{
if (blend != null)
ApplyBlendOverride(subCam, blend);
subCam.Priority = 0;
}
12.3 滚动限制模式
针对特定大型场景需要限制某轴的相机运动:
| 模式 | 典型场景 | 配置 |
|---|---|---|
| 横向自由 + 纵轴锁定 | 横向长廊、横向 Boss 房 | CameraAxisLock.LockY |
| 纵向自由 + 横轴锁定 | 竖井、电梯通道 | CameraAxisLock.LockX |
| 双轴自由 | 大型开放场景、探索大厅 | 无 Lock,Confiner 覆盖整个区域 |
| 双轴锁定(静止镜头) | 剧场演出、特定剧情房间 | 使用固定位置 VCam,Priority 最高 |
锁轴时的边缘提示:当房间宽度/高度接近相机视野的 1.5× 以内时,RoomVisibleArea 的 Gizmo 会在相应轴方向上绘制红色警告线,提示设计师考虑是否需要 CameraAxisLock。