信号(Signal)是Godot引擎中最强大、最重要的机制之一,它实现了观察者模式,让节点之间可以松耦合地通信。本教程将通过实际案例,带你全面掌握Godot中的信号使用方法。
什么是信号?
信号是一种事件通知机制。当一个节点发生某些事情时(比如按钮被点击、分数改变、动画播放完成等),它可以发出一个信号,其他节点可以"监听"这个信号,并在信号发出时执行相应的代码。
信号的核心优势:
- 解耦:节点之间不需要直接引用,降低代码耦合度
- 灵活:一个信号可以被多个节点监听
- 清晰:代码结构更清晰,易于维护
一、内置信号的使用
Godot的许多节点都内置了信号,比如Button节点就有pressed信号。
1.1 场景结构
我们的main.tscn场景包含:
- 一个
Button节点(按钮) - 一个
Label节点(标签),绑定label.gd脚本

1.2 在编辑器中连接信号

选中button后,在节点面板中设置信号
这表示:当Button的pressed信号发出时,调用Label节点的_on_button_pressed方法。
1.3 编写响应函数
在label.gd中,我们定义了响应函数:
extends Label
func _on_button_pressed() -> void:
# 这里就是按钮点后会执行代码的地方
self.text = "按钮被点击啦!!!!!"
运行效果:
- 点击按钮
Button发出pressed信号Label的_on_button_pressed函数被调用- 标签文本更新为"按钮被点击啦!!!!!"
二、自定义信号
除了内置信号,我们还可以创建自己的信号,用于传递自定义事件。
2.1 声明自定义信号
在score_manager.gd中,我们声明了一个带参数的信号:
extends Node
# 声明一个带参数的自定义信号,参数类型是整数 (int)
signal score_updated(new_score: int)
var current_score = 0
2.2 发出信号
当分数改变时,我们发出信号并传递新的分数值:
func increase_score(points: int):
current_score += points
# 当分数改变时,发出信号,并附带新的分数值
emit_signal("score_updated", current_score)
这里使用了emit_signal()函数,第一个参数是信号名称,后面是传递给信号的参数。
注意:在Godot 4中,你也可以直接使用信号名称来发出信号:
score_updated.emit(current_score)
2.3 连接自定义信号
在score_label.gd中,我们连接到这个信号:
extends Label
@onready var score_manager: Node2D = $".." #连接到场景中的根节点ScoreManager
func _ready():
# 在 _ready 函数中连接信号
# 当 score_manager 发出 score_updated 信号时,执行 _on_score_manager_score_updated
score_manager.score_updated.connect(_on_score_manager_score_updated)
# 这是我们响应信号的函数
func _on_score_manager_score_updated(new_score: int):
# 更新 Label 的文本,显示新的分数
self.text = "Score: " + str(new_score)
关键点解析:
@onready:延迟初始化,确保节点树已经构建完成connect():连接信号的方法- 响应函数的参数必须与信号声明的参数一致
2.4 测试信号
在score_manager.gd的_ready函数中,我们测试信号:
func _ready() -> void:
increase_score(10) # ScoreLabel 显示 Score: 10
await get_tree().create_timer(2.0).timeout # 等待2秒
increase_score(5) # ScoreLabel 显示 Score: 15
await get_tree().create_timer(2.0).timeout # 等待2秒
increase_score(5) # ScoreLabel 显示 Score: 20
运行效果:
- 场景加载后,分数立即变为10
- 等待2秒后,分数变为15
- 再等待2秒后,分数变为20
三、信号的两种连接方式
3.1 在编辑器中连接(可视化方式)
步骤:
- 选择要发出信号的节点(如Button)
- 在右侧"节点"面板中,找到"信号"选项卡
- 双击要连接的信号(如pressed)
- 选择接收信号的节点和方法
- Godot会自动生成响应函数的框架代码
优点:
- 可视化操作,直观易懂
- 不需要写连接代码
- 适合简单的信号连接
3.2 在代码中连接(编程方式)
score_manager.score_updated.connect(_on_score_manager_score_updated)
优点:
- 更灵活,可以在运行时动态连接
- 可以传递额外的参数
- 适合复杂的信号连接
四、信号的高级用法
4.1 断开信号连接
如果不再需要监听某个信号,可以断开连接:
score_manager.score_updated.disconnect(_on_score_manager_score_updated)
4.2 一次性信号
使用call_deferred可以让信号只触发一次:
button.pressed.connect(_on_button_pressed, CONNECT_ONE_SHOT)
4.3 信号带多个参数
信号可以传递多个参数:
signal player_died(player_name: String, score: int, cause: String)
emit_signal("player_died", "Player1", 100, "Enemy")
4.4 检查信号是否已连接
if score_manager.score_updated.is_connected(_on_score_manager_score_updated):
print("信号已连接")
五、最佳实践
5.1 命名规范
- 信号名称使用动词形式:
score_updated、player_died、game_over - 响应函数命名:
_on_节点名_信号名,如_on_button_pressed
5.2 什么时候使用信号?
适合使用信号的场景:
- UI交互(按钮点击、输入框变化)
- 游戏状态变化(分数更新、生命值改变)
- 动画事件(动画播放完成、帧事件)
- 碰撞检测(进入/退出碰撞区域)
不适合使用信号的场景:
- 需要返回值的操作
- 高频调用的每帧逻辑(使用
_process或_physics_process)
5.3 性能考虑
信号连接本身开销很小,但要注意:
- 避免在
_process中频繁连接/断开信号 - 大量信号监听者可能影响性能
六、总结
通过本教程,我们学习了:
- 内置信号:使用Godot预定义的信号(如Button的pressed)
- 自定义信号:创建和发出自己的信号
- 信号连接:在编辑器和代码中连接信号
- 信号参数:传递数据给信号监听者
- 高级用法:断开连接、一次性信号、多参数信号
信号是Godot开发中的核心概念,掌握它将让你的代码更加模块化、可维护。
项目文件说明
本教程项目包含以下文件:
main.tscn:演示内置信号(Button pressed)label.gd:响应按钮点击信号score_manager.tscn:演示自定义信号score_manager.gd:定义和发出自定义信号score_label.gd:监听并响应自定义信号
祝你在Godot开发之路上越走越远! 🚀
