摄像机区域的优化

This commit is contained in:
2026-05-17 07:56:12 +08:00
parent f264329751
commit d25f237e76
62 changed files with 25774 additions and 5450 deletions

View File

@@ -21,15 +21,81 @@ namespace BaseGames.Camera
[SerializeField] private PolygonCollider2D _confinerCollider;
[Header("可视区域(透视相机)")]
[Tooltip("摄像机应显示的最大可视矩形(世界坐标)。\n" +
[Tooltip("摄像机应显示的最大可视矩形(本地坐标,相对于此 GameObject 的 Transform 位置)。\n" +
"Scene 视图中可直接拖拽四条边编辑,然后点击 Inspector 中的\n" +
"「从可视区域更新限位区域(透视)」按钮将其换算为限位多边形。")]
[SerializeField] private Rect _visibleBounds = new Rect(-12f, -6f, 24f, 12f);
[Tooltip("摄像机到场景平面Z = 0的垂直距离用于透视视口尺寸计算。\n" +
"留 0 时自动取 transform.position.z 的绝对值(推荐)。")]
[HideInInspector]
[SerializeField] private float _cameraDepth = 0f;
[Header("镜头配置")]
[Tooltip("全局相机镜头参数 SO。与 CameraStateController 引用同一资产,\n" +
"保证 FOV 等参数在 Room 场景中也能正确读取。\n" +
"SO 中的 fieldOfView 发生变化时,编辑器会自动重新同步限位多边形。")]
[SerializeField] private CameraLensConfigSO _lensConfig;
// 编辑器通过它检测限位多边形是否需要重新同步(不展示在 Inspector 中)
[HideInInspector]
[SerializeField] private float _lastSyncFOV = 0f;
// ── 跟随行为 ──────────────────────────────────────────────────────────
[Header("跟随行为(覆盖全局 VCam 参数)")]
[Tooltip("启用后,进入此区域时将把以下参数写入全局 VCam\n" +
"关闭则 VCam 保持上一区域或 Inspector 中的默认值。")]
[SerializeField] private bool _overrideFollowBehaviour = true;
[Tooltip("玩家跟踪点在屏幕上的位置0 = 中心±0.5 = 边缘)。\n" +
"推荐 (0, -0.1):玩家稍低于中心,上方有更多视野(对横版山洞类游戏第三视角推荐)。")]
[SerializeField] private Vector2 _screenPosition = new Vector2(0f, -0.15f);
[Tooltip("水平X/ 垂直Y跟随阻尼。越大越滞后。\n" +
"推荐X=0.5 Y=0.2(水平稍慢、垂直快速响应)。\n" +
"同时挂载 CameraAsymmetricDampingExtension 时Y 分量自动被清零,改由下方两个字段控制。")]
[SerializeField] private Vector2 _damping = new Vector2(0.5f, 0.2f);
[Tooltip("非对称 Y 阻尼 —— 相机向下(下落)时的 Y 轴阻尼(秒)。越小相机越快跟随,玩家能提前看到地面。")]
[SerializeField] private float _dampingDown = 0.06f;
[Tooltip("非对称 Y 阻尼 —— 相机向上(起跳)时的 Y 轴阻尼(秒)。越大越慢,保留地面视野不被立刻拉高。")]
[SerializeField] private float _dampingUp = 0.65f;
[Tooltip("死区范围(全屏 = 1。玩家在死区内相机不移动产生松散跟随感。\n" +
"推荐X=0.1 Y=0.05。")]
[SerializeField] private Vector2 _deadZoneSize = new Vector2(0.15f, 0.05f);
[Tooltip("引领预测时长0 = 不引领)。相机超前于玩家移动方向,令玩家更早看到前方地形。")]
[Range(0f, 1f)]
[SerializeField] private float _lookaheadTime = 0.28f;
[Tooltip("引领算法平滑度0~30。越大越平滑但预测延迟更大。")]
[Range(0f, 30f)]
[SerializeField] private float _lookaheadSmoothing = 5f;
[Header("下坠视野偏置(需配合 CameraFallBiasExtension")]
[Tooltip("禁用此区域的下坠视野偏置效果。\n"
+ "在垂直高度较小的房间(短走廊 / 矬间)中建议开启,\n"
+ "防止相机因偏置超出 Confiner 边界。")]
[SerializeField] private bool _disableFallBias = false;
// ── 轴向约束 ──────────────────────────────────────────────────────────
[Header("轴向约束")]
[Tooltip("锁定相机 X 轴垂直竖井相机仅上下移动X 固定在限位区域中心)。")]
[SerializeField] private bool _lockHorizontal = false;
[Tooltip("锁定相机 Y 轴水平走廊相机仅左右移动Y 固定在限位区域中心)。")]
[SerializeField] private bool _lockVertical = false;
[Header("镜头尺寸(正交相机)")]
[Tooltip("进入此区域时的目标正交尺寸0 = 不覆盖当前尺寸)。\n" +
"适用于 Boss 战拉远或精密解谜区域拉近。")]
[SerializeField] private float _lensSize = 0f;
[Tooltip("镜头尺寸过渡时长。0 = 瞬间切换。")]
[Min(0f)]
[SerializeField] private float _lensSizeDuration = 0.5f;
[Header("混合配置")]
[SerializeField] private CameraBlendProfileSO _blendProfile;
@@ -44,24 +110,43 @@ namespace BaseGames.Camera
// ── 公开属性 ──────────────────────────────────────────────────────────
public PolygonCollider2D ConfinerCollider => _confinerCollider;
public CameraBlendProfileSO BlendProfile => _blendProfile;
public Rect VisibleBounds => _visibleBounds;
public bool HasDedicated => _dedicatedCamera != null;
public CinemachineCamera DedicatedCamera => _dedicatedCamera;
public int DedicatedPriority => _dedicatedPriority;
public PolygonCollider2D ConfinerCollider => _confinerCollider;
public CameraLensConfigSO LensConfig => _lensConfig;
public float LastSyncFOV => _lastSyncFOV;
public CameraBlendProfileSO BlendProfile => _blendProfile;
/// <summary>世界坐标可视区域(本地 _visibleBounds + transform.position。</summary>
public Rect VisibleBounds => new Rect(
_visibleBounds.x + transform.position.x,
_visibleBounds.y + transform.position.y,
_visibleBounds.width, _visibleBounds.height);
public bool HasDedicated => _dedicatedCamera != null;
public CinemachineCamera DedicatedCamera => _dedicatedCamera;
public int DedicatedPriority => _dedicatedPriority;
public bool OverrideFollowBehaviour => _overrideFollowBehaviour;
public Vector2 ScreenPosition => _screenPosition;
public Vector2 Damping => _damping;
public Vector2 DeadZoneSize => _deadZoneSize;
public float LookaheadTime => _lookaheadTime;
public float LookaheadSmoothing => _lookaheadSmoothing;
public bool DisableFallBias => _disableFallBias;
public bool LockHorizontal => _lockHorizontal;
public bool LockVertical => _lockVertical;
public float DampingDown => _dampingDown;
public float DampingUp => _dampingUp;
public float LensSize => _lensSize;
public float LensSizeDuration => _lensSizeDuration;
/// <summary>
/// 摄像机到场景平面的有效深度(用于透视视口换算)。
/// _cameraDepth &gt; 0 时使用配置值,否则自动读取 |transform.position.z|,再兜底 10
/// 来源:区域专有 _cameraDepth>0 时) → LensConfig SO
/// 未绑定 SO 时返回 0限位同步工具会在 Inspector 中给出警告。
/// </summary>
public float CameraDepth
{
get
{
if (_cameraDepth > 0f) return _cameraDepth;
float z = Mathf.Abs(transform.position.z);
return z > 0.01f ? z : 10f;
return _lensConfig != null ? _lensConfig.cameraDepth : 0f;
}
}
@@ -69,16 +154,33 @@ namespace BaseGames.Camera
private void OnDrawGizmosSelected()
{
// 黄色:可视区域
Vector3 center = new Vector3(_visibleBounds.center.x, _visibleBounds.center.y, 0f);
Vector3 size = new Vector3(_visibleBounds.width, _visibleBounds.height, 0.01f);
// 黄色:可视区域(本地坐标 + transform.position = 世界坐标)
Vector3 center = new Vector3(
_visibleBounds.center.x + transform.position.x,
_visibleBounds.center.y + transform.position.y, 0f);
Vector3 size = new Vector3(_visibleBounds.width, _visibleBounds.height, 0.01f);
Gizmos.color = new Color(1f, 0.85f, 0.15f, 0.10f);
Gizmos.DrawCube(center, size);
Gizmos.color = new Color(1f, 0.85f, 0.15f, 0.90f);
Gizmos.DrawWireCube(center, size);
// 青色:专有 VCam 指示线
// 青色:轴向锁定指示
if ((_lockHorizontal || _lockVertical) && _confinerCollider != null)
{
Gizmos.color = new Color(0.2f, 0.8f, 1f, 0.9f);
var bounds = _confinerCollider.bounds;
if (_lockHorizontal)
Gizmos.DrawLine(
new Vector3(bounds.center.x, bounds.min.y, 0f),
new Vector3(bounds.center.x, bounds.max.y, 0f));
if (_lockVertical)
Gizmos.DrawLine(
new Vector3(bounds.min.x, bounds.center.y, 0f),
new Vector3(bounds.max.x, bounds.center.y, 0f));
}
// 青绿:专有 VCam 指示线
if (_dedicatedCamera != null)
{
Gizmos.color = new Color(0.2f, 1f, 0.8f, 0.8f);