Signals
Signals let a node announce that something happened without knowing who listens.
17.1 What signals are
Signals let a node announce that something happened without knowing who listens. Listeners connect callables to them. This decouples your code ("signal up, call down").
17.2 Declaring and emitting
class_name Player
extends CharacterBody2D
signal died
signal health_changed(old_value: int, new_value: int)
signal item_collected(item_name: String, amount: int)
var health := 100
func take_damage(amount: int) -> void:
var old := health
health = max(health - amount, 0)
health_changed.emit(old, health)
if health == 0:
died.emit()17.3 Connecting in code
Bound arguments (bind) are passed after the emitted arguments.
signal_name.disconnect(callable), signal_name.is_connected(callable).
When either object is freed, its connections are removed automatically (lambdas capturing freed objects can error — prefer methods).
func _ready() -> void:
var player: Player = $Player
player.health_changed.connect(_on_player_health_changed)
player.died.connect(_on_player_died, CONNECT_ONE_SHOT) # auto-disconnect after first emit
player.item_collected.connect(func(item, n): print(item, " x", n))
$Timer.timeout.connect(spawn_enemy.bind("slime")) # extra bound argument
$Button.pressed.connect(_on_button_pressed, CONNECT_DEFERRED) # call at idle time
func _on_player_health_changed(old_value: int, new_value: int) -> void:
$HUD/HealthBar.value = new_value
func _on_player_died() -> void:
get_tree().reload_current_scene()
func spawn_enemy(kind: String) -> void:
print("spawning ", kind)17.4 Connecting in the editor
Select the emitting node → Node dock → Signals → double-click a signal → choose the receiving node → the editor creates a method like _on_button_pressed. Editor connections are stored in the .tscn and show a green icon next to the method in the script editor.
17.5 Common built-in signals
Button / BaseButton pressed, toggled(on), button_down, button_up
body_entered(body), body_exited, area_entered(area), area_exited
animation_finished(anim_name), animation_started ready, tree_entered, tree_exiting, tree_exited, renamed screen_entered, screen_exited
text_changed(text), text_submitted(text) process_frame, physics_frame, node_added, tree_changed
finished, step_finished, loop_finished request_completed(result, code, headers, body)
17.6 Signal objects and dynamic signals
var s: Signal = $Button.pressed
s.connect(_on_pressed)
print(s.get_name(), s.get_connections())
emit_signal("died") # string-based (legacy style, still works)
connect("died", _on_died)
add_user_signal("custom_event", [{"name": "value", "type": TYPE_INT}])17.7 Signal bus (event bus) pattern
An autoload with only signals lets distant nodes talk:
Godot 3 note: connect("pressed", self, "_on_pressed", [extra]) and emit_signal("died"). In 4.x signals and callables are first-class.
# res://autoload/events.gd (registered as autoload "Events")
extends Node
signal coin_collected(value: int)
signal player_died
signal level_completed(level: int)# coin.gd
func _on_body_entered(_body: Node2D) -> void:
Events.coin_collected.emit(10)
queue_free()
# hud.gd
func _ready() -> void:
Events.coin_collected.connect(func(v): score += v; update_label())