Sinais

Introdução

Sinais são a versão do Godot do padrão observador. Eles permitem que um nó envie uma mensagem que outros nós podem captar e responder. Por exemplo, ao invés de continuamente verificar um botão para saber se ele está sendo pressionado, o botão pode emitir um sinal quando for pressionado.

Nota

Você pode ler mais sobre o padrão observador aqui: http://gameprogrammingpatterns.com/observer.html

Sinais são um meio de desacoplar seus objetos de jogo, o que leva a um código mais organizado e gerenciável. Ao invés de forçar objetos de jogo a esperar que outros objetos estejam sempre presentes, eles podem emitir sinais para os quais qualquer objeto interessado pode inscrever-se e responder.

Abaixo, você pode ver alguns exemplos de como você pode usar sinais em seus próprios projetos.

Alguns exemplos

Para ver como sinais funcionam, vamos tentar usar um nó Timer. Crie uma nova cena com um Node e dois filhos: um Timer e um Sprite. Na Scene dock renomeie o nó para TimerExample.

Para a textura do Sprite, você pode usar o ícone Godot, ou qualquer outra imagem que desejar. Que é feito selecionando Load no menu suspenso do atributo Textura do Sprite. Anexe um script ao nó raiz, mas não adicione nenhum código ainda.

Sua árvore da cena deveria se parecer assim:

../../_images/signals_node_setup.png

Nas propriedades do nó Timer, marque a caixa “On” próximo a Autostart. Isso fará com que o Timer inicie automaticamente quando você executar a cena. Você pode deixar o Wait Time em 1 segundo.

Próximo à aba “Inspector” há uma aba chamada “Nó”. Clique nessa aba e você verá todos os sinais que o nó selecionado pode emitir. No caso do nó Timer, o que nos importa é o “timeout”. Este sinal é emitido sempre que o Timer chegar à 0.

../../_images/signals_node_tab_timer.png

Clique no sinal “timeout()” e clique em “Conectar…”. Você vai ver a seguinte janela, onde pode definir como você quer conectar o sinal:

../../_images/signals_connect_dialog_timer.png

Do lado esquerdo, você verá os nós na sua cena e pode selecionar o nó que você quer que “escute” para o sinal. Note que o nó Timer está vermelho - isso não é um erro, mas é uma indicação visual de que é esse o nó o qual está emitindo o sinal. Selecione o nó raiz.

Aviso

O nó alvo precisa ter um script anexado ou você vai receber uma mensagem de erro.

Em baixo da janela há um campo rotulado “Método no nó”. Esse é o nome da função no roteiro do nó alvo que você quer usar. Por padrão, Godot vai criar essa função usando a convenção de nomenclatura _on_<node_name>_<signal_name> mas você pode mudá-lo se desejar.

Clique em “Conectar” e você verá que a função foi criada no script:

extends Node

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

Agora podemos substituir o código placeholder com qualquer código que deseja executar quando o sinal for recebido. Vamos fazer o Sprite piscar:

extends Node

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 : Node
{
    public void _on_Timer_timeout()
    {
        var sprite = GetNode<Sprite>("Sprite");
        sprite.Visible = !sprite.Visible;
    }
}

Execute a cena e você verá o Sprite ligando e desligando a cada segundo. Você pode mudar a propriedade Wait Time do temporizador para alterar isso.

Conectando sinais por código

Você também pode fazer a conexão do sinal em código ao invés do editor. Isso é geralmente necessário quando você está instanciando nós via código e por isso não pode usar o editor para fazer a conexão.

Primeiro, desconecte o sinal selecionando a conexão na aba “Nó” do timer e clicando em desconectar.

../../_images/signals_disconnect_timer.png

Para fazer a conexão por código, nós podemos usar a função connect. Nós iremos colocá-la em _ready() para que a conexão sejá feita ao rodar. A sintaxe da função é <source_node>.connect(<signal_name>, <target_node>, <target_function_name>). Aqui está o código para nossa conexão com o Temporizador:

extends Node

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

func _on_Timer_timeout():
    $Sprite.visible = !$Sprite.visible
public class TimerExample : Node
{
    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;
    }
}

Sinais personalizados

Você também pode declarar seus próprios sinais na Godot:

extends Node

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

Quando declarado, seus sinais personalizados aparecerão no Inspetor e podem ser conectados da mesma forma que os sinais pré-incorporados em um node.

Para emitir um sinal por código, use a função emit_signal :

extends Node

signal my_signal

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

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

Conclusão

Na Godot, muitos dos nós embutidos proporcionam sinais que você pode usar para detectar eventos. Por exemplo, um Area2D <class_Area2D>`representando uma moeda emite um sinal ``body_entered` sempre quando o corpo físico do jogador entra na forma de colisão, permitindo você saber quando o jogador coletou ela.

Na próxima seção, Seu primeiro jogo, você criará um jogo completo contendo vários usos de sinais para conectar diferentes componentes do jogo.