添加对话播放速度设置,调整对话以打字机的形式显示
This commit is contained in:
parent
26b69bc870
commit
74ac8f199d
|
|
@ -2,7 +2,7 @@
|
||||||
# Id SpeakerId Expression SpeakerName Direction Text Emphasis ChapterId DialogId
|
# Id SpeakerId Expression SpeakerName Direction Text Emphasis ChapterId DialogId
|
||||||
# int string ExpressionType string int string EmphasisType int int
|
# int string ExpressionType string int string EmphasisType int int
|
||||||
# 对话行编号 策划备注 说话人Id 表情 显示人名 说话朝向 说话内容 演出效果 章节Id 对话Id
|
# 对话行编号 策划备注 说话人Id 表情 显示人名 说话朝向 说话内容 演出效果 章节Id 对话Id
|
||||||
100100001 Id规则为 Null None Null 0 相传。 None 1.00100001 1001.00001
|
100100001 Id规则为 Null None Null 0 相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。相传。 None 1.00100001 1001.00001
|
||||||
100100002 第1位数为章节Id Null None Null 0 Mask。 None 1.00100002 1001.00002
|
100100002 第1位数为章节Id Null None Null 0 Mask。 None 1.00100002 1001.00002
|
||||||
100100003 第2-4位数为对话Id Null None Null 0 很好。 None 1.00100003 1001.00003
|
100100003 第2-4位数为对话Id Null None Null 0 很好。 None 1.00100003 1001.00003
|
||||||
100200001 第5-9位数为对话行Id Xu Normal 徐晟壹 0 你好,王。 None 1.00200001 1002.00001
|
100200001 第5-9位数为对话行Id Xu Normal 徐晟壹 0 你好,王。 None 1.00200001 1002.00001
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ namespace CustomComponent
|
||||||
{
|
{
|
||||||
#region Property
|
#region Property
|
||||||
|
|
||||||
|
[SerializeField] private float _playingSpeed = 1.0f;
|
||||||
|
|
||||||
private const int DialogChapterDivisor = 1000;
|
private const int DialogChapterDivisor = 1000;
|
||||||
private const int LineChapterDivisor = 100000000;
|
private const int LineChapterDivisor = 100000000;
|
||||||
private const int LineDialogDivisor = 100000;
|
private const int LineDialogDivisor = 100000;
|
||||||
|
|
@ -35,6 +37,8 @@ namespace CustomComponent
|
||||||
private bool _isInitialized;
|
private bool _isInitialized;
|
||||||
private bool _isPlaying;
|
private bool _isPlaying;
|
||||||
|
|
||||||
|
public float PlayingSpeed => _playingSpeed;
|
||||||
|
|
||||||
public bool IsInitialized => _isInitialized;
|
public bool IsInitialized => _isInitialized;
|
||||||
|
|
||||||
public bool IsPlaying => _isPlaying;
|
public bool IsPlaying => _isPlaying;
|
||||||
|
|
@ -211,6 +215,7 @@ namespace CustomComponent
|
||||||
_formContext.DialogId = dialogRow.Id;
|
_formContext.DialogId = dialogRow.Id;
|
||||||
_formContext.DialogTitle = dialogRow.Title;
|
_formContext.DialogTitle = dialogRow.Title;
|
||||||
_formContext.DialogUIMode = dialogRow.UIMode;
|
_formContext.DialogUIMode = dialogRow.UIMode;
|
||||||
|
_formContext.PlayingSpeed = Mathf.Max(0f, _playingSpeed);
|
||||||
|
|
||||||
_currentLineIndex = 0;
|
_currentLineIndex = 0;
|
||||||
ApplyLineToContext(dialogLines[_currentLineIndex], _currentLineIndex, dialogLines.Count);
|
ApplyLineToContext(dialogLines[_currentLineIndex], _currentLineIndex, dialogLines.Count);
|
||||||
|
|
@ -350,6 +355,7 @@ namespace CustomComponent
|
||||||
_formContext.Direction = lineRow.Direction;
|
_formContext.Direction = lineRow.Direction;
|
||||||
_formContext.Text = lineRow.Text;
|
_formContext.Text = lineRow.Text;
|
||||||
_formContext.Emphasis = lineRow.Emphasis;
|
_formContext.Emphasis = lineRow.Emphasis;
|
||||||
|
_formContext.PlayingSpeed = Mathf.Max(0f, _playingSpeed);
|
||||||
_formContext.LineIndex = lineIndex;
|
_formContext.LineIndex = lineIndex;
|
||||||
_formContext.TotalLines = totalLines;
|
_formContext.TotalLines = totalLines;
|
||||||
_formContext.IsLastLine = lineIndex >= totalLines - 1;
|
_formContext.IsLastLine = lineIndex >= totalLines - 1;
|
||||||
|
|
@ -404,4 +410,4 @@ namespace CustomComponent
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ namespace UI
|
||||||
{
|
{
|
||||||
public class DialogFormContext : UIContext
|
public class DialogFormContext : UIContext
|
||||||
{
|
{
|
||||||
|
public float PlayingSpeed = 1f;
|
||||||
|
|
||||||
public int ChapterId = 0;
|
public int ChapterId = 0;
|
||||||
public int DialogId = 0;
|
public int DialogId = 0;
|
||||||
public string DialogTitle = string.Empty;
|
public string DialogTitle = string.Empty;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Definition.Enum;
|
using DG.Tweening;
|
||||||
|
using Definition.Enum;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
|
@ -10,6 +11,8 @@ namespace UI
|
||||||
{
|
{
|
||||||
public override DialogFormMode UIMode => DialogFormMode.BottomBox;
|
public override DialogFormMode UIMode => DialogFormMode.BottomBox;
|
||||||
|
|
||||||
|
[SerializeField] private GameObject _speakerArea;
|
||||||
|
|
||||||
[SerializeField] private TMP_Text _speakerNameText;
|
[SerializeField] private TMP_Text _speakerNameText;
|
||||||
|
|
||||||
[SerializeField] private TMP_Text _contentText;
|
[SerializeField] private TMP_Text _contentText;
|
||||||
|
|
@ -22,10 +25,15 @@ namespace UI
|
||||||
|
|
||||||
[SerializeField] private int _rightSpritePosition = -450;
|
[SerializeField] private int _rightSpritePosition = -450;
|
||||||
|
|
||||||
|
[SerializeField] private float _moveDuration = 0.25f;
|
||||||
|
|
||||||
|
[SerializeField] private Ease _moveEase = Ease.OutCubic;
|
||||||
|
|
||||||
private readonly int _singleSpeakerCenterPosition = Screen.width / 2;
|
private readonly int _singleSpeakerCenterPosition = Screen.width / 2;
|
||||||
|
|
||||||
private string _leftSpeakerToken = string.Empty;
|
private string _leftSpeakerToken = string.Empty;
|
||||||
private string _rightSpeakerToken = string.Empty;
|
private string _rightSpeakerToken = string.Empty;
|
||||||
|
private Sequence _layoutSequence;
|
||||||
|
|
||||||
public override void StartDialog(DialogFormContext context)
|
public override void StartDialog(DialogFormContext context)
|
||||||
{
|
{
|
||||||
|
|
@ -37,10 +45,11 @@ namespace UI
|
||||||
|
|
||||||
_context = context;
|
_context = context;
|
||||||
|
|
||||||
string speakerName = NormalizeValue(context.SpeakerName);
|
string speakerName = context.SpeakerName;
|
||||||
if (string.IsNullOrEmpty(speakerName))
|
|
||||||
|
if (_speakerArea != null)
|
||||||
{
|
{
|
||||||
speakerName = NormalizeValue(context.SpeakerId);
|
_speakerArea.SetActive(!string.IsNullOrEmpty(speakerName));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_speakerNameText != null)
|
if (_speakerNameText != null)
|
||||||
|
|
@ -48,15 +57,12 @@ namespace UI
|
||||||
_speakerNameText.text = speakerName;
|
_speakerNameText.text = speakerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_contentText != null)
|
PlayTypewriter(_contentText, context.Text, context.PlayingSpeed);
|
||||||
{
|
|
||||||
_contentText.text = NormalizeValue(context.Text);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(speakerName))
|
if (string.IsNullOrEmpty(speakerName))
|
||||||
{
|
{
|
||||||
ClearSpeakerState();
|
ClearSpeakerState();
|
||||||
ApplySpeakerLayout(false, false);
|
ApplySpeakerLayout(false, false, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,13 +78,14 @@ namespace UI
|
||||||
|
|
||||||
bool hasLeftSpeaker = !string.IsNullOrEmpty(_leftSpeakerToken);
|
bool hasLeftSpeaker = !string.IsNullOrEmpty(_leftSpeakerToken);
|
||||||
bool hasRightSpeaker = !string.IsNullOrEmpty(_rightSpeakerToken);
|
bool hasRightSpeaker = !string.IsNullOrEmpty(_rightSpeakerToken);
|
||||||
ApplySpeakerLayout(hasLeftSpeaker, hasRightSpeaker);
|
ApplySpeakerLayout(hasLeftSpeaker, hasRightSpeaker, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnClose(bool isShutdown, object userData)
|
protected override void OnClose(bool isShutdown, object userData)
|
||||||
{
|
{
|
||||||
ClearSpeakerState();
|
ClearSpeakerState();
|
||||||
ApplySpeakerLayout(false, false);
|
KillLayoutTween();
|
||||||
|
ApplySpeakerLayout(false, false, true);
|
||||||
base.OnClose(isShutdown, userData);
|
base.OnClose(isShutdown, userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,35 +95,164 @@ namespace UI
|
||||||
_rightSpeakerToken = string.Empty;
|
_rightSpeakerToken = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplySpeakerLayout(bool hasLeftSpeaker, bool hasRightSpeaker)
|
private void KillLayoutTween()
|
||||||
|
{
|
||||||
|
if (_layoutSequence != null)
|
||||||
|
{
|
||||||
|
_layoutSequence.Kill();
|
||||||
|
_layoutSequence = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplySpeakerLayout(bool hasLeftSpeaker, bool hasRightSpeaker, bool instant)
|
||||||
|
{
|
||||||
|
if (_leftSprite == null || _rightSprite == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool leftCurrentlyVisible = _leftSprite.gameObject.activeSelf;
|
||||||
|
bool rightCurrentlyVisible = _rightSprite.gameObject.activeSelf;
|
||||||
|
|
||||||
|
bool leftTargetVisible = hasLeftSpeaker;
|
||||||
|
bool rightTargetVisible = hasRightSpeaker;
|
||||||
|
|
||||||
|
float leftTargetX = GetTargetX(true, hasLeftSpeaker, hasRightSpeaker);
|
||||||
|
float rightTargetX = GetTargetX(false, hasLeftSpeaker, hasRightSpeaker);
|
||||||
|
|
||||||
|
KillLayoutTween();
|
||||||
|
|
||||||
|
PrepareStartState(
|
||||||
|
leftCurrentlyVisible,
|
||||||
|
rightCurrentlyVisible,
|
||||||
|
leftTargetVisible,
|
||||||
|
rightTargetVisible,
|
||||||
|
hasLeftSpeaker,
|
||||||
|
hasRightSpeaker);
|
||||||
|
|
||||||
|
if (instant || _moveDuration <= 0f)
|
||||||
|
{
|
||||||
|
SetSpritePosition(_leftSprite.rectTransform, leftTargetX);
|
||||||
|
SetSpritePosition(_rightSprite.rectTransform, rightTargetX);
|
||||||
|
SetSpriteVisible(_leftSprite, leftTargetVisible);
|
||||||
|
SetSpriteVisible(_rightSprite, rightTargetVisible);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_layoutSequence = DOTween.Sequence();
|
||||||
|
|
||||||
|
Tween leftTween = CreateMoveTween(_leftSprite.rectTransform, leftTargetX);
|
||||||
|
if (leftTween != null)
|
||||||
|
{
|
||||||
|
_layoutSequence.Join(leftTween);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tween rightTween = CreateMoveTween(_rightSprite.rectTransform, rightTargetX);
|
||||||
|
if (rightTween != null)
|
||||||
|
{
|
||||||
|
_layoutSequence.Join(rightTween);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_layoutSequence.active && _layoutSequence.Duration(false) > 0f)
|
||||||
|
{
|
||||||
|
_layoutSequence.OnComplete(() =>
|
||||||
|
{
|
||||||
|
SetSpriteVisible(_leftSprite, leftTargetVisible);
|
||||||
|
SetSpriteVisible(_rightSprite, rightTargetVisible);
|
||||||
|
_layoutSequence = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetSpritePosition(_leftSprite.rectTransform, leftTargetX);
|
||||||
|
SetSpritePosition(_rightSprite.rectTransform, rightTargetX);
|
||||||
|
SetSpriteVisible(_leftSprite, leftTargetVisible);
|
||||||
|
SetSpriteVisible(_rightSprite, rightTargetVisible);
|
||||||
|
_layoutSequence.Kill();
|
||||||
|
_layoutSequence = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrepareStartState(
|
||||||
|
bool leftCurrentlyVisible,
|
||||||
|
bool rightCurrentlyVisible,
|
||||||
|
bool leftTargetVisible,
|
||||||
|
bool rightTargetVisible,
|
||||||
|
bool hasLeftSpeaker,
|
||||||
|
bool hasRightSpeaker)
|
||||||
|
{
|
||||||
|
if (leftTargetVisible && !leftCurrentlyVisible)
|
||||||
|
{
|
||||||
|
float leftStartX = GetAppearStartX(true, rightCurrentlyVisible, hasLeftSpeaker, hasRightSpeaker);
|
||||||
|
SetSpritePosition(_leftSprite.rectTransform, leftStartX);
|
||||||
|
SetSpriteVisible(_leftSprite, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightTargetVisible && !rightCurrentlyVisible)
|
||||||
|
{
|
||||||
|
float rightStartX = GetAppearStartX(false, leftCurrentlyVisible, hasLeftSpeaker, hasRightSpeaker);
|
||||||
|
SetSpritePosition(_rightSprite.rectTransform, rightStartX);
|
||||||
|
SetSpriteVisible(_rightSprite, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leftCurrentlyVisible && !leftTargetVisible)
|
||||||
|
{
|
||||||
|
SetSpriteVisible(_leftSprite, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightCurrentlyVisible && !rightTargetVisible)
|
||||||
|
{
|
||||||
|
SetSpriteVisible(_rightSprite, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetAppearStartX(bool isLeft, bool otherCurrentlyVisible, bool hasLeftSpeaker,
|
||||||
|
bool hasRightSpeaker)
|
||||||
{
|
{
|
||||||
if (hasLeftSpeaker && hasRightSpeaker)
|
if (hasLeftSpeaker && hasRightSpeaker)
|
||||||
{
|
{
|
||||||
SetSpriteVisible(_leftSprite, true);
|
// single -> multi: hidden side starts from center, then both move to side positions.
|
||||||
SetSpriteVisible(_rightSprite, true);
|
if (otherCurrentlyVisible)
|
||||||
SetSpritePosition(_leftSprite.rectTransform, _leftSpritePosition);
|
{
|
||||||
SetSpritePosition(_rightSprite.rectTransform, _rightSpritePosition);
|
return _singleSpeakerCenterPosition;
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
return isLeft ? _leftSpritePosition : _rightSpritePosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasLeftSpeaker)
|
// single appears: active side starts from its side and moves to center.
|
||||||
|
return isLeft ? _leftSpritePosition : _rightSpritePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetTargetX(bool isLeft, bool hasLeftSpeaker, bool hasRightSpeaker)
|
||||||
|
{
|
||||||
|
if (hasLeftSpeaker && hasRightSpeaker)
|
||||||
{
|
{
|
||||||
SetSpriteVisible(_leftSprite, true);
|
return isLeft ? _leftSpritePosition : _rightSpritePosition;
|
||||||
SetSpriteVisible(_rightSprite, false);
|
|
||||||
SetSpritePosition(_leftSprite.rectTransform, _singleSpeakerCenterPosition);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasRightSpeaker)
|
if (hasLeftSpeaker || hasRightSpeaker)
|
||||||
{
|
{
|
||||||
SetSpriteVisible(_leftSprite, false);
|
// multi -> single: both move to center first, then inactive side hides.
|
||||||
SetSpriteVisible(_rightSprite, true);
|
return _singleSpeakerCenterPosition;
|
||||||
SetSpritePosition(_rightSprite.rectTransform, -_singleSpeakerCenterPosition);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSpriteVisible(_leftSprite, false);
|
return isLeft ? _leftSpritePosition : _rightSpritePosition;
|
||||||
SetSpriteVisible(_rightSprite, false);
|
}
|
||||||
|
|
||||||
|
private Tween CreateMoveTween(RectTransform rectTransform, float targetX)
|
||||||
|
{
|
||||||
|
if (rectTransform == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Mathf.Abs(rectTransform.anchoredPosition.x - targetX) < 0.01f)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rectTransform.DOAnchorPosX(targetX, _moveDuration).SetEase(_moveEase);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetSpriteVisible(Image spriteImage, bool visible)
|
private static void SetSpriteVisible(Image spriteImage, bool visible)
|
||||||
|
|
@ -141,4 +277,4 @@ namespace UI
|
||||||
rectTransform.anchoredPosition = anchoredPosition;
|
rectTransform.anchoredPosition = anchoredPosition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
|
using System.Collections;
|
||||||
using Definition.Enum;
|
using Definition.Enum;
|
||||||
using Event;
|
using Event;
|
||||||
|
using TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UI
|
namespace UI
|
||||||
{
|
{
|
||||||
public abstract class DialogFormBase : UGuiForm
|
public abstract class DialogFormBase : UGuiForm
|
||||||
{
|
{
|
||||||
[SerializeField] protected float _playSpeed;
|
|
||||||
|
|
||||||
protected DialogFormContext _context;
|
protected DialogFormContext _context;
|
||||||
|
private Coroutine _typingCoroutine;
|
||||||
|
private TMP_Text _typingTargetText;
|
||||||
|
private bool _isTypewriting;
|
||||||
|
|
||||||
public abstract DialogFormMode UIMode { get; }
|
public abstract DialogFormMode UIMode { get; }
|
||||||
|
|
||||||
|
|
@ -29,12 +32,18 @@ namespace UI
|
||||||
|
|
||||||
protected override void OnClose(bool isShutdown, object userData)
|
protected override void OnClose(bool isShutdown, object userData)
|
||||||
{
|
{
|
||||||
|
StopTypewriter();
|
||||||
_context = null;
|
_context = null;
|
||||||
base.OnClose(isShutdown, userData);
|
base.OnClose(isShutdown, userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnClickNextLine()
|
public void OnClickNextLine()
|
||||||
{
|
{
|
||||||
|
if (CompleteTypewriterIfRunning())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GameEntry.Event.Fire(this, DialogNextLineRequestEventArgs.Create());
|
GameEntry.Event.Fire(this, DialogNextLineRequestEventArgs.Create());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,24 +57,90 @@ namespace UI
|
||||||
GameEntry.Event.Fire(this, DialogStopRequestEventArgs.Create());
|
GameEntry.Event.Fire(this, DialogStopRequestEventArgs.Create());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static string NormalizeValue(string value)
|
protected void PlayTypewriter(TMP_Text targetText, string text, float charsPerSecond)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(value))
|
StopTypewriter();
|
||||||
|
|
||||||
|
if (targetText == null)
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(value, "Null", System.StringComparison.OrdinalIgnoreCase))
|
string finalText = text ?? string.Empty;
|
||||||
|
_typingTargetText = targetText;
|
||||||
|
|
||||||
|
if (charsPerSecond <= 0f || string.IsNullOrEmpty(finalText))
|
||||||
{
|
{
|
||||||
return string.Empty;
|
targetText.text = finalText;
|
||||||
|
targetText.maxVisibleCharacters = int.MaxValue;
|
||||||
|
_isTypewriting = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(value, "None", System.StringComparison.OrdinalIgnoreCase))
|
_isTypewriting = true;
|
||||||
|
_typingCoroutine = StartCoroutine(TypewriterRoutine(targetText, finalText, charsPerSecond));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void StopTypewriter()
|
||||||
|
{
|
||||||
|
if (_typingCoroutine != null)
|
||||||
{
|
{
|
||||||
return string.Empty;
|
StopCoroutine(_typingCoroutine);
|
||||||
|
_typingCoroutine = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
_typingTargetText = null;
|
||||||
|
_isTypewriting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CompleteTypewriterIfRunning()
|
||||||
|
{
|
||||||
|
if (!_isTypewriting || _typingTargetText == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_typingTargetText.maxVisibleCharacters = int.MaxValue;
|
||||||
|
StopTypewriter();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator TypewriterRoutine(TMP_Text targetText, string finalText, float charsPerSecond)
|
||||||
|
{
|
||||||
|
targetText.text = finalText;
|
||||||
|
targetText.ForceMeshUpdate();
|
||||||
|
|
||||||
|
int totalCharacters = targetText.textInfo.characterCount;
|
||||||
|
if (totalCharacters <= 0)
|
||||||
|
{
|
||||||
|
targetText.maxVisibleCharacters = int.MaxValue;
|
||||||
|
_typingCoroutine = null;
|
||||||
|
_typingTargetText = null;
|
||||||
|
_isTypewriting = false;
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetText.maxVisibleCharacters = 0;
|
||||||
|
float elapsed = 0f;
|
||||||
|
int visibleCharacters = 0;
|
||||||
|
|
||||||
|
while (visibleCharacters < totalCharacters)
|
||||||
|
{
|
||||||
|
elapsed += Time.unscaledDeltaTime;
|
||||||
|
int nextVisible = Mathf.Min(totalCharacters, Mathf.FloorToInt(elapsed * charsPerSecond));
|
||||||
|
if (nextVisible != visibleCharacters)
|
||||||
|
{
|
||||||
|
visibleCharacters = nextVisible;
|
||||||
|
targetText.maxVisibleCharacters = visibleCharacters;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetText.maxVisibleCharacters = int.MaxValue;
|
||||||
|
_typingCoroutine = null;
|
||||||
|
_typingTargetText = null;
|
||||||
|
_isTypewriting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ namespace UI
|
||||||
public class MaskDialogForm : DialogFormBase
|
public class MaskDialogForm : DialogFormBase
|
||||||
{
|
{
|
||||||
public override DialogFormMode UIMode => DialogFormMode.Mask;
|
public override DialogFormMode UIMode => DialogFormMode.Mask;
|
||||||
|
|
||||||
[SerializeField] private Image _maskImage;
|
[SerializeField] private Image _maskImage;
|
||||||
|
|
||||||
[SerializeField] private TMP_Text _text;
|
[SerializeField] private TMP_Text _text;
|
||||||
|
|
||||||
public override void StartDialog(DialogFormContext context)
|
public override void StartDialog(DialogFormContext context)
|
||||||
{
|
{
|
||||||
if (context == null)
|
if (context == null)
|
||||||
|
|
@ -29,10 +29,7 @@ namespace UI
|
||||||
_maskImage.gameObject.SetActive(true);
|
_maskImage.gameObject.SetActive(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_text != null)
|
PlayTypewriter(_text, context.Text, context.PlayingSpeed);
|
||||||
{
|
|
||||||
_text.text = NormalizeValue(context.Text);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ MonoBehaviour:
|
||||||
m_SelectedTrigger: Selected
|
m_SelectedTrigger: Selected
|
||||||
m_DisabledTrigger: Disabled
|
m_DisabledTrigger: Disabled
|
||||||
m_Interactable: 1
|
m_Interactable: 1
|
||||||
m_TargetGraphic: {fileID: 0}
|
m_TargetGraphic: {fileID: 3708131469420921886}
|
||||||
m_OnClick:
|
m_OnClick:
|
||||||
m_PersistentCalls:
|
m_PersistentCalls:
|
||||||
m_Calls:
|
m_Calls:
|
||||||
|
|
@ -321,7 +321,7 @@ GameObject:
|
||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
m_StaticEditorFlags: 0
|
m_StaticEditorFlags: 0
|
||||||
m_IsActive: 1
|
m_IsActive: 0
|
||||||
--- !u!224 &4594737505273760298
|
--- !u!224 &4594737505273760298
|
||||||
RectTransform:
|
RectTransform:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -679,12 +679,15 @@ MonoBehaviour:
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
_playSpeed: 0
|
_playSpeed: 0
|
||||||
|
_speakerArea: {fileID: 3736358320082617150}
|
||||||
_speakerNameText: {fileID: 2470970474825277305}
|
_speakerNameText: {fileID: 2470970474825277305}
|
||||||
_contentText: {fileID: 6431296888118130931}
|
_contentText: {fileID: 6431296888118130931}
|
||||||
_leftSprite: {fileID: 7945103967507868302}
|
_leftSprite: {fileID: 7945103967507868302}
|
||||||
_rightSprite: {fileID: 5385698520020721016}
|
_rightSprite: {fileID: 5385698520020721016}
|
||||||
_leftSpritePosition: 450
|
_leftSpritePosition: 450
|
||||||
_rightSpritePosition: -450
|
_rightSpritePosition: -450
|
||||||
|
_moveDuration: 0.25
|
||||||
|
_moveEase: 9
|
||||||
--- !u!1 &7381337123922490182
|
--- !u!1 &7381337123922490182
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -837,7 +840,7 @@ GameObject:
|
||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
m_StaticEditorFlags: 0
|
m_StaticEditorFlags: 0
|
||||||
m_IsActive: 1
|
m_IsActive: 0
|
||||||
--- !u!224 &1023330169278438415
|
--- !u!224 &1023330169278438415
|
||||||
RectTransform:
|
RectTransform:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
|
||||||
|
|
@ -841,6 +841,7 @@ MonoBehaviour:
|
||||||
m_Script: {fileID: 11500000, guid: d6174838c30e460429e5628757bbf015, type: 3}
|
m_Script: {fileID: 11500000, guid: d6174838c30e460429e5628757bbf015, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
|
_playingSpeed: 10
|
||||||
--- !u!1 &513208572
|
--- !u!1 &513208572
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue