摄像机区域的优化

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

@@ -0,0 +1,105 @@
using UnityEngine;
using Unity.Cinemachine;
namespace BaseGames.Camera
{
/// <summary>
/// 速度自适应 Lookahead 扩展。
///
/// 玩家水平速度越快Lookahead.Time 越接近 CameraArea 配置的最大值;
/// 静止时衰减至最大值的 <see cref="_restScale"/> 倍,避免静止时镜头无谓偏移。
///
/// 挂载位置Persistent 场景中的 VCamA / VCamB GameObject。
/// <see cref="CameraStateController.ConfigureSlot"/> 在每次切换区域时调用
/// <see cref="SetConfiguredMax"/> 传入该区域的 LookaheadTime。
/// </summary>
[AddComponentMenu("Cinemachine/Extensions/Camera Adaptive Lookahead")]
[DisallowMultipleComponent]
public class CameraAdaptiveLookaheadExtension : CinemachineExtension
{
[Tooltip("静止时 Lookahead 缩减比例0~1。\n" +
"0 = 静止时完全无 Lookahead0.25 = 静止时使用配置值的 25%。\n" +
"推荐 0.2~0.3。")]
[Range(0f, 1f)]
[SerializeField] private float _restScale = 0.25f;
[Tooltip("达到最大 Lookahead 所需的水平速度(世界单位/秒)。\n" +
"玩家以此速度奔跑时 Lookahead.Time = 100% 配置值。推荐 10~15。")]
[SerializeField] private float _speedAtFullLookahead = 12f;
[Tooltip("水平速度估算的平滑强度。越大响应越快。推荐 4~6。")]
[SerializeField] private float _speedSmoothing = 5f;
// ── 内部状态 ──────────────────────────────────────────────────────────
private float _configuredMaxTime = -1f; // -1 = ConfigureSlot 尚未调用
private float _estimatedSpeedX;
private float _lastFollowX;
private bool _trackingInitialized;
// ── 公开 API ──────────────────────────────────────────────────────────
/// <summary>
/// 由 <see cref="CameraStateController.ConfigureSlot"/> 调用,
/// 传入当前 CameraArea 配置的最大 Lookahead 时长。
/// </summary>
public void SetConfiguredMax(float maxTime) => _configuredMaxTime = maxTime;
// ── Extension ─────────────────────────────────────────────────────────
protected override void PostPipelineStageCallback(
CinemachineVirtualCameraBase vcam,
CinemachineCore.Stage stage,
ref CameraState state,
float deltaTime)
{
if (stage != CinemachineCore.Stage.Body) return;
// 编辑器预览时不运行
if (deltaTime <= 0f)
{
_trackingInitialized = false;
return;
}
// ConfigureSlot 尚未调用时跳过(避免覆盖默认值)
if (_configuredMaxTime < 0f) return;
// ── 估算玩家水平速度 ──────────────────────────────────────────────
Transform follow = vcam.Follow;
if (follow != null)
{
if (!_trackingInitialized)
{
_lastFollowX = follow.position.x;
_trackingInitialized = true;
}
float rawSpeedX = Mathf.Abs(follow.position.x - _lastFollowX) / deltaTime;
_lastFollowX = follow.position.x;
_estimatedSpeedX = Mathf.Lerp(_estimatedSpeedX, rawSpeedX, deltaTime * _speedSmoothing);
}
// ── 速度映射 → Lookahead 时长 ─────────────────────────────────────
float fraction = Mathf.Clamp01(_estimatedSpeedX / _speedAtFullLookahead);
float scaledTime = Mathf.Lerp(_configuredMaxTime * _restScale, _configuredMaxTime, fraction);
var composer = vcam.GetComponent<CinemachinePositionComposer>();
if (composer == null) return;
var lah = composer.Lookahead;
lah.Time = scaledTime;
composer.Lookahead = lah;
}
/// <summary>
/// 重置速度估算状态。在相机硬切时由 CameraStateController 调用,
/// 避免上一区域的奔跑速度影响新区域的初始 Lookahead 量。
/// </summary>
public void ResetState()
{
_estimatedSpeedX = 0f;
_trackingInitialized = false;
}
}
}