带参数的信号
本课属于 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 会在程序结束时报告实例泄漏。
挑战
简单钱包会通过信号报告每次变化,并携带相关数字。在 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])
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: GDScript 在线编译器