Files
aibis-dream/Assets/Scripts/Dialog System/OptionView.cs
T
dingyuntian c751a859ff feat(dialog): 添加梦境选项提示语支持
标记 #option_prompt 的台词不再进入普通台词流程,由 OptionView
暂存并在下一组 Dream Options 出现时显示在选项上方,同时通过
新增 LineHistoryAppend 事件加入对话历史。OnelineOptions 支持
提示语文本与独立选项根节点,并改为按实例追踪销毁按钮。
2026-07-19 00:00:17 +08:00

165 lines
5.0 KiB
C#

#nullable enable
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AibisDream.Framework;
using AibisDream.Utility;
using UnityEngine;
using Yarn.Unity;
namespace AibisDream
{
public class OptionView : DialoguePresenterBase
{
[SerializeField] private DefaultOptions defaultOptions;
[SerializeField] private CenterOptions centerOptions;
[SerializeField] private OnelineOptions onelineOptions;
[SerializeField] private DialogViewType defaultViewType = DialogViewType.StandardBubble;
private OptionExploreTracker? _tracker;
private LineInfo? _pendingOptionPrompt;
private void Awake()
{
_tracker = new OptionExploreTracker();
_tracker.Bind();
}
private void OnDestroy()
{
_tracker?.Unbind();
_tracker = null;
}
public override YarnTask OnDialogueStartedAsync()
{
ClearPendingOptionPrompt();
return YarnTask.CompletedTask;
}
public override YarnTask OnDialogueCompleteAsync()
{
ClearPendingOptionPrompt();
HideDialog();
return YarnTask.CompletedTask;
}
public override YarnTask RunLineAsync(LocalizedLine line, LineCancellationToken token)
{
if (line.IsOptionPromptLine())
{
_pendingOptionPrompt = LineInfo.Generate(line);
}
else
{
ClearPendingOptionPrompt();
}
return YarnTask.CompletedTask;
}
public override void OnNodeExit(string nodeName)
{
ClearPendingOptionPrompt();
}
public void LoadBubbles(BubbleSlotGroupData data)
{
defaultViewType = data.dialogViewType;
}
public override async YarnTask<DialogueOption?> RunOptionsAsync(DialogueOption[] dialogueOptions, LineCancellationToken cancellationToken)
{
EnumEventSystem.Global.Send(DialogEventEnum.OptionShow);
var optionSelectedSource = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var (nodeName, tags) = DialogController.Instance != null
? DialogController.Instance.GetCurrentNodeContext()
: (null, (IReadOnlyList<string>)Array.Empty<string>());
var options = DialogOption.GeneOptions(
dialogueOptions,
_tracker,
nodeName,
tags,
optionId => optionSelectedSource.TrySetResult(optionId));
var viewType = GetCurrentViewType(options);
var optionPrompt = _pendingOptionPrompt;
ClearPendingOptionPrompt();
switch (viewType)
{
case DialogViewType.Default:
case DialogViewType.StandardBubble:
defaultOptions.ShowOptions(options);
break;
case DialogViewType.OnelineBox:
onelineOptions.ShowOptions(options, optionPrompt?.lineText);
if (optionPrompt.HasValue)
{
EnumEventSystem.Global.Send(
DialogEventEnum.LineHistoryAppend,
optionPrompt.Value);
}
break;
case DialogViewType.CenterOption:
centerOptions.ShowOptions(options);
break;
default:
Debug.Log($"选项{options[0].Character.key}没有找到选项框{viewType}");
break;
}
using var cancellationReg = cancellationToken.NextContentToken.Register(() =>
{
optionSelectedSource.TrySetCanceled(cancellationToken.NextContentToken);
});
try
{
var selectedOptionId = await optionSelectedSource.Task;
foreach (var dialogueOption in dialogueOptions)
{
if (dialogueOption.DialogueOptionID == selectedOptionId)
{
return dialogueOption;
}
}
return null;
}
catch (TaskCanceledException)
{
HideDialog();
return null;
}
}
private void ClearPendingOptionPrompt()
{
_pendingOptionPrompt = null;
}
private DialogViewType GetCurrentViewType(DialogOption[] options)
{
var optionViewType = options[0].Character.dialogViewType;
if (optionViewType == DialogViewType.Default)
{
return defaultViewType;
}
return optionViewType;
}
public void HideDialog()
{
defaultOptions.HideOptions();
onelineOptions.HideOptions();
centerOptions.HideOptions();
}
}
}