144 lines
4.7 KiB
C#
144 lines
4.7 KiB
C#
|
|
using System.Collections.Generic;
|
|||
|
|
using Ichni.Menu.UI;
|
|||
|
|
using Ichni.UI;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
namespace Ichni.Story.UI
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 用于在剧情系统中管理并顺序展示 MessageBox 的独立 UI 页面。
|
|||
|
|
/// 支持动态实例化给定的 MessageBox Prefab,并在所有消息展示完毕后进行大页面的 FadeOut。
|
|||
|
|
/// </summary>
|
|||
|
|
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<PendingMessage> _messageQueue = new Queue<PendingMessage>();
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 将歌曲解锁提示加入弹窗队列。
|
|||
|
|
/// </summary>
|
|||
|
|
public void ShowUnlockMessage(string songUnlockKey)
|
|||
|
|
{
|
|||
|
|
string title = "New Song Unlocked!";
|
|||
|
|
string content = $"You have unlocked the song: {songUnlockKey}!";
|
|||
|
|
EnqueueMessage(title, content, defaultMessageBoxPrefab);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 将自定义文本提示加入弹窗队列。
|
|||
|
|
/// </summary>
|
|||
|
|
public void ShowCustomMessage(string title, string content)
|
|||
|
|
{
|
|||
|
|
EnqueueMessage(title, content, defaultMessageBoxPrefab);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 将指定消息入队。如果是空闲状态,则唤醒大页面并开始处理队列。
|
|||
|
|
/// </summary>
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 从队列中取出一个并实例化显示。
|
|||
|
|
/// </summary>
|
|||
|
|
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();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|