diff --git a/Assets/Scripts/Dialog System/LineSyncToken.cs b/Assets/Scripts/Dialog System/LineSyncToken.cs index 749f4d14b..ee3b5f69c 100644 --- a/Assets/Scripts/Dialog System/LineSyncToken.cs +++ b/Assets/Scripts/Dialog System/LineSyncToken.cs @@ -128,6 +128,15 @@ namespace AibisDream public async void TextShown() { + // UI completion events can arrive more than once (for example, when a typewriter is + // reused or a previous line finishes late). Only the active PlayText state is allowed + // to enter the post-display delay; otherwise a stale callback could regress a token + // from Advanced, or run before TextStart and corrupt the line lifecycle. + if (state != LineSyncState.PlayText) + { + return; + } + AdvanceDelayToken = new CancellationTokenSource(); EnumEventSystem.Global.Send(DialogEventEnum.LineShown); await _textShown.OnTextShown(this); diff --git a/Assets/Scripts/FixSystemNew/Screen System/FixPanel/ScreenPanel.cs b/Assets/Scripts/FixSystemNew/Screen System/FixPanel/ScreenPanel.cs index ef22478a9..897de43cb 100644 --- a/Assets/Scripts/FixSystemNew/Screen System/FixPanel/ScreenPanel.cs +++ b/Assets/Scripts/FixSystemNew/Screen System/FixPanel/ScreenPanel.cs @@ -43,6 +43,7 @@ namespace AibisDream.FixSystem { EnumEventSystem.Global.Send(ScreenEventEnum.Selected, gameObject); + logText.PrepareForLine(); logText.OnTextShown += () => token.TextShown(); bool isWarning = string.Equals(token.lineInfo.character.key, WarningCharacterKey, @@ -52,8 +53,8 @@ namespace AibisDream.FixSystem title.color = isWarning ? WarningRedColor : AmberColor; title.text = token.lineInfo.character.GetActorName(); logText.SetTypewriterSpeed(GetTextSpeedValue()); - logText.AddText(token.lineInfo.lineText); token.TextStart(); + logText.AddText(token.lineInfo.lineText); } else { diff --git a/Assets/Scripts/SceneManagement/SceneCenter/SubwayCenter.cs b/Assets/Scripts/SceneManagement/SceneCenter/SubwayCenter.cs index 82d39793c..471a43854 100644 --- a/Assets/Scripts/SceneManagement/SceneCenter/SubwayCenter.cs +++ b/Assets/Scripts/SceneManagement/SceneCenter/SubwayCenter.cs @@ -205,6 +205,7 @@ namespace AibisDream } yield return SubwayCenter.StateMachine.SwitchState(targetState); + yield return null; } [YarnCommand("arrive_at_station")] diff --git a/Assets/Scripts/UI/Components/TerminalText.cs b/Assets/Scripts/UI/Components/TerminalText.cs index a56123cd5..016b8cc1e 100644 --- a/Assets/Scripts/UI/Components/TerminalText.cs +++ b/Assets/Scripts/UI/Components/TerminalText.cs @@ -135,6 +135,20 @@ namespace AibisDream.UI #region 公共方法 + /// + /// 在注册新台词完成回调前停止旧动画,并丢弃可能迟到的旧回调。 + /// 保留终端中已经显示的历史文本。 + /// + public void PrepareForLine() + { + if (typewriter != null) + { + typewriter.StopShowingText(); + } + + OnTextShown = null; + } + /// /// 添加新文本(追加到现有文本) /// diff --git a/Assets/Scripts/UI/DialogUI/Bubbles/Bubble.cs b/Assets/Scripts/UI/DialogUI/Bubbles/Bubble.cs index a19a40e58..758bcea8c 100644 --- a/Assets/Scripts/UI/DialogUI/Bubbles/Bubble.cs +++ b/Assets/Scripts/UI/DialogUI/Bubbles/Bubble.cs @@ -45,6 +45,11 @@ namespace AibisDream _bubbleGroup = bubbleGroup; InitRefs(); + // Dialogue playback is started explicitly by BubbleGroup. OnEnable playback can + // resume fully displayed text when a pooled bubble is reactivated and synchronously + // emit onTextShowed for the wrong line. + _typewriter.startTypewriterMode = TypewriterCore.StartTypewriterMode.OnShowText; + role = data.actorRole; idx = data.idx; maxWidth = data.maxWidth; @@ -119,10 +124,16 @@ namespace AibisDream : characterVo.GetActorName(); } + public void PrepareForLine() + { + _typewriter.StopShowingText(); + OnLineShown = null; + gameObject.SetActive(true); + _typewriter.TextAnimator.SetText(string.Empty); + } + public void ShowLine(string line) { - _typewriter.TextAnimator.SetText(""); - gameObject.SetActive(true); HandleLayout(line); _typewriter.ShowText(line); } @@ -215,9 +226,10 @@ namespace AibisDream public int Idx { get; } public event Action OnLineShown; + public void PrepareForLine(); public void ShowActorName(CharacterVo characterVo); public void ShowLine(string line); public bool SkipLine(); public void Hide(); } -} \ No newline at end of file +} diff --git a/Assets/Scripts/UI/DialogUI/Bubbles/BubbleGroup.cs b/Assets/Scripts/UI/DialogUI/Bubbles/BubbleGroup.cs index 2857b0918..803c62f27 100644 --- a/Assets/Scripts/UI/DialogUI/Bubbles/BubbleGroup.cs +++ b/Assets/Scripts/UI/DialogUI/Bubbles/BubbleGroup.cs @@ -73,14 +73,19 @@ namespace AibisDream 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); - bubble.ShowLine(syncToken.lineInfo.lineText); syncToken.TextStart(); + bubble.ShowLine(syncToken.lineInfo.lineText); // 将非选定的Bubble隐藏 HideDialog(bubble); } @@ -138,4 +143,4 @@ namespace AibisDream #endregion } -} \ No newline at end of file +} diff --git a/Assets/Scripts/UI/DialogUI/CenterText.cs b/Assets/Scripts/UI/DialogUI/CenterText.cs index 612f4b1e3..b2653ac09 100644 --- a/Assets/Scripts/UI/DialogUI/CenterText.cs +++ b/Assets/Scripts/UI/DialogUI/CenterText.cs @@ -24,6 +24,13 @@ namespace AibisDream // 先中断结束事件 _autoHideToken?.Cancel(); _autoHideToken = null; + OnTextShowed = null; + + // 先停止旧动画并准备好激活状态,避免 OnEnable 或旧动画完成事件命中新 token。 + content.StopShowingText(); + box.SetActive(true); + content.StopShowingText(); + content.TextAnimator.SetText(string.Empty); // 注册事件 OnTextShowed += syncToken.TextShown; @@ -31,10 +38,8 @@ namespace AibisDream syncToken.OnAdvance += AfterAdvance; // 播放文字 - content.TextAnimator.SetText(string.Empty); - box.SetActive(true); - content.ShowText(syncToken.lineInfo.lineText); syncToken.TextStart(); + content.ShowText(syncToken.lineInfo.lineText); } private async void AfterAdvance() @@ -109,4 +114,4 @@ namespace AibisDream HideDialog(); } } -} \ No newline at end of file +}