Godot 3.1 – How to destroy object (Node)

Godot destroy object node logo

Destroying an object or node in Godot is quite easy. You can call queue_free() in the script that is attached to the node. Or you can call this method on any node reference. You can check if the node is still valid by calling is_instance_valid(node). In case you want to unload all nodes, or in short the entire scene you can easily get it by calling get_tree().get_current_scene() and removing it as child from the root node. If you want to remove a node with a delay you can choose to use timers that are linked to the “queue_free()” method.

How should I approach destroying objects in Godot?

When trying to destroy an object in Godot, you have to take into consideration that Godot works with nodes. Everything is a node in Godot. A scene is just a node that is placed at the top of the hierarchy, under the root node. The scene consists of multiple other nodes. There are several methods that allow you to destroy an object (node). Most of the operations mainly have to do with modifying the current node structure. In case you don’t understand how nodes can be obtained in Godot, then I recommend reading this article: How to obtain components (nodes) in Godot

How to remove a node directly

To free, destroy or remove a node you simply call this on the node:

queue_free()

This is the most standardized way of removing or “destroying objects” within Godot.
There is also free(), the main difference between them is that queue_free() gets called the next frame. Which generally is a safer. Mainly because there may be residing dependencies with the code that still gets executed by child nodes.

You can check if a node is already freed by calling the following code:

is_instance_valid(node)

In case you are interested in clearing all the children of a node. You can do so by calling:

for child in node.get_children():
	child.queue_free()

What is the difference between queue_free() and call_deferred(“free”)?

call_deferred(“free”) is a safe way to call free(), call_deferred(“method”) ensures the method gets called when the next idle frame happens on the main thread. Or in other words, it pushes a message and it’s parameters into a queue that gets de-queued in the main thread.

Calling call_deferred(“free”) is useful if the node you want to free a node that is currently locked.
If the node is locked and you call queue_free() you get this error: “Attempted to free a locked object (calling or emitting)”. Using call_deferred(“free”) will ensure the node gets destroyed, even if it is locked.

Destroying a node after a set time or delay

Sometimes when you have projectiles such as bullets in your game, you may want to display some kind of impact animation by scaling the button up. In this case it may be useful to start destroying the object node after a certain amount of time. It is useful to keep in mind that projectiles may still have collision after impact, so it is important to turn off all required logic after impact.

Methodology using a timer. As you can see in the code, a new timer instance gets created and added as a child to the node. Afterwards it gets bound to the “queue_free” method with a time set to 2 seconds.

# Add a timer to this node
var timer = Timer.new()
self.add_child(timer)
	
# Connect the timer to make it call "queue_free" after two seconds
timer.connect("timeout", self, "queue_free")
timer.set_wait_time(2)
timer.start()

Another methodology is to delay the current code execution of a method using yield.
Keep in mind that all the code after the yield is affected by the delay. So use with care.

yield(get_tree().create_timer(2.0), "timeout")
queue_free()

Destroying an entire scene?

All scenes are a child of the root node. So in order to remove a loaded scene you have to call this:

var root = get_tree().get_root()

# Remove the current level
var level = get_tree().get_current_scene()
root.remove_child(level)
level.call_deferred("free")

# Loading a new level
var other_level_resource = load("res://path/to/scene.tscn)
var other_level = new_level_resource.instance()
root.add_child(other_level)

However, there is also a method to just switch scenes. Which is a lot easier.

get_tree().change_scene("res://path/to/scene.tscn")

How performance intensive is it to remove nodes?

Godot does not work like Unity, there is no garbage allocation for objects and allocating and freeing scenes and classes is generally fast in Godot. Meaning that it isn’t necessary to pool objects. This means you don’t have to worry as much when freeing and allocating nodes.

Below is a post by the main developer of the Godot Engine.

Copyright © 2024 Godot Learn