mcpField
G
godot-signals-groups

godot-signals-groups

github.com/gamedev-skills开发5.4k6.9k 次安装1 天前更新
代码仓库

关于 godot-signals-groups

面向 Godot 4.7 开发者的技能指南,介绍如何用信号和组解耦节点,并集中处理多个节点。内容涵盖连接模式、广播及常见错误。

主要功能

  1. 01使用类型化信号传递事件
  2. 02通过 Callable 连接信号
  3. 03用组向多个节点广播
  4. 04等待信号后继续执行
  5. 05避免重复连接与失效监听器

适用场景

  1. 01让拾取物通知游戏状态更新
  2. 02一次暂停或统计一组敌人
  3. 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)。

核心工作流

  1. 确定方向。 子节点/子场景应向上发出信号;父节点负责连接信号。这样子节点可以复用,无需知道谁在监听。
  2. 在发出信号的节点上声明带类型的信号;事件发生时调用 emit() 发出信号。
  3. 使用 Callable 进行连接(sig.connect(_on_sig)),也可以在编辑器的 Node 面板中连接。使用 CONNECT_ONE_SHOT 实现仅触发一次的连接,使用 bind() 传递额外上下文。
  4. 使用分组进行广播:将节点添加到命名分组,然后遍历 get_tree().get_nodes_in_group(...) 或调用 call_group(...)。
  5. 按需断开连接(例如,在释放长期存在的监听节点之前),并检查 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