using BaseGames.Core.Events; using BaseGames.World; using UnityEngine; namespace BaseGames.Cutscene { /// /// 过场动画触发器(架构 14_NarrativeModule §11.5)。 /// 支持四种触发模式:进入区域、玩家交互、场景加载、事件频道。 /// 实现 IInteractable 以支持 OnInteract 模式。 /// public class CutsceneTrigger : MonoBehaviour, IInteractable { public enum TriggerMode { OnEnter, // 进入 Trigger 碰撞区域 OnInteract, // 玩家主动交互(IInteractable) OnSceneLoad, // 场景加载完毕(Start) OnEvent, // 订阅事件频道触发 } [SerializeField] private CutsceneSO _cutscene; [SerializeField] private TriggerMode _mode = TriggerMode.OnEnter; [SerializeField] private CutsceneManager _cutsceneManager; [SerializeField] private VoidEventChannelSO _triggerEventChannel; // OnEvent 模式使用 [SerializeField] private WorldStateRegistry _worldState; // SO 注入,记录/查询播放状态 private readonly CompositeDisposable _subs = new(); // ── IInteractable(OnInteract 模式)────────────────────────────── public bool CanInteract => _mode == TriggerMode.OnInteract; public string InteractPrompt => "查看"; public void Interact(Transform player) => TriggerCutscene(); public void OnPlayerEnterRange(Transform player) { } public void OnPlayerExitRange() { } // ── 生命周期 ────────────────────────────────────────────────────── private void OnEnable() { if (_mode == TriggerMode.OnEvent) _triggerEventChannel?.Subscribe(TriggerCutscene).AddTo(_subs); } private void OnDisable() { _subs.Clear(); } private void Start() { if (_mode == TriggerMode.OnSceneLoad) TriggerCutscene(); } private void OnTriggerEnter2D(Collider2D other) { if (_mode != TriggerMode.OnEnter) return; if (!other.CompareTag("Player")) return; TriggerCutscene(); } // ── 触发逻辑 ────────────────────────────────────────────────────── private void TriggerCutscene() { if (_cutscene == null || _cutsceneManager == null) return; // 已播放且仅播一次 → 跳过 if (_cutscene.playOnlyOnce && _worldState != null && _worldState.HasFlag($"cutscene_played_{_cutscene.cutsceneId}")) return; _cutsceneManager.PlayCutscene(_cutscene); _worldState?.SetFlag($"cutscene_played_{_cutscene.cutsceneId}"); // 区域触发后禁用自身,防止重入 if (_mode == TriggerMode.OnEnter) enabled = false; } } }