什么是信号?
本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 35 课,共 65 课。
游戏运行时,对象会发生各种变化:金币被收集,门打开,英雄的 hp 降到 0。程序的其他部分会对这些事件做出反应:分数增加,播放声音,出现游戏结束画面。
信号是对象在发生某件事时发送的消息。对象会发出信号,所有连接到该信号的函数都会运行:
# coin.gd
class_name Coin
extends RefCounted
signal collected
func collect() -> void:
print("Coin picked up")
collected.emit()signal collected 声明了信号,collected.emit() 会发送信号。硬币不知道谁在监听。关心硬币的代码会将自己的一个函数连接到这个信号:
# main.gd
func _ready():
var coin := Coin.new()
coin.collected.connect(_on_coin_collected)
coin.collect()
print("Done")
func _on_coin_collected() -> void:
print("Score +1")输出为 Coin picked up、Score +1、Done。发出信号会立即运行已连接的函数,在 emit() 后的那一行之前执行。没有连接任何函数的信号发出时不会执行任何操作。
如果没有信号,collect() 就必须自己调用计分代码,因此每个金币都需要引用计分板。有了信号后,金币只需发出事件通知,任意数量的监听器都可以响应该事件,也可以没有监听器响应。
Godot 自带的节点也是以同样的方式工作的:点击 Button 时会发出 pressed,计时结束时 Timer 会发出 timeout。
挑战
简单邮箱通过信号通知有新邮件。Mailbox 已声明 signal mail_arrived,并且有一个 letters 计数器。编写 deliver(kind):
- 当
kind是"letter"时,将1加到letters,并发出mail_arrived。 - 其他类型(广告、传单)都会被丢弃:计数不变,也不会发出信号。
提供的代码会连接一个打印 You've got mail! 的函数,然后读取后续行数并逐行投递。away 这一行会断开该函数的连接,home 则会重新连接它,因此你不在家时收到的信件会计数,但不会发出通知。输入以下几行:letter、ad、away、letter,程序会打印:
Delivering: letter
You've got mail!
Delivering: ad
Delivering: letter
Letters: 2将代码写在 mailbox.gd 中。main.gd 包含提供的输入/输出代码,不能编辑。
亲手试试
extends Node
func _ready():
# 提供的输入输出代码:保持原样。
var mailbox := Mailbox.new()
mailbox.mail_arrived.connect(_on_mail_arrived)
var count := int(OS.read_string_from_stdin())
for i in count:
var line := OS.read_string_from_stdin()
if line == "away":
mailbox.mail_arrived.disconnect(_on_mail_arrived)
elif line == "home":
mailbox.mail_arrived.connect(_on_mail_arrived)
else:
print("Delivering: ", line)
mailbox.deliver(line)
print("Letters: ", mailbox.letters)
func _on_mail_arrived() -> void:
print("You've got mail!")
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: GDScript 在线编译器