Files
2026-07-22 00:07:54 +08:00

147 lines
4.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using UnityEngine;
namespace AibisDream
{
public class BubbleGroup : MonoBehaviour, ILineView
{
private Dictionary<ActorRole, Bubble[]> _bubbleDict = new();
private BubbleFactory _bubbleFactory;
private CancellationTokenSource _autoHideToken;
#region 生命周期
private void Start()
{
_bubbleFactory = new BubbleFactory(this);
EnumEventSystem.Global.Register(DialogEventEnum.OptionShow, OnOptionShow);
DialogUIManager.Instance.RegisterScreenView(DialogViewType.StandardBubble, this);
}
private void OnDestroy()
{
EnumEventSystem.Global.UnRegister(DialogEventEnum.OptionShow, OnOptionShow);
DialogUIManager.Instance.UnRegisterScreenView(DialogViewType.StandardBubble);
}
private void OnOptionShow()
{
_autoHideToken?.Cancel();
_autoHideToken = null;
HideDialog();
}
public void LoadBubbles(BubbleSlotGroupData groupData)
{
// 回收旧泡泡
foreach (var oldBubble in _bubbleDict.Values.SelectMany(item => item))
{
oldBubble.Dispose();
}
// 加载新泡泡
_bubbleDict = groupData.bubbleSlots
.Select(item => _bubbleFactory.Create(item))
.GroupBy(item => item.Role)
.ToDictionary(group => group.Key, group => group.ToArray());
#if UNITY_EDITOR
var roleSummary = string.Join(", ", _bubbleDict.Select(kv => $"{kv.Key}({kv.Value.Length})"));
Debug.Log($"[BubbleGroup] 已加载 {groupData.dialogViewType}: {roleSummary}", this);
#endif
}
#endregion
#region 新对话框功能实现
public void RunLine(LineSyncToken syncToken)
{
// 先中断原来的事件
_autoHideToken?.Cancel();
_autoHideToken = null;
var character = syncToken.lineInfo.character;
if (TryGetBubble(character.role, character.bubbleIdx, out var bubble))
{
// Stop the previous typewriter and remove its completion callback before the new
// token is registered. A forcibly advanced line may otherwise finish late and
// complete the next token.
bubble.PrepareForLine();
// 注册事件
bubble.OnLineShown += syncToken.TextShown;
syncToken.SkipTextAnima += () => bubble.SkipLine();
syncToken.OnAdvance += AfterAdvance;
// 播放文字
bubble.ShowActorName(character);
syncToken.TextStart();
bubble.ShowLine(syncToken.lineInfo.lineText);
// 将非选定的Bubble隐藏
HideDialog(bubble);
}
else
{
Debug.LogWarning($"{character.GetActorName()}的Role {character.role}没有对应Bubble");
HideDialog();
}
}
private async void AfterAdvance()
{
_autoHideToken = new CancellationTokenSource();
try
{
await Task.Delay(ConstRef.AutoHideDelay, _autoHideToken.Token);
HideDialog();
}
catch (TaskCanceledException)
{
// 忽略取消
}
}
public void HideDialog()
{
foreach (var textBubble in _bubbleDict.Values.SelectMany(inner => inner))
{
textBubble.Hide();
}
}
private void HideDialog(IBubble activeBubble)
{
foreach (var textBubble in _bubbleDict.Values.SelectMany(inner => inner))
{
if (activeBubble != (IBubble)textBubble)
{
textBubble.Hide();
}
}
}
private bool TryGetBubble(ActorRole role, int idx, out IBubble bubble)
{
if (_bubbleDict.TryGetValue(role, out var bubbles))
{
bubble = bubbles.FirstOrDefault(item => item.Idx == idx);
return bubble != null;
}
bubble = null;
return false;
}
#endregion
}
}