关于 godot-signals-groups
面向 Godot 4.7 开发者的技能指南,介绍如何用信号和组解耦节点,并集中处理多个节点。内容涵盖连接模式、广播及常见错误。
主要功能
- 01使用类型化信号传递事件
- 02通过 Callable 连接信号
- 03用组向多个节点广播
- 04等待信号后继续执行
- 05避免重复连接与失效监听器
适用场景
- 01让拾取物通知游戏状态更新
- 02一次暂停或统计一组敌人
- 03在动画信号完成后生成战利品
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill godot-signals-groups安装后在 Claude Code 中输入/godot-signals-groups确认已加载。
附带文件references/signal-patterns.md
详细介绍
Godot 信号与分组(4.x)
使用观察者模式(信号)和分组(groups)解耦节点,并同时对多个节点执行操作,而不是在场景之间硬编码引用。目标版本为 Godot 4.7。
适用场景
- 当某个节点需要告知其他节点“发生了某件事”(玩家死亡、拾取物品、波次结束),但又不想持有对它们的直接引用时使用。
- 当你需要同时操作一整类节点时(“暂停所有敌人”“保存每个检查点”)。
不适用场景: 信号的基础语法 → godot-gdscript;场景结构和实例化 → godot-nodes-scenes。对于跨场景全局事件,请从自动加载项发出信号(参见 godot-nodes-scenes)。
核心工作流
- 确定方向。 子节点/子场景应向上发出信号;父节点负责连接信号。这样子节点可以复用,无需知道谁在监听。
- 在发出信号的节点上声明带类型的信号;事件发生时调用
emit()发出信号。 - 使用 Callable 进行连接(
sig.connect(_on_sig)),也可以在编辑器的 Node 面板中连接。使用CONNECT_ONE_SHOT实现仅触发一次的连接,使用bind()传递额外上下文。 - 使用分组进行广播:将节点添加到命名分组,然后遍历
get_tree().get_nodes_in_group(...)或调用call_group(...)。 - 按需断开连接(例如,在释放长期存在的监听节点之前),并检查
is_connected()以避免重复连接。
模式
1. 向上发出信号,由父节点连接
# coin.gd (reusable pickup — knows nothing about the player or HUD)
extends Area2D
signal collected(value: int)
func _on_body_entered(body: Node) -> void:
if body.is_in_group("player"):
collected.emit(10)
queue_free()
# level.gd (the parent wires the coin to game state)
func _ready() -> void:
for coin in get_tree().get_nodes_in_group("coins"):
coin.collected.connect(_on_coin_collected)
func _on_coin_collected(value: int) -> void:
GameState.add_score(value)
2. 连接标志:仅触发一次并绑定额外参数
func _ready() -> void:
# Fire exactly once, then auto-disconnect.
$Door.opened.connect(_on_door_opened, CONNECT_ONE_SHOT)
# bind() appends arguments supplied at connect time (after the signal's own args).
$RedButton.pressed.connect(_on_button.bind("red"))
func _on_button(color: String) -> void:
print("Pressed the %s button" % color)
3. 分组:向多个节点广播
func pause_all_enemies() -> void:
# Call a method on every node in the "enemies" group (no-op if missing).
get_tree().call_group("enemies", "set_paused", true)
func count_enemies() -> int:
return get_tree().get_nodes_in_group("enemies").size()
可以通过代码或编辑器的 Node > Groups 选项卡将节点添加到分组:
func _ready() -> void:
add_to_group("enemies") # remove_from_group("enemies") to leave
4. 内联等待信号
func open_chest() -> void:
$AnimationPlayer.play("open")
await $AnimationPlayer.animation_finished # pause until it emits
spawn_loot()
常见问题
- 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 在已连接对象释放时自动断开连接(节点会自动断开)。
- 分组是 SceneTree 全局共享的,而非场景独有。两个使用相同分组名称的关卡会共享成员。如果有需要,请为分组名称添加命名空间。
call_group会静默忽略缺少相应方法的节点。 方法名称拼错时不会报错——如果需要确保契约成立,请优先使用带类型的信号。- 信号参数必须匹配。 使用错误的参数数量或类型发出信号会导致错误;请声明带类型的参数,并按声明准确发出信号。
参考资料
- 有关连接标志、延迟连接、自定义信号参数、带超时等待信号,以及信号与直接调用的权衡,请阅读
references/signal-patterns.md。
相关技能
godot-gdscript— 信号和await的语法基础。godot-nodes-scenes— 用于全局事件总线的自动加载项。game-ai— 常用于驱动和接收这些事件的状态机。
评论
支持 Markdown