Signal
Встроенный тип, представляющий сигнал Object.
Описание
Signal — это встроенный тип Variant, который представляет сигнал экземпляра Object. Как и все типы Variant, он может храниться в переменных и передаваться в функции. Сигналы позволяют всем подключенным Callable (и соответственно, их соответствующим объектам) прослушивать и реагировать на события, не ссылаясь напрямую друг на друга. Это сохраняет код гибким и простым в управлении. Вы можете проверить, имеет ли Object заданное имя сигнала, используя Object.has_signal().
В GDScript сигналы можно объявлять с помощью ключевого слова signal. В C# вы можете использовать атрибут [Signal] для делегата.
signal attacked
# Могут быть объявлены дополнительные аргументы.
# Эти аргументы должны быть переданы при отправке сигнала.
signal item_dropped(item_name, amount)
[Signal]
delegate void AttackedEventHandler();
// Могут быть объявлены дополнительные аргументы.
// Эти аргументы должны быть переданы при отправке сигнала.
[Signal]
delegate void ItemDroppedEventHandler(string itemName, int amount);
Подключение сигналов — одна из самых распространенных операций в Godot, и API предоставляет множество вариантов для этого, которые описаны ниже. Блок кода ниже показывает рекомендуемый подход.
func _ready():
var button = Button.new()
# `button_down` здесь — тип Signal Variant. Поэтому мы вызываем метод Signal.connect(), а не Object.connect().
# Более подробный обзор API см. в обсуждении ниже.
button.button_down.connect(_on_button_down)
# Это предполагает, что существует класс `Player`, который определяет сигнал `hit`.
var player = Player.new()
# Мы снова используем Signal.connect(), а также метод Callable.bind(),
# который возвращает новый Callable с параметром binds.
player.hit.connect(_on_player_hit.bind("sword", 100))
func _on_button_down():
print("Кнопка нажата!")
func _on_player_hit(weapon_type, damage):
print("Hit with weapon %s for %d damage." % [weapon_type, damage])
public override void _Ready()
{
var button = new Button();
// C# поддерживает передачу сигналов как событий, поэтому мы можем использовать следующую идиоматическую конструкцию:
button.ButtonDown += OnButtonDown;
// Это предполагает, что существует класс `Player`, который определяет сигнал `Hit`.
var player = new Player();
// Мы можем использовать лямбда-выражения, когда нам нужно привязать дополнительные параметры.
player.Hit += () => OnPlayerHit("sword", 100);
}
private void OnButtonDown()
{
GD.Print("Кнопка нажата!");
}
private void OnPlayerHit(string weaponType, int damage)
{
GD.Print($"Hit with weapon {weaponType} for {damage} damage.");
}
``Object.connect()`` или ``Signal.connect()``?
Как видно выше, рекомендуемый метод для подключения сигналов — не Object.connect(). В блоке кода ниже показаны четыре варианта подключения сигналов с использованием либо этого устаревшего метода, либо рекомендуемого connect(), а также с использованием либо неявного Callable, либо определенного вручную.
func _ready():
var button = Button.new()
# Вариант 1: Object.connect() с неявным вызовом для определенной функции.
button.connect("button_down", _on_button_down)
# Вариант 2: Object.connect() с созданным Callable, использующим целевое имя объекта и метода.
button.connect("button_down", Callable(self, "_on_button_down"))
# Вариант 3: Signal.connect() с неявным вызовом для определенной функции.
button.button_down.connect(_on_button_down)
# Вариант 4: Signal.connect() с созданным Callable, использующим целевое имя объекта и метода.
button.button_down.connect(Callable(self, "_on_button_down"))
func _on_button_down():
print("Кнопка нажата!")
public override void _Ready()
{
var button = new Button();
// Вариант 1: В C# мы можем использовать сигналы как события и подключаться с помощью следующего идиоматического синтаксиса:
button.ButtonDown += OnButtonDown;
// Вариант 2: GodotObject.Connect() с созданным Callable из группы методов.
button.Connect(Button.SignalName.ButtonDown, Callable.From(OnButtonDown));
// Вариант 3: GodotObject.Connect() с созданным Callable, использующим целевое имя объекта и метода.
button.Connect(Button.SignalName.ButtonDown, new Callable(this, MethodName.OnButtonDown));
}
private void OnButtonDown()
{
GD.Print("Кнопка нажата!");
}
Хотя все варианты имеют одинаковый результат (BaseButton.button_down button будет подключен к _on_button_down), вариант 3 предлагает лучшую проверку: он выведет ошибку времени компиляции, если button_down Signal или _on_button_down Callable не определены. С другой стороны, вариант 2 полагается только на имена строк и сможет проверить только одно из имен во время выполнения: он выдаст ошибку во время выполнения, если "button_down" не является сигналом или если "_on_button_down" не является методом в объекте self. Основная причина использования опций 1, 2 или 4 — если вам действительно нужно использовать строки (например, для программного подключения сигналов на основе строк, считанных из файла конфигурации). В противном случае, опция 3 является рекомендуемым (и самым быстрым) методом.
Связывание и передача параметров:
Синтаксис для связывания параметров осуществляется через Callable.bind(), который возвращает копию Callable с привязанными параметрами.
При вызове emit() или Object.emit_signal() также могут быть переданы параметры сигнала. В примерах ниже показана связь между этими параметрами сигнала и привязанными параметрами.
func _ready():
# Это предполагает, что существует класс `Player`, который определяет сигнал `hit`.
var player = Player.new()
# Использование Callable.bind().
player.hit.connect(_on_player_hit.bind("sword", 100))
# Параметры, добавленные при передаче сигнала, передаются в первую очередь.
player.hit.emit("Dark lord", 5)
# При отправке мы передаем два аргумента (`hit_by`, `level`),
# и при подключении привязать еще два аргумента (`weapon_type`, `damage`).
func _on_player_hit(hit_by, level, weapon_type, damage):
print("Hit by %s (level %d) with weapon %s for %d damage." % [hit_by, level, weapon_type, damage])
public override void _Ready()
{
// Это предполагает, что существует класс `Player`, который определяет сигнал `Hit`.
var player = new Player();
// Использование лямбда-выражений, создающих замыкание, которое захватывает дополнительные параметры.
// Лямбда получает только параметры, определенные делегатом сигнала.
player.Hit += (hitBy, level) => OnPlayerHit(hitBy, level, "sword", 100);
// Параметры, добавленные при передаче сигнала, передаются в первую очередь.
player.EmitSignal(SignalName.Hit, "Dark lord", 5);
}
// При отправке мы передаем два аргумента (`hit_by`, `level`),
// и при подключении привязать еще два аргумента (`weapon_type`, `damage`).
private void OnPlayerHit(string hitBy, int level, string weaponType, int damage)
{
GD.Print($"Hit by {hitBy} (level {level}) with weapon {weaponType} for {damage} damage.");
}
Примечание
Существуют заметные различия при использовании данного API с C#. Подробнее см. API различия C# и GDScript.
Обучающие материалы
Конструкторы
Signal() |
|
Signal(object: Object, signal: StringName) |
Методы
void |
disconnect(callable: Callable) |
void |
emit(...) vararg const |
get_connections() const |
|
get_name() const |
|
get_object() const |
|
get_object_id() const |
|
has_connections() const |
|
is_connected(callable: Callable) const |
|
is_null() const |
Операторы
operator !=(right: Signal) |
|
operator ==(right: Signal) |
Описания конструктора
Создает пустой Signal без привязанного имени объекта или сигнала.
Создает Signal как копию заданного Signal.
Signal Signal(object: Object, signal: StringName)
Создает объект Signal, ссылающийся на сигнал с именем signal в указанном object.
Описания метода
int connect(callable: Callable, flags: int = 0) 🔗
Соединяет этот сигнал с указанным callable. Дополнительно можно указать flags для настройки поведения соединения (см. константы ConnectFlags). Вы можете передать дополнительные аргументы в связанный callable, используя Callable.bind().
Сигнал может быть соединён с одним и тем же Callable только один раз. Если сигнал уже соединён, метод вернёт @GlobalScope.ERR_INVALID_PARAMETER и сгенерирует ошибку, за исключением случая, когда сигнал соединён с флагом Object.CONNECT_REFERENCE_COUNTED. Чтобы избежать этого, сначала используйте is_connected() для проверки существующих соединений.
for button in $Buttons.get_children():
button.pressed.connect(_on_pressed.bind(button))
func _on_pressed(button):
print(button.name, " was pressed")
Примечание: Если объект callable освобождён, соединение будет потеряно.
void disconnect(callable: Callable) 🔗
Отключает этот сигнал от указанного Callable. Если соединение не существует, генерирует ошибку. Используйте is_connected(), чтобы убедиться, что соединение существует.
void emit(...) vararg const 🔗
Выдает этот сигнал. Все Callable, подключенные к этому сигналу, будут активированы. Этот метод поддерживает переменное количество аргументов, поэтому параметры можно передавать в виде списка, разделенного запятыми.
Array get_connections() const 🔗
Возвращает Array соединений для этого сигнала. Каждое соединение представлено как Dictionary, который содержит три записи:
signal— ссылка на этот сигнал;callable— ссылка на подключенный Callable;flags— комбинация ConnectFlags.
StringName get_name() const 🔗
Возвращает имя этого сигнала.
Возвращает объект, испускающий этот сигнал.
Возвращает идентификатор объекта, испускающего этот сигнал (см. Object.get_instance_id()).
bool has_connections() const 🔗
Возвращает true, если к этому сигналу подключен какой-либо Callable.
bool is_connected(callable: Callable) const 🔗
Возвращает true, если указанный Callable подключен к этому сигналу.
Возвращает true, если этот Signal не имеет объекта и имя сигнала пустое. Эквивалентно signal == Signal().
Описания оператора
bool operator !=(right: Signal) 🔗
Возвращает true, если сигналы не имеют одного и того же объекта и имени.
bool operator ==(right: Signal) 🔗
Возвращает true, если оба сигнала имеют один и тот же объект и имя.