Señales

Introducción

Las señales son en Godot una version del «patron del observador». Estas permiten a un nodo enviar un mensaje, que otros nodos pueden escuchar y responder. Por ejemplo, en vez de chequear continuamente si un botón esta siendo presionado, el botón puede emitir una señal cuando esta presionado.

Nota

Puedes leer mas sobre el patron del observador aqui: http://gameprogrammingpatterns.com/observer.html

Las señales son una forma de desacoplar los objetos del juego, lo que permite obtener un código mejor organizado y fácil de administrar. En lugar de forzar a los objetos del juego a esperar que otros objetos estén siempre presentes, pueden emitir señales a las que todos los objetos interesados puedan suscribirse y responder.

A continuación puedes ver algunos ejemplos de cómo puedes usar las señales en tus propios proyectos.

Ejemplo de 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.

cualquier otra imagen que desees. Para ello, selecciona Load en el menú desplegable del atributo Texture del Sprite. Agrega un script al nodo raíz, pero no le añadas ningún código todavía.

Tu árbol de la escena debería verse así:

../../_images/signals_node_setup.png

En las propiedades del nodo Temporizador, marca la casilla «On» que aparece junto a Autostart. Esto hará que el temporizador se inicie automáticamente cuando se ejecute la escena. Puedes dejar el Wait Time en 1 segundo.

Junto a la pestaña «Inspector» hay una pestaña con el nombre «Nodos». Haz clic en esta pestaña y verás todas las señales que puede emitir el nodo seleccionado. En el caso del nodo Timer, el que nos ocupa es el «timeout». Esta señal se emite cada vez que el temporizador alcanza 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.

Advertencia

El nodo de destino debe tener un script adjunto o recibirá un mensaje de error.

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.

Haz clic en «Conectar» y verás que la función ha sido creada en el 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.
    }
}

Ahora podemos reemplazar el código del placeholder con cualquier código que queramos ejecutar cuando recibamos la señal. Hagamos que el Sprite parpadee:

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;
    }
}

Ejecuta la escena y verás el Sprite parpadeando cada segundo. Se puede cambiar la propiedad Wait Time del temporizador para modificarla.

Conectar señales por código

También puedes hacer la conexión de la señal por código en lugar de hacerlo con el editor. Esto suele ser necesario cuando estás instanciando nodos mediante código, por lo que no puedes usar el editor para hacer la conexión.

Primero, desconecta la señal seleccionando la conexión en la pestaña «Nodos» del Timer y haciendo clic en desconectar.

../../_images/signals_disconnect_timer.png

Para realizar la conexión en código, podemos usar la función connect. La establecemos en _ready() para que la conexión se cree en ejecución. La sintaxis de la función es <source_node>.connect(<signal_name>, <target_node>, <target_function_name>). Aquí está el código para la conexión de nuestro 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;
    }
}

Señales personalizadas

También puedes declarar tus propia señales (signal) personalizadas dentro de Godot:

extends Node2D

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

Una vez declaradas, las señales personalizadas aparecerán en el Inspector y podrán conectarse de la misma forma que las señales integradas del nodo.

Para emitir una señal por código, utiliza la función 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));
    }
}

Conclusión

Muchos de los tipos de nodos incorporados en Godot proporcionan señales que puedes utilizar para detectar eventos. Por ejemplo, un Area2D, el cual representa una moneda, emite una señal del tipo body_entered cada vez que el cuerpo físico del jugador entra a su forma de colisión, permitiéndote saber cuando el jugador la ha recolectado.

En la siguiente sección, Tu primer juego, construirás un juego completo que incluirá varios usos de señales para conectar diferentes componentes del juego.