Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Signal

代表 Object 中某个信号的内置类型。

描述

Signal 是一种内置的 Variant 类型,它代表了一个 Object 实例的信号。和所有的 Variant 类型一样,它可以被存储在变量中,也可以被传递给函数。信号允许所有已连接的 Callable(以及它们各自所属的对象)去监听并响应事件,而无需彼此之间直接引用。这种设计让代码保持了极高的灵活性,也更易于管理。你可以使用 Object.has_signal() 方法来检查一个 Object 是否拥有指定名称的信号。

在 GDScript 中,可以使用 signal 关键字来声明信号;而在 C# 中,则可以在委托(delegate)上使用 [Signal] 特性(Attribute)来定义。

signal attacked

# 也可以声明额外的参数。
# 这些参数在发射信号时必须被传入。
signal item_dropped(item_name, amount)

在 Godot 中,连接信号是最常见的操作之一,API 提供了多种实现方式,下面会做详细介绍。下面的代码块展示了推荐的连接方法。

func _ready():
    var button = Button.new()
    # 这里的 button_down 是一个 Signal(信号)Variant 类型。因此,我们调用的是 Signal.connect() 方法,而不是 Object.connect()。
    # 关于该 API 更深入的介绍,请参见下方的讨论。
    button.button_down.connect(_on_button_down)

    # 这里假设存在一个定义了 `hit` 信号的 `Player` 类。
    var player = Player.new()
    # 我们再次使用了 Signal.connect(),同时还使用了 Callable.bind() 方法。
    # 它会返回一个新的 Callable,并且这个 Callable 已经绑定了相应的参数。
    player.hit.connect(_on_player_hit.bind("sword", 100))

func _on_button_down():
    print("Button down!")

func _on_player_hit(weapon_type, damage):
    print("Hit with weapon %s for %d damage." % [weapon_type, damage])

Object.connect() 还是 Signal.connect()

如上文所示,连接信号的推荐方法并不是 Object.connect()。下面的代码块展示了连接信号的四种选项,分别是使用这种旧版方法或推荐的 connect(),以及使用隐式的 Callable 或手动定义的 Callable

func _ready():
    var button = Button.new()
    # 方法一:使用 Object.connect(),并为定义好的函数隐式创建一个 Callable。
    button.connect("button_down", _on_button_down)
    # 方法二:使用 Object.connect(),并通过指定目标对象和方法名来手动构建一个 Callable。
    button.connect("button_down", Callable(self, "_on_button_down"))
    # 方法三:使用 Signal.connect(),并为定义好的函数隐式创建一个 Callable。
    button.button_down.connect(_on_button_down)
    # 方法四:使用 Signal.connect(),并通过指定目标对象和方法名来手动构建一个 Callable。
    button.button_down.connect(Callable(self, "_on_button_down"))

func _on_button_down():
    print("Button down!")

虽然所有选项的最终结果都一样(buttonBaseButton.button_down 信号都会被连接到 _on_button_down 上),但 选项 3 提供了最好的验证机制:如果 button_down Signal 或者 _on_button_down Callable 没有被定义,它会在编译阶段直接打印出错误。另一方面,选项 2 仅仅依赖于字符串名称,只能在程序运行时进行验证:如果 "button_down" 不是一个信号,或者 "_on_button_down" 不是 self 对象中的一个方法,它会在运行时产生一个错误。使用选项 1、2 或 4 的主要原因,是你确实需要使用字符串(例如,根据从配置文件中读取的字符串来以编程方式连接信号)。除此之外,选项 3 是最推荐(也是最快)的方法。

绑定和传递参数:绑定参数的语法是通过 Callable.bind(),它会返回一个绑定了参数的 Callable 副本。

当调用 emit()Object.emit_signal() 时,也可以传递信号参数。

下面的示例展示了这些信号参数与绑定参数之间的关系。

