Skip to content

Instantly share code, notes, and snippets.

@brihernandez
Last active January 9, 2021 16:07
Show Gist options
  • Save brihernandez/4c1e28ddb0599628810d597668894bfd to your computer and use it in GitHub Desktop.
Save brihernandez/4c1e28ddb0599628810d597668894bfd to your computer and use it in GitHub Desktop.
Extension method to reveal TextMeshPro characters over time. Requires UniTask.
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using TMPro;
public static class TextMeshProExtensions
{
private static Dictionary<TextMeshProUGUI, CancellationTokenSource> textToCancel = new Dictionary<TextMeshProUGUI, CancellationTokenSource>();
/// <summary>
/// Reveals characters of the given text with a delay between each character.
/// </summary>
/// <param name="milliseconds">Milliseconds between each character being shown.</param>
/// <param name="padding">Adds this to the number of characters to be revealed. Can be used if the text might
/// change while the reveal is happening to make sure all the characters are available.</param>
/// <example>
/// yourTMProText.RevealTextWithDelay(20).Forget();
/// </example>
public static async UniTaskVoid RevealTextWithDelay(this TextMeshProUGUI proText, int milliseconds = 10, int padding = 0)
{
// If this text is already in the middle of revealing text, cancel its currently running
// task so that the reveal process can be restarted.
if (textToCancel.ContainsKey(proText))
{
textToCancel[proText].Cancel();
textToCancel.Remove(proText);
}
// Create a cancellation token that can be called to interrupt this text in case it's told
// to reveal text while in the middle of already revealing it. Combo it with the typical
// Unity OnDestroy token to handle the usual case of the object disappearing while running.
var interruptShowingTextCancel = new CancellationTokenSource();
var superCancel = CancellationTokenSource.CreateLinkedTokenSource(
interruptShowingTextCancel.Token,
proText.GetCancellationTokenOnDestroy());
textToCancel.Add(proText, superCancel);
var lastUpdateTime = System.DateTime.Now;
int visibleCount = 0;
while (visibleCount < proText.text.Length + padding)
{
// Since frame times can be longer than the number of milliseconds desired between
// characters, account for how many letters would have passed since last cycle.
var timeSinceLast = System.DateTime.Now.Subtract(lastUpdateTime);
int extraCharacters = timeSinceLast.Milliseconds / milliseconds;
visibleCount += 1 + extraCharacters;
proText.maxVisibleCharacters = visibleCount;
lastUpdateTime = System.DateTime.Now;
await UniTask.Delay(milliseconds, cancellationToken: superCancel.Token);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment