Object.is_connected
2026/4/14大约 8 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — Object.is_connected
Object.is_connected
定义
is_connected 就像检查电线是否已经接好——你把一根信号线(信号名称)和一盏灯(处理方法)连在一起之前,先看看它们之间是不是已经接通了。如果已经接通,就不需要再接一次。
打个比方:你在微信群里,想看看某个人是不是已经在群里了。如果已经在群里,你就不用再拉他进群。is_connected 就是这个"看看在不在群里"的动作。
在游戏开发中,这个方法最常见的用途是防止重复连接。同一个信号连接到同一个方法两次,方法就会被调用两次,这往往不是你想要的结果。
一句话总结
is_connected 的作用是"检查电线是否接好":判断某个信号是否已经和某个方法建立了连接,避免重复接线。
函数签名
C#
// 方式一:使用 IsConnected 方法
public bool IsConnected(StringName signal, Callable callable)
// 方式二(推荐):使用 C# 事件检查
// 对于 Godot 内置信号,可以直接检查事件是否为 null
bool connected = someNode.Pressed != null; // 不推荐,仅供参考GDScript
is_connected(signal: StringName, callable: Callable) -> bool参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
| signal | StringName | 是 | 信号的名称,比如 "timeout"、"pressed"、"body_entered" 等 |
| callable | Callable | 要检查的处理方法。必须和之前 connect 时传入的 Callable 是同一个方法 |
返回值
| 类型 | 说明 |
|---|---|
| bool | 返回 true 表示信号已经连接到指定的方法;返回 false 表示没有连接 |
代码示例
基础用法
最简单的用法——检查按钮的 pressed 信号是否已经连接到某个方法:
C#
using Godot;
public partial class MyMenu : Control
{
private Button _startButton;
public override void _Ready()
{
_startButton = GetNode<Button>("StartButton");
// 先连接信号
_startButton.Pressed += OnStartButtonPressed;
// 检查是否已连接
bool connected = _startButton.IsConnected(
Button.SignalName.Pressed,
Callable.From(OnStartButtonPressed)
);
GD.Print("信号是否已连接: " + connected);
// 运行结果: 信号是否已连接: True
// 检查一个没有连接的方法
bool notConnected = _startButton.IsConnected(
Button.SignalName.Pressed,
Callable.From(OnOtherMethod)
);
GD.Print("未连接的方法: " + notConnected);
// 运行结果: 未连接的方法: False
}
private void OnStartButtonPressed()
{
GD.Print("按钮被按下了!");
}
private void OnOtherMethod()
{
GD.Print("这个方法没有连接到按钮");
}
}GDScript
extends Control
var _start_button: Button
func _ready() -> void:
_start_button = get_node("StartButton")
# 先连接信号
_start_button.pressed.connect(_on_start_button_pressed)
# 检查是否已连接
var connected = _start_button.is_connected("pressed", _on_start_button_pressed)
print("信号是否已连接: %s" % connected)
# 运行结果: 信号是否已连接: True
# 检查一个没有连接的方法
var not_connected = _start_button.is_connected("pressed", _on_other_method)
print("未连接的方法: %s" % not_connected)
# 运行结果: 未连接的方法: False
func _on_start_button_pressed() -> void:
print("按钮被按下了!")
func _on_other_method() -> void:
print("这个方法没有连接到按钮")实际场景
在实际游戏开发中,is_connected 最常用的场景是"防止重复连接"。比如在一个动态创建和销毁 UI 的系统中,每次打开菜单时都想给按钮绑定事件,但如果按钮已经绑过了,就不需要再绑一次:
C#
using Godot;
public partial class UIManager : Control
{
private Button _closeButton;
private Button _saveButton;
private bool _eventsRegistered = false;
public override void _Ready()
{
_closeButton = GetNode<Button>("Panel/CloseButton");
_saveButton = GetNode<Button>("Panel/SaveButton");
// 安全连接:先检查是否已经连过了
SafeConnect(_closeButton, Button.SignalName.Pressed, OnCloseClicked);
SafeConnect(_saveButton, Button.SignalName.Pressed, OnSaveClicked);
// 模拟再次调用(比如菜单被重新打开)
SafeConnect(_closeButton, Button.SignalName.Pressed, OnCloseClicked);
SafeConnect(_saveButton, Button.SignalName.Pressed, OnSaveClicked);
GD.Print("所有事件已安全注册");
// 运行结果:
// 连接关闭按钮事件...
// 连接保存按钮事件...
// 关闭按钮已经连接过了,跳过
// 保存按钮已经连接过了,跳过
// 所有事件已安全注册
}
/// <summary>
/// 安全连接信号:先检查是否已连接,避免重复绑定
/// </summary>
private void SafeConnect(GodotObject obj, StringName signal, Callable callable)
{
if (obj.IsConnected(signal, callable))
{
GD.Print("已经连接过了,跳过");
return;
}
obj.Connect(signal, callable);
GD.Print("连接事件...");
}
private void OnCloseClicked()
{
GD.Print("关闭菜单");
// 运行结果: 关闭菜单
}
private void OnSaveClicked()
{
GD.Print("保存游戏");
// 运行结果: 保存游戏
}
}GDScript
extends Control
var _close_button: Button
var _save_button: Button
func _ready() -> void:
_close_button = get_node("Panel/CloseButton")
_save_button = get_node("Panel/SaveButton")
# 安全连接:先检查是否已经连过了
safe_connect(_close_button, "pressed", _on_close_clicked)
safe_connect(_save_button, "pressed", _on_save_clicked)
# 模拟再次调用(比如菜单被重新打开)
safe_connect(_close_button, "pressed", _on_close_clicked)
safe_connect(_save_button, "pressed", _on_save_clicked)
print("所有事件已安全注册")
# 运行结果:
# 连接关闭按钮事件...
# 连接保存按钮事件...
# 已经连接过了,跳过
# 已经连接过了,跳过
# 所有事件已安全注册
## 安全连接信号:先检查是否已连接,避免重复绑定
func safe_connect(obj: Object, signal_name: StringName, callable: Callable) -> void:
if obj.is_connected(signal_name, callable):
print("已经连接过了,跳过")
return
obj.connect(signal_name, callable)
print("连接事件...")
func _on_close_clicked() -> void:
print("关闭菜单")
# 运行结果: 关闭菜单
func _on_save_clicked() -> void:
print("保存游戏")
# 运行结果: 保存游戏进阶用法
在更复杂的场景中,is_connected 可以结合 GetSignalConnectionList 一起使用,实现信号的动态管理和条件性断开/重连:
C#
using Godot;
public partial class SignalManager : Node
{
[Signal]
public delegate void PlayerHitEventHandler(int damage);
private int _hitCount = 0;
public override void _Ready()
{
// 连接信号
PlayerHit += OnPlayerHit;
// 检查并打印连接状态
PrintConnectionStatus();
// 触发几次信号
EmitSignal(SignalName.PlayerHit, 10);
EmitSignal(SignalName.PlayerHit, 25);
// 临时断开信号(比如暂停时)
GD.Print("\n--- 暂停游戏,断开信号 ---");
if (IsConnected(SignalName.PlayerHit, Callable.From(OnPlayerHit)))
{
Disconnect(SignalName.PlayerHit, Callable.From(OnPlayerHit));
GD.Print("信号已断开");
}
// 此时触发信号不会有反应
EmitSignal(SignalName.PlayerHit, 99);
GD.Print("(上面的信号没有被处理)");
// 恢复连接
GD.Print("\n--- 恢复游戏,重新连接信号 ---");
if (!IsConnected(SignalName.PlayerHit, Callable.From(OnPlayerHit)))
{
PlayerHit += OnPlayerHit;
GD.Print("信号已重新连接");
}
EmitSignal(SignalName.PlayerHit, 15);
// 运行结果:
// 当前 PlayerHit 信号连接数: 1
// 信号是否已连接: True
//
// 受到 10 点伤害,累计被击中 1 次
// 受到 25 点伤害,累计被击中 2 次
//
// --- 暂停游戏,断开信号 ---
// 信号已断开
// (上面的信号没有被处理)
//
// --- 恢复游戏,重新连接信号 ---
// 信号已重新连接
// 受到 15 点伤害,累计被击中 3 次
}
private void PrintConnectionStatus()
{
var connections = GetSignalConnectionList(SignalName.PlayerHit);
GD.Print($"当前 PlayerHit 信号连接数: {connections.Count}");
bool isConnected = IsConnected(
SignalName.PlayerHit,
Callable.From(OnPlayerHit)
);
GD.Print($"信号是否已连接: {isConnected}");
}
private void OnPlayerHit(int damage)
{
_hitCount++;
GD.Print($"受到 {damage} 点伤害,累计被击中 {_hitCount} 次");
}
}GDScript
extends Node
# 自定义信号
signal player_hit(damage: int)
var _hit_count: int = 0
func _ready() -> void:
# 连接信号
player_hit.connect(_on_player_hit)
# 检查并打印连接状态
print_connection_status()
# 触发几次信号
emit_signal("player_hit", 10)
emit_signal("player_hit", 25)
# 临时断开信号(比如暂停时)
print("\n--- 暂停游戏,断开信号 ---")
if is_connected("player_hit", _on_player_hit):
disconnect("player_hit", _on_player_hit)
print("信号已断开")
# 此时触发信号不会有反应
emit_signal("player_hit", 99)
print("(上面的信号没有被处理)")
# 恢复连接
print("\n--- 恢复游戏,重新连接信号 ---")
if not is_connected("player_hit", _on_player_hit):
player_hit.connect(_on_player_hit)
print("信号已重新连接")
emit_signal("player_hit", 15)
# 运行结果:
# 当前 player_hit 信号连接数: 1
# 信号是否已连接: True
#
# 受到 10 点伤害,累计被击中 1 次
# 受到 25 点伤害,累计被击中 2 次
#
# --- 暂停游戏,断开信号 ---
# 信号已断开
# (上面的信号没有被处理)
#
# --- 恢复游戏,重新连接信号 ---
# 信号已重新连接
# 受到 15 点伤害,累计被击中 3 次
func print_connection_status() -> void:
var connections = get_signal_connection_list("player_hit")
print("当前 player_hit 信号连接数: %d" % connections.size())
var is_conn = is_connected("player_hit", _on_player_hit)
print("信号是否已连接: %s" % is_conn)
func _on_player_hit(damage: int) -> void:
_hit_count += 1
print("受到 %d 点伤害,累计被击中 %d 次" % [damage, _hit_count])注意事项
- 必须同时匹配信号名和方法:
is_connected需要同时传入信号名和具体的Callable。如果你只传信号名不传方法,它无法判断——因为同一个信号可能连接了多个不同的方法。就好比你问"这个群有没有人",答案永远是"有";你得问"张三在不在群里"才能得到有意义的答案。 - Callable 必须是同一个对象的方法:检查时传入的
Callable必须和connect时传入的完全一致(同一个对象、同一个方法)。如果对象不同,即使方法名相同,is_connected也会返回false。 - C# 中推荐用事件语法连接,用 IsConnected 检查:虽然 C# 可以用
+=语法连接信号(如_button.Pressed += OnPressed),但检查连接状态时仍然需要用IsConnected(Button.SignalName.Pressed, Callable.From(OnPressed))。C# 的事件没有提供简单的"是否已订阅"检查方法。 - 不要和信号是否存在混淆:
is_connected检查的是"某个信号是否已经连接到某个方法",而不是"这个对象有没有这个信号"。如果要检查对象是否拥有某个信号,应该使用has_signal方法。 - 断开后再连接不会自动恢复标志:如果你用
ConnectFlags.OneShot等标志连接了一个信号,断开后重新连接时,之前的标志不会自动恢复,需要重新指定。 - C# 差异:C# 中方法名用 PascalCase(
IsConnected),GDScript 中用 snake_case(is_connected)。信号名称常量在 C# 中通过SignalName静态类访问(如Button.SignalName.Pressed),GDScript 中直接写字符串(如"pressed")。
