diff --git a/Assets/_Game/Scripts/Camera/CameraArea.cs b/Assets/_Game/Scripts/Camera/CameraArea.cs index 9d6275a..c089f42 100644 --- a/Assets/_Game/Scripts/Camera/CameraArea.cs +++ b/Assets/_Game/Scripts/Camera/CameraArea.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using UnityEngine; using Unity.Cinemachine; @@ -181,6 +182,31 @@ namespace BaseGames.Camera } } + // ── 静态注册表 ──────────────────────────────────────────────────────── + + private static readonly List s_All = new(); + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void ResetStaticState() => s_All.Clear(); + + /// + /// 从所有已激活的 中找出距 最近的一个。 + /// 仅考虑拥有专属 VCam 的区域;无可用区域时返回 null。 + /// 距离以各区域 transform.position 为参考点。 + /// + public static CameraArea FindNearest(Vector3 worldPos) + { + CameraArea best = null; + float bestSqDist = float.MaxValue; + foreach (var area in s_All) + { + if (area == null || !area.HasDedicated) continue; + float d = (area.transform.position - worldPos).sqrMagnitude; + if (d < bestSqDist) { bestSqDist = d; best = area; } + } + return best; + } + // ── Lifecycle ──────────────────────────────────────────────────────── private void Awake() @@ -191,6 +217,17 @@ namespace BaseGames.Camera _dedicatedCamera.Priority = 0; } + private void OnEnable() + { + if (Application.isPlaying && !s_All.Contains(this)) + s_All.Add(this); + } + + private void OnDisable() + { + s_All.Remove(this); + } + // ── Gizmo ──────────────────────────────────────────────────────────── private void OnDrawGizmosSelected() diff --git a/Assets/_Game/Scripts/Camera/CameraStateController.cs b/Assets/_Game/Scripts/Camera/CameraStateController.cs index aa68650..e3aa825 100644 --- a/Assets/_Game/Scripts/Camera/CameraStateController.cs +++ b/Assets/_Game/Scripts/Camera/CameraStateController.cs @@ -145,8 +145,12 @@ namespace BaseGames.Camera } /// - /// 返回当前应激活的区域: 中优先级最高的 - /// (同优先级取最近进入的),若触发集合为空则回退到 。 + /// 返回当前应激活的区域: + /// + /// 不为空时,返回其中优先级最高的(同优先级取最近进入的)。 + /// 触发集合为空时,返回距玩家最近的 ; + /// 无法确定玩家位置时回退到 + /// /// private CameraArea GetEffectiveArea() { @@ -154,7 +158,16 @@ namespace BaseGames.Camera int bestPriority = -1; foreach (var (a, p) in _activeZones) if (p >= bestPriority) { bestPriority = p; best = a; } - return best ?? _roomBaselineArea; + if (best != null) return best; + + // 触发集合为空:动态寻找距玩家最近的区域 + if (_currentFollowTarget != null) + { + CameraArea nearest = CameraArea.FindNearest(_currentFollowTarget.position); + if (nearest != null) return nearest; + } + + return _roomBaselineArea; } private void ActivateArea(CameraArea area, bool instantCut = false)