using UnityEngine; using Unity.Cinemachine; namespace BaseGames.Camera { /// /// 速度自适应 Lookahead 扩展。 /// /// 玩家水平速度越快,Lookahead.Time 越接近 CameraArea 配置的最大值; /// 静止时衰减至最大值的 倍,避免静止时镜头无谓偏移。 /// /// 挂载位置:Persistent 场景中的 VCamA / VCamB GameObject。 /// 在每次切换区域时调用 /// 传入该区域的 LookaheadTime。 /// [AddComponentMenu("Cinemachine/Extensions/Camera Adaptive Lookahead")] [DisallowMultipleComponent] public class CameraAdaptiveLookaheadExtension : CinemachineExtension { [Tooltip("静止时 Lookahead 缩减比例(0~1)。\n" + "0 = 静止时完全无 Lookahead;0.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 ────────────────────────────────────────────────────────── /// /// 由 调用, /// 传入当前 CameraArea 配置的最大 Lookahead 时长。 /// 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, 1f - Mathf.Exp(-deltaTime * _speedSmoothing)); } // ── 速度映射 → Lookahead 时长 ───────────────────────────────────── float fraction = Mathf.Clamp01(_estimatedSpeedX / _speedAtFullLookahead); float scaledTime = Mathf.Lerp(_configuredMaxTime * _restScale, _configuredMaxTime, fraction); var composer = vcam.GetComponent(); if (composer == null) return; var lah = composer.Lookahead; lah.Time = scaledTime; composer.Lookahead = lah; } /// /// 重置速度估算状态。在相机硬切时由 CameraStateController 调用, /// 避免上一区域的奔跑速度影响新区域的初始 Lookahead 量。 /// public void ResetState() { _estimatedSpeedX = 0f; _trackingInitialized = false; } } }