Node.get_parent
最后同步日期:2026-04-16 | Godot 官方原文 — Node.get_parent
Node.get_parent
定义
get_parent 就像在公司里"找你的直属上司"——每个节点在场景树中都有一个"上一级"(父节点),调用这个方法就能拿到它。
打个比方:想象你的游戏场景是一棵倒过来的家族树。如果"剑"是"右手"的子节点,"右手"是"玩家"的子节点,那么对"剑"调用 get_parent() 就能拿到"右手"——它的直接上级。对"右手"再调用一次,就能拿到"玩家"。通过不断往上找父节点,你可以沿着树从任意位置"爬"到最顶层。
这是 Godot 中实现"向上通信"的核心方法——子节点需要通知父节点、访问父节点的数据、或者判断自己处于场景树的哪个位置时,都会用到它。
函数签名
public Node GetParent()get_parent() -> Node参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
| — | — | — | 此方法没有参数 |
返回值
返回当前节点的父节点(一个 Node 对象)。
- 如果当前节点有父节点(在场景树中且不是根节点),返回父节点的引用。
- 如果当前节点没有父节点(是场景树的根节点
/root,或者还没有被添加到场景树中),返回 null。
返回的是 Node 基类
get_parent 返回的是 Node 类型,不是你父节点的具体类型(比如 Node2D、Control 等)。在 C# 中,如果你需要访问父节点特有的属性和方法,需要手动转型(例如 GetParent() as Node2D)或使用泛型辅助方法。GDScript 是动态类型,通常可以直接使用。
代码示例
基础用法
最简单的用法——获取当前节点的父节点,打印它的名字:
假设场景树结构如下:
Player
├── Weapon(当前脚本挂在这里)
└── Shieldpublic override void _Ready()
{
// 获取当前节点的父节点(Player)
var parent = GetParent();
// 打印父节点的名字
GD.Print(parent.Name); // 运行结果: Player
// 检查父节点是否是某个具体类型
if (parent is CharacterBody2D player)
{
GD.Print("父节点是玩家角色");
// 运行结果: 父节点是玩家角色
}
}func _ready():
# 获取当前节点的父节点(Player)
var parent = get_parent()
# 打印父节点的名字
print(parent.name) # 运行结果: Player
# 检查父节点是否是某个具体类型
if parent is CharacterBody2D:
print("父节点是玩家角色")
# 运行结果: 父节点是玩家角色实际场景
在游戏中,子弹节点打中敌人后需要通知"子弹管理器"(父节点)回收自己,并让管理器统计击杀数据:
场景树结构:
BulletManager
├── Bullet_0(当前脚本挂在这里)
└── Bullet_1public partial class Bullet : Area2D
{
// 子弹伤害值,可在编辑器中配置
[Export] public int ExDamage = 10;
// 内部变量:是否已经命中
private bool _hasHit = false;
public void OnHitEnemy()
{
if (_hasHit) return;
_hasHit = true;
// 找到父节点(BulletManager),通知它回收自己
var manager = GetParent() as BulletManager;
if (manager != null)
{
manager.OnBulletHit(this);
GD.Print("已通知管理器回收子弹");
// 运行结果: 已通知管理器回收子弹
}
}
}extends Area2D
# 子弹伤害值,可在编辑器中配置
@export var ex_damage: int = 10
# 内部变量:是否已经命中
var _has_hit: bool = false
func on_hit_enemy():
if _has_hit:
return
_has_hit = true
# 找到父节点(BulletManager),通知它回收自己
var manager = get_parent() as BulletManager
if manager != null:
manager.on_bullet_hit(self)
print("已通知管理器回收子弹")
# 运行结果: 已通知管理器回收子弹进阶用法
通过连续调用 get_parent 沿着场景树向上"爬",实现多层通信;同时处理根节点返回 null 的边界情况:
场景树结构:
Level(根场景)
├── Player
│ └── Body
│ └── Hand(当前脚本挂在这里)
└── EnemySpawnerpublic partial class Hand : Node2D
{
[Export] public float ExReachDistance = 50f;
private CharacterBody2D _cachedPlayer;
private Node _cachedLevel;
public override void _Ready()
{
// 1. 向上一级:Hand -> Body
var body = GetParent();
GD.Print("我的上级: " + body.Name); // 运行结果: 我的上级: Body
// 2. 向上两级:Hand -> Body -> Player
var player = body.GetParent();
GD.Print("我的上上级: " + player.Name); // 运行结果: 我的上上级: Player
// 缓存为具体类型,方便后续使用
_cachedPlayer = player as CharacterBody2D;
// 3. 向上三级:Hand -> Body -> Player -> Level
var level = player.GetParent();
if (level != null)
{
GD.Print("场景根节点: " + level.Name); // 运行结果: 场景根节点: Level
_cachedLevel = level;
}
// 4. 安全检查:如果再往上找,可能就没有父节点了
var aboveLevel = level?.GetParent();
if (aboveLevel == null)
{
GD.Print("已经到顶了,没有更上层的节点");
// 运行结果: 已经到顶了,没有更上层的节点
}
// 5. 实用技巧:用 GetParent() 判断节点是否在场景树中
if (GetParent() != null)
{
GD.Print("我在场景树中,路径: " + GetPath());
// 运行结果: 我在场景树中,路径: /root/Level/Player/Body/Hand
}
}
}extends Node2D
@export var ex_reach_distance: float = 50.0
var _cached_player: CharacterBody2D
var _cached_level: Node
func _ready():
# 1. 向上一级:Hand -> Body
var body = get_parent()
print("我的上级: " + body.name) # 运行结果: 我的上级: Body
# 2. 向上两级:Hand -> Body -> Player
var player = body.get_parent()
print("我的上上级: " + player.name) # 运行结果: 我的上上级: Player
# 缓存为具体类型,方便后续使用
_cached_player = player as CharacterBody2D
# 3. 向上三级:Hand -> Body -> Player -> Level
var level = player.get_parent()
if level != null:
print("场景根节点: " + level.name) # 运行结果: 场景根节点: Level
_cached_level = level
# 4. 安全检查:如果再往上找,可能就没有父节点了
var above_level = level.get_parent() if level != null else null
if above_level == null:
print("已经到顶了,没有更上层的节点")
# 运行结果: 已经到顶了,没有更上层的节点
# 5. 实用技巧:用 get_parent() 判断节点是否在场景树中
if get_parent() != null:
print("我在场景树中,路径: " + str(get_path()))
# 运行结果: 我在场景树中,路径: /root/Level/Player/Body/Hand连续调用 get_parent 时注意空值
每次调用 get_parent() 都可能返回 null(特别是到达根节点时)。如果需要连续向上查找多层,务必在每一层都做 null 检查,否则对一个 null 调用 .GetParent() 会导致程序崩溃。
注意事项
- 返回 null 的情况:以下两种情况
get_parent会返回 null:(1)当前节点是场景树的根节点(/root);(2)当前节点还没有被添加到场景树中(即没有通过add_child挂到任何节点下面)。使用返回值前务必做 null 检查。 - 返回的是直接父节点:
get_parent只返回你的直接上级,不会跳级。如果需要找到更上层的祖先节点,需要连续调用多次(如示例 3 所示),或者使用GetNode("../..")路径语法。 - 不要过度依赖向上查找:虽然
get_parent很方便,但过度使用它会让代码和场景树结构"绑死"——一旦场景树的层级关系改变,所有依赖get_parent的代码都可能出错。更好的做法是通过[Export]属性或信号(Signal)来解耦节点之间的依赖。 - 与
get_node("..")的关系:get_parent()和get_node("..")的效果是一样的(".."在路径中表示父节点),但get_parent()语义更清晰、不需要传参数,推荐优先使用。 - 缓存引用避免重复查找:如果你需要频繁访问父节点,建议在
_Ready()中调用一次GetParent()并把结果保存到变量中(如示例中的_cachedPlayer),后续直接使用变量即可,不需要每次都重新查找。 - C# 差异:C# 中方法名用 PascalCase(
GetParent),GDScript 中用 snake_case(get_parent)。C# 返回的是Node基类,如需使用子类特有成员,需要用as关键字转型(例如GetParent() as Node2D)。
