Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Usando sinais
Nesta lição, veremos os sinais. São mensagens que os nós emitem quando algo específico acontece com eles, como um botão sendo pressionado. Outros nós podem se conectar a esse sinal e chamar uma função quando o evento ocorrer.
Os sinais são um mecanismo de delegação embutido no Godot que permite que um objeto do jogo reaja a uma mudança em outro sem que eles façam referência um ao outro. O uso de sinais limita o acoplamento e mantém seu código flexível.
For example, you might have a life bar on the screen that represents the player's health. When the player takes damage or uses a healing potion, you want the bar to reflect the change. To do so, in Godot, you would use signals.
Assim como métodos (Callable), sinais são um tipo de dado de primeira classe desde a Godot 4.0. Isso significa que você pode passá-los diretamente como argumentos de método sem precisar usá-los como strings, o que permite um melhor autocompletar e reduz a chance de erros. Consulte a referência da classe Signal para ver uma lista do que você pode fazer diretamente com o tipo "Signal".
Ver também
Conforme mencionado na introdução, os sinais são a versão de Godot do padrão do observador. Você pode aprender mais sobre isso aqui: Padrões de Programações de Jogos.
Vamos agora usar um sinal para fazer nosso ícone Godot da lição anterior (Capturando os controles de entrada do jogador) se mover e parar ao pressionar um botão.
Nota
Para esse projeto, vamos seguir as convenções de nomeação do Godot.
GDScript: Classes (nós) usam o estilo
PascalCase
(IniciaisMaiúsculas), variáveis e funções usamsnake_case
(minúsculas_separadas_por_sublinha) e constantes usamALL_CAPS
(TODAS_MAIÚSCULAS) (Veja mais em Guia de Estilo GDScript).C#: Classes, variáveis de exportação e métodos usam PascalCase, campos privados usam _camelCase, variáveis locais e parâmetros usam camelCase (Veja :ref: doc_c_sharp_styleguide). Tenha o cuidado de digitar os nomes dos métodos com precisão ao conectar os sinais.
Configuração da cena
To add a button to our game, we will create a new scene which will include
both a Button and the sprite_2d.tscn
scene we created in
the Criando seu primeiro script lesson.
Crie uma nova cena acessando o menu Cena -> Nova cena.

In the Scene dock, click the 2D Scene button. This will add a Node2D as our root.

In the FileSystem dock, click and drag the sprite_2d.tscn
file you saved
previously onto the Node2D to instantiate it.

We want to add another node as a sibling of the Sprite2D. To do so, right-click on Node2D and select Add Child Node.

Search for the Button node and add it.

O nó é pequeno por padrão. Clique e arraste a alça inferior direita do Button na viewport para redimensioná-lo.

Se você não vir as alças, verifique se a ferramenta de seleção está ativa na barra de ferramentas.

Clique e arraste o botão para aproximá-lo do sprite.
You can also write a label on the Button by editing its Text property in the
Inspector. Enter Toggle motion
.

Sua árvore da cena e o Viewport devem se parecer com isso.

Save your newly created scene as node_2d.tscn
, if you haven't already.
You can then run it with F6 (Cmd + R on macOS).
At the moment, the button will be visible, but nothing will happen if you
press it.
Conectando um sinal no editor
Here, we want to connect the Button's "pressed" signal to our Sprite2D, and we want to call a new function that will toggle its motion on and off. We need to have a script attached to the Sprite2D node, which we do from the previous lesson.
Você pode conectar sinais no painel do Nó. Selecione o nó Botão e, no lado direito do editor, clique na aba "Nó" ao lado do Inspetor.

O painel exibe uma lista de sinais disponíveis no nó selecionado.

Clique duas vezes no sinal "pressed" para abrir a janela de conexão do nó.

There, you can connect the signal to the Sprite2D node. The node needs a receiver method, a function that Godot will call when the Button emits the signal. The editor generates one for you. By convention, we name these callback methods "_on_node_name_signal_name". Here, it'll be "_on_button_pressed".
Nota
Ao conectar sinais por meio do encaixe do nó do editor, você pode usar dois modos. O simples permite apenas conectar-se a nós que possuem um script anexado a eles e cria uma nova função de retorno de chamada neles.

O avançado permite conectar-se a qualquer nó e qualquer função integrada, adicionar argumentos ao retorno de chamada e definir opções. Você pode alternar o modo no canto inferior esquerdo da janela clicando no botão Avançado.
Nota
If you are using an external editor (such as VS Code), this automatic code generation might not work. In this case, you need to connect the signal via code as explained in the next section.
Clique no botão Conectar para concluir a conexão do sinal e vá para a área de trabalho Script. Você deve ver o novo método com um ícone de conexão na margem esquerda.

