In Godot, a signal is a message that an object emits when something occurs to it. It's a core concept in Godot. Many nodes emit signals when something happens to them.Here are some examples:
When pressing a button, the button emits the pressed signal.
When a physics body (like a playable character) enters an Area2D or Area3D node, the area emits the body_entered signal.
When making a node visible or invisible, the node emits the visibility_changed signal.
When a Timer node times out, it emits the timeout signal.
We can connect a signal to any compatible function. Once connected, when the signal emits, the engine immediately calls the connected function.Here is an example with a healing status effect that restores some health periodically. It's like the regen spell in Final Fantasy games. We use a Timer node that cycles and emits the timeout signal every second. We connect the signal to a function that restores some health to the character each time the signal emits.
var health :=10var max_health :=100var timer := Timer.new()func_ready()->void:add_child(timer) timer.timeout.connect(regen) timer.start()funcregen()->void: health +=5if health > max_health: health = max_health
Let's break down the code:
We declare two variables, health and max_health, which store the character's current and maximum health, respectively.
We create a Timer node and store it in the timer variable. Storing it in a variable is optional, but it allows us to access and stop the timer later if we need to.
In the _ready() function, we add the timer as a child of the current node, which is necessary to use it. We connect the timeout signal to the regen() function and start the timer.
The timer node cycles by default and emits the timeout signal every second. Each time a cycle ends, the timeout signal emits, and Godot calls the connected regen() function. So, the character restores some health every second.That's one example of how to use signals. They are a powerful feature that allows us to create complex interactions between objects in our game.Note that you can disconnect a signal at any time using the signal's disconnect()method. For example, to disconnect the timeout signal from the regen() function, you would write timer.timeout.disconnect(regen).
There's a common programming pattern called the observer pattern. It's a way to notify objects when something happens to another object. The pattern is widely used in software development: it's built into the JavaScript programming language as events, it's called signals and slots in the popular user interface framework Qt, and it's generally present in many technologies. Signals are Godot's implementation of this popular pattern.
Naming convention for signals
We usually name signals using the past tense. For example, died, pressed, body_entered, etc. This convention helps communicate that the signal is emitted when something just happened to the object.Often, we need to create a function only to respond to a signal. We name these functions using the _on_<node_name>_<signal_name> convention. For example, if we connect the pressed signal of a Button node to a function, we name the function _on_button_pressed. This convention helps communicate that this function only exists to respond to the signal.
extendsButtonfunc_ready()->void: pressed.connect(_on_button_pressed)func_on_button_pressed():print("Button was pressed!")
Of course, you can connect signals to any function you want. If an existing function already does what you need, you can connect the signal to it. Here's an example where we free the button when it's pressed. In this case, we don't need to create a new function to respond to the signal:
You can create your own signals in a script. This example shows how to both define and emit a custom signal. We'll break it down below.
extendsNode# This line defines a signal named "health_changed". It takes one argument, "new_health".signalhealth_changed(new_health:int)functake_damage(amount:int)->void: health -= amount
# We use the signal's emit() member function to emit it.# Because the signal takes an argument, we pass one argument in parentheses: the new health value.# Any function connected to the signal will receive the new health value as an argument. health_changed.emit(health)
In this example, we define a new signal named health_changed. For example, you can use this signal to update the user interface when the player's health changes.You can define signals at the top of your script, outside of any function. The syntax is:
signalsignal_name()
You can optionally give them arguments similar to functions:
signalsignal_name(argument_1, argument_2)
Our previous example defined a signal named health_changed that takes one argument, new_health:
signalhealth_changed(new_health:int)
To emit a signal, you use the signal's emit() member function:
health_changed.emit(health)
Signals are first-class values in Godot. This means that you can directly reference them in your code.