88 lines
3.1 KiB
C#
88 lines
3.1 KiB
C#
using System.Collections.Generic;
|
||
using Ichni.Story.Dialogue;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
namespace Ichni.Story.UI
|
||
{
|
||
/// <summary>
|
||
/// 对话记录覆盖面板。
|
||
/// <para>它不是独立 UIPage:打开时覆盖在 DialogUIPage 上方,并由全屏 Raycast Target 阻断底层输入;
|
||
/// 关闭后仅恢复对话画面,不推进 Yarn 对话。</para>
|
||
/// </summary>
|
||
public class DialogueHistoryPage : MonoBehaviour
|
||
{
|
||
[Header("References")]
|
||
[Tooltip("覆盖全屏的 CanvasGroup。根物体应位于 DialogCanvas 顶层,并包含可接收 Raycast 的全屏透明 Image。")]
|
||
[SerializeField] private CanvasGroup canvasGroup;
|
||
[SerializeField] private ScrollRect scrollRect;
|
||
[SerializeField] private RectTransform entryContainer;
|
||
[SerializeField] private DialogueHistoryEntryView entryPrefab;
|
||
[SerializeField] private Button closeButton;
|
||
|
||
/// <summary>当前覆盖层是否正在显示并拦截 DialogUIPage 输入。</summary>
|
||
public bool IsOpen => _isOpen;
|
||
|
||
private readonly List<DialogueHistoryEntryView> _spawnedEntries = new();
|
||
private bool _isOpen;
|
||
|
||
private void Awake()
|
||
{
|
||
if (closeButton != null)
|
||
closeButton.onClick.AddListener(Close);
|
||
|
||
SetVisible(false);
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
if (closeButton != null)
|
||
closeButton.onClick.RemoveListener(Close);
|
||
}
|
||
|
||
/// <summary>以当前一次 TextBlock 对话的内存记录刷新并打开覆盖面板。</summary>
|
||
public void Open(IReadOnlyList<DialogueHistoryEntry> entries)
|
||
{
|
||
RebuildEntries(entries);
|
||
SetVisible(true);
|
||
Canvas.ForceUpdateCanvases();
|
||
|
||
// 记录按时间从上到下排列;打开后停在最早一条,玩家可向下浏览最新内容。
|
||
if (scrollRect != null)
|
||
scrollRect.verticalNormalizedPosition = 1f;
|
||
}
|
||
|
||
/// <summary>关闭覆盖面板,不修改当前 Yarn 进度或选项状态。</summary>
|
||
public void Close() => SetVisible(false);
|
||
|
||
private void RebuildEntries(IReadOnlyList<DialogueHistoryEntry> entries)
|
||
{
|
||
foreach (DialogueHistoryEntryView view in _spawnedEntries)
|
||
if (view != null)
|
||
Destroy(view.gameObject);
|
||
_spawnedEntries.Clear();
|
||
|
||
if (entries == null || entryPrefab == null || entryContainer == null)
|
||
return;
|
||
|
||
foreach (DialogueHistoryEntry entry in entries)
|
||
{
|
||
DialogueHistoryEntryView view = Instantiate(entryPrefab, entryContainer);
|
||
view.SetUp(entry);
|
||
_spawnedEntries.Add(view);
|
||
}
|
||
}
|
||
|
||
private void SetVisible(bool visible)
|
||
{
|
||
_isOpen = visible;
|
||
if (canvasGroup == null)
|
||
return;
|
||
|
||
canvasGroup.alpha = visible ? 1f : 0f;
|
||
canvasGroup.interactable = visible;
|
||
canvasGroup.blocksRaycasts = visible;
|
||
}
|
||
}
|
||
}
|