Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Dynamic, scrolling text support

Discussion in 'UGUI & TextMesh Pro' started by JimmyRoberts, Oct 8, 2015.

  1. JimmyRoberts

    JimmyRoberts

    Joined:
    Oct 8, 2015
    Posts:
    3
    Greetings,

    I'm working on creating a game console prefab in my project using the new Unity UI. I seem to have come across a limitation that I am not sure the best way to deal with. Any insight would be very much appreciated.

    Here are the details of my setup:

    The console in action:


    The hierarchy:


    The GameConsoleScrollView object has a mask:


    The GameConsoleContent panel uses a Vertical Layout Group and Content Size Fitter:


    I've created a message prefab that uses a Layout Element and is added to the GameConsoleContent panel during runtime:


    And finally, the GameConsole object in the hierarchy has my custom GameConsole component attached:
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4.  
    5. public class GameConsole : MonoBehaviour
    6. {
    7.     public GameObject ContentPanel;
    8.     public GameObject MessagePrefab;
    9.  
    10.     #region Unity Events
    11.  
    12.     private void Start()
    13.     {
    14.         for(int i = 0; i < 75; ++i)
    15.         {
    16.             WriteLine("I've constructed a fairly long sentence that will be output to the console to show that after a certain amount of content has been generated, an exception will be thrown saying that there are too many vertices in the parent canvas.");
    17.         }
    18.     }
    19.  
    20.     #endregion
    21.  
    22.     #region Private Methods
    23.  
    24.     private GameObject GenerateTextObject(string content)
    25.     {
    26.         GameObject messagePrefab = Instantiate(MessagePrefab);
    27.         Text textComponent = messagePrefab.GetComponent<Text>();
    28.  
    29.         textComponent.text = content;
    30.         messagePrefab.transform.SetParent(ContentPanel.transform, false);
    31.  
    32.         return messagePrefab;
    33.     }
    34.  
    35.     #endregion
    36.  
    37.     public void WriteLine(string content, params object[] args)
    38.     {
    39.         WriteLine(string.Format(content, args));
    40.     }
    41.  
    42.     public void WriteLine(string content)
    43.     {
    44.         GenerateTextObject("<" + DateTime.Now.ToShortTimeString() + "> " + content);
    45.      }
    46. }
    I love how easy it is to set this up using the new UI system. Everything works as expected until too much content has been added. In this case, outputting the message 50 times works, but 75 is too much. Of course that would directly relate to the size of the strings being generated.

    I understand why there is a vertex limitation for a canvas, but I'm not sure what the best approach is here to deal with the situation. I believe I would need to limit the amount of text objects generated to ensure the vertex limit is not hit, but in doing so wouldn't that require a bunch of extra code to monitor the scroll position, etc? I feel like doing that would defeat the purpose of the simplicity of the current UI system. Is there an easier way?

    I've done quite a bit of searching around on this topic and haven't been able to find much. Any thoughts or suggestions would be very much appreciated.

    Thank you for your time,
    Jimmy
     
  2. jcredible

    jcredible

    Joined:
    Dec 4, 2012
    Posts:
    24
    You have some options:

    1. Batch up your objects into separate canvases. I actually am not sure how you'd do this but an individual canvas has the vertex limit.
    2. Write a scroll rect that virtualizes the data and only shows certain pieces at once (this is what I do but I haven't perfected it yet, mostly because of dynamically sized text and how Unity doesn't know the size until the end of a frame; it's also tricky if your text/object takes up more space than the scroll rect container size)
    3. Throw away messages after a set amount, you'd have to be conservative... unless you added code to determine how many characters were in a message.
    4. Don't use a scroll rect for all the data. Instead, do something called paging (with forward/backward buttons) where you only display a bit of the data at the time. So say only show 25 messages in the scrollrect at a time. More klunky but it's probably the easiest imo
     
    Last edited: Oct 9, 2015
  3. JimmyRoberts

    JimmyRoberts

    Joined:
    Oct 8, 2015
    Posts:
    3
    All of those still seem like overkill or hacks... there's got to be an easier way??

     
  4. jcredible

    jcredible

    Joined:
    Dec 4, 2012
    Posts:
    24
    I wouldn't call them hacks.. WPF supports virtualization for large data sets and paging is a common technique on the web. But yes, they are less than ideal.

    That being said, in Unity 5.2 it looks like they added a new component: RectMask2D which might work for your data set.

    I'm curious how well it would work for millions of items though...something I'll need to test out. Unfortunately, it means I need to upgrade to 5.2..something I've been avoiding.
     
  5. JimmyRoberts

    JimmyRoberts

    Joined:
    Oct 8, 2015
    Posts:
    3
    Yeah, sorry. I meant that all of that work required to virtualize the data and provide scrolling support seemed like a lot of work compared to the simplicity of everything else.

    Excellent call on the new RectMask2D! I updated to Unity 5.2 and tried it out... that was the exact missing piece of the puzzle! Thank you.

    For anyone else that is attempting to do something similar, all I did to fix this was add the new Rect Mask 2D component to my GameConsoleScrollView object shown in my original post, and voilà!
     
    gresolio and jcredible like this.
  6. RJ45

    RJ45

    Joined:
    Mar 27, 2015
    Posts:
    7
    Here is a working demo of how to do scrolling text. There are a number of challenges with it.

    On the test script click the stop button to make the text stop generating and you'll see the scrollbar works perfectly as well.
     

    Attached Files:

    LasseSimonsen likes this.