Vous en etes la : vous avez une scene principale avec un Player et un HUD, tout est bien en place... mais c'est encore un peu le calme plat (rien ne reagit, rien ne repond). Et c'est justement la que les signaux entrent en scene : c'est ce qui transforme une interface "statique" en jeu qui ecoute et reagit. Accrochez-vous, on va voir ca ensemble, tranquillement, et surtout en testant a chaque etape.
1) Contexte rapide (ou on en est)
Vous avez deja :
- une scene Main.tscn (souvent
Node2DouControlen racine), - un noeud Player (immobile pour l'instant, et c'est ok),
- un noeud HUD (avec au moins un
Label).
Ce qu'il manque, c'est le "clic" (au sens propre) : un menu, un bouton, une reaction visible. Et ca, c'est exactement le job des signaux.
2) Objectifs du module (clairs et mesurables)
A la fin de ce module, vous saurez :
- Expliquer ce qu'est un signal dans Godot (et pourquoi c'est utile).
- Creer un premier bouton Play dans une scene de menu simple.
- Connecter un signal
pressed()d'unButtondepuis l'editeur. - Reagir a ce signal avec une action verifiable (
printpuis changement deLabel). - Connecter un signal par code avec
.connect(...)(optionnel, mais tres utile). - Utiliser un
Timeret son signaltimeout()pour comparer (bonus). - Verifier votre scene avec une checklist finale + un mini quiz (pour etre sur que tout marche).
3) Mini glossaire (simple, sans jargon)
- Signal : un evenement emis par un noeud (ex : "on a clique", "le timer a fini").
- Emettre : le noeud annonce "il vient de se passer X".
- Ecouter : un autre noeud dit "quand X arrive, je veux etre prevenu".
- Connecter : relier un signal a une methode pour que Godot l'appelle au bon moment.
- Recepteur (receiver) : le noeud/script qui recoit le signal et reagit.
- Callback / methode : la fonction appelee quand le signal arrive (souvent
_on_X_pressed()). - Decouplage : deux noeuds collaborent sans se connaitre trop intimement (plus propre, plus flexible).
- @onready : permet de recuperer un noeud une fois la scene prete (evite des
null).
4) Comprendre "emettre" vs "ecouter" (analogie simple)
Imaginez une sonnette chez vous.
- Le bouton de sonnette, c'est un noeud qui emet un evenement : "quelqu'un a appuye".
- Vous, dans la maison, vous ecoutez cette sonnette : quand ca sonne, vous faites quelque chose (ouvrir, parler, ignorer...).
- La connexion entre la sonnette et votre reaction, c'est le fait de dire : "quand ca sonne, appelle cette action".
Dans Godot c'est pareil :
- Le
Buttonemet le signalpressed(). - Votre script ecoute le signal.
- Quand le signal est emis, Godot appelle votre methode.
L'avantage : le bouton n'a pas besoin de connaitre toute votre logique de jeu. Il se contente d'emettre "pressed". Et vous, vous decidez quoi faire.
5) Pas a pas guide (avec checkpoints)
Etape 1 : Creer une scene de menu dediee (Menu.tscn)
Scene > New Scene- Choisissez Control en racine (ideal pour l'UI).
- Renommez la racine en Menu
- Sauvegardez :
res://Menu.tscn
Checkpoint
- Vous avez
Menu.tscnavec un noeud racineMenu (Control).
Etape 2 : Ajouter un bouton "Play"
- Clic droit sur
Menu>Add Child Node... - Ajoutez un Button
- Renommez-le Play
- Dans l'Inspector :
Text:Play- (optionnel) ajustez position/taille pour le voir facilement
Optionnel (mais pratique) : ajoutez un Label titre, genre Mon Premier Menu !.
Hierarchie typique :
Menu (Control)
├── TitleLabel (Label) (optionnel)
└── Play (Button)
Checkpoint
- Le bouton
Playest visible dans la scene (dans l'editeur).
Etape 3 : Ajouter un Label pour un retour visuel (recommande)
Un print() dans l'Output, c'est bien. Mais voir un texte changer a l'ecran, c'est encore mieux pour un debutant.
- Sous
Menu, ajoutez unLabel - Renommez-le
StatusLabel - Texte initial :
Appuyez sur Play
Hierarchie :
Menu (Control)
├── TitleLabel (Label) (optionnel)
├── Play (Button)
└── StatusLabel (Label)
Checkpoint
-
StatusLabelexiste et affiche "Appuyez sur Play" dans l'editeur.
Etape 4 : Ajouter un script au Menu
- Clic droit sur
Menu>Attach Script - Enregistrez :
res://Menu.gd - Gardez
extends Control
Vous avez un squelette du genre :
extends Control
func _ready():
pass
Checkpoint
-
Menu.gdest attache aMenu.
Etape 5 : Connecter pressed() depuis l'editeur (methode visuelle)
Vous vous demandez peut-etre "ou sont les signaux dans Godot ?" C'est dans l'onglet Node (a cote de Inspector).
- Selectionnez le noeud Play (le bouton)
- A droite, ouvrez l'onglet Node
- Dans la liste des signaux, double-cliquez sur pressed()
- Dans la fenetre :
- Receiver :
Menu - Methode : laissez Godot proposer
_on_play_pressed(ou similaire)
- Receiver :
- Cliquez Connect
Godot ajoute automatiquement une fonction dans Menu.gd.
Checkpoint
- Vous voyez une methode
_on_play_pressed()(ou proche) dansMenu.gd. - Le signal
pressed()est connecte (dans l'onglet Node, vous voyez la connexion).
6) Code par petits blocs (et test a chaque bloc)
Bloc 1 : Reaction simple avec print
Dans Menu.gd, completez la methode creee par Godot :
extends Control
func _on_play_pressed():
print("Game started")
Pourquoi on commence par print ?
- C'est le test le plus simple : si vous voyez le message dans l'Output, le signal est bien connecte.
- Ensuite seulement, on ajoute des effets plus "visuels".
Test
- Sauvegardez
Menu.tscn - Pour tester, il faut l'afficher depuis
Main.tscn(etape suivante), ou lancerMenu.tscndirectement si vous la mettez en scene principale temporairement.
Checkpoint
- Quand vous cliquez sur Play, vous voyez
Game starteddans l'onglet Output.
Etape 6 : Instancier Menu dans Main pour un test "reel"
Comme votre contexte dit que Main.tscn charge deja Player et HUD, on va juste ajouter le menu en plus pour le moment.
Dans Main.tscn :
- Ouvrez
Main.tscn - Ajoutez
Menu.tscnen enfant (glisser-deposerMenu.tscndans la hierarchie, ouInstance Child Scene) - Lancez
Main.tscn(F6)
Checkpoint
- Le menu s'affiche dans le jeu.
- Cliquer sur
PlayafficheGame starteddans Output.
Bloc 2 : Changer un Label (plus visible qu'un print)
Maintenant on veut une reaction a l'ecran, pas seulement dans la console.
Dans Menu.gd, on recupere StatusLabel et on change son texte au clic :
extends Control
@onready var status_label = $StatusLabel
func _on_play_pressed():
status_label.text = "Game started"
print("Game started")
Note sur @onready :
- Sans
@onready, vous risquez de lire$StatusLabeltrop tot (avant que la scene soit prete). - Avec
@onready, Godot initialise la variable au bon moment.
Test
- Lancez, cliquez Play.
Checkpoint
- Le texte du label change quand vous cliquez.
- Le
print("Game started")apparait toujours.
7) Bonus : comparer avec un Timer (signal automatique)
Un bouton, c'est l'utilisateur qui declenche. Un Timer, c'est le jeu qui declenche tout seul (et c'est tres utile pour des cooldowns, des clignotements, des spawns, etc).
Etape Timer : Ajouter un Timer et connecter timeout()
Dans Menu.tscn :
- Ajoutez un
TimersousMenu - Renommez-le
DemoTimer - Dans l'Inspector :
Wait Time:2.0Autostart:On
Connectez timeout() :
- Selectionnez
DemoTimer - Onglet Node
- Double-clic sur
timeout() - Connectez au
Menu
Dans Menu.gd, ajoutez :
func _on_demo_timer_timeout():
status_label.text = "Timer tick... " + str(Time.get_time_dict_from_system().second)
Test
- Lancez la scene, observez le label (il change toutes les 2 secondes).
Checkpoint
- Sans cliquer, le label change tout seul (toutes les 2s).
8) Connecter un signal via le code (quand vous voulez du dynamique)
La connexion par l'editeur, c'est parfait pour debuter (et souvent suffisant). Mais si vous instanciez des scenes a la volee, ou si vous voulez centraliser la logique dans le script, vous pouvez connecter par code.
Dans Menu.gd, vous pouvez connecter dans _ready() :
extends Control
@onready var status_label = $StatusLabel
@onready var play_button = $Play
func _ready():
play_button.pressed.connect(_on_play_pressed)
func _on_play_pressed():
status_label.text = "Game started"
print("Game started")
Attention :
- Si vous aviez deja connecte
pressed()via l'editeur, vous risquez d'appeler la methode deux fois. - Choisissez une seule methode de connexion pour eviter les surprises.
Checkpoint
- Le clic appelle la methode une seule fois (pas de double print).
9) Erreurs frequentes (si tu vois X, c'est surement Y)
- Tu cliques, rien ne se passe
- souvent : signal non connecte, ou vous testez une autre scene que celle modifiee, ou vous n'avez pas lance
Main.tscn.
- souvent : signal non connecte, ou vous testez une autre scene que celle modifiee, ou vous n'avez pas lance
- Erreur "Invalid get index" / null
- souvent :
$StatusLabeln'existe pas, mauvais nom, ou vous avez oublie@onready.
- souvent :
- La fonction ne se declenche pas
- souvent : vous avez connecte
pressed()puis vous avez renomme le bouton, ou le script n'est pas sur le bon noeud.
- souvent : vous avez connecte
- Ca se declenche deux fois
- souvent : connecte via l'editeur + via code en meme temps.
- Le menu disparait derriere
- souvent : ordre d'affichage UI /
Controlmal ancre (pas bloquant ici, mais a garder en tete).
- souvent : ordre d'affichage UI /
10) Exercices (1 facile + 1 challenge)
Exercice facile : "Play" affiche "Game started" dans Output
Objectif :
- Au clic sur
Play, faire :print("Game started")
Critere de reussite :
- Vous voyez le message dans Output a chaque clic.
Challenge : ajouter un bouton "Quit" ou "Options"
Ajoutez un second bouton sous Play.
Option A (desktop) : Quitter le jeu
- Bouton :
Quit - Connectez
pressed() - Code :
func _on_quit_pressed():
get_tree().quit()
Option B (placeholder) : Options
func _on_options_pressed():
status_label.text = "Options : bientot implemente !"
Bonus (si vous etes chaud) : afficher/masquer un Panel d'options (meme vide), juste pour pratiquer le "toggle".
11) Recap + checklist (ce qui doit etre vrai a la fin)
Ce que vous avez fait, c'est simple, mais c'est un enorme pas : vous avez une scene UI qui reagit sans que tout le projet soit en spaghetti.
Checklist finale :
-
Menu.tscnexiste (racineControl) -
Play (Button)existe et est cliquable -
pressed()est connecte (editeur ou code) - Un clic affiche
print("Game started") - (Recommande) Un clic change le texte de
StatusLabel - Bonus : un
Timeremettimeout()et met a jour le label - Vous savez reperer les erreurs classiques (signal pas connecte, mauvais chemin, double connexion)
Mini quiz (2 minutes, pour verifier)
-
Un signal dans Godot, c'est plutot :
- A) une variable
- B) un evenement emis par un noeud
- C) un fichier de configuration
-
Qui "emet"
pressed()?- A) le script du Menu
- B) le Button
- C) le HUD
-
Que fait une connexion de signal ?
- A) Elle renomme automatiquement vos noeuds
- B) Elle dit a Godot quelle methode appeler quand l'evenement arrive
- C) Elle lance la scene principale
(Reponses : 1B, 2B, 3B)
12) Pont vers le module suivant (sans spoiler)
Maintenant que votre jeu sait "ecouter" et "reagir", la suite logique, c'est de brancher ces signaux sur du concret : afficher/mettre a jour le HUD, declencher le mouvement du Player, et organiser proprement le passage "Menu -> Jeu". Bref, on passe de l'interface qui clique a l'action qui joue (et c'est vraiment le moment ou le projet prend vie).