Godot 信号与节点组
将以下提示词粘贴到你的 AI 对话框中:
请根据 https://skillhub.cn/install/skillhub.md,安装 @user_3c6cb52e/godot-signals-groups-sh-xj3104
技能介绍
要解决的具体问题
写"事件发生、多个节点要响应"时,最常见的写法是让节点互相 get_node() 拿引用:敌人持有玩家引用,UI 持有血条引用。场景一复用引用链就断,节点忘了释放还会留下悬空引用。另一个反复出现的问题是"一次操作一类节点"——暂停全部敌人、保存全部检查点——通常只能遍历场景树找标签,既脆弱又慢。
这份技能用两种机制覆盖这两个场景:信号负责单向解耦("某件事发生了"),节点组负责按类别广播("对这一类全部做点什么")。
技能怎么用
核心流程分五步:
- 定方向:子节点/子场景向上
emit,父节点负责connect。孩子因此保持可复用,不需要知道谁在监听。 - 声明类型化信号:在发射者上声明信号,事件发生时调用
emit()。 - 用 Callable 连接:
sig.connect(_on_sig),也可以在编辑器 Node dock 里连。一次性回调用CONNECT_ONE_SHOT,要带额外上下文用bind()。 - 节点组广播:把节点加进命名组,然后迭代
get_tree().get_nodes_in_group(...),或直接call_group(...)。组可以从代码加,也可以在编辑器 Node > Groups 标签里加。 - 按需断开:长生命周期监听者在释放前断开,并用
is_connected()检查,避免重复连接。
适用边界与坑
- 3.x 的连接签名已经移除:
connect("died", self, "_on_died")要改成died.connect(_on_died),Callable 里隐含了目标。旧的Object.connect("died", Callable(self, "_on_died"))还能用,但方法名字符串形式不行了。 - 重复连接会让回调触发多次:在
_ready()里反复重连会叠加回调,用if not sig.is_connected(cb): sig.connect(cb)兜住。 - 连到已释放节点会报错:要么手动断开,要么依赖 Godot 在被连对象释放时自动断开(对 Node 是生效的)。
- 组是 SceneTree 全局的,不是每个场景一份。不同层级用了同名组会共享成员,需要时给组名加命名空间。
call_group会静默忽略没有该方法的节点:方法名写错了不会报错,契约重要时优先用类型化信号。- 信号参数必须匹配:数量或类型不对会直接报错,声明和
emit()要保持一致。
另外注意边界:信号语法本身的基础用法归 godot-gdscript,场景结构和实例化归 godot-nodes-scenes;跨场景的全局事件建议从 autoload 发出。连接标志、延迟连接、自定义信号参数、带超时的 await,以及信号与直接调用的取舍,写在 references/signal-patterns.md 里。
使用场景
- 开发波次生存游戏:玩家死亡时要同时通知 UI、存档和敌人 AI,不能在敌人节点里硬编码玩家引用。
- 做暂停功能:点击暂停需要停掉场上所有敌人的 AI,想用节点组一次广播而不是逐节点找标签。
- 设计可复用子场景:陷阱和门作为独立场景放进多个关卡,向上发信号让父关卡决定扣血或播放动画。
- 修复重复触发 bug:同一个检查点被连续踩两次导致存档写了两遍,需要用 is_connected 防止重复连接。
适合人员
- 独立游戏开发者:场景间引用缠成网,新关卡复用旧组件就报错,想用信号和组把耦合拆开。
- 从 Godot 3.x 迁移的老项目作者:connect 旧签名全面报错,需要按 Callable 写法逐个迁移连接代码。
- 波次或 roguelike 玩法的小型团队:需要对场上所有敌人、所有检查点做整体暂停和批量操作。
- Game AI 课程讲师:要给学生讲清事件通知和组广播的正确姿势,以及重复连接、全局组名这类坑。