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;
}
}
}