新闻详情

新闻详情

首页 / 资讯中心 / 详情

GDScript 入门笔记(十):信号

发布时间:2026/9/7 21:42:35来源:尧图网络
GDScript 入门笔记(十):信号
在 Godot 里写游戏逻辑迟早会遇到一个情况某个事件发生了其他节点需要知道并做出反应。比如玩家按了按钮门开了敌人死了分数增加了计时器到时间了角色能行动了。这些“发生了什么”的通信Godot 提供了一套专门的机制叫信号signal。信号本质上就是事件的广播系统某个节点发出一个信号其他关心这个信号的节点可以提前连接并收到通知。这篇笔记就聊聊信号怎么用怎么自定义信号以及它在实际项目里的好处。一、为什么需要信号假设你有一个玩家节点当玩家死亡时你要做很多事情播放死亡动画、更新 UI、扣除生命数、显示游戏结束画面。如果不用信号你可能会在玩家脚本里直接去调用其他节点的函数比如func die(): $AnimationPlayer.play(die) $UI.update_score() $GameManager.player_died()这样写玩家脚本就不得不知道动画、UI、游戏管理器这些节点的存在耦合很紧。一旦这些节点改了名字或结构玩家脚本也得跟着改。信号解决了这个问题。玩家只需要在死亡时发射一个信号比如died而关心这个信号的其他节点各自在自己的脚本里连接这个信号并处理玩家根本不需要知道它们是谁。这种模式让代码更容易维护和扩展也是 Godot 官方推荐的做法。二、信号的基本概念信号是 Godot 对象所有继承自Object的类包括节点的一种特殊属性。你可以把信号理解成一个“事件名称”当事件发生时用emit_signal()把它发射出去所有连接到这个信号的函数都会被调用。发射信号由某个对象发起通知“某件事发生了”。连接信号其他对象监听这个信号当信号发射时它们注册的函数就会被执行。一个信号可以连接多个函数同一个函数也可以连接到多个信号。三、使用内置信号Godot 的很多节点自带信号比如按钮的pressed、计时器的timeout、碰撞体的body_entered。这些信号我们不需要定义直接连接就能用。代码连接最常见的方式是在_ready()里用connect()方法连接信号。extends Node2D onready var button $Button func _ready(): button.pressed.connect(_on_button_pressed) func _on_button_pressed(): print(按钮被按下了)button.pressed是按钮节点的信号。.connect(_on_button_pressed)把这个信号连接到_on_button_pressed函数。当按钮被按下pressed信号发射_on_button_pressed就会被调用。连接的方法名没有强制要求但通常以_on_开头表示这是一个信号回调方便阅读。编辑器连接在 Godot 编辑器里你也可以通过“节点”面板的“信号”页签来连接信号。选中节点点击信号旁边的“连接”然后选择目标节点和方法编辑器会自动生成连接代码。这样更直观但代码连接更灵活、可读性更好尤其在动态创建节点时。四、自定义信号除了内置信号你也可以在脚本中定义自己的信号。语法是用signal关键字写在成员变量区域。extends Node2D signal health_changed(new_health) signal died定义信号时可以带参数表示发射信号时会传递的数据。health_changed带一个参数new_health而died不带参数。发射自定义信号用emit_signal()发射信号参数按定义时的顺序传递。func take_damage(amount): health - amount emit_signal(health_changed, health) if health 0: emit_signal(died)第一个参数是信号名字符串后面是信号携带的参数。注意信号名字不要写错否则会报错。为了安全也可以用emit_signal(health_changed, health)但 GDScript 4 支持直接用信号名health_changed.emit(health)更简洁也能避免拼写错误。使用信号名直接发射推荐GDScript 4 中signal定义后可以像调用方法一样使用.emit()发射不需要用字符串health_changed.emit(health) died.emit()这样更安全编辑器也会检查。五、连接自定义信号连接自定义信号和连接内置信号一样用connect()。# 在另一个节点脚本中 onready var player $Player func _ready(): player.health_changed.connect(_on_player_health_changed) player.died.connect(_on_player_died) func _on_player_health_changed(new_health): print(玩家血量变化, new_health) func _on_player_died(): print(玩家死了)连接时回调函数的参数需要和信号定义的参数匹配。如果信号带一个参数回调函数也要有一个参数。六、断开信号如果不再需要接收信号可以用disconnect()断开连接。player.health_changed.disconnect(_on_player_health_changed)通常在节点销毁前如果连接的信号来自其他对象最好手动断开但 Godot 在节点释放时会自动断开相关连接如果是对象间的连接当接收者被释放时自动断开。不过如果你手动管理连接还是显式断开更清晰。七、信号连接的几种写法1. 使用connect()方法这是最标准的方式上面已经演示。2. 使用 lambda 表达式GDScript 4 支持用 lambda 作为回调适合简单逻辑不用单独定义函数。button.pressed.connect(func(): print(按钮被按下) )如果信号带参数lambda 也可以接收player.health_changed.connect(func(new_health): print(血量:, new_health) )3. 使用Callable可以把函数引用存成变量再连接。var callback Callable(self, _on_button_pressed) button.pressed.connect(callback)不过最常用的还是直接方法名。八、信号参数的传递信号可以传递任意数量和类型的参数。定义时写参数名发射时按顺序传入连接时回调函数按顺序接收。signal player_scored(player_name, points) func _ready(): player_scored.emit(Tom, 10) func _on_player_scored(player_name, points): print(player_name, 获得 , points, 分)参数个数必须匹配否则连接时会出错或运行时报错。九、await 与信号GDScript 的await关键字可以暂停函数执行直到某个信号发射。这常用于协程式逻辑比如等待按钮点击再继续。func wait_for_button(): await button.pressed print(按钮终于被按了)这行代码会让函数暂停在await处直到button.pressed信号发射然后继续执行后面的代码。await还可以获取信号参数如果信号带参数func wait_for_health_change(): var new_health await player.health_changed print(血量变化为:, new_health)注意await会挂起整个函数的执行但不会阻塞主线程其他节点的逻辑照常运行。它是实现异步逻辑的好工具。十、信号与代码解耦实例假设我们有一个游戏管理器需要知道玩家死亡和得分事件。不用信号时管理器要引用玩家节点。用信号后玩家只负责发信号管理器连接信号即可。玩家脚本class_name Player extends CharacterBody2D signal died signal score_changed(new_score) var score 0 func add_score(amount): score amount score_changed.emit(score) func die(): died.emit() queue_free()游戏管理器脚本extends Node onready var player $Player func _ready(): player.died.connect(_on_player_died) player.score_changed.connect(_on_score_changed) func _on_player_died(): print(游戏结束) func _on_score_changed(new_score): print(当前分数, new_score)这样玩家脚本完全不知道管理器的存在管理器只依赖玩家的信号。当玩家死亡管理器自动收到通知耦合度大大降低。十一、信号使用中的注意事项发射信号时必须确保有连接吗不需要。如果没人连接发射信号不会做任何事也不会报错。信号发射是同步的所有连接的回调会立即执行执行完毕后emit_signal()才返回。所以不要在回调里做可能无限递归的事情。连接要避免重复如果同一个信号连接了同一个函数两次信号发射时函数会被调用两次。需要小心尤其是在动态连接时可能无意识重复连接。可以在连接前先检查is_connected()。回调函数不要依赖顺序多个回调的执行顺序不保证不要依赖。信号名命名习惯用过去式或事件名比如died、health_changed、item_picked_up。十二、总结信号是 Godot 中最重要的通信机制它让节点之间解耦代码更清晰。这篇笔记涵盖了信号的概念和为什么使用信号使用内置信号自定义信号及发射连接和断开信号信号参数的传递await与信号的结合实际解耦示例掌握信号后你会发现写游戏逻辑时少了很多“找节点”的烦恼。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

