Skip to content

Instantly share code, notes, and snippets.

@unitycoder
Last active April 11, 2024 08:11
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save unitycoder/19625fed364a39cb278f to your computer and use it in GitHub Desktop.
Save unitycoder/19625fed364a39cb278f to your computer and use it in GitHub Desktop.
Type out UI text one character at a time
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
// attach to UI Text component (with the full text already there)
public class UITextTypeWriter.cs : MonoBehaviour
{
Text txt;
string story;
void Awake ()
{
txt = GetComponent<Text> ();
story = txt.text;
txt.text = "";
// TODO: add optional delay when to start
StartCoroutine (PlayText());
}
IEnumerator PlayText()
{
foreach (char c in story)
{
txt.text += c;
yield return new WaitForSeconds (0.125f);
}
}
}
@arkms
Copy link

arkms commented Feb 11, 2016

This can be a good version for set delay, start on awake and with a function how can be call from other script.

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class UITextTypeWriter.cs : MonoBehaviour
{

    Text txt;
    string story;
    public bool PlayOnAwake = true;
    public float Delay;

    void Awake()
    {
        txt = GetComponent<Text>();
        if (PlayOnAwake)
            ChangeText(txt.text, Delay);
    }

    //Update text and start typewriter effect
    public void ChangeText(string _text, float _delay= 0f)
    {
        StopCoroutine(PlayText()); //stop Coroutime if exist
       story = _text;
        txt.text = ""; //clean text
        Invoke("Start_PlayText", _delay); //Invoke effect
    }

    void Start_PlayText()
    {
        StartCoroutine(PlayText());
    }

    IEnumerator PlayText()
    {
        foreach (char c in story)
        {
            txt.text += c;
            yield return new WaitForSeconds(0.125f);
        }
    }

}

@davidhaley
Copy link

davidhaley commented Feb 11, 2017

Hello guys,

Thank you both for the script. I added another feature - briefly pause when a period or comma is detected. I find it provides better flow.

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Text;
using System;

public class UITextTypeWriter: MonoBehaviour
{
    public Text text;
    public bool playOnAwake = true;
    public float delayToStart;
    public float delayBetweenChars = 0.125f;
    public float delayAfterPunctuation = 0.5f;

    private string story;
    private float originDelayBetweenChars;
    private bool lastCharPunctuation = false;
    private char charComma;
    private char charPeriod;

    void Awake()
    {
        text = GetComponent<Text>();
        originDelayBetweenChars = delayBetweenChars;

        charComma = Convert.ToChar(44);
        charPeriod = Convert.ToChar(46);

        if (playOnAwake)
        {
            ChangeText(text.text, delayToStart);
        }
     }

    //Update text and start typewriter effect
    public void ChangeText(string textContent, float delayBetweenChars = 0f)
    {
        StopCoroutine(PlayText()); //stop Coroutime if exist
        story = textContent;
        text.text = ""; //clean text
        Invoke("Start_PlayText", delayBetweenChars); //Invoke effect
    }

    void Start_PlayText()
    {
        StartCoroutine(PlayText());
    }

    IEnumerator PlayText()
    {

        foreach (char c in story)
        {
            delayBetweenChars = originDelayBetweenChars;

            if (lastCharPunctuation)  //If previous character was a comma/period, pause typing
            {
                yield return new WaitForSeconds(delayBetweenChars = delayAfterPunctuation);
                lastCharPunctuation = false;
            }
         
            if (c == charComma || c == charPeriod)
            {
                lastCharPunctuation = true;
            }

            text.text += c;
            yield return new WaitForSeconds(delayBetweenChars);
        }
    }
}

@ChazM
Copy link

ChazM commented Dec 16, 2019

Now you can play a nice typping sound using this :D and stopping a litle on blank space, just play with time to find the perfect typping mood

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using TMPro;
using System;

public class TypeWriterEffect : MonoBehaviour
{
public TextMeshProUGUI text;
public bool playOnAwake = true;
public float delayToStart;
public float delayBetweenChars = 0.125f;
public float delayAfterPunctuation = 0.5f;
private string story;
private float originDelayBetweenChars;
private bool lastCharPunctuation = false;
private char charComma;
private char charPeriod;
private char charEmpty;
public GameObject AudioTypping;
private AudioSource TyppingFX;

void Awake()
{
    TyppingFX = GetComponent<AudioSource>();
    TyppingFX.clip = AudioTypping.GetComponent<AudioSource>().clip;

    text = GetComponent<TextMeshProUGUI>();
    originDelayBetweenChars = delayBetweenChars;

    charComma = Convert.ToChar(44);
    charPeriod = Convert.ToChar(46);
    charEmpty = Convert.ToChar(" ");//Convert.ToChar(255);

    if (playOnAwake)
    {
        ChangeText(text.text, delayToStart);
    }
}

//Update text and start typewriter effect
public void ChangeText(string textContent, float delayBetweenChars = 0f)
{
    StopCoroutine(PlayText()); //stop Coroutime if exist
    story = textContent;
    text.text = ""; //clean text
    Invoke("Start_PlayText", delayBetweenChars); //Invoke effect
}

void Start_PlayText()
{
    StartCoroutine(PlayText());
}

IEnumerator PlayText()
{

    foreach (char c in story)
    {
        delayBetweenChars = originDelayBetweenChars;

        if (lastCharPunctuation)  //If previous character was a comma/period, pause typing
        {
            TyppingFX.Pause();
            yield return new WaitForSeconds(delayBetweenChars = delayAfterPunctuation);
            lastCharPunctuation = false;
        }

        if ( c == charEmpty || c == charComma || c == charPeriod  )
        {
          TyppingFX.Pause();
          lastCharPunctuation = true;
        }

        TyppingFX.PlayOneShot(TyppingFX.clip,0.3f);
        text.text += c;
        yield return new WaitForSeconds(delayBetweenChars);
    }
}

}