Se você clicar no ícone, uma janela aparecerá e exibirá informações sobre a conexão. Este recurso está disponível apenas ao conectar nós no editor.

Vamos substituir a linha com a palavra-chave pass
com o código que alternará o movimento do nó.
Our Sprite2D moves thanks to code in the _process()
function. Godot provides
a method to toggle processing on and off: Node.set_process(). Another method of the Node class,
is_processing()
, returns true
if idle processing is active. We can use
the not
keyword to invert the value.
func _on_button_pressed():
set_process(not is_processing())
// We also specified this function name in PascalCase in the editor's connection window.
private void OnButtonPressed()
{
SetProcess(!IsProcessing());
}
Esta função alternará o processamento e, por sua vez, o movimento do ícone ligado e desligado ao pressionar o botão.
Antes de testar o jogo, precisamos simplificar nossa função _process()
para mover o nó automaticamente e não esperar pela entrada do usuário. Substitua-o pelo seguinte código, que vimos duas lições atrás:
func _process(delta):
rotation += angular_speed * delta
var velocity = Vector2.UP.rotated(rotation) * speed
position += velocity * delta
public override void _Process(double delta)
{
Rotation += _angularSpeed * (float)delta;
var velocity = Vector2.Up.Rotated(Rotation) * _speed;
Position += velocity * (float)delta;
}
Your complete sprite_2d.gd
code should look like the following.
extends Sprite2D
var speed = 400
var angular_speed = PI
func _process(delta):
rotation += angular_speed * delta
var velocity = Vector2.UP.rotated(rotation) * speed
position += velocity * delta
func _on_button_pressed():
set_process(not is_processing())
using Godot;
public partial class MySprite2D : Sprite2D
{
private float _speed = 400;
private float _angularSpeed = Mathf.Pi;
public override void _Process(double delta)
{
Rotation += _angularSpeed * (float)delta;
var velocity = Vector2.Up.Rotated(Rotation) * _speed;
Position += velocity * (float)delta;
}
// We also specified this function name in PascalCase in the editor's connection window.
private void OnButtonPressed()
{
SetProcess(!IsProcessing());
}
}
Execute a cena agora e clique no botão para ver o sprite andar e parar.
Conectando um sinal via código
Você pode conectar sinais via código em vez de usar o editor. Isso é necessário quando você cria nós ou instancia cenas dentro de um script.
Vamos usar um nó diferente aqui. Godot tem um nó Timer que é útil para implementar o tempo de resfriamento de habilidades, recarga de armas e muito mais.
Head back to the 2D workspace. You can either click the "2D" text at the top of the window or press Ctrl + F1 (Ctrl + Cmd + 1 on macOS).
In the Scene dock, right-click on the Sprite2D node and add a new child node. Search for Timer and add the corresponding node. Your scene should now look like this.

With the Timer node selected, go to the Inspector and enable the Autostart property.

Click the script icon next to Sprite2D to jump back to the scripting workspace.