C语言文件操作全解析:从流模型到实战避坑指南 2026/9/8 1:49:21

C语言文件操作全解析:从流模型到实战避坑指南

很多人学C语言,学到指针就觉得到头了,结果一写到文件读写就卡壳。我自己带过几个实习生,问fopen返回NULL怎么办,有人直接回答“报错呗”,再往下问errno、perror、文本模式和二进制模式的区别,基本就没人能接…

阅读更多 →
KPanel 实战:多窗口终端 + AI 运维的 Linux 服务器管理 2026/9/8 1:49:21

KPanel 实战:多窗口终端 + AI 运维的 Linux 服务器管理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
STM32F407工程模板搭建:从CubeMX到日志与I2C模块 2026/9/8 1:49:21

STM32F407工程模板搭建:从CubeMX到日志与I2C模块

简介:STM32F407工程模板是一套基于Cortex-M4内核的预配置Keil MDK开发框架,面向嵌入式开发入门者、电子类专业学生以及需要快速验证外设功能的软硬件工程师。模板将项目常用的底层配置、启动文件、HAL库封装和链接脚本打包在一起,可直接应用于…

阅读更多 →
crass-0.4.14.0:经典游戏资源解包工具原理与实操指南 2026/9/8 1:49:21

crass-0.4.14.0:经典游戏资源解包工具原理与实操指南

简介:面向视觉小说玩家与游戏资源爱好者的GALGAME资源提取工具crass 0.4.14.0,带有图形界面CrageGUI,可解析并提取游戏包中加密或定制的图像、音频与剧本文件,解决普通解压软件无法直接读取这些封装资源的痛点。资源为rar压缩包&a…

阅读更多 →
用 Electron 打造 UDP 数据报调试工具:主进程与 dgram 模块实战解析 2026/9/8 1:49:21

用 Electron 打造 UDP 数据报调试工具:主进程与 dgram 模块实战解析

简介:这是一份基于Electron构建的UDP调试工具源码包,面向需要在桌面端快速创建多个UDP客户端和服务器的JavaScript开发者。工具支持任意主机与端口添加实例,内置随机数据生成器,可按固定时间间隔自动发送数据报,非常适…

阅读更多 →
Docker镜像构建全流程实战:从分层原理到生产级优化 2026/9/8 1:46:21

Docker镜像构建全流程实战:从分层原理到生产级优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