SceneTree.has_group
2026/4/14大约 5 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — SceneTree.has_group
SceneTree.has_group
定义
has_group 就像查班级花名册——你问一句"这个学校有没有篮球队?",它回答你"有"或者"没有"。它只关心这个分组(Group)是否存在,不关心组里有几个人。
打个比方:你想往"三班"送一封信,但你不确定这个班存不存在。于是你先查一下花名册,确认"三班"存在后再送信。has_group 就是这个"查花名册"的动作——在做分组相关操作之前,先确认分组确实存在,避免出错。
在实际开发中,这通常用于防御性编程:在调用 CallGroup 或 GetNodesInGroup 之前,先用 HasGroup 检查分组是否存在,避免对不存在的分组执行操作。
函数签名
C#
public bool HasGroup(StringName group)GDScript
func has_group(group: StringName) -> bool参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
group | StringName | 是 | 要检查的分组名称,例如 "enemies"、"players" |
返回值
bool——分组是否存在:
| 返回值 | 含义 |
|---|---|
true | 该分组存在(组内至少有一个节点) |
false | 该分组不存在(没有任何节点加入过这个组) |
代码示例
基础用法:检查分组是否存在
C#
public override void _Ready()
{
// 检查 "enemies" 分组是否存在
if (GetTree().HasGroup("enemies"))
{
GD.Print("敌人分组存在!");
// 运行结果: 敌人分组存在!
}
else
{
GD.Print("敌人分组不存在。");
}
// 检查一个不存在的分组
if (GetTree().HasGroup("dragons"))
{
GD.Print("龙分组存在!");
}
else
{
GD.Print("龙分组不存在。");
// 运行结果: 龙分组不存在。
}
}GDScript
func _ready():
# 检查 "enemies" 分组是否存在
if get_tree().has_group("enemies"):
print("敌人分组存在!")
# 运行结果: 敌人分组存在!
else:
print("敌人分组不存在。")
# 检查一个不存在的分组
if get_tree().has_group("dragons"):
print("龙分组存在!")
else:
print("龙分组不存在。")
# 运行结果: 龙分组不存在。实际场景:安全地操作分组
C#
using Godot;
public partial class PowerUp : Area2D
{
[Export] public int ExDamageBonus = 20;
public void Activate()
{
// 在操作分组之前先检查它是否存在
if (GetTree().HasGroup("players"))
{
// 安全地通知所有玩家获得伤害加成
GetTree().CallGroup("players", "AddDamageBonus", ExDamageBonus);
GD.Print($"所有玩家获得 {ExDamageBonus} 点伤害加成!");
// 运行结果: 所有玩家获得 20 点伤害加成!
}
else
{
GD.Print("没有找到玩家分组,道具无效。");
}
// 同样检查敌人分组
if (GetTree().HasGroup("enemies"))
{
int enemyCount = GetTree().GetNodesInGroup("enemies").Count;
GD.Print($"当前场景中有 {enemyCount} 个敌人");
// 运行结果: 当前场景中有 5 个敌人
}
}
}GDScript
extends Area2D
@export var ex_damage_bonus: int = 20
func activate():
# 在操作分组之前先检查它是否存在
if get_tree().has_group("players"):
# 安全地通知所有玩家获得伤害加成
get_tree().call_group("players", "add_damage_bonus", ex_damage_bonus)
print("所有玩家获得 %d 点伤害加成!" % ex_damage_bonus)
# 运行结果: 所有玩家获得 20 点伤害加成!
else:
print("没有找到玩家分组,道具无效。")
# 同样检查敌人分组
if get_tree().has_group("enemies"):
var enemy_count = get_tree().get_nodes_in_group("enemies").size()
print("当前场景中有 %d 个敌人" % enemy_count)
# 运行结果: 当前场景中有 5 个敌人进阶用法:动态分组管理系统
C#
using Godot;
public partial class GroupManager : Node
{
/// <summary>
/// 安全地对分组执行操作,分组不存在时自动创建提示
/// </summary>
public void SafeCallGroup(string groupName, string methodName, params Variant[] args)
{
if (!GetTree().HasGroup(groupName))
{
GD.Print($"[警告] 分组 '{groupName}' 不存在,跳过操作");
// 运行结果(分组不存在时): [警告] 分组 'bosses' 不存在,跳过操作
return;
}
int memberCount = GetTree().GetNodesInGroup(groupName).Count;
GD.Print($"正在对 '{groupName}' 组的 {memberCount} 个成员调用 {methodName}");
GetTree().CallGroup(groupName, methodName, args);
}
/// <summary>
/// 打印当前所有分组信息(调试用)
/// </summary>
public void PrintAllGroups()
{
// 常见的分组名称列表
string[] commonGroups = { "players", "enemies", "collectibles", "destructibles", "projectiles", "npc" };
GD.Print("=== 分组状态 ===");
foreach (string group in commonGroups)
{
if (GetTree().HasGroup(group))
{
int count = GetTree().GetNodesInGroup(group).Count;
GD.Print($" {group}: {count} 个成员");
}
}
// 运行结果:
// === 分组状态 ===
// players: 1 个成员
// enemies: 5 个成员
// collectibles: 12 个成员
// destructibles: 3 个成员
}
}GDScript
extends Node
## 安全地对分组执行操作,分组不存在时自动创建提示
func safe_call_group(group_name: String, method_name: String, args: Array = []):
if not get_tree().has_group(group_name):
print("[警告] 分组 '%s' 不存在,跳过操作" % group_name)
# 运行结果(分组不存在时): [警告] 分组 'bosses' 不存在,跳过操作
return
var member_count = get_tree().get_nodes_in_group(group_name).size()
print("正在对 '%s' 组的 %d 个成员调用 %s" % [group_name, member_count, method_name])
get_tree().call_group(group_name, method_name, args)
## 打印当前所有分组信息(调试用)
func print_all_groups():
# 常见的分组名称列表
var common_groups = ["players", "enemies", "collectibles", "destructibles", "projectiles", "npc"]
print("=== 分组状态 ===")
for group in common_groups:
if get_tree().has_group(group):
var count = get_tree().get_nodes_in_group(group).size()
print(" %s: %d 个成员" % [group, count])
# 运行结果:
# === 分组状态 ===
# players: 1 个成员
# enemies: 5 个成员
# collectibles: 12 个成员
# destructibles: 3 个成员注意事项
- 分组是动态的:一个分组在"至少有一个节点加入"时才算存在。如果组内最后一个节点被移除或销毁,该分组自动消失,
HasGroup将返回false。 - 分组名区分大小写:
"Enemies"和"enemies"是两个不同的分组。建议在项目中统一使用小写字母命名分组,避免混乱。 - 不检查组内成员数量:
HasGroup只回答"这个组存不存在",不告诉你组里有几个节点。如果需要知道数量,请使用GetNodesInGroup().Count。 - 性能开销很小:
HasGroup是一个非常轻量的操作,可以放心在频繁调用的代码(如_Process)中使用。 - 防御性编程的好习惯:虽然
CallGroup和GetNodesInGroup在分组不存在时不会崩溃(它们只是什么都不做 / 返回空数组),但用HasGroup做预检查可以让你的代码逻辑更清晰,也方便输出调试信息。 - C# 差异:C# 中方法名用 PascalCase(
HasGroup),GDScript 中用 snake_case(has_group)。