func _ready():
    # 这里假设存在一个定义了 `hit` 信号的 `Player` 类。
    var player = Player.new()
    # 使用 Callable.bind()。
    player.hit.connect(_on_player_hit.bind("sword", 100))

    # 发射信号时添加的参数会最先传递。
    player.hit.emit("Dark lord", 5)

# 我们在发射信号时传递了两个参数 (`hit_by`, `level`),
# 并在连接信号时绑定了另外两个参数 (`weapon_type`, `damage`)。
func _on_player_hit(hit_by, level, weapon_type, damage):
    print("Hit by %s (level %d) with weapon %s for %d damage." % [hit_by, level, weapon_type, damage])

注意: 在布尔环境下,如果信号为 null(空),它的求值结果将为 false(假)(详见 is_null())。除此之外,信号的求值结果始终为 true(真)。

备注

通过 C# 使用该 API 时会有显著不同,详见 C# API 与 GDScript 的差异

教程

构造函数

Signal

Signal()

Signal

Signal(from: Signal)

Signal

Signal(object: Object, signal: StringName)

方法

int

connect(callable: Callable, flags: int = 0)

void

disconnect(callable: Callable)

void

emit(...) vararg const

Array

get_connections() const

StringName

get_name() const

Object

get_object() const

int

get_object_id() const

bool

has_connections() const

bool

is_connected(callable: Callable) const

bool

is_null() const

运算符

bool

operator !=(right: Signal)

bool

operator ==(right: Signal)


构造函数说明

Signal Signal() 🔗

构造空的 Signal,没有绑定对象和信号名称。


Signal Signal(from: Signal)

构造给定 Signal 的副本。


Signal Signal(object: Object, signal: StringName)

新建 Signal 对象,引用 object 对象中名为 signal 的信号。


方法说明

int connect(callable: Callable, flags: int = 0) 🔗

将信号连接到可调用体 callable。还可以添加 flags 对连接的行为进行配置(见 ConnectFlags 常量)。可以使用 Callable.bind() 为连接的 callable 提供额外的参数。

一个信号只能和同一个 Callable 连接一次。如果信号已连接,则会返回 @GlobalScope.ERR_INVALID_PARAMETER 并生成错误,除非信号是用 Object.CONNECT_REFERENCE_COUNTED 连接的。要防止这个问题,请先使用 is_connected() 检查已有连接。

for button in $Buttons.get_children():
    button.pressed.connect(_on_pressed.bind(button))

func _on_pressed(button):
    print(button.name, " 被按了一下")

注意:如果 callable 的对象被释放,连接会丢失。


void disconnect(callable: Callable) 🔗

将该信号与给定的 Callable 断开连接。如果该连接不存在,则会生成错误。请使用 is_connected() 来确保连接存在。


void emit(...) vararg const 🔗

发出该信号。与该信号相连的所有 Callable 都将被触发。此方法支持可变数量的参数,所以参数可以用逗号分隔列表的形式传递。


Array get_connections() const 🔗

返回该信号的连接 Array。连接用 Dictionary 表示,包含三个条目:

  • signal 是对此信号的引用。

  • callable 是对连接的 Callable 的引用。

  • flagsConnectFlags 的组合。


StringName get_name() const 🔗

返回该信号的名称。


Object get_object() const 🔗

返回发出该信号的对象。


int get_object_id() const 🔗

返回发出该信号的对象的 ID(见 Object.get_instance_id())。


bool has_connections() const 🔗

如果存在连接到该信号的 Callable,则返回 true


bool is_connected(callable: Callable) const 🔗

如果指定的 Callable 已连接到此信号,则返回 true


bool is_null() const 🔗

如果该 Signal 不存在对象且信号名为空,则返回 true。等价于 signal == Signal()


运算符说明

bool operator !=(right: Signal) 🔗

如果信号的对象或名称不同,则返回 true


bool operator ==(right: Signal) 🔗

如果信号的对象和名称相同,则返回 true