using BaseGames.Core; using BaseGames.Core.Events; using UnityEngine; namespace BaseGames.World { /// /// 房间/场景过渡触发器。玩家进入触发器或按交互键时,广播 。 /// /// 通过 控制过渡演出: /// /// Room:极短淡出,无加载画面,适合相邻房间边界。 /// Scene:完整淡出 + 加载画面,适合大区域切换。 /// /// 如需门动画,请改用 组件,它会在动画完成后内部触发本组件。 /// /// [RequireComponent(typeof(Collider2D))] public class RoomTransition : MonoBehaviour, IInteractable { [Header("本传送门标识")] [SerializeField] private string _transitionId; // 本出口唯一 ID(供 SceneLoader 写入复活点) [Header("目标")] [SerializeField] private string _targetSceneAddress; // Addressable key(目标场景) [SerializeField] private string _targetTransitionId; // 目标房间出生点 ID [Header("过渡类型")] [Tooltip("Seamless:无缝切换,流式系统标准选项,绝大多数房间门使用此类型。\n" + "AtmosphericFade:短暂淡出 + 区域名提示,适合跨大区域边界。\n" + "Room:极短淡出,不走流式系统(仅用于非流式独立场景切换)。\n" + "Scene:完整淡出 + 加载画面,大区域/地图间传送专用。")] [SerializeField] private TransitionType _transitionType = TransitionType.Seamless; [Header("触发方式")] [SerializeField] private bool _autoTrigger = true; // true = 玩家进入触发器自动触发 [Header("钥匙物品校验")] [SerializeField] private bool _requiresKeyItem; // 是否需要持有指定钥匙物品 [SerializeField] private string _requiredItemId; // 钥匙物品 ID(_requiresKeyItem = true 时生效) [Header("世界状态")] [SerializeField] private WorldStateRegistry _worldState; // ── IInteractable ───────────────────────────────────────────────────── public bool CanInteract => !_autoTrigger; public string InteractPrompt => _transitionType == TransitionType.Scene ? "前往下一区域" : "进入"; public void Interact(Transform player) => RequestTransition(); public void OnPlayerEnterRange(Transform player) { } public void OnPlayerExitRange() { } // ── Auto Trigger ────────────────────────────────────────────────────── private void OnTriggerEnter2D(Collider2D other) { if (!_autoTrigger) return; if (!other.CompareTag("Player")) return; RequestTransition(); } /// 触发过渡。可由触发器、交互系统或 调用。 public void RequestTransition() { if (_requiresKeyItem && !HasItem(_requiredItemId)) return; var request = new SceneLoadRequest { SceneName = _targetSceneAddress, EntryTransitionId = _targetTransitionId, TransitionType = _transitionType, ShowLoadingScreen = _transitionType == TransitionType.Scene, IsRespawn = false, }; var sceneService = ServiceLocator.GetOrDefault(); if (sceneService != null) { sceneService.RequestTransition(request); return; } Debug.LogWarning("[RoomTransition] 无法发送过渡请求:ISceneService 未在 ServiceLocator 中注册。", this); } /// 检查玩家是否持有指定物品(通过 WorldStateRegistry.IsCollected 检查)。 private bool HasItem(string itemId) { if (string.IsNullOrEmpty(itemId)) return true; if (_worldState == null) { Debug.LogWarning($"[RoomTransition] WorldStateRegistry 未配置,钥匙 {itemId} 检查跳过"); return false; } return _worldState.IsCollected(itemId); } private void OnDrawGizmos() { var col = GetComponent(); if (col == null) return; Gizmos.color = _transitionType == TransitionType.Scene ? new Color(1f, 0.6f, 0f, 0.6f) // 橙色:大区域切换 : new Color(0f, 1f, 0.5f, 0.6f); // 绿色:房间切换 Gizmos.DrawWireCube(transform.position, col.bounds.size); } } }