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...
Примірник із сигналами
Сигнали забезпечують спосіб відокремлення ігрових об’єктів, що дозволяє уникнути примусового фіксованого розташування вузлів. Однією з ознак того, що може знадобитися сигнал, є те, що ви використовуєте get_parent(). Звернення безпосередньо до батьківського вузла означає, що ви не можете легко перемістити цей вузол в інше місце в дереві сцени. Це може бути особливо проблематично, коли ви створюєте екземпляри об’єктів під час виконання та можете розмістити їх у довільному місці в дереві запущеної сцени.
Нижче ми розглянемо приклад такої ситуації: стрільба кулями.
Приклад зйомки
Розглянемо персонаж гравця, який може обертатися та стріляти в бік миші. Щоразу, коли натискається кнопка миші, ми створюємо екземпляр кулі в місці розташування гравця. Дивіться Створення екземплярів для деталей.
Ми будемо використовувати Area2D для кулі, яка рухається прямолінійно із заданою швидкістю:
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;
}
}
Однак, якщо кулі додаються як діти гравця, вони залишаться «прикріпленими» до гравця, коли він обертається:
Натомість нам потрібно, щоб кулі не залежали від руху гравця — після пострілу вони мають рухатися по прямій лінії, і гравець більше не зможе на них впливати. Замість того, щоб додавати кулю до дерева сцен як дочірню для гравця, доцільніше додати кулю як дочірню для «основної» ігрової сцени, яка може бути батьківською для гравця або навіть вище в дереві.
Ви можете зробити це, додавши кулю безпосередньо до головної сцени:
var bullet_instance = Bullet.instantiate()
get_parent().add_child(bullet_instance)
Node bulletInstance = Bullet.Instantiate();
GetParent().AddChild(bulletInstance);
Однак це призведе до іншої проблеми. Тепер, якщо ви спробуєте самостійно протестувати свою сцену «Програвач», вона вийде з ладу під час зйомки, оскільки немає батьківського вузла для доступу. Це значно ускладнює незалежне тестування коду вашого гравця, а також означає, що якщо ви вирішите змінити структуру вузла вашої основної сцени, батьківський вузол гравця може більше не бути відповідним вузлом для отримання куль.
Вирішення цього полягає у використанні сигналу для «випромінювання» куль від гравця. Тоді гравцеві не потрібно «знати», що станеться з кулями після цього — будь-який вузол, підключений до сигналу, може «отримати» кулі та вжити відповідних дій, щоб їх породити.
Ось код для гравця, який використовує сигнали для випуску кулі:
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());
}
}
У головній сцені ми підключаємо сигнал гравця (він з’явиться у вкладці «Вузол» Інспектора)
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);
}
Тепер кулі рухатимуться незалежно від обертання гравця: