Need help with math (or coding) for transform manipulation of a grand child

Hi all,

this might be a beginner question for most of you, but after a whole afternoon of googling, reading and trial & error I’m out of ideas. I am fighting with Unity transforms, and at least for a beginner like me, it’s a night mare since the objects all have “relative” coordinates instead of fixed ones (and most likely, I maybe didn’t set up everything correctly). Please take a look at the enclosed image.

I have a Grandchild (child of a child) object, named “MainMenuButtons”, it’s a empty gameobject that I used to group together some buttons. This group of buttons is animated, and when the scene first loads, I need to play the “load animation” (they start in the position of the “Spawner_MainMenuButtons” and then grow to the virtual screen that is seen in my canvas… but for a smooth animation, I need them to go in their invisible and microscaled start position (the spawners position). I could totally avoid all this trouble if I just simply set the initial transform that way in the scene view, but I need these things visible in the scene view to work with them (at least for now), so I have to have them stay in normal size.

So, I want to use the script to move them in their hide position by changing their transform position and scale.
The logs show, my code actually works, but the math is wrong, I think it’s calculating everything in world coordinates, and not the “local of the local of the worldspace” if you know what I mean.

Can someone please help me out here ? I goggled a lot and found, that there is something called “localPosition” for the child, but it’s not working either.

In the Image you can see the canvas at 0,0,0, the Spawner_MainMenuButtons on it’s own Transform, and then the MainMenuButtons (which has only a normal transform, and no Rect Transform for whatever reason).

I need to move the MainMenuButtons-Object to the LOCAL coordinates that are displayed in the lower right (z-values can remain unchanged). The logs show, the code is being executed , but it uses a wrong coordinate system.

The code in question is this method:

In Start, I use :

Transform mainMenuBlock = transform.Find("MainMenuButtons");

and later the method:

    void HideMainMenu()
    {
    Debug.Log("I'm inside the Hide Method");
    Debug.Log(mainMenuBlock.transform.position);
    mainMenuBlock.transform.localPosition = new Vector3(20f, -70f, transform.position.z);
    mainMenuBlock.transform.localScale = new Vector3(0.01f, 0.05f, transform.localScale.z);
    Debug.Log("New:" + mainMenuBlock.transform.position);

Thank you in advance for helping me out here.
(P.S. Ignore the red errors, it’s just a missing singleton since I didn’t started in the correct scene)

You appear to be mixing Transform and RectTransform objects in a hierarchy. Pretty sure there IS a way to get that to work, but when you are dealing with UI, you want to use only RectTransform objects in that hierarchy.

RectTransform objects operate in the numeric context of the Canvas RectTransform under which they all live. This could be various coordinate systems based on the “Render Mode” setting field in that root Canvas object.

If you are trying to calculate and drive meaningful values in code for sub-objects, you will need to know the values in the RectTransform of the Canvas as well, as they are implicitly relative.

I’d recommend starting with a single Image GameObject under a Canvas, then take references to the RectTransforms in each and do some Debug.Log() printing to see what their values and relationships are. It’s pretty straightforward but there are some surprises in terms of what fields mean what, anchors, pivots, positions, sizes, etc.

Luckily the entire Unity UI codebase is open source on Bitbucket for your ultimate reference (Google) in case you get stuck on how something is calculated.

Honestly, I don’t even understand why there is Rect Transform and Transform mixed. Maybe because some elements are UI stuff, and others are empty game objects ? I try rebuilding it tomorrow, but quick first try didn’t gave me the hint about that, it seems to do that automatically. I’m pretty sure though that the UI codebase will be far beyond my expertise, I’m just at the beginning of learning C# :slight_smile:

Welcome! Unity is one of the funnest places to learn programming. Stick with it and it will come to you. Make small incremental changes from known working stuff until you understand each step of the way. Hop right in, the water’s fine!

The Unity editor sorta tries to help you there: if you create a blank game object under a Canvas, it will contain a RectTransform. If you create it NOT under a Canvas, it will contain a Transform.

If you want to create a GameObject in code and yet have it contain a RectTransform, use the form of GameObject constructor that takes the type arguments:

It’s something like so:

 GameObject foo = new GameObject( "MyFoo", typeof( RectTransform));

Then you can use foo.transform.SetParent() to parent it wherever you want (under the Canvas hierarchy), and then move it around in Canvas space, etc.

Thank you for that, I also noticed yesterday at last, that when I use “create empty child” it did make a rect transform, but I had canvas selected… However, a quick try turned out with the absolutly same problem, I cannot modify it’s transform coordinates. I will rebuild the interface now clean, but I believe the issue is somewhere else. Currently I have the “interface controller” on the spawner, maybe if I make an additional script and put it directly on the buttons objects, then the “transform.localPosition” works different.

Made some test, the reason must be the canvas. As long as I’m a child of the canvas, I am unable to manipulate the transform of the ChildObject. Even If I put the script direct on the low level group object, and then try to retrieve it’s transform, I’m now getting 0,0,0 as a transform value (which is true for Canvas AND my test object) back, which seems to be ok for world coordinates.

No matter how often I redo or reset it, the coordinates in the editor always show up like in my image above. But now, when I try to change the position , even if starting by 0,0,0, the code returns me even a changed transform, __but the object has not moved at al__l. Using localPosition or just position has also no different effect.

Now the fun part :

It works as supposed when I put the object in the main level, it even works great when it place the object as a child of a new gameobject, as long as it is not beneath the canvas, everything works.

Is it possible that this could be a bug ? I’m using Unity 2017.31f1

Sorry for spamming around here, but we all know that fighting through errors is the best way to learn anything, and I learned quite something since yesterday… I was now playing around, changed my code too and I’m now specifically searching for the child first, and changed the object to RectTransform. Also, I set the Canvas to Worldspace, before I had it “screenspace camera”…

I’m nearly there, I am now able to retrieve the correct transform values of the child as they are being displayed in the inspector :

However, as you can see here, even though it says it’s changed the transform in the blue line, the object itself wasn’t taking effect (again)…So, editing the GrandChild is still making trouble… however, my original code now allows me to modify the transform value of the canvas child itself (it’s what I call “Spawner-MainMenuButtons”)… , that works due to the change to the canvas rendermode.

Now, final question : Is there a specific command if I want to change children transforms ?

It still looks like this :

(Start)

Transform transformChild = transform.Find("MainMenuButtons");

HideMainMenu();

(below Start)

    void HideMainMenu()
    {
    Debug.Log("I'm inside the Hide Method");
    Debug.Log(transformChild.localPosition +" " + transformChild.localScale);
    transformChild.localPosition = new Vector3(20f, -70f, transform.position.z);
    transformChild.localScale = new Vector3(0.01f, 0.05f, transform.localScale.z);
    Debug.Log("New:" + transformChild.localPosition +" " + transformChild.localScale);
    mainMenuLoaded = false;
    }