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.connect("timeout", self, "_on_timer_timeout")
func _on_timer_timeout() -> void:
pass
Then in that method _on_timer_timeout
, you can call queue_free
:
timer.connect("timeout", self, "_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.
You may want to use the SceneTreeTimer
, like in the following code:
func die(delay: float):
yield(get_tree().create_timer(delay), "timeout")
queue_free()
Please refer to Godot Engine's documentation.
To build off of slay's answer...
In C# you can write
await ToSignal(GetTree().CreateTimer(1.5f), "timeout");`
QueueFree();
Incase you don't want to instance a timer, You can also use _process()
if you simply need a count down:
extends Node
signal timeout
var count_down=5
func _process(delta): # or you can use _physics_process()
count_down-=delta
if(count_down<=0):
emit_signal("timeout")
set_process(false)
Although this might have an error of ±delta
time
© 2022 - 2024 — McMap. All rights reserved.