using System.Collections.Generic; using Ichni.Menu.UI; using Ichni.UI; using UnityEngine; namespace Ichni.Story.UI { /// /// 用于在剧情系统中管理并顺序展示 MessageBox 的独立 UI 页面。 /// 支持动态实例化给定的 MessageBox Prefab,并在所有消息展示完毕后进行大页面的 FadeOut。 /// public class StoryMessageBoxUIPage : UIPageBase { public static StoryMessageBoxUIPage instance; [Header("Prefabs & Containers")] [Tooltip("默认使用的 MessageBox 预制体(请从 Project 中拖拽,而非场景中的实例)")] public MessageBox defaultMessageBoxPrefab; [Tooltip("生成的 MessageBox 挂载在哪?如果不填,默认挂载在自己身上")] public Transform messageContainer; // 用于排队的内部消息数据结构 private struct PendingMessage { public string title; public string content; public MessageBox customPrefab; // 支持未来传入不同种类的 Prefab } private Queue _messageQueue = new Queue(); private MessageBox _currentActiveBox; private bool _isPageActive = false; protected override void Awake() { base.Awake(); if (instance == null) { instance = this; } else { Debug.LogWarning("[StoryMessageBoxUIPage] 场景中存在多个实例,正在销毁多余的实例。"); Destroy(gameObject); return; } if (messageContainer == null) { messageContainer = this.transform; } } /// /// 将歌曲解锁提示加入弹窗队列。 /// public void ShowUnlockMessage(string songUnlockKey) { string title = "New Song Unlocked!"; string content = $"You have unlocked the song: {songUnlockKey}!"; EnqueueMessage(title, content, defaultMessageBoxPrefab); } /// /// 将自定义文本提示加入弹窗队列。 /// public void ShowCustomMessage(string title, string content) { EnqueueMessage(title, content, defaultMessageBoxPrefab); } /// /// 将指定消息入队。如果是空闲状态,则唤醒大页面并开始处理队列。 /// private void EnqueueMessage(string title, string content, MessageBox prefab) { if (prefab == null) { Debug.LogError("[StoryMessageBoxUIPage] 没有可用的 MessageBox 预制体!"); return; } _messageQueue.Enqueue(new PendingMessage { title = title, content = content, customPrefab = prefab }); // 如果当前页面没有在显示中,则开始整体流程 if (!_isPageActive) { _isPageActive = true; // 唤醒大页面(执行 UIPageBase 的渐入并拦截底层射线) this.FadeIn(0.5f, false, ShowNextInQueue); } } /// /// 从队列中取出一个并实例化显示。 /// private void ShowNextInQueue() { if (_messageQueue.Count == 0) { // 队列处理完毕,大页面整体退场 _currentActiveBox = null; _isPageActive = false; this.FadeOut(); return; } PendingMessage msg = _messageQueue.Dequeue(); // 实例化预制体 _currentActiveBox = Instantiate(msg.customPrefab, messageContainer); // 订阅“当这个消息框彻底结束关闭时”的事件 _currentActiveBox.onAllMessagesClosed.AddListener(() => { // 销毁旧实例 if (_currentActiveBox != null) { Destroy(_currentActiveBox.gameObject); } // 检查并显示下一个 ShowNextInQueue(); }); // 配置并启动 MessageBox _currentActiveBox.Clear(); _currentActiveBox.AddInfo(msg.title, msg.content, null); // MessageBox.SetUp() 内部会激活自己并执行自己的 FadeIn _currentActiveBox.gameObject.SetActive(true); _currentActiveBox.SetUp(); } } }