Reparented node reference

Godot Version

4.4.7

Question

I have a reference to node declared as follows:

@onready var ball: Ball = $"Ball"

When I reparent this node at the runtime to other parent, the reference ball is no longer valid. How I can get the reference valid when moving between different parents? I’m a C++ programmer, and it seems strange for me — changing the parent node should just move the reference (pointer) to another space in the scene without changing it…

Your problem is not clear to me, what code are you using for this and what exactly do you want to happen?

Lat say, we have simple soccer game and class Ball representing the ball:

When the player kicks the ball, we call method Ball::fly(), which detaches the ball from player node and add it to stadium node:

class_name Ball extends RigidBody3D

func fly(impulse: Vector3) -> void:
...
	reparent(stadium)
...

When the player is near the ball, it is then attached back to him:

func attach_to_player(player: Player) -> void:
...
	reparent(player, false)
...

The problem is, that in other classes (e.g. Camera), where I have reference to the ball declared like this:

@onready var ball: Ball = $"Ball"

the reference ball is invalid, after reparent is called.

Now, I think if you use get_node the problem will be solved, if it doesn’t work please message again, I have an optimized solution which I prefer to be the last option as it requires a plugin

I just did a small test and my reference never gets lost after reparenting.
See below the video:


I am reparenting the “Ball” node a couple of times and the reference that I call in the “BallChecker” node works without a problem. If the reference got lost, the counter would start throwing “null instance” errors, but it counts without a problem.
Maybe you can also try to make an isolated test? In case your reference still gets lost, share your project through GitHub and we can check what’s going on.

Big thanks for your efforts! The sample that you provided works well for me too, but the difference is that I reparent node between scenes…

@Mahan thanks for the suggestion — unfortunately, the get_node solution gives the same results…

That shouldn’t make any difference. A scene is unpacked to just a tree of nodes during runtime anyway, so reparenting between Scenes is the same as reparenting between Nodes.
I think the problem is somewhere else, not the reparenting itself.
I suggest that you can maybe add print statements right before and after reparenting, something like that:

	print("----- before: " + str(ball))
	ball.reparent(other_parent)
	print("----- after: " + str(ball))

if both “before” and “after” lines print the same reference ID to Ball (which I believe it will), then you can rule out that the reparenting is the problem.

Are you sure the node that receives the reparented node is not being deleted after the reparent operation? Showing the code that handles the reparent operation and the code from the node that receives the new node can help.

1 Like

@wchc you are right, the references stay equal:

----- before: Ball:<RigidBody3D#38000395859>
----- after: Ball:<RigidBody3D#38000395859>

@matheusmdx I don’t delete anything, there is nothing fancy in the code

It seems that I must miss something…

If you don’t mind - you can share your project through GitHub and I can have a look at it.

@wchc Big thanks for your proposal, but this project is maintained by other company and I can’t share it in any way.

Oh, ok. Then you’re on your own with the debugging process then, sorry :slight_smile:
But if you have any other questions - let me know.

1 Like

Okay, sorry for the delay, I was very busy, this works if you only have one node of this class:

Install SLib on your project and execute this function after the ball is moved:

ball = SLib.find_child_of_class(parent_node: Node, "RigidBody3D", true)

NOTE: does not find class_name declarations!