Up to date
This page is up to date for Godot 4.2
.
If you still find outdated information, please open an issue.
Instancing with signals¶
Сигналы обеспечивают способ развязки игровых объектов, позволяя вам избежать принудительного фиксированного расположения узлов. Одним из признаков того, что сигнал может быть востребован, является использование get_parent()
. Прямая ссылка на родителя узла означает, что вы не можете легко переместить этот узел в другое место в дереве сцены. Это может быть особенно проблематично, если вы создаете объекты во время выполнения и хотите поместить их в произвольное место в дереве сцены.
Below we'll consider an example of such a situation: firing bullets.
Пример стрельбы¶
Consider a player character that can rotate and shoot towards the mouse. Every time the mouse button is clicked, we create an instance of the bullet at the player's location. See Создание экземпляров for details.
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;
}
}
Однако, если пули добавятся как дети игрока, то они останутся "привязанными" к тому как игрок вращается (нагляднее ниже):
Вместо этого, нам нужно чтобы пули были независимыми от движения игрока после выстрела, они должны продолжать движение по прямой линии, и игрок больше не должен влиять на них. Вместо того, чтобы быть добавлены к дереву сцены в качестве ребенка игрока, имеет больше смысла добавить пулю в качестве дочернего элемента "основной" игровой сцены, которая может быть родителем игрока или даже дальше выше по дереву сцен.
You could do this by adding the bullet to the main scene directly:
var bullet_instance = Bullet.instantiate()
get_parent().add_child(bullet_instance)
Node bulletInstance = Bullet.Instantiate();
GetParent().AddChild(bulletInstance);
Однако это приведет к другой проблеме. Теперь, если вы попытаетесь протестировать сцену "Player" самостоятельно, она потерпит крах при съемке, поскольку нет родительского узла для доступа. Это значительно усложняет самостоятельное тестирование кода игрока, а также означает, что если вы решите изменить структуру узлов вашей основной сцены, родительский узел игрока может перестать быть подходящим узлом для получения пуль.
Решение заключается в использовании сигнала, сообщающего об "испускании" пули от игрока. Игроку не нужно "знать", что происходит с пулями. Узел подключенный сигналом может "получить" пули и предпринять соответствующие действия для их порождения.
Вот код для игрока с использованием сигналов для испускания пуль:
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);
}
Теперь пули будут продолжать свое собственное движение независимо от вращения игрока: