SuperAPI AI 工具集

godot-signal-architecture

编程与开发

查看项目

更新于 10-15 18:28

技能介绍

用途

本技能提供 Godot 引擎中信号驱动架构的专家级蓝图,围绕“Signal Up, Call Down”(信号向上、调用向下)模式实现节点间的松耦合。适用于实现事件系统或解耦节点,关键词包括 signal、emit、connect、CONNECT_ONE_SHOT、CONNECT_REFERENCE_COUNTED、event bus、AutoLoad、decoupling。

核心原则

  • 子节点 → 父节点:使用过去时信号(如 health_changed、died)。
  • 父节点 → 子节点:使用直接调用或属性(如 apply_damage、play_anim)。
  • 兄弟节点:通过父级中介或谨慎限定范围的 Autoload 总线,绝不使用兄弟硬引用。

信号适用于:UI 按下、死亡 → 游戏结束、拾取 → 库存、跨场景总线事件。直接调用适用于:父级命令子级、本地属性访问。

禁止事项(NEVER Do)

  • 绝不使用遗留的基于字符串的 Object.connect()——拼写错误会导致静默失败。始终使用 signal.connect(_callback) 以获得编译期校验。
  • 绝不使用信号自上而下地规定行为——信号是过去时事件(如“died”)。命令(如“kill”)应使用直接方法调用。
  • 绝不将同一信号连接到同一 Callable 两次——除非使用 Object.CONNECT_REFERENCE_COUNTED 标志堆叠连接,否则运行时会抛出 ERR_INVALID_PARAMETER。
  • 绝不为本地数据使用全局信号总线——会污染全局状态并增加调试难度。场景特定逻辑应使用本地连接。
  • 绝不假设回调必须接受所有信号参数——使用 unbind() 丢弃不需要的参数以保持 API 整洁。
  • 绝不创建循环信号依赖——A 信号 B,B 又信号回 A?使用中介(父级或 AutoLoad)打破循环。
  • 绝不跳过信号类型标注——signal moved 不带类型会缺少编辑器支持。始终使用 signal moved(dir: Vector2)。
  • 绝不忘记断开动态信号——幽灵连接会导致“call on null instance”错误。在 _exit_tree() 中或重定向时断开。
  • 绝不在发射器上发射带即时副作用的信号——如果 died.emit() 调用 queue_free(),监听者可能无法响应。应先发射。
  • 绝不为高频数据流使用信号——每秒发送 1000+ 信号(如逐粒子更新)效率低下。应使用共享数组或直接缓冲区。

连接位置决策树

范围 模式 强制脚本
子节点通知父节点 / UI 父节点 _ready 中的本地 signal.connect signal_up_call_down_pattern.gd
父节点编排子节点 向下方法调用(非信号) 同上
跨场景 / 系统(成就、存档) Autoload 总线 global_signal_bus_router.gd / global_event_bus.gd
线性异步步骤(加载 → 淡出 → 生成) await 信号序列 await_signal_sequencing.gd / complex_signal_sequencer.gd
重定向跟踪(新敌人) 先断开旧的 disconnect_ghost_signals.gd
一次性 / 物理安全 CONNECT_ONE_SHOT / CONNECT_DEFERRED one_shot_deferred_connections.gd
额外上下文 / 丢弃参数 Callable.bind / unbind callable_bind_context.gd / unbind_unwanted_args.gd

可用脚本

  • signal_up_call_down_pattern.gd——层级接线前必读。
  • global_signal_bus_router.gd / global_event_bus.gd——Autoload 总线前必读。
  • disconnect_ghost_signals.gd——切换被跟踪发射器时必读。
  • await_signal_sequencing.gd / complex_signal_sequencer.gd——多步 await 时必读。
  • safe_dynamic_connections.gd——is_connected 守卫。
  • one_shot_deferred_connections.gd——一次性 / 延迟标志。
  • callable_bind_context.gd / unbind_unwanted_args.gd——bind/unbind。
  • track_signal_emitter_source.gd——CONNECT_APPEND_SOURCE_OBJECT。
  • signal_debugger.gd / signal_spy.gd——调试 / 测试间谍。

Lambda 捕获清理

Godot 在节点释放时会自动断开大多数连接。例外:捕获局部变量的 lambda——必须手动断开。

var my_lambda: Callable

func _ready() -> void:
    var x := 10
    my_lambda = func(): print(x)
    player.died.connect(my_lambda)

func _exit_tree() -> void:
    if player and player.died.is_connected(my_lambda):
        player.died.disconnect(my_lambda)

重定向时优先使用命名方法或 disconnect_ghost_signals.gd。

CONNECT_REFERENCE_COUNTED 的正确语义

CONNECT_REFERENCE_COUNTED 表示多次相同连接共享一个带引用计数的连接(连接 N 次 / 断开 N 次)。它并非“发射器释放时自动清理”,也不能修复捕获 lambda 的泄漏。

  • 释放时自动清理:对 Object 方法的普通连接(非捕获)在任一方释放时被清除。
  • 捕获 lambda:始终手动 disconnect(见上)。
  • 发射后自动移除:CONNECT_ONE_SHOT。

深入配方(按需)

模式 1–7 及注意事项见 references/implementation-patterns.md。

参考

官方文档

  • Using signals——核心 emit/connect 模型,以及信号为何能在无硬引用下解耦节点。
  • Scene organization——规范的“signal up, call down”所有权规则,保持父→子命令流明确。
  • Instancing with signals——从生成的场景发射,使父级/管理器无需固定节点路径即可接收子弹、战利品等产物。
  • Autoloads versus regular nodes——何时全局 EventBus 合理,何时场景本地信号接线更安全。
  • Singletons (Autoload)——如何注册跨场景存活的类型化信号总线。
  • Signal——类型化 Signal API:emit、connect、is_connected 及断开辅助方法。
  • Callable——bind() / unbind() 用于注入或丢弃回调上下文,无需包装 lambda。
  • Object——CONNECT_ONE_SHOT、CONNECT_DEFERRED、CONNECT_REFERENCE_COUNTED 和 CONNECT_APPEND_SOURCE_OBJECT 标志。
  • GDScript basics——类型化 signal 声明及对信号 await 实现线性异步序列。
  • Using SceneTree——连接在进入/退出树时的生命周期,以及动态监听器重定向时为何必须断开。
  • Godot notifications——相对于 _ready、父级缓存和用户信号的安全连接时机。
  • Idle and Physics Processing——当回调在物理步中修改物理体时,延迟信号处理器为何重要。

相关技能

前置:godot-project-foundations、godot-gdscript-mastery、godot-autoload-architecture。

互补:godot-composition、godot-scene-management、godot-state-machine-advanced、godot-resource-data-patterns、godot-testing-patterns、godot-ui-containers。

下游/消费者:godot-dialogue-system、godot-ability-system、godot-combat-system、godot-performance-optimization。

大师:godot-master。