Files
zeling_v2/Assets/_Game/Scripts/Cutscene/CutsceneTrigger.cs

89 lines
3.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BaseGames.Core.Events;
using BaseGames.World;
using UnityEngine;
namespace BaseGames.Cutscene
{
/// <summary>
/// 过场动画触发器(架构 14_NarrativeModule §11.5)。
/// 支持四种触发模式:进入区域、玩家交互、场景加载、事件频道。
/// 实现 IInteractable 以支持 OnInteract 模式。
/// </summary>
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();
// ── IInteractableOnInteract 模式)──────────────────────────────
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;
// 捕获局部变量,避免回调内通过 this 访问被销毁的对象
var cutsceneId = _cutscene.cutsceneId;
var worldState = _worldState;
_cutsceneManager.PlayCutscene(_cutscene, onCompleted: () =>
{
// 过场完全结束后才写入 flag确保异常中断时可重触
worldState?.SetFlag($"cutscene_played_{cutsceneId}");
});
// 区域触发后禁用自身,防止重入
if (_mode == TriggerMode.OnEnter) enabled = false;
}
}
}