This commit is contained in:
2025-11-05 23:59:55 +08:00
parent 80b26ade3b
commit b10e641105
28 changed files with 1089 additions and 1263 deletions
@@ -55,7 +55,7 @@ namespace AibisDream
[YarnCommand("hide_dialog")]
public static void HideDialog()
{
DialogCanvasManager.Instance.HideDialog();
BubbleGroup.Instance.HideDialog();
}
[YarnCommand("fade_in")]
@@ -135,13 +135,6 @@ namespace AibisDream
return panel.FlashRed(duration);
}
[YarnCommand("switch_dialog_viewer")]
public static void SwitchDialogViewer(string viewerTypeStr)
{
var viewType = Enum.Parse<DialogViewType>(viewerTypeStr);
DialogCanvasManager.Instance.SwitchDialogView(viewType);
}
#endregion
}
}
@@ -2,7 +2,6 @@ using System;
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEngine;
using UnityEngine.Events;
using Yarn.Unity;
namespace AibisDream
@@ -12,12 +11,9 @@ namespace AibisDream
private DialogueRunner _dialogueRunner;
private LocalisedLineProvider _lineProvider;
# region controller状态标识
[SerializeField] private LineAdvanceInput lineAdvanceInput;
public bool quickRunMode;
public bool autoRunMode;
# endregion
public AdvanceMode advanceMode;
private void Start()
{
@@ -34,6 +30,28 @@ namespace AibisDream
});
}
private void OnEnable()
{
EnumEventSystem.Global.Register(GameLoopEnum.GameStart, ResetAdvanceMode);
}
private void OnDisable()
{
EnumEventSystem.Global.UnRegister(GameLoopEnum.GameStart, ResetAdvanceMode);
}
private void ResetAdvanceMode()
{
advanceMode = new AdvanceMode
{
isAuto = false,
isQuick = false
};
Time.timeScale = 1f;
lineAdvanceInput.ResetAdvanceMode();
}
#region Yarn控制
/// <summary>
@@ -46,13 +64,12 @@ namespace AibisDream
_lineProvider.InitStringTable(yarnProject.name);
_dialogueRunner.StartDialogue("Start");
}
public void StopDialog()
{
_dialogueRunner.Stop();
StorageSystem.Instance.Clear();
DialogCanvasManager.Instance.HideDialog();
DialogCanvasManager.Instance.SwitchDialogView(DialogViewType.StandardBubble);
DialogUIManager.Instance.HideDialog();
}
public void LoadDialog(YarnProject yarnProject)
@@ -70,13 +87,13 @@ namespace AibisDream
Debug.LogWarning($"对话正在运行中,无法启动新节点: {nodeName}");
return;
}
if (CheckIfNodeExistInCurrentYarnProject(nodeName))
{
_dialogueRunner.StartDialogue(nodeName);
}
}
private bool CheckIfNodeExistInCurrentYarnProject(string nodeName)
{
YarnProject currentProject = _dialogueRunner.yarnProject;
@@ -93,16 +110,56 @@ namespace AibisDream
}
#endregion
/// <summary>
/// 跳到下一句
/// </summary>
public void JumpLine()
#region
public void SwitchAutoMode()
{
if (!DialogCanvasManager.Instance.TrySkipLine())
advanceMode.isAuto = !advanceMode.isAuto;
lineAdvanceInput.SwitchAdvanceHandler(advanceMode.CurrentMode);
}
public void SwitchQuickMode()
{
advanceMode.isQuick = !advanceMode.isQuick;
lineAdvanceInput.SwitchAdvanceHandler(advanceMode.CurrentMode);
Time.timeScale = advanceMode.CurrentMode == AdvanceModeEnum.Quick ? 8f : 1f;
}
#endregion
}
public struct AdvanceMode
{
public bool isAuto;
public bool isQuick;
public AdvanceModeEnum CurrentMode
{
get
{
DialogCanvasManager.Instance.NextStep();
if (isAuto)
{
return AdvanceModeEnum.Auto;
}
else if (isQuick)
{
return AdvanceModeEnum.Quick;
}
else
{
return AdvanceModeEnum.Default;
}
}
}
}
public enum AdvanceModeEnum
{
Default,
Auto,
Quick
}
}
@@ -1,4 +1,5 @@
using AibisDream.Framework;
using System;
using AibisDream.Framework;
using UnityEngine;
namespace AibisDream
@@ -11,82 +12,123 @@ namespace AibisDream
private bool _isDialog;
private LineSyncToken _curSyncToken;
private ILineAdvanceHandler _handler;
#endregion
[SerializeField] private KeyCode advanceKey;
private void OnEnable()
{
RegisterEvents();
}
private void OnDisable()
{
UnRegisterEvents();
}
private ILineAdvanceHandler _defaultHandler = new DefaultAdvanceHandler();
private ILineAdvanceHandler _quickHandler;
private ILineAdvanceHandler _autoHandler = new AutoAdvanceHandler();
public void RunLine(LineSyncToken lineSyncEvent)
{
_curSyncToken = lineSyncEvent;
}
private void Update()
{
_handler.Handle(_curSyncToken, IsInputAvailable);
}
public void SwitchAdvanceHandler(AdvanceModeEnum advanceMode)
{
_handler = advanceMode switch
{
AdvanceModeEnum.Auto => _autoHandler,
AdvanceModeEnum.Quick => _quickHandler,
AdvanceModeEnum.Default => _defaultHandler,
_ => _defaultHandler,
};
}
public void ResetAdvanceMode()
{
_handler = _defaultHandler;
}
#region
private bool IsInputAvailable()
{
return _inGame && _isDialog && _curSyncToken != null && _curSyncToken.state != LineSyncState.Advanced;
}
private void OnAdvanceInput()
#endregion
}
public interface ILineAdvanceHandler
{
void Handle(LineSyncToken token, Func<bool> isAvailable);
static ILineAdvanceHandler Create(bool autoMode)
{
if (!IsInputAvailable())
return autoMode ? new AutoAdvanceHandler() : new DefaultAdvanceHandler();
}
}
public class DefaultAdvanceHandler : ILineAdvanceHandler
{
public void Handle(LineSyncToken token, Func<bool> isAvailable)
{
if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space))
{
if (isAvailable())
{
HandleInput(token);
}
}
}
private void HandleInput(LineSyncToken token)
{
switch (token.state)
{
case LineSyncState.PlayText:
token.TrySkip();
break;
case LineSyncState.WaitForAdvance:
token.TryAdvance();
break;
}
}
}
public class AutoAdvanceHandler : ILineAdvanceHandler
{
public void Handle(LineSyncToken token, Func<bool> isAvailable)
{
if (!isAvailable())
{
return;
}
switch (_curSyncToken.state)
// 如果已经可以继续了,就直接往下
if (token.state == LineSyncState.WaitForAdvance)
{
case LineSyncState.PlayText:
_curSyncToken.TrySkip();
break;
case LineSyncState.WaitForAdvance:
_curSyncToken.TryAdvance();
break;
token.TryAdvance();
}
}
private void Update()
}
public class QuickAdvanceHandler : ILineAdvanceHandler
{
public void Handle(LineSyncToken token, Func<bool> isAvailable)
{
if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space))
if (!isAvailable())
{
OnAdvanceInput();
return;
}
// 加速模式强制快进
if (token.state == LineSyncState.PlayText)
{
token.TrySkip();
}
// 如果已经可以继续了,就直接往下
if (token.state is LineSyncState.AdvanceDelay or LineSyncState.WaitForAdvance)
{
token.ForceAdvance();
}
}
#region
private IUnRegister[] _unRegisters;
private void RegisterEvents()
{
_unRegisters = new IUnRegister[6];
_unRegisters[0] = EnumEventSystem.Global.Register(GameLoopEnum.GameStart, () => _inGame = true);
_unRegisters[1] = EnumEventSystem.Global.Register(GameLoopEnum.UnPauseGame, () => _inGame = true);
_unRegisters[2] = EnumEventSystem.Global.Register(GameLoopEnum.GameQuit, () => _inGame = false);
_unRegisters[3] = EnumEventSystem.Global.Register(GameLoopEnum.PauseGame, () => _inGame = false);
_unRegisters[4] = EnumEventSystem.Global.Register(InteractionEventEnum.DialogStart, () => _isDialog = true);
_unRegisters[5] = EnumEventSystem.Global.Register(InteractionEventEnum.DialogEnd, () => _isDialog = true);
}
private void UnRegisterEvents()
{
foreach (var unRegister in _unRegisters)
{
unRegister.UnRegister();
}
}
#endregion
}
}
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AibisDream.Utility;
using UnityEngine;
using Yarn.Unity;
namespace AibisDream
{
public class LineRunner : DialogueViewBase
{
[SerializeField] private DialogViewType[] lineViewTypes;
[SerializeField] private LineAdvanceInput advanceInput;
[SerializeField] private BubbleGroup bubbleGroup;
private readonly Dictionary<DialogViewType, ILineView> _screenViewDict = new();
public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
{
LineSyncToken lineSyncEvent;
if (!lineViewTypes.Contains(dialogueLine.GetCharacterVo().dialogViewType))
{
// 手动推进视图
lineSyncEvent = new LineSyncToken(dialogueLine, onDialogueLineFinished);
bubbleGroup.RunLine(lineSyncEvent);
}
else
{
// 自动推进视图
lineSyncEvent = new LineSyncToken(dialogueLine, onDialogueLineFinished, true);
if (_screenViewDict.TryGetValue(dialogueLine.GetCharacterVo().dialogViewType, out var view))
{
view.RunLine(lineSyncEvent);
}
else
{
Debug.LogWarning($"未注册的视图类型: {dialogueLine.GetCharacterVo().dialogViewType}");
}
}
// 最后交给推进处理
advanceInput.RunLine(lineSyncEvent);
}
public void RegisterView(DialogViewType dialogViewType, ILineView view)
{
_screenViewDict.Add(dialogViewType, view);
}
public void UnRegisterView(DialogViewType dialogViewType)
{
_screenViewDict.Remove(dialogViewType);
}
}
public interface ILineView
{
void RunLine(LineSyncToken token);
}
}
@@ -0,0 +1,153 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using AibisDream.Kit;
using AibisDream.Utility;
using UnityEngine;
using Yarn.Unity;
namespace AibisDream
{
public class LineSyncToken
{
private Action _nextStep;
private readonly ITextShown _textShown;
public LineInfo lineInfo;
public LineSyncState state;
public CancellationTokenSource AdvanceDelayToken { get; private set; }
public event Action SkipTextAnima;
public event Action OnAdvance;
public LineSyncToken(LocalizedLine lineInfo, Action nextStep, bool isAutoSkip = false)
{
this.lineInfo = LineInfo.Generate(lineInfo);
_nextStep = nextStep;
state = LineSyncState.PlayText;
if (this.lineInfo.isAutoSkip && isAutoSkip)
{
_textShown = new AutoNextTextShown();
}
else
{
_textShown = new DefaultTextShown();
}
}
public void TrySkip()
{
if (state == LineSyncState.PlayText)
{
SkipTextAnima?.Invoke();
SkipTextAnima = null;
}
else
{
Debug.Log($"line{lineInfo.lineId} 状态为{state.ToString()}, 不能跳过文本");
}
}
public void TryAdvance()
{
if (state == LineSyncState.WaitForAdvance)
{
Advance();
Dispose();
}
else
{
Debug.Log($"line{lineInfo.lineId} 状态为{state.ToString()}, 不能向前推进");
}
}
public void ForceAdvance()
{
// 先中断延时
AdvanceDelayToken?.Cancel();
// 推进
Advance();
Dispose();
}
private void Advance()
{
OnAdvance?.Invoke();
OnAdvance = null;
_nextStep?.Invoke();
state = LineSyncState.Advanced;
}
private void Dispose()
{
_nextStep = null;
SkipTextAnima = null;
}
public async void TextShown()
{
AdvanceDelayToken = new CancellationTokenSource();
await _textShown.OnTextShown(this);
}
}
public struct LineInfo
{
public string lineId;
public string lineText;
public CharacterVo character;
public bool isAutoSkip;
public static LineInfo Generate(LocalizedLine dialogueLine)
{
return new LineInfo
{
lineId = dialogueLine.TextID,
lineText = dialogueLine.TextWithoutCharacterName.Text,
character = dialogueLine.GetCharacterVo(),
isAutoSkip = dialogueLine.IsAutoSkipLine()
};
}
public int CalcDelayTime()
{
var delayTime = lineText.RemoveRichTextTags().Length * ConstRef.CharacterDelayTime;
return CommonUtil.Limit(delayTime, ConstRef.LineMaxDelay, ConstRef.LineMinDelay);
}
}
public interface ITextShown
{
Task OnTextShown(LineSyncToken token);
}
public class DefaultTextShown : ITextShown
{
public async Task OnTextShown(LineSyncToken token)
{
token.state = LineSyncState.AdvanceDelay;
await Task.Delay(token.lineInfo.CalcDelayTime(), token.AdvanceDelayToken.Token);
token.state = LineSyncState.WaitForAdvance;
}
}
public class AutoNextTextShown : ITextShown
{
public async Task OnTextShown(LineSyncToken token)
{
token.state = LineSyncState.AdvanceDelay;
await Task.Delay(token.lineInfo.CalcDelayTime(), token.AdvanceDelayToken.Token);
token.state = LineSyncState.WaitForAdvance;
token.TryAdvance();
}
}
public enum LineSyncState
{
Default,
PlayText,
AdvanceDelay,
WaitForAdvance,
Advanced
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fc70491af0c642d28147d3dbf6a70ca6
timeCreated: 1761551427
+60 -60
View File
@@ -11,65 +11,65 @@ namespace AibisDream
/// </summary>
public class LineView : DialogueViewBase
{
public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
{
string lineId = dialogueLine.TextID;
string shortText = dialogueLine.TextWithoutCharacterName.Text.Length > 30
? dialogueLine.TextWithoutCharacterName.Text.Substring(0, 30) + "..."
: dialogueLine.TextWithoutCharacterName.Text;
Debug.Log($"[对话流程] [{lineId}] ===== 开始处理 =====");
Debug.Log($"[对话流程] [{lineId}] 文本内容: {shortText}");
EnumEventSystem.Global.Send(DialogEventEnum.LineStart, DialogText.GetLine(dialogueLine));
HandleLineOutput(dialogueLine, NextStep);
if (DialogController.Instance.quickRunMode)
{
Debug.Log($"[快速模式] [{lineId}] ===== 快速处理开始 =====");
// 快速模式:直接跳过文本显示并继续
bool skipResult = DialogCanvasManager.Instance.TrySkipLine(true);
Debug.Log($"[快速模式] [{lineId}] TrySkipLine结果: {skipResult}");
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
Debug.Log($"[快速模式] [{lineId}] LineShown事件已发送");
DialogCanvasManager.Instance.NextStep();
Debug.Log($"[快速模式] [{lineId}] NextStep已调用");
Debug.Log($"[快速模式] [{lineId}] ===== 快速处理完成 =====");
}
else
{
Debug.Log($"[正常模式] [{lineId}] 等待用户交互");
}
Debug.Log($"[对话流程] [{lineId}] ===== 处理完成 =====");
return;
void NextStep()
{
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
onDialogueLineFinished();
}
}
private void HandleLineOutput(LocalizedLine dialogueLine, Action onDialogueLineFinished)
{
string lineId = dialogueLine.TextID;
Debug.Log($"[文本显示] [{lineId}] 开始显示文本");
DialogCanvasManager.Instance.ShowLine(dialogueLine.TextWithoutCharacterName.Text,
dialogueLine.GetCharacterVo(), onDialogueLineFinished, dialogueLine.TextID,
dialogueLine.IsAutoSkipLine());
}
public override void RunOptions(DialogueOption[] dialogueOptions, Action<int> onOptionSelected)
{
Debug.Log($"[选项显示] ===== 显示 {dialogueOptions.Length} 个选项 =====");
EnumEventSystem.Global.Send(DialogEventEnum.OptionShow);
var options = DialogOption.GeneOptions(dialogueOptions, onOptionSelected);
DialogCanvasManager.Instance.ShowOptions(options);
}
// public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
// {
// string lineId = dialogueLine.TextID;
// string shortText = dialogueLine.TextWithoutCharacterName.Text.Length > 30
// ? dialogueLine.TextWithoutCharacterName.Text.Substring(0, 30) + "..."
// : dialogueLine.TextWithoutCharacterName.Text;
//
// Debug.Log($"[对话流程] [{lineId}] ===== 开始处理 =====");
// Debug.Log($"[对话流程] [{lineId}] 文本内容: {shortText}");
//
// EnumEventSystem.Global.Send(DialogEventEnum.LineStart, DialogText.GetLine(dialogueLine));
//
// HandleLineOutput(dialogueLine, NextStep);
//
// if (DialogController.Instance.quickRunMode)
// {
// Debug.Log($"[快速模式] [{lineId}] ===== 快速处理开始 =====");
//
// // 快速模式:直接跳过文本显示并继续
// bool skipResult = DialogCanvasManager.Instance.TrySkipLine(true);
// Debug.Log($"[快速模式] [{lineId}] TrySkipLine结果: {skipResult}");
//
// EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
// Debug.Log($"[快速模式] [{lineId}] LineShown事件已发送");
//
// DialogCanvasManager.Instance.NextStep();
// Debug.Log($"[快速模式] [{lineId}] NextStep已调用");
// Debug.Log($"[快速模式] [{lineId}] ===== 快速处理完成 =====");
// }
// else
// {
// Debug.Log($"[正常模式] [{lineId}] 等待用户交互");
// }
//
// Debug.Log($"[对话流程] [{lineId}] ===== 处理完成 =====");
// return;
//
// void NextStep()
// {
// EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
// onDialogueLineFinished();
// }
// }
//
// private void HandleLineOutput(LocalizedLine dialogueLine, Action onDialogueLineFinished)
// {
// string lineId = dialogueLine.TextID;
// Debug.Log($"[文本显示] [{lineId}] 开始显示文本");
// DialogCanvasManager.Instance.ShowLine(dialogueLine.TextWithoutCharacterName.Text,
// dialogueLine.GetCharacterVo(), onDialogueLineFinished, dialogueLine.TextID,
// dialogueLine.IsAutoSkipLine());
// }
//
// public override void RunOptions(DialogueOption[] dialogueOptions, Action<int> onOptionSelected)
// {
// Debug.Log($"[选项显示] ===== 显示 {dialogueOptions.Length} 个选项 =====");
// EnumEventSystem.Global.Send(DialogEventEnum.OptionShow);
// var options = DialogOption.GeneOptions(dialogueOptions, onOptionSelected);
// DialogCanvasManager.Instance.ShowOptions(options);
// }
}
}
-116
View File
@@ -1,116 +0,0 @@
using System;
using System.Threading.Tasks;
using AibisDream.Kit;
using AibisDream.Utility;
using UnityEngine;
using Yarn.Unity;
namespace AibisDream
{
public class LineViewNew : DialogueViewBase
{
[SerializeField] private LineAdvanceInput advanceInput;
// [SerializeField] private BubbleCenter bubbleCenter;
public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
{
// 预处理Line和Event
var lineSyncEvent = new LineSyncToken(dialogueLine, onDialogueLineFinished);
// bubbleCenter.RunLine(lineSyncEvent);
advanceInput.RunLine(lineSyncEvent);
}
}
public class LineSyncToken
{
public LineInfo lineInfo;
public LineSyncState state;
public Action nextStep;
public event Action SkipTextAnima;
public LineSyncToken(LocalizedLine lineInfo, Action nextStep)
{
this.lineInfo = LineInfo.Generate(lineInfo);
this.nextStep = nextStep;
state = LineSyncState.PlayText;
}
public bool TrySkip()
{
if (state == LineSyncState.PlayText)
{
SkipTextAnima?.Invoke();
SkipTextAnima = null;
return true;
}
else
{
Debug.Log($"line{lineInfo.lineId} 状态为{state.ToString()}, 不能跳过文本");
return false;
}
}
public bool TryAdvance()
{
if (state == LineSyncState.WaitForAdvance)
{
nextStep?.Invoke();
state = LineSyncState.Advanced;
Dispose();
return true;
}
else
{
Debug.Log($"line{lineInfo.lineId} 状态为{state.ToString()}, 不能向前推进");
return false;
}
}
private void Dispose()
{
nextStep = null;
SkipTextAnima = null;
}
public void TextStart()
{
state = LineSyncState.PlayText;
}
public void TextShown()
{
state = LineSyncState.AdvanceDelay;
// 延时
state = LineSyncState.WaitForAdvance;
}
}
public struct LineInfo
{
public string lineId;
public string lineText;
public CharacterVo character;
public bool isAutoSkip;
public static LineInfo Generate(LocalizedLine dialogueLine)
{
return new LineInfo
{
lineId = dialogueLine.TextID,
lineText = dialogueLine.TextWithoutCharacterName.Text,
character = dialogueLine.GetCharacterVo(),
isAutoSkip = dialogueLine.IsAutoSkipLine()
};
}
}
public enum LineSyncState
{
PlayText,
AdvanceDelay,
WaitForAdvance,
Advanced
}
}