Signaux

Introduction

Les signaux sont la version de Godot du modèle observer. Ils permettent à un nœud d'envoyer un message que les autres nœuds peuvent écouter et auquel ils peuvent répondre. Par exemple, au lieu de vérifier en continu si un bouton est appuyé, le bouton peut émettre un signal lorsqu'il est pressé.

Note

Vous pouvez en savoir plus sur le modèle observer ici : https://gameprogrammingpatterns.com/observer.html

Les signaux sont un moyen de rendre vos objets de jeu indépendants, ce qui conduit à un code mieux organisé et plus facile à gérer. Au lieu de forcer les objets du jeu à s'attendre à ce que d'autres objets soient toujours présents, ils peuvent émettre des signaux auxquels tout objet intéressé peut s'abonner et répondre.

Vous trouverez ci-dessous quelques exemples d'utilisation des signaux dans vos propres projets.

Exemple de Timer

Pour voir comment fonctionnent les signaux, essayons d'utiliser un nœud Timer. Créez une nouvelle scène avec un nœud Node2D et deux enfants : un Timer et un Sprite. Dans le dock scène, renommez Node2D en TimerExample.

Pour la texture du Sprite, vous pouvez utiliser l'icône Godot, ou toute autre image que vous souhaitez. Pour ce faire, sélectionnez Load dans le menu déroulant de l'attribut Texture du Sprite. Attachez un script au nœud racine, mais n'y ajoutez pas encore de code.

L'arbre de la scène devrait ressembler à ceci :

../../_images/signals_node_setup.png

Dans les propriétés du nœud Timer, cochez la case "On" à côté de Autostart. Le Timer démarrera automatiquement lorsque vous exécuterez la scène. Vous pouvez laisser le Wait Time (temps d'attente) à 1 seconde.

À côté de l'onglet "Inspecteur" se trouve un onglet intitulé "Nœud". Cliquez sur cet onglet et vous verrez tous les signaux que le nœud sélectionné peut émettre. Dans le cas du nœud Timer, celui qui nous intéresse est "timeout". Ce signal est émis chaque fois que la minuterie atteint 0.

../../_images/signals_node_tab_timer.png

Cliquez sur le signal "timeout()" et cliquez sur "Connecter...". Vous verrez la fenêtre suivante dans laquelle vous pouvez définir comment vous voulez connecter le signal :

../../_images/signals_connect_dialog_timer.png

Sur le côté gauche, vous verrez les nœuds de votre scène et pourrez sélectionner le nœud que vous souhaitez faire "écouter" le signal. Notez que le nœud Timer est bleu, c'est une indication visuelle que c'est le nœud qui émet le signal. Sélectionnez le nœud racine.

Avertissement

Le nœud cible doit être associé à un script ou vous recevrez un message d'erreur.

Si vous basculez le menu sur Avancé, vous verrez sur la droite que vous pouvez lier un nombre arbitraire d'arguments de (éventuellement) différents types. Cela peut être utile lorsque vous avez plus d'un signal connecté à la même méthode, car chaque propagation de signal donnera des valeurs différentes pour ces arguments d'appel supplémentaires.

Au bas de la fenêtre se trouve un champ intitulé "Méthode receveur". Il s'agit du nom de la fonction dans le script du nœud cible que vous souhaitez utiliser. Par défaut, Godot créera cette fonction en utilisant la convention de dénomination _on_<nom_nœud>_<nom_signal> mais vous pouvez la modifier si vous le souhaitez.

Cliquez sur "Connecter" et vous verrez que la fonction a été créée dans le script :

extends Node2D


func _on_Timer_timeout():
    pass # Replace with function body.
public class TimerExample : Node2D
{
    public void _on_Timer_timeout()
    {
        // Replace with function body.
    }
}

Nous pouvons maintenant remplacer le code de l’espace réservé par le code que nous souhaitons exécuter à la réception du signal. Faisons clignoter le Sprite :

extends Node2D


func _on_Timer_timeout():
    # Note: the `$` operator is a shorthand for `get_node()`,
    # so `$Sprite` is equivalent to `get_node("Sprite")`.
    $Sprite.visible = !$Sprite.visible
public class TimerExample : Node2D
{
    public void _on_Timer_timeout()
    {
        var sprite = GetNode<Sprite>("Sprite");
        sprite.Visible = !sprite.Visible;
    }
}

Exécutez la scène et vous verrez le Sprite clignoter à chaque seconde. Vous pouvez modifier la propriété Wait Time du Timer pour modifier cela.

Connecter des signaux dans le code

Vous pouvez également établir la connexion du signal en code plutôt qu'avec l'éditeur. Cela est généralement nécessaire lorsque vous instanciez des nœuds via du code et vous ne pouvez donc pas utiliser l'éditeur pour établir la connexion.

Commencez par déconnecter le signal en sélectionnant la connexion dans l'onglet "Nœud" du Timer et en cliquant sur Déconnecter.

../../_images/signals_disconnect_timer.png

Pour établir la connexion en code, nous pouvons utiliser la fonction connect. Nous allons la mettre dans _ready() afin que la connexion soit établie lors de l'exécution. La syntaxe de la fonction est <nœud_source>.connecter(<nom_signal>, <nœud_cible>, <nom_fonction_ cible>). Voici le code pour la connexion de notre Timer :

extends Node2D


func _ready():
    $Timer.connect("timeout", self, "_on_Timer_timeout")


func _on_Timer_timeout():
    $Sprite.visible = !$Sprite.visible
public class TimerExample : Node2D
{
    public override void _Ready()
    {
        GetNode("Timer").Connect("timeout", this, nameof(_on_Timer_timeout));
    }

    public void _on_Timer_timeout()
    {
        var sprite = GetNode<Sprite>("Sprite");
        sprite.Visible = !sprite.Visible;
    }
}

Signaux personnalisés

Vous pouvez également déclarer vos propres signaux personnalisés dans Godot :

extends Node2D


signal my_signal
public class Main : Node2D
{
    [Signal]
    public delegate void MySignal();
}

Une fois déclarés, vos signaux personnalisés apparaîtront dans l'inspecteur et pourront être connectés de la même manière que les signaux intégrés d'un nœud.

Pour émettre un signal par le code, utilisez la fonction emit_signal :

extends Node2D


signal my_signal


func _ready():
    emit_signal("my_signal")
public class Main : Node2D
{
    [Signal]
    public delegate void MySignal();

    public override void _Ready()
    {
        EmitSignal(nameof(MySignal));
    }
}

Un signal peut aussi déclarer en option un ou plusieurs arguments. Spécifiez les noms des arguments entre parenthèses :

extends Node


signal my_signal(value, other_value)
public class Main : Node
{
    [Signal]
    public delegate void MySignal(bool value, int other_value);
}

Note

Les arguments du signal apparaissent dans le dock des nœuds de l'éditeur, et Godot peut les utiliser pour générer des fonctions de rappel pour vous. Cependant, vous pouvez toujours émettre un nombre quelconque d'arguments lorsque vous émettez des signaux. C'est donc à vous d'émettre les valeurs correctes.

Pour passer des valeurs, ajoutez-les comme deuxième argument à la fonction emit_signal :

extends Node


signal my_signal(value, other_value)


func _ready():
    emit_signal("my_signal", true, 42)
public class Main : Node
{
    [Signal]
    public delegate void MySignal(bool value, int other_value);

    public override void _Ready()
    {
        EmitSignal(nameof(MySignal), true, 42);
    }
}

Conclusion

De nombreux types de nœuds intégrés de Godot fournissent des signaux que vous pouvez utiliser pour détecter des événements. Par exemple, un Area2D représentant une pièce de monnaie émet un signal body_entered chaque fois que le corps physique du joueur entre en collision avec, ce qui vous permet de savoir quand le joueur la récupère.

Dans la section suivante Votre premier jeu, vous construirez un jeu complet comprenant plusieurs utilisations de signaux pour connecter différents composants du jeu.