Menu
CoddyTech

Сигналы с аргументами

Часть раздела Объектно-ориентированное программирование путешествия по GDScript на Coddy. Урок 38 из 65.

Сигнал может передавать значения. Перечисли их в объявлении, как параметры функции:

signal damaged(amount: int, hp_left: int)
signal died

Передай значения в emit() в том же порядке:

func take_damage(amount: int) -> void:
	hp = maxi(hp - amount, 0)
	damaged.emit(amount, hp)
	if hp == 0:
		died.emit()

Подключённая функция получает значения в качестве параметров, поэтому для каждого значения ей нужен отдельный параметр:

hero.damaged.connect(_on_hero_damaged)

func _on_hero_damaged(amount: int, hp_left: int) -> void:
	print("-%d HP, %d left" % [amount, hp_left])

Типы в объявлении документируют значения: GDScript не проверяет их при отправке сигнала. Несоответствие обнаруживается в принимающей функции. Функция с неправильным количеством параметров или типизированным параметром, который не может содержать это значение, вызывает ошибку в строке с emit(), и эта функция не выполняется.

bind() добавляет ваши собственные значения после переданных сигналом. Тогда один метод может слушать нескольких героев и при этом знать, кого из них ударили:

ada.damaged.connect(_on_damaged.bind("Ada"))
bo.damaged.connect(_on_damaged.bind("Bo"))

func _on_damaged(amount: int, hp_left: int, who: String) -> void:
	print(who, " lost ", amount, " HP")

Аргументы передают слушателю необходимые данные, поэтому ему не нужно считывать их у отправителя сигнала. Никогда не подключай лямбда-функцию, которая использует сам объект, отправляющий сигнал, например hero.died.connect(func(): print(hero.hp)): лямбда-функция удерживает hero в памяти, hero удерживает лямбда-функцию, ни один из них никогда не освобождается, и Godot сообщает об утёкших экземплярах при завершении программы.

challenge icon

Задание

Легко

Кошелёк сообщает о каждом изменении с помощью сигналов, которые передают числовые значения. В Wallet добавь параметры к обоим сигналам и напиши два метода:

  • balance_changed(old_balance: int, new_balance: int) и purchase_failed(price: int, missing: int)
  • add(amount) добавляет монеты и отправляет сигнал balance_changed с балансом до и после изменения.
  • buy(price): если баланса достаточно, вычти стоимость и отправь сигнал balance_changed. Иначе ничего не меняй и отправь сигнал purchase_failed, передав стоимость и количество недостающих монет.

Предоставленный код подключает по одной функции к каждому сигналу, считывает количество следующих команд, выполняет каждую команду (add 20, buy 15) и в конце выводит оставшееся количество монет. Для add 20, buy 15, buy 10, add 5, buy 10 он выводит:

Balance: 0 -> 20
Balance: 20 -> 5
Cannot buy for 10: 5 coins missing
Balance: 5 -> 10
Balance: 10 -> 0
Coins left: 0

Твой код нужно написать в wallet.gd. В main.gd находится предоставленный код ввода/вывода, и его нельзя редактировать.

Попробуйте сами

extends Node

func _ready():
	# Предоставленный код ввода/вывода: оставьте его без изменений
	var wallet := Wallet.new()
	wallet.balance_changed.connect(_on_balance_changed)
	wallet.purchase_failed.connect(_on_purchase_failed)
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var parts := OS.read_string_from_stdin().split(" ")
		if parts[0] == "add":
			wallet.add(int(parts[1]))
		else:
			wallet.buy(int(parts[1]))
	print("Coins left: ", wallet.balance)

func _on_balance_changed(old_balance: int, new_balance: int) -> void:
	print("Balance: %d -> %d" % [old_balance, new_balance])

func _on_purchase_failed(price: int, missing: int) -> void:
	print("Cannot buy for %d: %d coins missing" % [price, missing])
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор GDScript