Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

set_as_toplevel() affects child nodes as well #24154

Closed
ageofabenius opened this issue Dec 4, 2018 · 9 comments
Closed

set_as_toplevel() affects child nodes as well #24154

ageofabenius opened this issue Dec 4, 2018 · 9 comments

Comments

@ageofabenius
Copy link

ageofabenius commented Dec 4, 2018

Godot version: 3.0

Issue description:

In a chain of nodes, if one node1 is disconnected from its parents' transform via node1.set_as_toplevel(true), then node2 becomes disconnected from node1's transform as well. node1.set_as_toplevel() should disconnect node1 from its parent's transform, yet preserve node1's children's connections to its transform.

Steps to reproduce:
In the following tree of nodes:

node1
. node2 # has been set_as_toplevel(true)
.. node3
... node4 # has been set_as_toplevel(true)
.... node5

If node1 is moved, node2 remains stationary, this is as expected.
If node2 is moved, node3 and its children remain stationary, this is not as expected, node3 should move with node2.
If node3 is moved, node4 remains stationary, this is as expected.
If node4 is moved, node5 remains stationary, this is not as expected, node5 should move with node4.

@KoBeWi
Copy link
Member

KoBeWi commented Jun 29, 2020

I can't reproduce this (even in 3.0).

@ageofabenius Can you provide some minimal project? Also test this in 3.2.2.

@akien-mga
Copy link
Member

Closing due to lack of update. Please comment if you can still reproduce this issue in the latest stable version of Godot.

@elvisish
Copy link

elvisish commented Mar 23, 2022

This is still an issue:

for c in get_children():
	c.set_as_toplevel(true)
rotation_degrees = Vector3(0,properties["rotation"],0)
for c in get_children():
	c.set_as_toplevel(false)

Children will be rotated.

@akien-mga
Copy link
Member

@elvisish That's not a bug, it works as intended.

You set the children back to toplevel = false after setting their parent's rotation, and naturally they will start taking into account the parent rotation again.

Toplevel means that the node ignores its parent transform. If it's not toplevel, it will not ignore its parent transform.

@elvisish
Copy link

@elvisish That's not a bug, it works as intended.

You set the children back to toplevel = false after setting their parent's rotation, and naturally they will start taking into account the parent rotation again.

Toplevel means that the node ignores its parent transform. If it's not toplevel, it will not ignore its parent transform.

The rotation is only happening at that one part when I set the rotation when the child are not toplevel, they should not rotate at all if the only rotation to the parent is happening when they are not set as toplevel?

@akien-mga
Copy link
Member

akien-mga commented Mar 23, 2022

You misunderstand how rotation works in Godot. It's not a discrete operation that sets the rotation only for the non top-level node.
It sets the local transform of the node. When the children are set to non top-level again, their local transform hasn't been changed, but their global transform (what you see on screen) is calculated via the local transforms of its parents.

It's the same for all transform components, position, rotation and scale.

If you move the root node to position (200, 0), and its child nodes have position (0, 0), they will all be at the global (scene) position (200, 0). If you make the child nodes top-level, they will move to position (0, 0) as their local transform is now used as global transform, bypassing the parent transform. If you then move the root node to (300, 0), and disable top-level on the child nodes, they will snap back to their parent since their local position relative to the parent is still (0, 0).

You cannot work things around by setting top-level temporarily, that doesn't do anything. Top-level defines whether the parent transform is respected each time there's a transform update (i.e. each frame). If you disable it, then the parent transform will be respected again.

If you want to rotate a node without rotating its children, you should offset the children rotation in the opposite direction:

rotation_degrees = Vector3(0,properties["rotation"],0)
for c in get_children():
c.rotation_degrees -= rotation_degrees

@elvisish
Copy link

You misunderstand how rotation works in Godot. It's not a discrete operation that sets the rotation only for the non top-level node. It sets the local transform of the node. When the children are set to non top-level again, their local transform hasn't been changed, but their global transform (what you see on screen) is calculated via the local transforms of its parents.

It's the same for all transform components, position, rotation and scale.

If you move the root node to position (200, 0), and its child nodes have position (0, 0), they will all be at the global (scene) position (200, 0). If you make the child nodes toplevel, they will move to position (0, 0) as their local transform is now used as global transform, bypassing the parent transform.

You cannot work things around by setting top-level temporarily, that doesn't do anything. Top-level defines whether the parent transform is respected each time there's a transform update (i.e. each frame). If you disable it, then the parent transform will be respected again.

Strangely enough, I did this toplevel trick with local positioning of the parent spatial and it did work, when the children's toplevel was turned off, they were still in the same position they were globally before i moved the parent spatial. Does it work differently for rotation?

@akien-mga
Copy link
Member

Can you provide a reproduction project? I tested in 2D and both for position and rotation it works exactly as I describe.

@elvisish
Copy link

elvisish commented Mar 23, 2022

Can you provide a reproduction project? I tested in 2D and both for position and rotation it works exactly as I describe.

I'll try to make one later once I've isolated the parts from this large project, but the code was:

mesh.set_as_toplevel(true)
col.set_as_toplevel(true)
set_translation(get_translation() + dir * x_y_z * hinge_dir)
mesh.set_as_toplevel(false)
col.set_as_toplevel(false)

I assumed it would work (and did) since I just thought set_as_toplevel(false) would make it respect the parent's transform at the time of setting set_as_toplevel(false).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants