Search Unity

Resolved Move text independent from object

Discussion in 'UGUI & TextMesh Pro' started by ARunitystudi, Jun 21, 2021.

  1. ARunitystudi

    ARunitystudi

    Joined:
    Apr 25, 2021
    Posts:
    21
    Hello everybody, I need to add a textMesh in front of each gameObject in my scene. My scene consists of hundreds of gameObjects. Therefore, I have to do it with a script. I am currently using TextMeshPro and I am adding my text with the following code, which is inspired by the TextMeshPro examples:

    Code (CSharp):
    1. TextMeshPro textMesh = gameObject.AddComponent<TextMeshPro>();
    2. textMesh.transform.localPosition = gameObject.transform.localPosition + Vector3(1.0f, 1.0f, 15.0f);
    My problem is, that not only the textMesh moves to the new position, but also the gameObject moves with it to that position. I want the gameObject to stay where it is, and only its textMesh to move a bit to the front. Any ideas to achieve this are very appreciated.
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    In that case you need to create a new GameObject, and call AddComponent on that, rather than on the gameObject the code above is attached to.

    You can set its parent to transform.parent, if you want it to be at the same level of the scene hierarchy as this gameObject; or you might try setting its parent to transform, which makes it a child of this gameObject.
     
  3. ARunitystudi

    ARunitystudi

    Joined:
    Apr 25, 2021
    Posts:
    21
    Thank you! I tried to do it this way, but my text is displayed in a wrong position and size. Also, the text does not adapt to a change, when my gameObject is moved or scaled. I thought that this was the purpose of setting the parent.

    I used the following code:
    Code (CSharp):
    1. GameObject myNewObject = new GameObject();
    2. myNewObject.transform.localPosition = gameObject.transform.localPosition;
    3. myNewObject.transform.localScale = gameObject.transform.localScale;
    4. myNewObject.transform.parent = gameObject.transform;
    5.  
    6. TextMeshPro textMesh = myNewObject.AddComponent<TextMeshPro>();
    7. textMesh.transform.localPosition = myNewObject.transform.localPosition;
    In my understanding, the position and scale of the text should now be the same as the position and scale of the gameObject (as it also was before without the offset), but this is not the case. When I print the values, then the positions match, but myNewObject and textMesh have both a scale factor of 1000 instead of just 1 as the gameObject. When I remove line 3 of the code posted, nothing changes. What am I doing wrong?
     
    Last edited: Jun 22, 2021
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    You're setting the local position/scale of myNewObject before setting the parent. Until line 4, your new object is at the root level of the scene hierarchy, so its local position/scale are the same as world position/scale. But gameObject's local position and scale may be different — they would be relative to whatever container that gameObject is in.

    The cleaner (and more likely correct) way to do it is to set the parent before setting the local position and scale, and then set those to position 0,0,0 and scale 1 (remember, these are relative to the parent). Also, remember that textMesh here was created on myNewObject. So textMesh.transform is literally the very same thing as myNewObject.transform; line 7 above does nothing. Similarly, gameObject.transform is the same thing as just transform (since this code is running on the object that gameObject refers to).

    Code (CSharp):
    1. GameObject myNewObject = new GameObject();
    2. myNewObject.transform.parent = transform;
    3. myNewObject.transform.localPosition = Vector3.zero;
    4. myNewObject.transform.localScale = Vector3.one;
    5.  
    6. TextMeshPro textMesh = myNewObject.AddComponent<TextMeshPro>();
    Let me know if any of this is unclear!
     
    ARunitystudi likes this.
  5. ARunitystudi

    ARunitystudi

    Joined:
    Apr 25, 2021
    Posts:
    21
    Many thanks, now things are much clearer. The scale of the text is now correct, but the position unfortunately not. The text is widely shifted at least towards the -x and the y axis (originally it was not, without creating a new gameObject). So, I created a sphere the same way to get sure that the position used is correct. The sphere is displayed at the correct place, but the text is not.
    I used for both the same code you posted (for the sphere I skipped line 6), with just a small difference in line 2, where I used "gameObject.transform" instead of just "transform", as I else get the error "The name 'transform' does not exist in the current context". I think that this is the case since my script is not directly attached to a gameObject, so it is not clear on which ones it should be applied. But in my opinion, and also with your explanation I think this change should not make a difference.

    So, how can I correct the position of the text?

    Edit: Very interesting. When I add line 6 to the sphere object created, the text is placed correctly, but it is not the case, with myNewObject.
     
    Last edited: Jun 22, 2021
  6. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    That's odd. I'm curious about this script — it's not a MonoBehavior? But it has a gameObject property?

    As for the position, I think at this point you need to run the app, cause this code to do its thing, and then pause the game and inspect the situation using the Scene view and the Inspector panel. Make sure your text object really is at 0,0,0 (the positions shown in the Inspector are always the local position, not the world position). Switch the scene view to the Rect tool, and you should be able to see the bounds of the text object. Perhaps its bounds are bigger than it needs to be, and the alignment is set to Left or something, causing the visible words to be not centered on the intended position.
     
  7. ARunitystudi

    ARunitystudi

    Joined:
    Apr 25, 2021
    Posts:
    21
    The main script is a MonoBehavior and there I instantiate all gameObjects in my scene. Then, I go through all of them and call this affected method for every gameObject. The method gets a gameObject as an input and sets the text for this object. It is in a different class, which is not a MonoBehaviour.
    I just tested, what would happen if I make it a MonoBehavior. Then, one of the gameObjects is selected and shown in the middle of the scene, which is not really what I want.

    Thanks for your help. For the position, I had before just used the sphere, as I noticed that the sphere is not rendered anymore as soon as I attach a textMeshPro-component to it. Now, I just changed the first line again to create a new gameObject instead of a sphere, and nothing seems to have changed. So, my text is now rendered in the correct position, even with an empty gameObject, but I cannot say what was the reason that it has not worked before.
    The position is for all objects just zero, and the localPosition has in most of the cases different values. So, I am also wondering what the gameObject.transform.position property is good for. I have seen that it is used for the global position, but if I change it to something else, nothing changes in my scene. When I print its values after I change it, they also remain being zero.
     
  8. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    That's not true (at least, in general). Assigning a new value to transform.position really does move the object so that its global position is the new value. I have never seen this fail, and I don't believe it can fail — though of course, something else in your code could immediately change it back.

    Make a simple project that tests just this, and you will see that it works. It sounds like your "real" project has gotten rather complex, and you no longer understand everything it does. Like the Marine Corps motto: Simplify!
     
  9. ARunitystudi

    ARunitystudi

    Joined:
    Apr 25, 2021
    Posts:
    21
    Thank you, it is very helpful to know that it should work in general. With primitive objects from Unity is really does.
    I am using my own models and had also faced the problem in the beginning in getting their correct positions in Unity. So, maybe it was not the most convenient way to read the values from outside and set only their local positions in Unity. I will see if I can find a way to get their real global positions.