Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

TextMesh Pro Scrolling Text Box with Text Reveal

Discussion in 'UGUI & TextMesh Pro' started by wickedpopular, Aug 21, 2019.

  1. wickedpopular


    Oct 29, 2016
    Hello! I am attempting to implement the following using Text Mesh Pro, and am hitting some snags. What I am trying to do is:
    • Starting from the top of the text box, the text types in until the text box is filled.
    • Once filled, it stops and awaits confirmation
    • Once a button confirms it, the text scrolls up until the top line is out of the Masked area
    • The next line types in until the Masked area is filled again
    • This continues until the entire string has been displayed.
    To do this, I started with the TextMeshPro demo scene "Old Computer Terminal." This showed how to create the "typing" effect as the text is revealed using maxVisibleCharacters. Then I created a method that updates the position of the RectTransform of the text object, moving it up 1 line width (I'm estimating this value, but I'm guessing I need to find the maximum height of a character in the font I'm using.)

    What I need now is some way of determining when the text box has been filled with text, and when a single line has been fully displayed. How would I do this? I don't believe I can do this by counting characters per line, because words can wrap around to new lines.

    Thank you! :)
  2. Stephan_B


    Unity Technologies

    Feb 26, 2017
    How many characters and lines of text does the string contain? Lines of text are delimited by the Line Feed character / char(10).
  3. wickedpopular


    Oct 29, 2016
    Hello Stephan! Thanks for the reply.:) The input string may contain an arbitrary number of characters and the text box that contains then may be of an arbitrary size, so I need to be able to handle strings of various lengths.

    If I am understanding you though, are you saying that when lines of text are automatically wrapped, that char(10) is inserted into them at that location?

    Does that mean that if I get the text string back from the TMP Text object, I can divide the string using char(10) as a delimiter to build a list of strings? Or would I simply fire off the event to scroll down & wait for input whenever my viewcharacter loop reaches a char(10)?

    Edit: After some testing, I've determined that as far as I can tell, linebreaks are not automatically added to a string that is allowed to wrap around inside the text box, so that seems like a dead end.

    Edit 2: I believe I have it! Or at least have found an approach to do it. What I was looking for was TMP_TextInfo.lineInfo. LineInfo is an array that stores information on each line in the text, and in that information it stores the index of the first and last characters of that line. So I was able to get this started by changing the coroutine from the Old Computer demo to the following:

    Code (CSharp):
    1.    IEnumerator RevealCharacters(TMP_Text textComponent)
    2.     {
    3.         textComponent.ForceMeshUpdate();
    5.         TMP_TextInfo textInfo = textComponent.textInfo;
    6.         int currentLine = 0;
    10.         int totalVisibleCharacters = textInfo.characterCount; // Get # of Visible Character in text object
    11.         int visibleCount = 0;
    13.         while (true)
    14.         {
    15.             if (hasTextChanged)
    16.             {
    17.                 totalVisibleCharacters = textInfo.characterCount; // Update visible character count.
    18.                 hasTextChanged = false;
    19.             }
    21.             if (visibleCount > totalVisibleCharacters)
    22.             {
    23.                 yield return new WaitForSeconds(1.0f);
    24.                 visibleCount = 0;
    25.             }
    27.             textComponent.maxVisibleCharacters = visibleCount; // How many characters should TextMeshPro display?
    28.             //Debug.Log((System.Convert.ToInt32(textComponent.text[visibleCount])));
    30.             if (visibleCount >= textInfo.lineInfo[currentLine].lastCharacterIndex)
    31.             {
    32.                 rect.anchoredPosition = new Vector2(0, rect.anchoredPosition.y + lineHeight);
    33.                 currentLine += 1;
    34.             }
    36.             visibleCount += 1;
    40.             yield return null;
    41.         }
    42.     }
    I can now add some conditional checks to that to get the behavior I wanted.
    Last edited: Aug 21, 2019
  4. Stephan_B


    Unity Technologies

    Feb 26, 2017
    I am asking about the amount of text as you might chose to handle this differently (for performance reasons) if the text is going to be very long.

    TMP does not insert anything in the text. The question was related to handling of super long text where you might want to break this up per line instead of handling the entire text. See this post which provided some insight on this other possible handling.

    Using the information contains in the TextInfo and sub structures like characterInfo and lineInfo is the way to go. This will allow you to track the position of each line (including wrapping) relative to your text container. In addition to the textInfo, the following property might prove useful.

    Code (csharp):
    2. /// <summary>
    3. /// The first character which exceeds the vertical bounds of its text container.
    4. /// </summary>
    5. public int firstOverflowCharacterIndex
    6. {
    7.      get { return m_firstOverflowCharacterIndex; }
    8. }
  5. wickedpopular


    Oct 29, 2016
    Yes! This should help a lot! Thank you!