godot-signals-groups

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Godot Signals & Groups (4.x)

Godot 信号与节点组(4.x版本)

Decouple nodes with the observer pattern (signals) and act on many nodes at once (groups), instead of hard-coding references between scenes. Targets Godot 4.3+.
通过观察者模式(信号)实现节点解耦,并通过节点组一次性操作多个节点,替代场景间硬编码引用。适用于**Godot 4.3+**版本。

When to use

适用场景

  • Use when a node needs to tell others "something happened" (player died, item picked up, wave cleared) without holding direct references to them.
  • Use when you need to address a whole category of nodes at once ("pause all enemies", "save every checkpoint").
When not to use: raw signal syntax basics →
godot-gdscript
; scene structure and instancing →
godot-nodes-scenes
. For cross-scene global events, emit from an autoload (see
godot-nodes-scenes
).
  • 当某个节点需要告知其他节点“发生了某件事”(比如玩家死亡、物品拾取、关卡波次完成),但无需持有这些节点的直接引用时使用。
  • 当你需要一次性操作某一类节点时使用(比如“暂停所有敌人”、“保存所有 checkpoint”)。
不适用场景:信号基础语法 → 参考
godot-gdscript
;场景结构与实例化 → 参考
godot-nodes-scenes
。跨场景全局事件可通过自动加载(autoload)节点发送(见
godot-nodes-scenes
)。

Core workflow

核心工作流程

  1. Decide the direction. A child/sub-scene should emit a signal upward; the parent connects to it. This keeps the child reusable and ignorant of who listens.
  2. Declare typed signals on the emitter;
    emit()
    them when the event occurs.
  3. Connect with a Callable (
    sig.connect(_on_sig)
    ), optionally in the editor's Node dock. Use
    CONNECT_ONE_SHOT
    for fire-once,
    bind()
    to pass extra context.
  4. Use groups for broadcast: add nodes to a named group, then iterate
    get_tree().get_nodes_in_group(...)
    or
    call_group(...)
    .
  5. Disconnect when needed (e.g. before freeing a long-lived listener) and check
    is_connected()
    to avoid duplicate connections.
  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()
    检查避免重复连接。

Patterns

常见模式

1. Emit upward, connect from the parent

1. 向上发送信号,父节点连接

gdscript
undefined
gdscript
undefined

coin.gd (reusable pickup — knows nothing about the player or HUD)

coin.gd(可复用的拾取物——无需知晓玩家或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()

```gdscript
extends Area2D signal collected(value: int)
func _on_body_entered(body: Node) -> void: if body.is_in_group("player"): collected.emit(10) queue_free()

```gdscript

level.gd (the parent wires the coin to game state)

level.gd(父节点将金币与游戏状态关联)

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)
undefined
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)
undefined

2. Connect flags: one-shot and bind extra arguments

2. 连接标记:一次性连接与绑定额外参数

gdscript
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)
gdscript
func _ready() -> void:
    # 仅触发一次,之后自动断开连接。
    $Door.opened.connect(_on_door_opened, CONNECT_ONE_SHOT)
    # bind()会将连接时传入的参数追加到信号自身参数之后。
    $RedButton.pressed.connect(_on_button.bind("red"))

func _on_button(color: String) -> void:
    print("Pressed the %s button" % color)

3. Groups: broadcast to many nodes

3. 节点组:向多个节点广播

gdscript
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()
Add a node to a group from code or via the editor's Node > Groups tab:
gdscript
func _ready() -> void:
    add_to_group("enemies")        # remove_from_group("enemies") to leave
gdscript
func pause_all_enemies() -> void:
    # 调用"enemies"组中所有节点的set_paused方法(节点无该方法时无操作)。
    get_tree().call_group("enemies", "set_paused", true)

func count_enemies() -> int:
    return get_tree().get_nodes_in_group("enemies").size()
可通过代码或编辑器的Node > Groups标签页将节点添加到组中:
gdscript
func _ready() -> void:
    add_to_group("enemies")        # 调用remove_from_group("enemies")可退出组

4. Await a signal inline

4. 内联等待信号

gdscript
func open_chest() -> void:
    $AnimationPlayer.play("open")
    await $AnimationPlayer.animation_finished   # pause until it emits
    spawn_loot()
gdscript
func open_chest() -> void:
    $AnimationPlayer.play("open")
    await $AnimationPlayer.animation_finished   # 暂停执行直到信号发送
    spawn_loot()

Pitfalls

常见陷阱

  • 3.x connect signature is gone.
    connect("died", self, "_on_died")
    died.connect(_on_died)
    . The target is implied by the Callable. The legacy
    Object.connect("died", Callable(self, "_on_died"))
    works but the method-name string form does not.
  • Duplicate connections fire handlers multiple times. Connecting again in
    _ready()
    after re-adding a node stacks callbacks. Guard with
    if not sig.is_connected(cb): sig.connect(cb)
    .
  • Connecting to a freed node errors. Disconnect long-lived listeners, or rely on Godot auto-disconnecting when the connected object is freed (it does for nodes).
  • Groups are global to the SceneTree, not per-scene. Two levels using the same group name share membership. Namespace group names if that matters.
  • call_group
    silently ignores nodes lacking the method.
    Typos in the method name fail quietly — prefer a typed signal when the contract matters.
  • Signal args must match. Emitting with the wrong arg count/types raises an error; declare typed params and emit exactly those.
  • 3.x版本的connect签名已移除。原写法
    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

参考资料

  • For connection flags, deferred connections, custom signal arguments, awaiting with timeouts, and signals vs. direct calls trade-offs, read
    references/signal-patterns.md
    .
  • 关于连接标记、延迟连接、自定义信号参数、带超时的await以及信号与直接调用的权衡,可阅读
    references/signal-patterns.md

Related skills

相关技能

  • godot-gdscript
    — signal/
    await
    syntax fundamentals.
  • godot-nodes-scenes
    — autoloads for global event buses.
  • game-ai
    — state machines that often drive and consume these events.
  • godot-gdscript
    —— 信号/
    await
    语法基础。
  • godot-nodes-scenes
    —— 用于全局事件总线的自动加载节点。
  • game-ai
    —— 常驱动并消费这些事件的状态机。