Timers are incredibly useful mechanisms in games.
They can be used to create cooldown effects, delay methods from executing immediately, or simply show the player how much time has passed in a game.
So, how do you measure time in Godot?
Godot includes a built-in Timer Node that allows you to specify a wait time which, once it reaches zero, will fire a signal that can be used to trigger other events in the game.
Timer Nodes, however, only count down. This means that to measure time elapsed (such as for a stopwatch, for example) you’ll need to keep track of the amount of time that has passed by adding up the Delta Time every frame and storing it in a variable.
In this article, I’ll show you how to use both Godot’s built-in timer node and how to measure time using variables.
Let’s get started.
What you’ll find on this page
- Using the Timer Node in Godot (countdown timer)
- Delay a method using the timeout signal in Godot
- How to connect a signal via a script in Godot
- Create a one-shot timer in code
- How to begin a game with a 3, 2, 1 timer
- Use a timer to limit weapon fire in Godot (cooldown)
- How to create a timer without using the Timer Node
- How to create a stopwatch style timer (count up)
- How to display a time value in Godot in minutes and seconds
Using the Timer Node in Godot (countdown timer)
The Timer Node is ideal for quickly and easily adding a countdown timer to a scene.
If you select a timer node in the scene tree, you’ll see its properties in the inspector to the right.
- Process Mode: changes whether the timer is updated during idle time or the physics step.
- Wait Time: the duration of the timer in seconds.
- One Shot: if true, the timer repeats until it’s stopped. Otherwise, it will count down from the Wait Time to 0 only once.
- Autostart: whether the timer will begin counting down as soon as it enters the scene tree and is ready.
If you navigate to the Node tab, you’ll see the available signals the node has.
Signals are emitted when certain conditions are met. For example when a node is renamed, or when it enters the scene tree.
The timer-specific signal timeout() is emitted when time_left reaches 0.
You can connect this signal to methods in a script to run them when the timer depletes.
It’s important to note that methods connected in this way will only run if the signal passes the same amount of parameters.
This means that if you want to connect the timeout signal to another method, it must accept the same parameters as the timeout signal (which is none).
In the example above, you can tell that the signals don’t pass any parameters because there is nothing between the parentheses () of each signal.
How to delay a method using the timeout signal in Godot
The timeout signal can be used to delay methods in Godot.
Let’s see how this works with a simple scene. We’ll create a scene with a label that will alternate between shown and hidden every two seconds.
Go to Scene > New Scene. Click on 2D Scene. This will add a Node2D as the root of the scene. We use a Node2D because it has 2D transform properties such as position which allows us to move it (and its children) around.
I’m using a 2D Scene for these examples, but timers work in any scene and in any dimension.
Double-click the Node2D to rename it. I named mine TimerExampleA.
Add a label and a timer as children by clicking the plus button and searching for them.
Select the label and add some text in the Text property on the right.
As for the timer, set the Wait Time to 2, and enable Autostart. This will make it so the timer starts counting down from two seconds. I’m leaving One Shot unchecked because I want the timer to repeat so that I can see when the timeout signal is emitted.
The default label doesn’t have a built-in way to toggle its own visibility so I’m going to add this functionality to the label by attaching a script to it.
I renamed the label to CustomLabel and used the Attach Script button. You can always right-click a node to view these options too.
Adding a script will open up the script editor. For this example, I’ve created a simple method to toggle the visibility of the label:
extends Label func toggle_visibility() -> void: visible = not visible
Importantly, I’ve made sure that this method has no parameters so that the timer’s timeout signal can safely connect to it.
Click on the timer in the scene tree and navigate to the Node tab to display the timer’s signals. Double-click on the timeout signal to open the connection dialogue.
Keeping the default name of _on_Timer_timeout() creates a new method automatically with that name.
This naming convention is useful to keep track of what’s triggering the method but, for this example, I’m going to use the toggle_visibility method we just created.
Once connected in this way, there are a few UI elements that can help to keep track of signals within the editor.
First off, the timer has a new signal icon in the scene tree.
The signal also lists what Node and methods it’s connected to. You can disconnect signals here too.
Finally, you can click this icon in the script editor to see what signals are connected to the method.
If you press F6 to run the scene, you’ll see the label flash every two seconds.
How to connect the timeout signal via a script in Godot
Connecting signals in this way has its benefits. One of which is that we’re able to easily see what signals are connected to in the editor.
However, it’s also possible to connect and disconnect signals during run-time via scripts.
As a general rule, parent nodes look after their child nodes so I’m going to use TimerExampleA to manage signals between CustomLabel and Timer.
Here’s how to connect the timeout() signal to the CustomLabel:
extends Node2D # We cache the children should we need to access them again onready var timer := $Timer onready var label := $CustomLabel func _ready() -> void: timer.connect("timeout", label, "toggle_visibility")
The timeout signal is connected as soon as the TimerExampleA node has entered the scene tree and is ready, but you can connect or disconnect signals from anywhere in a script which makes this a powerful tool.
Create a one-shot timer in code ()
It’s also possible to create a one-shot timer on the fly. It begins counting down immediately and frees itself from memory after it emits its timeout signal.
# Creates a one-shot timer that lasts wait_time before emitting the timeout signal var scene_tree_timer := get_tree().create_timer(wait_time)
By combining it with the built-in yield function, we can delay parts of a method from executing.
For example, to delay the playback of a song until the timeout signal is emitted by the scene tree timer:
func play_song(delay_time: float) -> void: yield(get_tree().create_timer(delay_time), "timeout") # Play the song after delay_time # ...
Typically, this is used when you only need to fire a timer once and you won’t restart it.
Which is helpful, as it cuts out the need for creating a timer node that’ll be redundant after one use.
How to begin a game with a 3, 2, 1 countdown in Godot
Just like in the previous example, where I used a timer node to update a label, it’s possible to give timer nodes extra functionality by adding a script.
Such as using a timer node to count down to the start of a game.
Like before, I’ll be using the timeout signal except I’ll be using it to trigger a custom signal, counted_down, which passes a number along with it to keep track of a count variable.
The counted_down signal can then be used to update a label or to trigger some another function.
extends Timer signal counted_down(number) export var _count := 5
The export keyword allows me to change this in the inspector.
Connect the timeout signal to the _on_timeout() method in the ready step in the same way as before.
However, rather than connect to another object, this custom timer is connecting to itself.
func _ready() -> void: connect("timeout", self, "_on_timeout") func _on_timeout() -> void: emit_signal("counted_down", _count) _count -= 1 if _count < 0: stop()
This works because the timer is repeatedly measuring a second. Then when the timer reaches zero, it will emit the counted_down signal to pass along the current count and then reduce the count by 1.
The timer will then stop once the count reaches zero.
How to use a timer node to limit weapon fire in Godot (cooldown timer)
While timers are often used to measure and display time, they are also useful for implementing gameplay mechanics.
Such as for limiting input. For example, you may want to add a cooldown to a weapon or skill so that it can only be re-triggered after a specified delay.
Let’s say that you want to make a laser that can only fire a second time after cooling down for one second.
First, attach a timer as a child.
Next, make sure the timer is set to One Shot.
We can then use a script to limit input after the laser is fired.
# Laser.gd extends Node2D onready var timer := $Timer func _input(event : InputEvent) -> void: if not timer.is_stopped(): return if event is InputEventMouseButton: if event.button_index == BUTTON_LEFT and event.pressed: fire() func fire() -> void: timer.start() print("laser fired")
Every time the player clicks, the Laser fires and starts the timer.
When the _input() function is triggered, it checks to see if the timer is running (or, specifically, if it has not stopped) and, if it is still running, returns to prevent the laser from firing until the timer has stopped.
Using Animation Players as timers in Godot
It’s worth noting that you could also use an Animation Player instead of a timer to limit fire or an action. After all, an animation has a set duration as well which you can tweak in the editor.
extends Node2D onready var animation_player := $AnimationPlayer func _input(event : InputEvent) -> void: if animation_player.is_playing(): return if event is InputEventMouseButton: if event.button_index == BUTTON_LEFT and event.pressed: fire() func fire() -> void: animation_player.play("fire") print("laser fired")
This could be useful if you want to tie the gameplay to a specific animation. For example, if you want a sword to finish swinging before you can attack again.
How to create a timer in Godot without using the Timer Node
Timer nodes in Godot are great for many things, but they’re no use if you want to keep track of an unspecified amount of time.
For example, if you want to continuously count up, and measure how much time has elapsed, like a stopwatch.
For that, you’ll need to add up time as it passes every frame (using the delta value), storing it in a float variable.
How to create a stopwatch style timer in Godot (count up)
To create a stopwatch timer, create a new scene with a label and attach a script.
At its simplest, we just need to keep track of one thing: the elapsed time.
extends Label var time_elapsed := 0.0
To keep track of how much time has elapsed, add the amount of time that the last frame took (the delta value) to the time_elapsed variable every frame using the _process() method.
func _process(delta: float) -> void: time_elapsed += delta
The delta value allows you to calculate time independently of framerate. So if a frame takes longer to process, because of increased graphics or cpu load for example, the time value is still measured accurately.
This will give you a time value, in seconds, that you can then use in your game.
But how can you display the raw seconds value in a useful format?
Such as in minutes and seconds, for example?
How to display a time value in Godot in minutes and seconds
If you’re using timers to measure time elapsed or time remaining, you’ll likely want to show the time value in a format that the player is used to. Such as in minutes, seconds and, possibly, milliseconds too.
First, you’ll need to calculate the minutes, seconds and milliseconds individually.
For this to work, you’ll need a base time value, which needs to be in seconds.
To calculate the minutes, divide time by 60.
var minutes := time / 60
You might have noticed that this integer division returns a float instead of an integer. In this example, we don’t need to use an integer because we can chop off any decimal places when we insert the value into a string.
To get the seconds, you’ll need to get the remainder after dividing by 60 using the built-in fmod function. The fmod function is a modulo function that specifically works with floats.
var seconds := fmod(time, 60)
Modulo is a calculation that returns the remainder of a value after division by another. In this case, we’re using it to get the number of seconds that don’t make up a whole minute.
We’re using the fmod function specifically because we’re working with floats. If we were using integers, we’d use the percent symbol %, which is how modulo typically works, and how it works in other languages:
# Prints 40 print(100 % 60)
To get milliseconds, use the fmod function but, this time, with a divisor of 1. Just like when getting the seconds, this will return a remainder except, in this case, it will be the remaining amount that doesn’t make up a whole second. We’ll chop off any extra digits when we format the string.
var milliseconds := fmod(time, 1) * 100
Next, insert the minutes, seconds and millisecond time values into strings using format specifiers. We’ll use the decimal integral
d to insert the decimals we’ve calculated above. We also define the padding as
02 which will make sure the value has two characters. The
0 here makes any padding a “0”.
var time_string := "%02d:%02d:%02d" % [minutes, seconds, milliseconds]
In this example, I’m using the decimal integral d to insert the calculated time values. Defining the padding as 02 will make sure that each value has two digits. The 0 makes any padded value a zero.
Here’s what all of that looks like in a reusable method:
func _format_seconds(time : float, use_milliseconds : bool) -> String: var minutes := time / 60 var seconds := fmod(time, 60) if not use_milliseconds: return "%02d:%02d" % [minutes, seconds] var milliseconds := fmod(time, 1) * 100 return "%02d:%02d:%02d" % [minutes, seconds, milliseconds]
The method takes the time in seconds and returns a formatted string which can be displayed using a label node.
Note that I added a second boolean parameter called use_milliseconds, which can be used to switch between showing milliseconds or not.
The label’s text can be updated in the _process() method which is called every frame. The _delta parameter is the time in seconds between the current frame and the last frame and will vary depending on the framerate.
extends Label onready var countdown := $Timer func _process(_delta : float) -> void: text = _format_seconds(countdown.time_left, use_milliseconds)
Now it’s your turn
How are you using timers in your project?
Are you using the Timer Node, or are you making them via scripting?
Whatever it is let us know by leaving a comment.
Godot Engine Logo (edited for use on this site) by Andrea Calabró licensed under a Creative Commons Attribution 4.0 International License (CC-BY-4.0 International) https://creativecommons.org/licenses/by/4.0/.
Get Game Development Tips, Straight to Your inbox
Get helpful tips & tricks and master game development basics the easy way, with deep-dive tutorials and guides.
My favourite time-saving Unity assets
Rewired (the best input management system)
Rewired is an input management asset that extends Unity's default input system, the Input Manager, adding much needed improvements and support for modern devices. Put simply, it's much more advanced than the default Input Manager and more reliable than Unity's new Input System. When I tested both systems, I found Rewired to be surprisingly easy to use and fully featured, so I can understand why everyone loves it.
DOTween Pro (should be built into Unity)
An asset so useful, it should already be built into Unity. Except it's not. DOTween Pro is an animation and timing tool that allows you to animate anything in Unity. You can move, fade, scale, rotate without writing Coroutines or Lerp functions.
Easy Save (there's no reason not to use it)
Easy Save makes managing game saves and file serialization extremely easy in Unity. So much so that, for the time it would take to build a save system, vs the cost of buying Easy Save, I don't recommend making your own save system since Easy Save already exists.
Aren’t these centiseconds, that you are calculating?`
Other than that: Thank you! Great help!