4
\$\begingroup\$

I suspect there is a well-known and easy to explain reason for the behavior I'm seeing, but I am having difficulty explaining it (and likely not able to Google for the answer).

When adding a child GameObject to a translated parent, the child's localPosition is modified so that the child's position stays the same after the parent's transformation is applied. Is there a way to not have this be the case?

In the following example, I create a parent object and move it to (1,1,1), and then attach the child. I would like the child's position to be (1,1,1), that is (0,0,0) relative to the parent. However, the child's position is modified to be (-1,-1,-1) so that it is (0,0,0) relative to the world.

Here is a repro:

// Create parent.
GameObject parent = new GameObject();
parent.name = "Parent GameObject";
parent.transform.parent = foregroundObject.transform;

// Move the parent.
parent.transform.Translate(1, 1, 1);

// Add a child under the parent GameObject.
GameObject child = (GameObject) GameObject.Instantiate(guildiePrefab);
child.name = "Child GameObject";

child.transform.parent = parent.transform;

// PROBLEM: localPosition is set so that the "global" position is (0,0,0).
// How can I add the child object and have its position be (1,1,1)?
this.Assert(child.transform.localPosition.ToString() == "(-1.0, -1.0, -1.0)");
this.Assert(child.transform.position.ToString() == "(0.0, 0.0, 0.0)");

Is there a different way I should be adding child as a child of parent? Or, should I always zero-out the position of parent before adding a child? If that is the case, any reason why I need to do this? What is the rational for this design choice?

\$\endgroup\$
4
\$\begingroup\$

When you instantiate using the default constructor for Instantiate, the position is set to (0,0,0). You can use the alternative constructor for Instantiate, and supply a position and rotation. If you want the child object to be position at zero relative to the parent, you can supply the parent position as the position to instantiate to.

GameObject child = 
   (GameObject) GameObject.Instantiate(guildiePrefab,
                                       parent.transform.position,
                                       parent.transform.rotation);
child.name = "Child GameObject";

child.transform.parent = parent.transform;

Or if you have a specific offset you're interested in simply add it to the position when you instantiate:

GameObject child = 
   (GameObject) GameObject.Instantiate(guildiePrefab,
                                       parent.transform.position + offset,
                                       parent.transform.rotation);

Either way, the child's position shown in the Inspector tab will be the child's position relative to the parent. The child's position found through transform.position will be the world position.

\$\endgroup\$
3
\$\begingroup\$

There is a different way.

Instead of:

child.transform.parent = parent.transform;

Use:

child.transform.SetParent(parent.transform, false)

The false argument specifies to not perform the relative adjustment you are talking about.

I'm guessing the reason it doesn't do this by default is because the code is most typically called from the editor, in which case you probably don't want the object you are assigning to a new parent to suddenly relocate when you drop it on the parent.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.