using Ichni.Story.Dialogue; using Ichni.UI; using UnityEngine; using UnityEngine.Events; namespace Ichni.Story.UI { /// /// 对话系统专用的 UI 页面容器。 /// 接管整个对话面板的淡入淡出及交互状态控制, /// 将显示生命周期与对话流逻辑 (VNDialoguePresenter) 彻底解耦。 /// public class DialogUIPage : UIPageBase { public static DialogUIPage instance; [Header("立绘舞台")] public VNPortraitStage portraitStage; [Header("台词区")] public TMPro.TextMeshProUGUI dialogueText; public GameObject speakerContainer; public TMPro.TextMeshProUGUI speakerText; [Header("推进按钮")] public UnityEngine.UI.Button advanceButton; [Tooltip("点击后自动快进;已记忆选项会自动跨过,遇到需要玩家选择的新选项时停止。")] public UnityEngine.UI.Button fastForwardButton; [Header("对话辅助功能")] [Tooltip("中途退出当前 TextBlock;本次尚未完成的选项、变量和进度会恢复到进入前状态。")] [SerializeField] private UnityEngine.UI.Button backButton; [Tooltip("打开当前一次 TextBlock 的临时对话记录。")] [SerializeField] private UnityEngine.UI.Button showHistoryButton; [Tooltip("覆盖在对话上方的记录面板;它不是独立 UIPage。")] [SerializeField] private DialogueHistoryPage dialogueHistoryPage; [Header("选项区")] public GameObject choiceFrame; public ChoiceButton[] choiceButtons = new ChoiceButton[4]; [Header("动态组件")] public DialogWheel dialogWheel; protected override void Awake() { base.Awake(); if (instance == null) { instance = this; } else { Destroy(gameObject); return; } // 默认启动时强制隐藏 if (mainCanvasGroup != null) { mainCanvasGroup.alpha = 0f; mainCanvasGroup.interactable = false; mainCanvasGroup.blocksRaycasts = false; mainCanvasGroup.gameObject.SetActive(false); } } private void Start() { if (backButton != null) backButton.onClick.AddListener(OnBackButtonClicked); if (showHistoryButton != null) showHistoryButton.onClick.AddListener(OnShowHistoryButtonClicked); } private void OnDestroy() { if (backButton != null) backButton.onClick.RemoveListener(OnBackButtonClicked); if (showHistoryButton != null) showHistoryButton.onClick.RemoveListener(OnShowHistoryButtonClicked); if (instance == this) instance = null; } public void PlayFadeIn(UnityAction onComplete = null) { FadeIn(0.2f, false, onComplete); } public void PlayFadeOut(UnityAction onComplete = null) { FadeOut(0.2f, false, onComplete); } private void OnBackButtonClicked() { // History 覆盖层本身会拦截输入;此处额外保护,避免错误配置导致 Back 穿透到底层对话。 if (dialogueHistoryPage != null && dialogueHistoryPage.IsOpen) return; StoryDialogueController.instance?.CancelActiveDialogue(); } private void OnShowHistoryButtonClicked() { if (dialogueHistoryPage == null || dialogueHistoryPage.IsOpen) return; // 打开记录不会推进 Yarn;仅取消快进并补全正在显示的一句,避免记录与画面不同步。 StoryDialogueController.instance?.dialogueRunner ?.GetComponent() ?.PrepareForHistory(); dialogueHistoryPage.Open(DialogueHistory.Entries); } } }