How do I remove a node and all its descendants from the scene tree?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By thoth

I have identified a node using a raycast. I would like to remove that node from the scene tree. If I use

func _physics_process(_delta):
	#...
	remove_child(nodec)
	nodec.queue_free()

The StaticBody that is nodec seems to be gone (raycasts no longer hit it), but the MeshInstance that was its child is still visible?

(Edit) The result of get_children().size() appears to be holding steady at 262 no matter how many I delete. Are the results from the get_world().direct_space_state.intersect_ray(...) in a different tree than my scene nodes?

(Edit) In case it helps, here is the code that constructs the nodes I am trying to delete

func make_bar(x,z, y_size, radius):
	var bar1 = MeshInstance.new()
	var mesh = CubeMesh.new()
	mesh.surface_set_material(0, material)
	bar1.mesh = mesh
	bar1.translation = Vector3(x, y_size,z)
	bar1.scale = Vector3(radius, y_size, radius)

	var n
	if true:
		var body = StaticBody.new()
		body.add_child(bar1)
		body.add_child(CollisionShape.new())
		bar1.create_convex_collision()
		n=body
	else:
		n=bar1
	
	bars.push_back(n)
	add_child(n)
	return n

What is the correct procedure to remove the node and all its descendants from existence?

Just calling queue_free() should remove both the targeted node and all of its children from the scene tree. Are you sure that’s not the case?

See the 3.2 docs here (though, that’s a really old version of Godot).

Node — Godot Engine (3.2) documentation in English

jgodfrey | 2023-01-24 14:52

Just a thought - how and when are you checking for the existence of the node(s) you’ve deleted? If you’re checking immediately after calling queue_free(), the deletion may not have happened yet (it is queued after all). So, it could take a number of frames depending on the situation…

jgodfrey | 2023-01-24 15:22

I am checking using my eyeballs. The mesh “cubes” are not disappearing. I will update the question with the code that constructs the nodes.

thoth | 2023-01-24 15:33

Are you sure nodec is the staticbody?

SteveSmith | 2023-01-24 15:41

Also, is this a custom build of Godot?

SteveSmith | 2023-01-24 15:42

When I stuff nodec.get_type() into the text of a label as part of a debug message, it reports StaticBody.
This build of Godot is installed from the Ubuntu 20 LTS app “store” . Its About dialog identifies it as v3.2.stable.custom_build .

thoth | 2023-01-24 15:52

1 Like
:bust_in_silhouette: Reply From: Gluon

Can you try this?

nodec.call_deferred("queue_free")
:bust_in_silhouette: Reply From: thoth

It turns out that my creation code ended up creating two StaticBodys. The parent body was not being returned by the intersect_ray() call. What was being returned was the StaticBody child of bar1 created by bar1.create_convex_collision().

I have altered my creation code to look like

func make_bar(x,z, y_size, radius):
	var bar1 = MeshInstance.new()
	var mesh = CubeMesh.new()
	mesh.surface_set_material(0, material)
	bar1.mesh = mesh
	bar1.translation = Vector3(x, y_size,z)
	bar1.scale = Vector3(radius, y_size, radius)

	bar1.create_convex_collision()
	bar1.name = "bar %d"% bars.size()
	var body1:StaticBody = bar1.get_child(0)
	print("new bar [%d] %s"%[bar1.get_child_count(),body1.get_class()])
	body1.collision_layer = 0x2
	var n=bar1

	bars.push_back(n)
	add_child(n)
	return n

So I have eliminated the wrapper StaticBody, and the CollisionShape because create_convex_collision() creates the necessary stuff for me.

When it comes time to delete I use nodec.get_parent() to get the MeshInstance and deleting that removes the mesh from the scene.

I suspect my confusion stemmed from the difference in node layout between the Create Convex Collision Sibling UI operation and the results documented for create_convex_collision().

Glad you figured it out. And, while I’m not familiar with the details here, the (3.2) docs do state this:

void create_convex_collision ( )

This helper creates a StaticBody child node with a ConvexPolygonShape collision shape calculated from the mesh geometry. It's mainly used for testing.

…which seems to be roughly the structure you describe above. That said, doc improvements are always a good thing…

jgodfrey | 2023-01-25 03:19

You are correct, jgodfrey, as is the documentation. Perhaps my confusion came from https://forum.godotengine.org/45050/how-to-set-a-mesh-as-a-collision-shape which shows a different node layout for creating collision nodes via the UI.

I also wonder if there is a better alternative to create_convex_collision when you are not testing, but instead are dynamically creating physics objects.

thoth | 2023-01-25 14:34