using System.Collections; using Animancer; using BaseGames.Core; using BaseGames.Core.Events; using UnityEngine; namespace BaseGames.World { /// /// 门过渡组件。挂载在有物理门对象的 GameObject 上。 /// /// 触发流程: /// /// 玩家进入触发器或按交互键 → 播放 开门动画 /// 动画完成后发出 ,类型由 决定 /// 目标场景出生点侧的 引用, /// 由外部调用 播放玩家进入门的过渡动画 /// /// /// /// 若不需要门动画,直接使用 即可。 /// /// [RequireComponent(typeof(Collider2D))] public class DoorTransition : MonoBehaviour, IInteractable { [Header("目标")] [SerializeField] private string _targetSceneAddress; [SerializeField] private string _targetTransitionId; [Header("过渡类型")] [Tooltip("Room:极短淡出,无加载画面。\nScene:完整淡出 + 加载画面。")] [SerializeField] private TransitionType _transitionType = TransitionType.Room; [Header("触发方式")] [Tooltip("true = 玩家进入触发器自动触发;false = 需要玩家按交互键。")] [SerializeField] private bool _autoTrigger = false; [Header("门动画")] [SerializeField] private AnimancerComponent _animancer; [Tooltip("玩家从外侧进入时播放的开门动画(出口侧)。留空则跳过动画直接过渡。")] [SerializeField] private AnimationClip _openClip; [Tooltip("玩家从内侧走出时播放的动画(入口侧,由 PlayerSpawnPoint 在玩家出生后触发)。留空则跳过。")] [SerializeField] private AnimationClip _enterClip; [Header("钥匙物品校验")] [SerializeField] private bool _requiresKeyItem; [SerializeField] private string _requiredItemId; [Header("世界状态")] [SerializeField] private WorldStateRegistry _worldState; private bool _triggered; // ── IInteractable ───────────────────────────────────────────────────── public bool CanInteract => !_autoTrigger; public string InteractPrompt => "进入"; public void Interact(Transform player) => TryTrigger(); public void OnPlayerEnterRange(Transform player) { } public void OnPlayerExitRange() { } // ── 触发 ────────────────────────────────────────────────────────────── private void OnTriggerEnter2D(Collider2D other) { if (!_autoTrigger) return; if (!other.CompareTag("Player")) return; TryTrigger(); } private void TryTrigger() { if (_triggered) return; if (_requiresKeyItem && !HasItem(_requiredItemId)) return; _triggered = true; StartCoroutine(OpenAndTransition()); } private void OnDisable() => _triggered = false; // ── 动画流程 ────────────────────────────────────────────────────────── private IEnumerator OpenAndTransition() { if (_animancer != null && _openClip != null) { var state = _animancer.Play(_openClip); yield return state; // 等待动画完成 } var request = new SceneLoadRequest { SceneName = _targetSceneAddress, EntryTransitionId = _targetTransitionId, TransitionType = _transitionType, IsRespawn = false, }; var sceneService = ServiceLocator.GetOrDefault(); if (sceneService != null) { sceneService.RequestTransition(request); yield break; } Debug.LogWarning("[DoorTransition] 无法发送过渡请求:ISceneService 未在 ServiceLocator 中注册。", this); } /// /// 玩家从门内侧走出时的动画(由出生点侧的 在玩家出生后调用)。 /// 若未配置 则静默跳过。 /// public void PlayEnterAnimation() { if (_animancer != null && _enterClip != null) _animancer.Play(_enterClip); } // ── 辅助 ────────────────────────────────────────────────────────────── private bool HasItem(string itemId) { if (string.IsNullOrEmpty(itemId)) return true; if (_worldState == null) { Debug.LogWarning($"[DoorTransition] WorldStateRegistry 未配置,钥匙 {itemId} 检查跳过"); return false; } return _worldState.IsCollected(itemId); } private void OnDrawGizmos() { var col = GetComponent(); if (col == null) return; // 紫色区分门过渡 Gizmos.color = new Color(0.7f, 0.3f, 1f, 0.7f); Gizmos.DrawWireCube(transform.position, col.bounds.size); Gizmos.color = new Color(0.7f, 0.3f, 1f, 0.3f); Gizmos.DrawCube(transform.position, col.bounds.size); } } }