@unitycoder
Copy link
Author

Text typing effect for Unity uGUI Text components https://github.com/redbluegames/unity-text-typer

@unitycoder
Copy link
Author

@qba210
Copy link

qba210 commented Jul 26, 2022

Added an option to disable typing sound.
Also added a volume slider.

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Text;
using System;
using TMPro;

[RequireComponent(typeof(TextMeshProUGUI))]
public class UITextTypewriter : MonoBehaviour
{
    [Header("Typing Settings")]
    public TextMeshProUGUI text;
    public bool playOnAwake = true;
    public float delayToStart;
    public float delayBetweenChars = 0.125f;
    public float delayAfterPunctuation = 0.5f;
    private string story;
    private float originDelayBetweenChars;
    private bool lastCharPunctuation = false;
    private char charComma;
    private char charPeriod;
    private char charEmpty;
    [Header("Audio Settings")]
    [Tooltip("When true requires AudioSource on this object.")]
    public bool useAudio = true;
    [Range(0f, 2f)]
    public float volume = .3f;
    [Tooltip("GameObject with AudioSource component.")]
    public GameObject AudioTypping;
    private AudioSource TyppingFX;

    void Awake()
    {
        if (useAudio) {
            TyppingFX = GetComponent<AudioSource>();
            TyppingFX.clip = AudioTypping.GetComponent<AudioSource>().clip;
        }

        text = GetComponent<TextMeshProUGUI>();
        originDelayBetweenChars = delayBetweenChars;

        charComma = Convert.ToChar(44);
        charPeriod = Convert.ToChar(46);
        charEmpty = Convert.ToChar(" ");//Convert.ToChar(255);

        if (playOnAwake)
        {
            ChangeText(text.text, delayToStart);
        }
    }

    //Update text and start typewriter effect
    public void ChangeText(string textContent, float delayBetweenChars = 0)
    {
        StopCoroutine(PlayText()); //stop Coroutime if exist
        story = textContent;
        text.text = ""; //clean text
        Invoke("Start_PlayText", delayBetweenChars); //Invoke effect
    }

    public void StartTypewriter()
    {
        StopCoroutine(PlayText()); //stop Coroutime if exist
        text.text = ""; //clean text
        Invoke("Start_PlayText", delayBetweenChars); //Invoke effect
    }

    void Start_PlayText()
    {
        StartCoroutine(PlayText());
    }

    IEnumerator PlayText()
    {

        foreach (char c in story)
        {
            delayBetweenChars = originDelayBetweenChars;

            if (lastCharPunctuation)  //If previous character was a comma/period, pause typing
            {
                if (useAudio) TyppingFX.Pause();
                yield return new WaitForSeconds(delayBetweenChars = delayAfterPunctuation);
                lastCharPunctuation = false;
            }

            if (c == charEmpty || c == charComma || c == charPeriod)
            {
                if (useAudio) TyppingFX.Pause();
                lastCharPunctuation = true;
            }

            if (useAudio) TyppingFX.PlayOneShot(TyppingFX.clip, volume);
            text.text += c;
            yield return new WaitForSeconds(delayBetweenChars);
        }
    }
}

@spider853
Copy link

spider853 commented Apr 4, 2023

Here is a simplier approach, without audio

using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;

[RequireComponent(typeof(TextMeshProUGUI))]
public class ScrollText : MonoBehaviour
{
    public string GameSceneName;
    public float InitialDelay = 0.1f;
    public float CharWait = 0.5f;
    public float CommaWait = 0.3f;
    public float PeriodWait = 0.5f;

    TextMeshProUGUI textMesh;
    string text;

    // Start is called before the first frame update
    void Start()
    {
        textMesh = GetComponent<TextMeshProUGUI>();
        text = textMesh.text;
        textMesh.text = "";
        StartCoroutine(TypeText());
    }

    IEnumerator TypeText()
	{
        yield return new WaitForSeconds(InitialDelay);
        foreach (char c in text)
		{
			textMesh.text += c;
            yield return new WaitForSeconds(CharWait);
			if (c == ',')
				yield return new WaitForSeconds(CommaWait);
			if (c == '.')
				yield return new WaitForSeconds(PeriodWait);
		}
        SceneManager.LoadScene(GameSceneName);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment