ziva-sh/godot-signals

Modèles de signaux Godot 4 et leurs modes d'échec - déclaration de signaux typés, emit(), connect() et disconnect() avec Callables, bind() et unbind(), lambdas, CONNECT_ONE_SHOT et CONNECT_DEFERRED, await sur signaux et minuteurs, connexions de l'éditeur stockées dans les fichiers .tscn, et la règle « appel vers le bas, signal vers le haut ». À utiliser pour câbler des boutons UI, des minuteurs, des événements Area2D ou body et des événements de jeu personnalisés, pour remplacer le code Godot 3 connect("signal", self, "method") ou yield, ou pour déboguer « already connected », « ... ».

Qu'est-ce que godot-signals ?

Cette compétence fournit un guide complet et technique sur les signaux dans Godot 4, expliquant leur utilisation correcte et les pièges fréquents à éviter. Elle détaille la déclaration de signaux typés, les méthodes emit(), connect() et disconnect() avec les Callables, ainsi que les fonctions bind() et unbind() pour ajouter ou supprimer des arguments. La compétence couvre également les connexions uniques (CONNECT_ONE_SHOT) et différées (CONNECT_DEFERRED), l'utilisation de lambdas (en attirant l'attention sur leur nécessité d'être stockés dans des variables pour la déconnexion), et le mot-clé await pour les coroutines. Elle explique les connexions éditées dans le dock de l'éditeur, stockées dans les fichiers .tscn, et leur interaction avec le code. Enfin, elle présente le patron de conception « call down, signal up » et l'utilisation d'un autoload comme bus d'événements. Elle inclut un tableau de migration de Godot 3 vers Godot 4. Supportée sur toutes les plateformes où Godot 4 fonctionne, cette compétence est essentielle pour tout développeur travaillant avec le système de signaux de Godot 4.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ziva-sh/godot-skills/tree/HEAD/skills/godot-signals

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Signaux dans Godot 4

Dans Godot 4, un signal est une valeur Signal de première classe et une référence de méthode est une Callable. Utilisez la syntaxe objet (button.pressed.connect(_on_pressed)) partout. L'analyseur rejette alors un gestionnaire mal orthographié, et un signal mal orthographié sur self ; un signal mal orthographié sur un autre nœud typé est détecté lorsque unsafe_property_access est réglé sur Erreur (voir la compétence godot-4-api-pitfalls). Les formes textuelles (connect("pressed", ...), emit_signal("died")) ne sont vérifiées qu'à l'exécution.

Déclarer, émettre, connecter

extends Node

signal health_changed(old_value: int, new_value: int)
signal died

var health := 100


func take_damage(amount: int) -> void:
	var old := health
	health = maxi(health - amount, 0)
	health_changed.emit(old, health)
	if health == 0:
		died.emit()
extends Control

@onready var start_button: Button = %StartButton
@onready var quit_button: Button = %QuitButton


func _ready() -> void:
	start_button.pressed.connect(_on_start_pressed)
	quit_button.pressed.connect(get_tree().quit)
	start_button.mouse_entered.connect(func() -> void: start_button.grab_focus())


func _on_start_pressed() -> void:
	get_tree().change_scene_to_file("res://level_1.tscn")

Le gestionnaire doit accepter exactement les arguments émis par le signal. Une incompatibilité n'est pas une erreur d'analyse ; au moment de l'émission, Godot affiche Erreur lors de l'appel du signal 'x' à callable : '...': La méthode attendait 0 argument(s), mais a été appelée avec 1. et ignore le gestionnaire.

bind() et unbind()

  • bind(a, b) ajoute des arguments supplémentaires après les propres arguments du signal. Un gestionnaire pour pressed lié avec une valeur prend un paramètre ; pour health_changed(old, new) lié avec une valeur, il en prend trois, dans l'ordre old, new, lié.
  • unbind(n) supprime les n derniers arguments du signal, permettant à une fonction sans argument de gérer un signal qui en envoie certains.
extends HBoxContainer

signal slot_chosen(index: int)

var slot_buttons: Array[Button] = []


func _ready() -> void:
	for i in 4:
		var button := Button.new()
		button.text = "Slot %d" % (i + 1)
		add_child(button)
		slot_buttons.append(button)
		button.pressed.connect(_on_slot_pressed.bind(i))
	var timer := Timer.new()
	add_child(timer)
	timer.timeout.connect(_refresh)
	slot_chosen.connect(_refresh.unbind(1))
	timer.start(1.0)


func _on_slot_pressed(index: int) -> void:
	slot_chosen.emit(index)


func _refresh() -> void:
	for button in slot_buttons:
		button.disabled = false

Déconnecter, doublons et connexions uniques

  • disconnect() nécessite une Callable égale à celle connectée. _handler.bind(1) reconstruit de manière égale et fonctionne. Une lambda ne le fait pas : conservez-la dans une variable et déconnectez cette variable.
  • Connecter la même Callable deux fois affiche Le signal 'x' est déjà connecté à la callable donnée ... et conserve une connexion. Protégez-vous avec is_connected() lorsque le code peut s'exécuter deux fois, par exemple dans _ready() d'un nœud qui est réajouté à l'arbre.
  • connect(callable, CONNECT_ONE_SHOT) se déconnecte après la première émission. CONNECT_DEFERRED exécute le gestionnaire au temps d'inactivité. Utilisez-le (ou set_deferred()) lorsqu'un callback physique tel que body_entered modifie l'état physique ; le faire directement affiche Impossible de modifier cet état pendant le vidage des requêtes.
  • Les connexions à un objet sont supprimées lorsque cet objet est libéré.
extends Area2D

@onready var shape: CollisionShape2D = $CollisionShape2D
var _on_first_touch := func(body: Node2D) -> void: print(body.name, " a touché en premier")


func _ready() -> void:
	body_entered.connect(_on_first_touch, CONNECT_ONE_SHOT)
	body_entered.connect(_close_after_entry, CONNECT_DEFERRED)
	if not body_entered.is_connected(_on_body_entered):
		body_entered.connect(_on_body_entered)


func _on_body_entered(body: Node2D) -> void:
	print(body.name, " est entré")


func _close_after_entry(_body: Node2D) -> void:
	shape.disabled = true


func stop_listening() -> void:
	body_entered.disconnect(_on_body_entered)

await

await signal met la fonction en pause jusqu'à ce que le signal se déclenche et renvoie ses arguments : null pour aucun argument, la valeur pour un, un Array pour deux ou plus. Une fonction qui contient await est une coroutine ; les appelants qui ont besoin de son résultat doivent aussi await la fonction, sinon ils continuent immédiatement.

extends Node2D

signal door_opened(door_name: String)


func _ready() -> void:
	await get_tree().create_timer(0.5).timeout
	var opened_by: String = await door_opened
	print("Porte ouverte : ", opened_by)
	await play_intro()
	print("Introduction terminée")


func play_intro() -> void:
	var tween := create_tween()
	tween.tween_property(self, "modulate:a", 1.0, 1.0).from(0.0)
	await tween.finished

await n'expire jamais. Si le signal n'est jamais émis (ou son émetteur est libéré en premier), la fonction s'arrête simplement là, sans erreur. Utilisez un Timer ou une connexion unique lorsqu'un chemin de repli est nécessaire.

Connexions de l'éditeur

Les connexions effectuées dans le dock Nœuds sont enregistrées dans le fichier de scène, pas dans le script :

[connection signal="pressed" from="StartButton" to="." method="_on_start_button_pressed"]

Si la méthode est renommée ou supprimée dans le script, la connexion reste dans le fichier .tscn. Dans Godot 4.7.2, émettre un signal dont la méthode connectée n'existe plus n'affiche aucune erreur, donc le bouton cesse simplement de fonctionner. Après avoir renommé un gestionnaire, recherchez dans les scènes method="ancien_nom" et mettez-les à jour, ou reconnectez dans le dock Nœuds. Connectez dans le code lorsque le script doit être autonome ; connectez dans l'éditeur lorsque les concepteurs câblent des scènes. Évitez de faire les deux pour le même signal et la même méthode : la seconde connexion affiche "déjà connecté".

Appeler vers le bas, signaler vers le haut

Un nœud appelle des méthodes sur ses enfants (il les possède et sait qu'ils existent) et émet des signaux auxquels son parent ou ses frères peuvent réagir (il ne doit pas savoir qui écoute). Le parent, ou le nœud qui compose les deux, effectue la connexion :

extends Node2D

@onready var player: Node2D = $Player
@onready var health_bar: ProgressBar = $HUD/HealthBar


func _ready() -> void:
	player.connect(&"health_changed", _on_player_health_changed)


func _on_player_health_changed(_old_value: int, new_value: int) -> void:
	health_bar.value = new_value

Ce parent ne connaît le Player que comme un Node2D, il nomme donc le signal personnalisé comme une chaîne. Donnez au script du joueur un class_name Player, tapez la variable comme Player et écrivez player.health_changed.connect(_on_player_health_changed) pour que l'analyseur vérifie aussi le nom.

Pour les événements dont de nombreuses scènes non liées se soucient (joueur mort, niveau terminé), un modèle courant est un script autoload qui ne déclare que des signaux, utilisé comme bus d'événements : Events.player_died.emit() et Events.player_died.connect(_on_player_died).

Formes Godot 3 à remplacer

Godot 3Godot 4
connect("pressed", self, "_on_pressed")pressed.connect(_on_pressed)
connect("pressed", self, "_on_pressed", [id])pressed.connect(_on_pressed.bind(id))
connect("timeout", self, "_on_timeout", [], CONNECT_ONESHOT)timeout.connect(_on_timeout, CONNECT_ONE_SHOT)
disconnect("pressed", self, "_on_pressed")pressed.disconnect(_on_pressed)
is_connected("pressed", self, "_on_pressed")pressed.is_connected(_on_pressed)
emit_signal("died")died.emit()
yield(obj, "signal_name")await obj.signal_name
funcref(obj, "method")Callable(obj, "method") ou obj.method

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

ziva-sh/godot-4-api-pitfalls

Fixes Godot 3 APIs and GDScript syntax that AI assistants write into Godot 4 projects, such as KinematicBody2D, move_and_slide(velocity), export, onready, setget, yield, string connect(), instance(), rand_range, the Tween node, File, change_scene, Spatial, rect_* properties, Pool*Array, OS time functions and the old TileMap API. Use when writing, reviewing or porting GDScript for Godot 4.x, when a script fails with "not declared", "not found in base", "was removed in Godot 4" or "is not present

ziva-sh/godot-control-layout

Builds Godot 4 Control UIs that resize instead of clipping or overlapping - containers versus anchors, anchor presets from code, size flags, custom_minimum_size, MarginContainer margins, Label wrapping, mouse_filter, CanvasLayer HUDs, Godot 4 theme override names (add_theme_color_override and friends) and the display/window/stretch settings for multiple resolutions. Use when creating or fixing menus, HUDs, dialogs and inventory screens, when UI elements are cut off, zero-sized, overlapping, igno

ziva-sh/godot-scene-organization

Structures Godot 4 projects so scenes stay reusable and references do not break - when to make a scene, a script or a Resource, instancing with @export PackedScene, preload and load, @onready and %UniqueName node access, _ready order, groups, autoloads, class_name, and resource UIDs with the .uid files added in Godot 4.4, including how to move or rename files safely. Use when creating new scenes or scripts, deciding how nodes find each other, adding global state or an event bus, moving or renami

ziva-sh/godot-tilemaplayer

Correct Godot 4.3+ TileMapLayer code - set_cell(coords, source_id, atlas_coords), reading cells and custom data, erasing, coordinate conversion, terrains, tile collision through TileSet physics layers, finding the tile a body hit, and migrating from the deprecated TileMap node and its layer-index API. Use when placing, reading or erasing tiles from GDScript, building a TileSet in code, generating levels procedurally, handling tile collisions, or porting TileMap code from Godot 3 or Godot 4.0 to

Skills associés