Godot 系列导航
想按顺序学习,可以先看合集,再根据当前任务跳到对应主题:
- 使用 AI Codex 开发 Godot 游戏入门:从环境搭建到瓦片地图的文章合集
- DeepSeek V4 Flash 做 Godot 游戏 Demo:几毛钱能跑通到什么程度?
- Godot 游戏开发入门:从节点、场景到第一个 2D 小游戏
- GodotPrompter:给 AI 编码助手补上 Godot 项目经验
- gd-agentic-skills:把 Godot 开发经验拆成 AI 可调用的技能
- Godot 新手起步:用 VS Code 和 Codex 扩展开发 2D 游戏
- Godot Agent Skill 对比:haxqer/godot-skill、agent-skill-godot 与 GD-Agentic-Skills 该装哪个
- Godot 标准版和 .NET 版怎么选:GDScript、C# 与导出平台对比
- Godot 渲染器怎么选:Forward+、Mobile 和 Compatibility 对比
- Godot 信号是什么:signal、connect 和 emit 用法详解
- Godot 瓦片地图入门:TileMapLayer、TileSet、碰撞和 Codex 辅助开发
- Godot Tileset AI 生成提示词:可直接复制的瓦片素材图集 Prompt
- 如何让 AI 用 tileset 拼出完整场景:结构合理、道路连通、可导入 Godot 的提示词 Godot 中的“信号”可以理解成节点发出的通知:
某件事情发生了,谁关心这件事,谁就来处理。
例如:
- 按钮:我被点击了。
- 金币:我被玩家收集了。
- 玩家:我的生命值改变了。
- 敌人:我死亡了。
- 计时器:时间到了。
其他节点可以连接这些信号,并在信号发出时执行一个函数。发送者不需要直接找到接收者,这能减少节点之间的相互依赖。
信号的三个核心步骤
一个完整的信号流程通常有三步:
- 声明信号。
- 连接信号。
- 发出信号。
可以把它想象成门铃:
| 概念 | 类比 |
|---|---|
signal |
安装门铃 |
connect |
把门铃接到屋内响铃器 |
emit |
按下门铃 |
| 接收函数 | 屋里的人听到后开门 |
所以最重要的记忆方式是:
|
|
Godot 有两类信号
Godot 中常见的信号可以分为两类:内置信号和自定义信号。
内置信号
内置信号是 Godot 节点本身已经提供的信号。
常见例子:
Button.pressedTimer.timeoutArea2D.body_enteredArea2D.body_exited
如果金币节点继承自 Area2D,那么它天然就有 body_entered 信号。当 CharacterBody2D 进入金币的碰撞区域时,Godot 会自动发出这个信号。
自定义信号
自定义信号由我们自己声明。
例如金币被收集:
|
|
这个 collected 不是 Godot 自带的,而是我们自己定义的通知类型。
金币示例中的两层信号
一个简单的金币脚本可以这样写:
|
|
这里实际使用了两层信号。
第一层:body_entered
这句代码:
|
|
意思是:
当有物理对象进入 Coin 的
Area2D时,调用_on_body_entered()。
流程如下:
|
|
传入的 body 就是进入金币区域的节点。如果 Player 进入金币区域,那么:
|
|
第二层:collected
这句代码:
|
|
是在声明信号,表示 Coin 可以发出一个名叫 collected 的通知。
接着:
|
|
表示正式发出通知:
这个金币已经被收集了。
但要注意:发出信号,不代表一定有人接收。
如果没有节点连接 collected,它仍然会发出,但不会产生额外效果。金币之所以消失,是因为后面还有:
|
|
并不是因为 collected.emit() 会自动让金币消失。
完整通信流程
金币被玩家碰到以后,完整流程是:
|
|
这里有两个发送者:
|
|
body_entered 负责告诉 Coin:“有东西进入了你的区域。”
collected 负责告诉 Main:“这个金币被收集了。”
怎样让 Main 接收金币信号
假设场景结构如下:
|
|
可以用编辑器连接,也可以用代码连接。
方法一:在 Godot 编辑器里连接
打开 main.tscn。
第一步,选中场景树里的:
|
|
第二步,在右侧面板从“检查器”切换到:
|
|
英文界面是:
|
|
第三步,找到自定义信号:
|
|
双击它。
第四步,选择接收节点:
|
|
点击“连接”。Godot 会在 Main 的脚本中生成类似函数:
|
|
把它改成:
|
|
运行后,收集金币时会输出:
|
|
方法二:用代码连接信号
也可以不通过编辑器,直接在 main.gd 中连接:
|
|
核心代码是:
|
|
它表示:
|
|
Godot 4 推荐直接通过 Signal 对象调用 connect(),例如:
|
|
不要照搬一些 Godot 3 老教程里的旧写法。
让信号携带数据
信号不只能通知“事情发生了”,还可以携带数据。
例如不同金币分值不同:
|
|
普通金币可以设置:
|
|
大金币可以设置:
|
|
Main 接收时也要增加参数:
|
|
通信过程:
|
|
为什么不让 Coin 直接修改 UI
不推荐这样写:
|
|
因为这样会让 Coin 依赖 Main 的具体节点结构:
- Coin 必须知道
ScoreLabel在哪里。 - Coin 必须知道分数如何保存。
- Coin 必须知道 UI 怎样更新。
只要你移动 UI 节点,Coin 的路径就可能失效。
更好的结构是:
|
|
也就是:
|
|
这正是信号降低节点耦合的作用。
最容易混淆的三个概念
signal
声明一个信号:
|
|
相当于创建一种通知类型。
connect()
指定信号发出后调用哪个函数:
|
|
emit()
正式发出信号:
|
|
记忆方式:
|
|
推荐的金币代码
coin.gd:
|
|
main.gd:
|
|
最核心的一句话是:
信号负责通知发生了什么,不负责决定所有节点接下来怎么做。
理解这一点后,Godot 里的按钮、金币、敌人、计时器、生命值、UI 更新,都可以用信号组织得更清晰。