Skip to content

How do I connect a signal in code?

Godot 4.x

The script sits on Main, and the button is its child:

  • MainNode2Dhas scriptthe script goes here
    • ButtonButton

In _ready(), take the signal, call .connect() on it, and hand it the function that should run. You pass the function itself, not a call to it, so there are no parentheses after its name:

main.gd
extends Node2D
func _ready() -> void:
$Button.pressed.connect(_on_button_pressed)
func _on_button_pressed() -> void:
print("Button pressed")

Run the scene and click the button. Every click prints a line, with nothing set up in the editor.

Some signals send data along. Area2D.body_entered tells you which body came in, so the handler takes that body as a parameter:

main.gd
func _ready() -> void:
$Area2D.body_entered.connect(_on_body_entered)
func _on_body_entered(body: Node2D) -> void:
print(body.name, " entered")

The handler must take the same parameters the signal sends, in the same order. To see what a signal sends, select the node, open the Node → Signals dock and read the signature next to its name.

Sometimes the handler needs something the signal does not send, like which button was pressed when several share one function. Call .bind() on the function and pass the extra values. They arrive after the signal’s own arguments:

  • MainNode2Dhas script
    • HBoxContainerHBoxContainer
      • RedButtonButton
      • GreenButtonButton
main.gd
extends Node2D
func _ready() -> void:
$HBoxContainer/RedButton.pressed.connect(_on_color_pressed.bind(Color.RED))
$HBoxContainer/GreenButton.pressed.connect(_on_color_pressed.bind(Color.GREEN))
func _on_color_pressed(color: Color) -> void:
print("Picked ", color)

pressed sends nothing, so color is the only parameter. With a signal that does send data, the signal’s arguments come first and the bound ones after. Binding to body_entered gives a handler of (body: Node2D, side: String):

main.gd
func _ready() -> void:
$LeftZone.body_entered.connect(_on_zone_entered.bind("left"))
$RightZone.body_entered.connect(_on_zone_entered.bind("right"))
func _on_zone_entered(body: Node2D, side: String) -> void:
print(body.name, " entered the ", side, " zone")

In C# there is no Bind. A lambda that calls your method with the extra value does the same job.

Declare the signal at the top of the script with the parameters it will send, then call .emit() where the value changes:

  • MainNode2Dhas scriptconnects to the signal
    • PlayerCharacterBody2Dhas scriptowns and emits the signal
player.gd
extends CharacterBody2D
signal health_changed(new_health: int)
var health := 100
func take_damage(amount: int) -> void:
health -= amount
health_changed.emit(health)
main.gd
extends Node2D
func _ready() -> void:
$Player.health_changed.connect(_on_player_health_changed)
func _on_player_health_changed(new_health: int) -> void:
print("Health: ", new_health)

Notice the direction. Player owns the signal and emits it without knowing who is listening. Main, the node above, connects to it. The child never reaches up to its parent, so you can drop Player into any scene and it still works.