Precisamos fazer duas operações para conectar os nós via código:
Get a reference to the Timer from the Sprite2D.
Call the
connect()
method on the Timer's "timeout" signal.
Nota
To connect to a signal via code, you need to call the connect()
method of the signal you want to listen to. In this case, we want to
listen to the Timer's "timeout" signal.
We want to connect the signal when the scene is instantiated, and we can do that using the Node._ready() built-in function, which is called automatically by the engine when a node is fully instantiated.
Para obter uma referência a um nó relativo ao atual, usamos o método Node.get_node(). Podemos armazenar a referência em uma variável.
func _ready():
var timer = get_node("Timer")
public override void _Ready()
{
var timer = GetNode<Timer>("Timer");
}
The function get_node()
looks at the Sprite2D's children and gets nodes by
their name. For example, if you renamed the Timer node to "BlinkingTimer" in the
editor, you would have to change the call to get_node("BlinkingTimer")
.
We can now connect the Timer to the Sprite2D in the _ready()
function.
func _ready():
var timer = get_node("Timer")
timer.timeout.connect(_on_timer_timeout)
public override void _Ready()
{
var timer = GetNode<Timer>("Timer");
timer.Timeout += OnTimerTimeout;
}
The line reads like so: we connect the Timer's "timeout" signal to the node to
which the script is attached. When the Timer emits timeout
, we want to call
the function _on_timer_timeout()
, that we need to define. Let's add it at the
bottom of our script and use it to toggle our sprite's visibility.
Nota
Por convenção, nomeamos estes métodos de callback em GDScript como "_on_nome_do_no_nome_do_sinal" e em C# como "OnNomeDoNoNomeDoSinal". Aqui, ele será "_on_timer_timeout para GDScript e OnTimerTimeout() para C#.
func _on_timer_timeout():
visible = not visible
private void OnTimerTimeout()
{
Visible = !Visible;
}
A propriedade visible
é um booleano que controla a visibilidade do nosso nó. A linha visible = not visible
alterna o valor. Se visible
for true
, torna-se false
, e vice-versa.
If you run the Node2D scene now, you will see that the sprite blinks on and off, at one second intervals.
Script completo
That's it for our little moving and blinking Godot icon demo!
Here is the complete sprite_2d.gd
file for reference.
extends Sprite2D
var speed = 400
var angular_speed = PI
func _ready():
var timer = get_node("Timer")
timer.timeout.connect(_on_timer_timeout)
func _process(delta):
rotation += angular_speed * delta
var velocity = Vector2.UP.rotated(rotation) * speed
position += velocity * delta
func _on_button_pressed():
set_process(not is_processing())
func _on_timer_timeout():
visible = not visible
using Godot;
public partial class MySprite2D : Sprite2D
{
private float _speed = 400;
private float _angularSpeed = Mathf.Pi;
public override void _Ready()
{
var timer = GetNode<Timer>("Timer");
timer.Timeout += OnTimerTimeout;
}
public override void _Process(double delta)
{
Rotation += _angularSpeed * (float)delta;
var velocity = Vector2.Up.Rotated(Rotation) * _speed;
Position += velocity * (float)delta;
}
// We also specified this function name in PascalCase in the editor's connection window.
private void OnButtonPressed()
{
SetProcess(!IsProcessing());
}
private void OnTimerTimeout()
{
Visible = !Visible;
}
}
Sinais personalizados
Nota
Esta seção é uma referência sobre como definir e usar seus próprios sinais e não se baseia no projeto criado nas lições anteriores.
Você pode definir sinais personalizados em um script. Digamos, por exemplo, que você deseja mostrar uma tela de game over quando a saúde do jogador chegar a zero. Para fazer isso, você pode definir um sinal chamado "died" ou "health_depleted" quando a saúde chegar a 0.
extends Node2D
signal health_depleted
var health = 10
using Godot;
public partial class MyNode2D : Node2D
{
[Signal]
public delegate void HealthDepletedEventHandler();
private int _health = 10;
}
Nota
Como os sinais representam eventos que acabaram de ocorrer, geralmente usamos um verbo de ação no pretérito em seus nomes.
Seus sinais funcionam da mesma forma que os integrados: eles aparecem na guia Nó e você pode se conectar a eles como qualquer outro.

To emit a signal in your scripts, call emit()
on the signal.
func take_damage(amount):
health -= amount
if health <= 0:
health_depleted.emit()
public void TakeDamage(int amount)
{
_health -= amount;
if (_health <= 0)
{
EmitSignal(SignalName.HealthDepleted);
}
}
Um sinal também pode opcionalmente declarar um ou mais argumentos. Especifique os nomes dos argumentos entre parênteses:
extends Node2D
signal health_changed(old_value, new_value)
var health = 10
using Godot;
public partial class MyNode : Node
{
[Signal]
public delegate void HealthChangedEventHandler(int oldValue, int newValue);
private int _health = 10;
}
Nota
Os argumentos de sinal aparecem na aba nó do editor e o Godot pode usá-los para gerar funções de retorno de chamada para você. No entanto, você ainda pode emitir qualquer número de argumentos ao emitir sinais. Então cabe a você emitir os valores corretos.
To emit values along with the signal, add them as extra arguments to the
emit()
function:
func take_damage(amount):
var old_health = health
health -= amount
health_changed.emit(old_health, health)
public void TakeDamage(int amount)
{
int oldHealth = _health;
_health -= amount;
EmitSignal(SignalName.HealthChanged, oldHealth, _health);
}
Resumo
Qualquer nó em Godot emite sinais quando algo específico acontece com eles, como um botão sendo pressionado. Outros nós podem se conectar a sinais individuais e reagir a eventos selecionados.
Os sinais têm muitos usos. Com eles, você pode reagir a um nó entrando ou saindo do mundo do jogo, a uma colisão, a um personagem entrando ou saindo de uma área, a um elemento da interface que muda de tamanho e muito mais.
Por exemplo, um Area2D representando uma moeda emite um sinal body_entered
sempre que o corpo físico do jogador entra em forma de colisão, permitindo que você saiba quando o jogador a coletou.
Na próxima seção, doc_your_first_game, você criará um jogo completo contendo vários usos de sinais para conectar diferentes componentes do jogo.