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:
TextMeshPro textMesh = gameObject.AddComponent<TextMeshPro>();
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.
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.
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:
GameObject myNewObject = new GameObject();
myNewObject.transform.localPosition = gameObject.transform.localPosition;
myNewObject.transform.localScale = gameObject.transform.localScale;
myNewObject.transform.parent = gameObject.transform;
TextMeshPro textMesh = myNewObject.AddComponent<TextMeshPro>();
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?
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).
GameObject myNewObject = new GameObject();
myNewObject.transform.parent = transform;
myNewObject.transform.localPosition = Vector3.zero;
myNewObject.transform.localScale = Vector3.one;
TextMeshPro textMesh = myNewObject.AddComponent<TextMeshPro>();
Let me know if any of this is unclear!
1 Like
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.
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.
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.
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!
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.