Menu
CoddyTech

Подключение к сигналам

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

connect() принимает функцию для выполнения в виде Callable. Укажи метод без скобок или напиши лямбда-функцию:

chest.opened.connect(_on_chest_opened)          # метод этого скрипта
chest.opened.connect(quest_log.add_entry)       # метод другого объекта
chest.opened.connect(func(): print("Creak!"))   # лямбда-функция

Godot называет метод-обработчик: сначала _on_, затем отправитель, а потом сигнал: _on_chest_opened. К сигналу можно подключить множество функций, и они выполняются в том порядке, в котором были подключены.

Объект, который отслеживает сигнал, обычно подключается к нему самостоятельно в методе, получающем источник сигнала:

# quest_log.gd
class_name QuestLog
extends RefCounted

var chests_opened := 0

func track(chest: Chest) -> void:
	if not chest.opened.is_connected(_on_chest_opened):
		chest.opened.connect(_on_chest_opened)

func untrack(chest: Chest) -> void:
	if chest.opened.is_connected(_on_chest_opened):
		chest.opened.disconnect(_on_chest_opened)

func _on_chest_opened() -> void:
	chests_opened += 1

Подключать одну и ту же функцию к одному и тому же сигналу дважды — ошибка, как и отключать функцию, которая не подключена. Сначала проверьте это с помощью is_connected(). disconnect() прекращает прослушивание, и при следующем испускании сигнала эта функция уже не будет запущена.

Передай CONNECT_ONE_SHOT в качестве второго аргумента, и соединение удалится после первого вызова: chest.opened.connect(_on_first_open, CONNECT_ONE_SHOT).

Лямбда сохраняет значение локальной переменной на момент создания лямбды. count += 1 внутри подключённой лямбды изменяет эту копию, а count в _ready() остаётся равным 0. Храни счётчик в переменной-члене объекта-обработчика, как это делает QuestLog.

challenge icon

Задание

Легко

На стрельбище есть мишени, которые при попадании испускают сигнал hit. Напишите ScoreBoard, который будет на них подписываться:

  • watch(target) подключает сигнал hit мишени к _on_target_hit. Повторная подписка на уже отслеживаемую мишень ничего не меняет.
  • ignore(target) отключает сигнал. Отмена подписки на мишень, за которой не следят, ничего не меняет.
  • _on_target_hit() добавляет 10 к points и выводит Hit! Score: N.

Повторная подписка или отмена подписки на мишень, за которой не следят, не должны приводить к ошибке, потому что любая ошибка провалит тест. Файл target.gd уже готов.

Предоставленный код считывает количество мишеней, затем команды, такие как watch 0, ignore 0 и shoot 0, и выводит итоговый счёт. Для двух мишеней и команд watch 0, shoot 0, shoot 1, watch 1, watch 1, shoot 1, ignore 0, shoot 0 программа выводит:

Shot target 0
Hit! Score: 10
Shot target 1
Shot target 1
Hit! Score: 20
Shot target 0
Final score: 20

Ваш код нужно поместить в score_board.gd и target.gd. В main.gd находится предоставленный код ввода-вывода, и его нельзя редактировать.

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

extends Node

func _ready():
	# Предоставленный код ввода-вывода: оставьте его без изменений
	var board := ScoreBoard.new()
	var targets: Array[Target] = []
	for i in int(OS.read_string_from_stdin()):
		targets.append(Target.new())
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var parts := OS.read_string_from_stdin().split(" ")
		var target := targets[int(parts[1])]
		if parts[0] == "watch":
			board.watch(target)
		elif parts[0] == "ignore":
			board.ignore(target)
		else:
			print("Shot target ", parts[1])
			target.shoot()
	print("Final score: ", board.points)
quiz iconПроверьте себя

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

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

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