Search Unity

TextMeshPro not updating text?

Discussion in 'UGUI & TextMesh Pro' started by kanth0917, Sep 26, 2019.

  1. kanth0917

    kanth0917

    Joined:
    Sep 22, 2017
    Posts:
    11
    I'm using TextMeshPro (the 3d one in this case, not TextMeshPro UGUI) in my 2d game, and it often fails to update the text when I change it via script.
    When I change the text value and print it to console like
    Code (CSharp):
    1. Debug.Log(GetChild(0).GetComponent<TextMeshPro>().text)
    , it outputs the new text correctly, but both the game and the inspector show the old text.

    While writing this, I think I figured how this might happen. If I instantiate a prefab and change its child's textmeshpro component's text within that same frame, it grabs and edits the component's text with no problem, but any graphical change onto that component is not updated and lost. Maybe a script that re-renders the mesh is not being called on the same frame the text is changed?

    One way I found to avoid this is by starting a coroutine that waits one frame after the object is instantiated, and then changing the text. This certainly works while not being the best option.

    Is this a known bug that's fixed in any of the later Unity/TMPro versions?


    Unity version: 2019.1.14f1
     
  2. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    How are you changing the text of the text component? Are you using the .text property or SetText()?

    Can you provide a simple script that I can add to a text component to reproduce this behavior?

    BTW: The text should change on the same frame and before the frame is rendered. However, if you were to change the text in a coroutine with something like WaitForEndOfFrame then the change would only be reflected on the next frame since this processing would occur after the frame has already been rendered.
     
  3. kanth0917

    kanth0917

    Joined:
    Sep 22, 2017
    Posts:
    11
    I'm changing .text property instead of SetText().

    So I looked into it today and was able to reproduce only a part of the issue. I wasn't able to reproduce the disparity between the Getcomponent data and the inspector, but some odd execution order in Start() and function calls to the instantiated object. This might just be my misunderstanding in Unity's initialization pipeline, but here it goes.

    In a nutshell, setting the text of a prefab(with TMP component) right after instantiating it, gets overridden by the instantiated object's Start() function.

    Say, a Singleton GameObject TMPSpawner has a function:
    Code (CSharp):
    1. public class TMPSpawner : MonoBehaviour
    2. {
    3.     public static TMPSpawner instance;
    4.     public GameObject TMP_Prefab;
    5.  
    6.     private void Awake()
    7.     {
    8.         instance = this;    //singleton
    9.     }
    10.  
    11.     public void CreateAndChangeTMP()
    12.     {
    13.         GameObject objInstance = Instantiate(TMP_Prefab);
    14.         objInstance.GetComponent<TMPObject>().SetTMPText("new-text");
    15.     }
    16. }
    17.  
    And TMP_Prefab has script:
    Code (CSharp):
    1. public class TMPObject : MonoBehaviour
    2. {
    3.     public TextMeshPro tmpComponent;
    4.     void Start()
    5.     {
    6.         tmpComponent.text = "old-text";
    7.     }
    8.  
    9.     public void SetTMPText(string s)
    10.     {
    11.         tmpComponent.text = s;
    12.     }
    13. }
    14.  
    Calling TMPSpawner.instance.CreateAndChangeTMP() creates a TMP object with a text saying "old-text", instead of "new-text".
    Shouldn't Start() be called before the line after Instantiate() is called, not the other way around?

    Attached is a scene with some prefabs thrown in for demo.
     

    Attached Files: