Segnali

Introduzione

I segnali sono la versione di Godot degli observer pattern. Consentono ad un nodo di inviare un messaggio che un altro nodo può ascoltare e rispondere. Per esempio, piuttosto che controllare in continuazione un bottone per verificare se è premuto, il bottone può emettere un segnale quando è premuto.

Nota

Puoi scoprire di più relativamente agli observer pattern qui: http://gameprogrammingpatterns.com/observer.html

I segnali sono un modo per disaccoppiare i tuoi oggetti di gioco, il che comporta un codice meglio organizzato e più gestibile. Al posto di forzare gli oggetti di gioco ad aspettarsi che altri oggetti siano sempre presenti, possono invece emettere segnali che tutti gli oggetti interessati possono ascoltare e rispondere.

Sotto puoi vedere alcuni esempi di come puoi usare i segnali nei tuoi progetti.

Esempio di Timer

To see how signals work, let’s try using a Timer node. Create a new scene with a Node2D and two children: a Timer and a Sprite. In the Scene dock, rename Node2D to TimerExample.

Per la texture dello Sprite, puoi usare l’icona di Godot, o qualsiasi altra immagine ti piaccia. Puoi farlo selezionando Load tra gli attibuti nel menu a tendina della Texture del nodo Sprite. Attacca uno script al nodo radice, ma non aggiungere nessun codice per ora.

Il tuo albero di scena dovrebbe essere simile a questo:

../../_images/signals_node_setup.png

Nelle proprietà del nodo Timer, spunta la casella «On» vicino a Autostart. Questo farà in modo che il timer parta automaticamente quando viene avviata la scena. Puoi lasciare Wait Time impostato ad un secondo.

Vicino alla tab «Inspector» ne è presente una chiamata «Node». Clicca questa tab e vedrai tutti i segnali che il nodo selezionato può emettere. Nel caso del nodo Timer, quello che c’interessa è «timeout». Questo segnale viene emesso ogni volta il Timer raggiunge 0.

../../_images/signals_node_tab_timer.png

Click on the «timeout()» signal and click «Connect…» at the bottom of the signals panel. You’ll see the following window, where you can define how you want to connect the signal:

../../_images/signals_connect_dialog_timer.png

On the left side, you’ll see the nodes in your scene and can select the node that you want to «listen» for the signal. Note that the Timer node is blue, this is a visual indication that it’s the node that is emitting the signal. Select the root node.

Avvertimento

Il nodo target deve avere uno script attaccato altrimenti riceverai un messaggio di errore.

On the bottom of the window is a field labeled «Receiver Method». This is the name of the function in the target node’s script that you want to use. By default, Godot will create this function using the naming convention _on_<node_name>_<signal_name> but you can change it if you wish.

Clicca «Connetti» e vedrai che la funzione è stata creata nello script:

extends Node2D

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

Ora possiamo sostituire il codice segnaposto con qualsiasi codice vogliamo eseguire quando il segnale viene ricevuto. Facciamo «lampeggiare» lo 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;
    }
}

Esegui la scena e vedrai lo Sprite che lampeggia ogni secondo. Puoi cambiare il Tempo di Attesa del Timer nelle proprietà per alterare questa funzionalità.

Collegamento di segnali nel codice

Puoi anche connettere i segnali da codice invece che dall’editor. Questo è di solito necessario quando stai instanziando nodi da codice e quindi non puoi usare l’editor per fare la connessione.

Per prima cosa, sconnetti il segnale selezionando la connessione nella tab «Node» del nodo timer e fai click su sconnetti.

../../_images/signals_disconnect_timer.png

Per creare la connessione da codice, possiamo utilizzare la funzione connect. La inseriremo in _ready() cosi che la connessione venga creata durante l’esecuzione. La sintassi della funzione è <source_node>.connect(<signal_name>, <target_node>, <target_function_name>). Qui c’è il codice per la connessione del nostro 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;
    }
}

Segnali personalizzati

Puoi anche dichiarare i tuoi segnali personalizzati in Godot:

extends Node2D

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

Una volta dichiarati, i tuoi segnali personalizzati appariranno nell’Ispettore e potranno essere connessi nello stesso modo di un segnale pre-costruito.

Per emettere un segnale da codice, usa la funzione 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));
    }
}

Conclusione

Tanti dei Nodi di Godot forniscono segnali che puoi usare per rilevare eventi. Per esempio, un Area2D che rappresenta una moneta emette un segnale body_entered quando il corpo del giocatore entra nella sua collision shape, facendoti capire quando il giocatore l’ha raccolta.

Nella prossima sezione, Il tuo primo gioco, creerai un gioco completo includendo l’uso di segnali per connettere differenti componenti di gioco.