Menu
CoddyTech

带参数的信号

本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 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")

参数会向监听器提供所需的数据,因此监听器不必从发出信号的对象中读取数据。不要连接使用发出信号的对象本身的 lambda,例如 hero.died.connect(func(): print(hero.hp)):这个 lambda 会让 hero 保持存活,hero 又会保留这个 lambda,两者都不会被释放,而且 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 在线编译器