Blinking cursor when the text is finished

Announcements, support questions, and discussion for the Dialogue System.
AoF
Posts: 241
Joined: Sun May 12, 2019 8:36 pm

Re: Blinking cursor when the text is finished

Post by AoF »

Here's a gif showing it happening (notice the left and side text): https://cdn.discordapp.com/attachments/ ... 71/gif.gif

I'll email you my project. Thanks!
User avatar
Tony Li
Posts: 22104
Joined: Thu Jul 18, 2013 1:27 pm

Re: Blinking cursor when the text is finished

Post by Tony Li »

This is the core code to blink the cursor. After setting TMP's text, it needs to call ForceMeshUpdate() to rebuild the visible mesh of the text. In the loop, this version changes the number of characters to show instead of changing the text, since changing the text would require it to rebuild the mesh every time.

Code: Select all

    private IEnumerator BlinkCursor()
    {
        text.text += " x";
        text.ForceMeshUpdate();
        var fullLength = text.textInfo.characterCount;
        while (blink)
        {
            text.maxVisibleCharacters = fullLength;
            yield return new WaitForSeconds(.5f);
            text.maxVisibleCharacters = fullLength - 1;
            yield return new WaitForSeconds(.5f);
        }
    }
AoF
Posts: 241
Joined: Sun May 12, 2019 8:36 pm

Re: Blinking cursor when the text is finished

Post by AoF »

I tried that and modified it for my needs. It worked well, but what I didn't like is it put the sprite at the very end as soon as the text completed, almost as if it was part of the dialogue. I thought it would look better if there was a delay before it showed up. I thought this would be extremely straight forward, but for some reason, it doesn't work at all when I attempt it. Here's my code:

Code: Select all

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

public class BlinkingCursor : MonoBehaviour
{
    private const string CURSOR_1 = " <sprite=\"cursors\" index=0>";
    private const string CURSOR_2 = " <sprite=\"cursors\" index=1>";
    public TextMeshProUGUI text;
    private bool blink = false;
    private Coroutine coroutine;

    public void OnBegin()
    {
        Debug.LogError("OnBegin");
        blink = false;
        if (coroutine != null)
        {
            StopCoroutine(coroutine);
        }
    }

    public void OnEnd()
    {
        Debug.LogError("OnEnd");
        blink = true;
        coroutine = StartCoroutine(BlinkCursor());
    }

    private IEnumerator BlinkCursor()
    {
        yield return new WaitForSeconds(1f);  // works exactly as expected when this line is removed
        Debug.LogError("gonna blink! " + blink);
        text.text += " " + CURSOR_1;
        text.ForceMeshUpdate();
        var fullLength = text.textInfo.characterCount;
        while (blink)
        {
            text.text = text.text.Replace(CURSOR_1, CURSOR_2);
            text.ForceMeshUpdate();
            yield return new WaitForSeconds(.5f);
            text.text = text.text.Replace(CURSOR_2, CURSOR_1);
            text.ForceMeshUpdate();
            yield return new WaitForSeconds(.5f);
        }
    }
}
Any idea why waiting at the beginning of the Coroutine would prevent the cursor from showing completely? This is the log output:
User avatar
Tony Li
Posts: 22104
Joined: Thu Jul 18, 2013 1:27 pm

Re: Blinking cursor when the text is finished

Post by Tony Li »

After a little research, it turns out that ForceMeshLayout() doesn't update a TextMeshProUGUI's internal cache of sprite references. I restructured the script to deactivate and immediately reactivate its GameObject when starting to blink, which forces it to refresh its sprite references. The script now also turns off the typewriter effect's Play On Enable checkbox since this would be unintentionally triggered by deactivating and reactivating the GameObject.
Post Reply