Up to date
This page is up to date for Godot 4.2
.
If you still find outdated information, please open an issue.
Instanciando com sinais¶
Signals provide a way to decouple game objects, allowing you to avoid forcing a
fixed arrangement of nodes. One sign that a signal might be called for is when
you find yourself using get_parent()
. Referring directly to a node's parent
means that you can't easily move that node to another location in the scene tree.
This can be especially problematic when you are instancing objects at runtime
and may want to place them in an arbitrary location in the running scene tree.
Below we'll consider an example of such a situation: firing bullets.
Exemplo de Disparo¶
Considere um personagem de jogador que possa girar e atirar em direção ao mouse. Toda vez que o botão do mouse é clicado, criamos uma instância do projétil no local do jogador. Veja Criando instâncias para detalhes.
We'll use an Area2D
for the bullet, which moves in a straight line at a
given velocity:
extends Area2D
var velocity = Vector2.RIGHT
func _physics_process(delta):
position += velocity * delta
using Godot;
public partial class Bullet : Area2D
{
public Vector2 Velocity { get; set; } = Vector2.Right;
public override void _PhysicsProcess(double delta)
{
Position += Velocity * (float)delta;
}
}
Entretanto, se as balas forem anexadas ao jogador, então elas continuarão "anexadas" ao jogador enquanto ele gira:
Ao contrário disso, nós precisamos que as balas sejam independentes do movimento do jogador - uma vez disparadas, elas devem continuar se movendo em linha reta e o jogador não pode mais afetá-las. Invés de serem adicionadas a árvore da cena como filha do jogador, faz mais sentido adicionar as balas como filha da cena "principal" do jogo, a qual deve ser o nó pai do jogador ou em uma hierarquia mais alta.
Você poderia fazer isso adicionando a bala diretamente à cena principal:
var bullet_instance = Bullet.instantiate()
get_parent().add_child(bullet_instance)
Node bulletInstance = Bullet.Instantiate();
GetParent().AddChild(bulletInstance);
No entanto, isto levará a um problema diferente. Agora, se você tentar testar sua cena "Player" de forma independente, ela cairá ao disparar, porque não há um nó pai para acessar. Isto torna muito mais difícil testar seu código de jogador independentemente e também significa que se você decidir mudar a estrutura do nó principal de sua cena, o nó pai do jogador pode não ser mais o nó apropriado para receber as balas.
A solução para isso é usar um sinal para "emitir" as balas do jogador. Com isso não há mais necessidade do jogador "saber" o que acontece com as balas depois de disparadas - qualquer nó que estiver conectado ao sinal pode "receber" as balas e tomar a ação apropriada para gerar elas.
Aqui está o código para o jogador usar sinais para emitir a bala:
extends Sprite2D
signal shoot(bullet, direction, location)
var Bullet = preload("res://bullet.tscn")
func _input(event):
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
shoot.emit(Bullet, rotation, position)
func _process(delta):
look_at(get_global_mouse_position())
using Godot;
public partial class Player : Sprite2D
{
[Signal]
public delegate void ShootEventHandler(PackedScene bullet, float direction, Vector2 location);
private PackedScene _bullet = GD.Load<PackedScene>("res://Bullet.tscn");
public override void _Input(InputEvent @event)
{
if (@event is InputEventMouseButton mouseButton)
{
if (mouseButton.ButtonIndex == MouseButton.Left && mouseButton.Pressed)
{
EmitSignal(SignalName.Shoot, _bullet, Rotation, Position);
}
}
}
public override void _Process(double delta)
{
LookAt(GetGlobalMousePosition());
}
}
In the main scene, we then connect the player's signal (it will appear in the "Node" tab of the Inspector)
func _on_player_shoot(Bullet, direction, location):
var spawned_bullet = Bullet.instantiate()
add_child(spawned_bullet)
spawned_bullet.rotation = direction
spawned_bullet.position = location
spawned_bullet.velocity = spawned_bullet.velocity.rotated(direction)
private void OnPlayerShoot(PackedScene bullet, float direction, Vector2 location)
{
var spawnedBullet = bullet.Instantiate<Bullet>();
AddChild(spawnedBullet);
spawnedBullet.Rotation = direction;
spawnedBullet.Position = location;
spawnedBullet.Velocity = spawnedBullet.Velocity.Rotated(direction);
}
Agora as balas terão seu movimento conservado independente da rotação do jogador: