信号系统

信号系统

信号是 Godot 中实现松耦合事件处理的核心机制。

什么是信号

信号是一种观察者模式,允许节点在特定事件发生时通知其他对象。

内置信号

许多节点都有内置信号,可以直接连接。

# Button 节点
button.pressed.connect(_on_button_pressed)
button.toggled.connect(_on_button_toggled)

# Timer 节点
timer.timeout.connect(_on_timer_timeout)

# Area2D 节点
area2D.body_entered.connect(_on_body_entered)
area2D.body_exited.connect(_on_body_exited)

# AnimationPlayer
animation_player.animation_finished.connect(_on_animation_finished)

# 纹理按钮
texture_button.button_down.connect(_on_button_down)
texture_button.button_up.connect(_on_button_up)

自定义信号

定义信号

extends Node

# 定义信号
signal health_changed(new_value: int)
signal died()
signal item_collected(item_name: String, value: int)

发射信号

# 发射不带参数的信号
died.emit()

# 发射带参数的信号
health_changed.emit(50)
item_collected.emit("Coin", 10)

连接信号

# 在代码中连接
func _ready() -> void:
    health_changed.connect(_on_health_changed)
    died.connect(_game_over)

信号回调函数

func _on_health_changed(new_value: int) -> void:
    update_health_bar(new_value)

func _game_over() -> void:
    show_game_over_screen()

在编辑器中连接信号

  1. 选择节点
  2. 在右侧面板找到 "Node" 标签
  3. 双击想要连接的信号
  4. 选择接收信号的对象
  5. 选择回调函数

断开信号

# 断开特定连接
signal_name.disconnect(callback_function)

# 断开所有连接(需要手动管理)

信号参数

# 多个参数
signal player_data(name: String, level: int, exp: int)

player_data.emit("Hero", 5, 1000)

信号传递

向父节点发送信号

# 子节点
signal request_action()

# 连接父节点方法
func _ready() -> void:
    request_action.connect(get_parent()._handle_action)

跨场景通信

# 使用全局单例或信号总线
# Global.gd
extends Node

signal player_died()
signal level_completed(level: int)

# 任何节点都可以访问
Global.player_died.connect(show_game_over)

信号最佳实践

  1. 使用有意义的名称health_changedchanged 更清晰
  2. 参数类型明确:在信号定义中指定参数类型
  3. 及时断开:不再需要时断开信号连接,避免内存泄漏
  4. 单一职责:每个信号处理一件事情

常用场景示例

extends Area2D

signal coin_collected(value: int)

func _on_body_entered(body: Node2D) -> void:
    if body.is_in_group("player"):
        coin_collected.emit(10)
        queue_free()
extends CharacterBody2D

signal health_changed(current: int, max_health: int)
signal died

var health: int = 100
var max_health: int = 100

func take_damage(amount: int) -> void:
    health -= amount
    health_changed.emit(health, max_health)
    if health <= 0:
        died.emit()
        queue_free()

Callable 对象(Godot 4)

# 使用 Callable 对象
var callable = Callable(self, "_on_timeout")
timer.timeout.connect(callable)