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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|