using BaseGames.Camera; using BaseGames.Core; using UnityEngine; namespace BaseGames.World { /// /// 房间控制器。挂在每个房间场景的 [RoomRoot] 下。 /// Start 时切换摄像机到玩家当前所在的 CameraArea,并提供出生点查询。 /// 支持房间内存在多个 CameraArea 的情况:动态检测玩家位于哪个触发区域, /// 无匹配时回退到场景内第一个 CameraArea。 /// public class RoomController : MonoBehaviour { [SerializeField] private string _roomId; [SerializeField] private PlayerSpawnPoint[] _spawnPoints; [Tooltip("(可选)显式指定此房间的基线相机区域。\n" + "设置后将优先使用此区域作为房间基准,而非动态检测玩家所在触发区域。\n" + "通常由 SceneObjectPlacerTool 自动赋值,也可手动拖入。")] [SerializeField] private CameraArea _cameraArea; public string RoomId => _roomId; private void Start() { // 显式覆盖优先:直接使用编辑器/工具指定的基线区域 CameraArea area = _cameraArea != null ? _cameraArea : FindAreaForPlayer(); if (area != null) // instantCut = true:房间入口传送后相机硬切,无混合拖影 ServiceLocator.GetOrDefault()?.SwitchArea(area, 0, instantCut: true); else Debug.LogError($"[RoomController] {name}:未找到任何 CameraArea,相机不会切换。"); } /// /// 查找玩家当前所在的 CameraArea。 /// 优先检测玩家位置与哪个 CameraTriggerZone 重叠,选取其中优先级最高者; /// 无重叠时回退到场景内第一个 CameraArea。 /// private CameraArea FindAreaForPlayer() { GameObject player = GameObject.FindWithTag("Player"); if (player != null) { Vector2 playerPos = player.transform.position; // 使用 CameraTriggerZone 静态注册表,避免 FindObjectsOfType 全场景扫描 var zones = CameraTriggerZone.AllZones; // 选取优先级最高的匹配区域(避免多区域重叠时选错基线) CameraArea bestArea = null; int bestPriority = int.MinValue; foreach (var zone in zones) { if (zone == null) continue; if (zone.ContainsPoint(playerPos)) { var area = zone.GetComponentInParent(); if (area != null && zone.Priority > bestPriority) { bestPriority = zone.Priority; bestArea = area; } } } if (bestArea != null) return bestArea; } // 回退:返回场景中第一个 CameraArea #if UNITY_6000_0_OR_NEWER var fallback = Object.FindFirstObjectByType(); #else var fallback = Object.FindObjectOfType(); #endif if (fallback != null) Debug.LogWarning($"[RoomController] {name}:玩家不在任何触发区域内,回退到 {fallback.name}。建议确认玩家出生位置与 CameraTriggerZone 的重叠关系。"); return fallback; } /// 通过 transitionId 查找对应的出生点。 public PlayerSpawnPoint GetSpawnPoint(string transitionId) { if (_spawnPoints == null) return null; foreach (var sp in _spawnPoints) { if (sp != null && sp.TransitionId == transitionId) return sp; } // Fallback:返回第一个出生点 return _spawnPoints.Length > 0 ? _spawnPoints[0] : null; } } }