Best way to fade-in text line by line?

Hi!

I’m making a VR poem experience. What I have right now is, when player moves to a certain area, the first line of a stanza appears with a fade-in animation.

Then, if player presses the A button, the next line of poem appears as well. However, because this is done by changing the text of the TMP object through a script, I can’t fade the new lines in. I guess a way would be to make new tmp objects and use them as obj references to enable whenever A button press is detected, but that feels way too sloppy.

Does anyone have good ideas on how to do this?

If you want to load line by line you can use TMP_Text.maxVisibleLines. This alone won’t give you a fade in effect (you could manipulate the rich text for that with additional logic, it might be complicated), but it will load each line of the text sequentially. This approach can get weird with what TMP considers a “line” vs what you might consider a “line”.

[SerializeField] TMP_Text m_TextString;
[SerializeField] float m_LineDisplayWaitTime = 1.0f;

IEnumerator DisplayLinesSequentially()
{   
    for (int i = 0; i <= m_TextString.GetTextInfo(m_TextString.text).lineCount; i++)
    {
        m_TextString.maxVisibleLines = i;
        yield return new WaitForSeconds(m_LineDisplayWaitTime);
    }
}

Another slightly less optimized (but probably better TBH) solution could be to keep track of each line individually as their own TMP_Text component and then fade each one sequentially setting their colors alpha for each line. This approach will require more manual setup and will be slightly less performant, but it will probably look the best and be the most consistent. This approach will also require you to handle assigning each TMP Text component text field based on each specific line. Code would be more like this:

[SerializeField] TMP_Text[] m_TextStrings;
[SerializeField] float m_FadeTime = 1.0f;
[SerializeField] float m_WaitTimeBetweenLines = 1.0f;
[SerializeField] float m_InitialWaitTime = 1.0f;

IEnumerator FadeTextComponentsSequentially()
{
    yield return new WaitForSeconds(m_InitialWaitTime);
    foreach(var tmp in m_TextStrings)
    {
        float alpha = 0f;

        while(alpha < 1.0f)
        {
            alpha += Time.deltaTime / m_FadeTime;
            tmp.color = new Color(tmp.color.r, tmp.color.g, tmp.color.b, alpha);
            yield return null;
        }
        tmp.color = new Color(tmp.color.r, tmp.color.g, tmp.color.b, alpha);
        yield return new WaitForSeconds(m_WaitTimeBetweenLines);
    }
}

fadelineovertime

Hope this helps and may the odds be ever in your favor!
-Joegre