feature: Messages are now animated

This commit is contained in:
Gerard Gascón 2024-01-26 22:58:49 +01:00
parent 1c8fbc94e0
commit 923b7b6f62
6 changed files with 83 additions and 8 deletions

View file

@ -1,19 +1,32 @@
using System; using System;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
using Utilities;
namespace Messaging { namespace Messaging {
public class Message : MonoBehaviour{ public class Message : MonoBehaviour {
public RectTransform RectTransform { private set; get; } public RectTransform RectTransform { private set; get; }
public string Text => messageText.text; public string Text => messageText.text;
[SerializeField] private TMP_Text messageText; [SerializeField] private TMP_Text messageText;
private TextTyper _textTyper;
private Coroutine _typingCoroutine;
private void Awake() { private void Awake() {
RectTransform = GetComponent<RectTransform>(); RectTransform = GetComponent<RectTransform>();
_textTyper = new TextTyper(messageText);
} }
public void SetMessageText(string text) { public void SetMessageText(string text, bool animate) {
if (_textTyper.IsMessageAnimating()) {
_textTyper.SkipToEndOfCurrentMessage();
}
this.EnsureCoroutineStopped(ref _typingCoroutine);
if (animate)
_typingCoroutine = StartCoroutine(_textTyper.AnimateTextIn(text, null));
else
messageText.text = text; messageText.text = text;
} }
} }

View file

@ -1,3 +1,5 @@
using System;
using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
namespace Messaging { namespace Messaging {
@ -10,16 +12,34 @@ namespace Messaging {
_messages = messageStructureGenerator.GenerateMessages(); _messages = messageStructureGenerator.GenerateMessages();
} }
private async void Start() {
await Task.Delay(2000);
CreateMessage("asl;dkrhjufioe qvnfioeqlcnnmcuq");
await Task.Delay(2000);
CreateMessage("asl;dkrhjufioe qvnfioeqlcnnmcuq");
await Task.Delay(2000);
CreateMessage("asl;dkrhjufioe qvnfioeqlcnnmcuq");
await Task.Delay(2000);
CreateMessage("asl;dkrhjufioe qvnfioeqlcnnmcuq");
await Task.Delay(2000);
CreateMessage("asl;dkrhjufioe qvnfioeqlcnnmcuq");
}
public void CreateMessage(string message) { public void CreateMessage(string message) {
ModifyMessageText(message, _messages.Length - 1); ModifyMessageText(message, _messages.Length - 1);
} }
private void ModifyMessageText(string message, int index) { private void ModifyMessageText(string message, int index) {
ModifyPreviousMessageText(_messages[index].Text, index - 1);
_messages[index].SetMessageText(message, true);
}
private void ModifyPreviousMessageText(string message, int index) {
if(index < 0) return; if(index < 0) return;
ModifyMessageText(_messages[index].Text, index - 1); ModifyPreviousMessageText(_messages[index].Text, index - 1);
_messages[index].SetMessageText(message); _messages[index].SetMessageText(message, false);
} }
} }
} }

View file

@ -10,13 +10,16 @@ namespace Messaging {
private readonly TMP_Text _textBox; private readonly TMP_Text _textBox;
static readonly Color32 Clear = new(0, 0, 0, 0);
private const float SecondsPerCharacter = 1f / 60f;
public TextTyper(TMP_Text textBox) { public TextTyper(TMP_Text textBox) {
_textBox = textBox; _textBox = textBox;
} }
public IEnumerator AnimateTextIn(string processedMessage, Action onFinish) { public IEnumerator AnimateTextIn(string processedMessage, Action onFinish) {
_textAnimating = true; _textAnimating = true;
float secondsPerCharacter = 1f / 150f; _stopAnimating = false;
float timeOfLastCharacter = 0; float timeOfLastCharacter = 0;
TMP_TextInfo textInfo = _textBox.textInfo; TMP_TextInfo textInfo = _textBox.textInfo;
@ -50,10 +53,10 @@ namespace Messaging {
visibleCharacterIndex = charCount; visibleCharacterIndex = charCount;
FinishAnimating(onFinish); FinishAnimating(onFinish);
} }
if (ShouldShowNextCharacter(secondsPerCharacter, timeOfLastCharacter)) { if (ShouldShowNextCharacter(SecondsPerCharacter, timeOfLastCharacter)) {
if (visibleCharacterIndex <= charCount) { if (visibleCharacterIndex <= charCount) {
if (visibleCharacterIndex < charCount && if (visibleCharacterIndex < charCount &&
ShouldShowNextCharacter(secondsPerCharacter, timeOfLastCharacter)) { ShouldShowNextCharacter(SecondsPerCharacter, timeOfLastCharacter)) {
charAnimStartTimes[visibleCharacterIndex] = Time.unscaledTime; charAnimStartTimes[visibleCharacterIndex] = Time.unscaledTime;
visibleCharacterIndex++; visibleCharacterIndex++;
timeOfLastCharacter = Time.unscaledTime; timeOfLastCharacter = Time.unscaledTime;
@ -64,6 +67,20 @@ namespace Messaging {
} }
} }
for (int j = 0; j < charCount; j++) {
TMP_CharacterInfo charInfo = textInfo.characterInfo[j];
if (!charInfo.isVisible) continue;
int vertexIndex = charInfo.vertexIndex;
int materialIndex = charInfo.materialReferenceIndex;
Color32[] destinationColors = textInfo.meshInfo[materialIndex].colors32;
Color32 theColor = j < visibleCharacterIndex ? originalColors[materialIndex][vertexIndex] : Clear;
destinationColors[vertexIndex + 0] = theColor;
destinationColors[vertexIndex + 1] = theColor;
destinationColors[vertexIndex + 2] = theColor;
destinationColors[vertexIndex + 3] = theColor;
}
_textBox.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); _textBox.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32);
for (int i = 0; i < textInfo.meshInfo.Length; i++) { for (int i = 0; i < textInfo.meshInfo.Length; i++) {
TMP_MeshInfo theInfo = textInfo.meshInfo[i]; TMP_MeshInfo theInfo = textInfo.meshInfo[i];

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1edc85165243485db8a6f414074b8f6c
timeCreated: 1706301321

View file

@ -0,0 +1,11 @@
using UnityEngine;
namespace Utilities {
public static class MonoBehaviourExtensions {
public static void EnsureCoroutineStopped(this MonoBehaviour value, ref Coroutine routine) {
if (routine == null) return;
value.StopCoroutine(routine);
routine = null;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6950117e9f384976acc9489f6f1ae482
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: