How do I create a timer in Godot which destroys the script's object after a given amount of time? I am looking to remove bullets from a game after a while to reduce lag.
There is a Timer node that you can use. You can add it as a child, set the wait time (in seconds) - you could set it as one shot, and auto start - connect the "timeout" signal to your script, and on the method call queue_free to have the Node (and children, which includes the Timer) freed safely.
You can do that from code too, if that is what you prefer. So, let us go over what I just said, but instead of doing it from the editor, let us see the equivalent code:
Create a Timer, add it as a child:
var timer := Timer.new()
add_child(timer)
Set the wait time (in seconds):
timer.wait_time = 1.0
Set as oneshot:
timer.one_shot = true
Instead of setting it to auto start (which would be timer.autostart = true), let us start it:
timer.start()
Connect the "timeout" signal to a method. In this case, I'll call the method "_on_timer_timeout":
timer.timeout.connect(_on_timer_timeout)
func _on_timer_timeout() -> void:
pass
Note: it is also possible to the signal by name
timer.connect("timeout", _on_timer_timeout)
func _on_timer_timeout() -> void:
pass
See also:
Then in that method _on_timer_timeout, you can call queue_free:
timer.timeout.connect(_on_timer_timeout)
func _on_timer_timeout() -> void:
queue_free()
Edit: I stand corrected, the best approach is to use a callback like Theraot's answer says:
func _on_timer_timeout_funcname() -> void:
# Do stuff here...
queue_free() # removes this node from scene
var timer := Timer.new()
timer.wait_time = 1.0 # 1 second
timer.one_shot = true # don't loop, run once
timer.autostart = true # start timer when added to a scene
timer.connect("timeout", self, "_on_timer_timeout_funcname")
return add_child(timer)
I'm leaving my answer below here for people who are more comfortable with a sequential approach, but it can be a bit more tricky to deal with.
In Godot 4, there's an easy way to do this:
# Do some action
await get_tree().create_timer(1.0).timeout # waits for 1 second
# Do something afterwards
queue_free() # Deletes this node (self) at the end of the frame
Important: if you do this in the _process() or _physics_process() functions, more timers get created every frame, which causes several runs to occur all at once before then running the following code. To handle this, simply track whether a timed event is happening.
Example in the _process() with simple attack logic:
var attack_started = false;
func _process(delta):
if attack_started:
print("Not attacking, attack code running in background")
return
else:
attack_started = true
prepare_attack()
await get_tree().create_timer(1.0).timeout # wait for 1 second
begin_attack()
attack_started = false
This await keyword works with everything that emits signals, including collision events!
FYI: yield was replaced with await in Godot 4, and await really just waits for a signal/callback to complete:
await object.signal
get_tree().create_timer(5.0) will create a timer that runs for 5 seconds, and then has a timeout callback/signal you can tap into.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With