Up to date
This page is up to date for Godot 4.2
.
If you still find outdated information, please open an issue.
Instanziierung mit Signalen¶
Signale bieten eine Möglichkeit, Spielobjekte zu entkoppeln, so dass Sie eine feste Anordnung von Nodes vermeiden können. Ein Anzeichen dafür, dass ein Signal notwendig sein könnte, ist, wenn Sie get_parent()
verwenden. Ein direkter Verweis auf den Elternteil eines Nodes bedeutet, dass man diesen Node nicht einfach an eine andere Stelle im Szenenbaum verschieben kann. Dies kann besonders problematisch sein, wenn Sie Objekte zur Laufzeit instanziieren und sie an einer beliebigen Stelle im laufenden Szenenbaum platzieren möchten.
Im Folgenden betrachten wir ein Beispiel für eine solche Situation: das Abfeuern von Geschossen.
Beispiel für Geschosse¶
Nehmen wir eine Spielerfigur, die sich drehen und in Richtung der Maus schießen kann. Jedes Mal, wenn die Maustaste geklickt wird, erstellen wir eine Instanz des Geschosses an der Position des Spielers. Siehe Instanzen erstellen für Details.
Wir verwenden ein Area2D
für das Geschoss, das sich mit einer bestimmten Geschwindigkeit in einer geraden Linie bewegt:
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;
}
}
Wenn die Geschosse jedoch als Child-Elemente des Spielers hinzugefügt werden, bleiben sie an dem Spieler "gebunden", während er sich dreht:
Stattdessen müssen die Geschosse unabhängig von der Bewegung des Spielers sein - einmal abgefeuert, sollten sie sich weiterhin in einer geraden Linie bewegen und der Spieler kann sie nicht mehr beeinflussen. Anstatt das Geschoss als Child-Element des Spielers in den Szenenbaum hinzuzufügen, ist es sinnvoller, das Geschoss als Child-Element der "Haupt"-Spielszene hinzuzufügen, die entweder das übergeordnete Objekt des Spielers oder sogar weiter oben im Baum sein kann.
Sie können dies tun, indem Sie das Geschoss direkt hinzufügen:
var bullet_instance = Bullet.instantiate()
get_parent().add_child(bullet_instance)
Node bulletInstance = Bullet.Instantiate();
GetParent().AddChild(bulletInstance);
Dies führt jedoch zu einem anderen Problem. Wenn Sie nun versuchen, Ihre "Spieler"-Szene unabhängig voneinander zu testen, stürzt sie beim Schießen ab, da es keinen Parent-Node gibt, auf den Sie zugreifen können. Dies macht es viel schwieriger, den Spieler-Code unabhängig zu testen. Wenn Sie sich entscheiden, die Node-Struktur der Hauptszene zu ändern, ist das Parent-Element des Spielers möglicherweise nicht mehr der geeignete Node, um das Geschoss zu empfangen.
Die Lösung dafür ist, ein Signal zu verwenden, um die Geschosse vom Spieler "abzufeuern". Der Spieler muss dann nicht "wissen", was danach mit den Geschossen geschieht. Jeder Node, der mit dem Signal verbunden ist, kann die Geschosse "empfangen" und entsprechende Aktionen durchführen, um sie zu erzeugen.
Hier ist der Code für den Spieler, der Signale verwendet, um das Geschoss auszusenden:
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 der Hauptszene verbinden wir dann das Signal des Spielers (es erscheint im "Node"-Tab des Inspektors)
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);
}
Jetzt werden die Geschosse ihre Bewegung beibehalten, unabhängig von der Rotation des Spielers: