Node
2026/4/14大约 5 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — Node
Node
节点继承关系
继承链:Node(万物之始,没有父类)
定义
Node 是 Godot 中所有节点的最基础父类。它本身不显示任何东西,只提供最基本的功能:生命周期回调(_Ready、_Process)、信号机制、父子关系管理、分组等。
一句话理解:Node 就像一张白纸——什么都没有,但你可以往上面加任何东西。
你可以把它想象成一张空白的档案卡。这张卡片上没有照片、没有文字,但它有挂孔(可以挂到其他卡片下面)、有编号(可以在一堆卡片中找到它)、还有一栏"备注"(可以在上面写东西)。Godot 里所有看得见、摸得着的节点,都是从这张空白卡片"进化"来的。
节点用途
- 充当纯逻辑容器——不显示任何画面,只负责管理和协调
- 作为场景的根节点来组织子节点结构
- 编写自定义管理器(全局单例、游戏管理器、音频管理器等)
- 在场景树中作为"文件夹"来分组管理节点
使用场景
典型场景
- 游戏管理器:控制游戏状态(开始、暂停、结束),管理分数和关卡切换。它不需要显示任何画面,只需要"在后台默默工作"。
- 全局单例(Autoload):比如一个
AudioManager节点,负责全场景的背景音乐和音效播放。它在整个游戏运行期间都存在。 - 逻辑容器:把一组功能相关的节点放在一个
Node下面,方便统一管理。比如把所有"敌人"节点放在一个叫Enemies的Node下面。
不适用场景
常用节点搭配
| 搭配节点 | 用途 | 必需? |
|---|---|---|
| 任意子节点 | 作为逻辑容器组织子节点 | 是 |
| Node2D | 2D 场景中作为不可见的容器 | 视需求 |
| Node3D | 3D 场景中作为不可见的容器 | 视需求 |
生效必备素材/资源
Node 本身不需要任何外部资源即可工作。它是最纯粹的逻辑节点,不依赖贴图、模型、音频等任何素材。
节点属性与信号
通用属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
| Name | String | — | — | 节点名称,在场景树中唯一标识这个节点 |
| ProcessMode | ProcessModeEnum | Inherit | — | 处理模式,控制 _Process 和 _PhysicsProcess 是否执行 |
| ProcessPriority | int | 0 | — | 处理优先级,值越大越先执行 |
| PhysicsInterpolationMode | InterpolationModeEnum | Inherit | — | 物理插值模式 |
| UniqueNameInOwner | bool | false | — | 在所有者场景中是否必须唯一 |
| EditorDescription | String | "" | — | 编辑器中显示的描述信息 |
| Script | Script | null | — | 附加到这个节点的脚本 |
生命周期信号
| 信号 | 触发时机 | 继承自 | 说明 |
|---|---|---|---|
Ready | 节点及其所有子节点都进入场景树后 | — | 初始化逻辑的最佳时机,只触发一次 |
TreeEntered | 节点进入场景树时 | — | 比 Ready 更早触发,此时子节点可能还没准备好 |
TreeExiting | 节点即将离开场景树时 | — | 清理资源的时机 |
TreeExited | 节点已经离开场景树后 | — | 节点已不在场景树中 |
Renamed | 节点名称被修改时 | — | 名称变更通知 |
ChildEnteredTree | 子节点进入场景树时 | — | 子节点加入通知 |
ChildExitingTree | 子节点即将离开场景树时 | — | 子节点离开通知 |
ChildOrderChanged | 子节点顺序变化时 | — | 子节点排序变更通知 |
核心生命周期方法
| 方法 | 调用时机 | 说明 |
|---|---|---|
_EnterTree() | 节点进入场景树时 | 初始化引用,比 _Ready 更早 |
_Ready() | 节点及其所有子节点都进入场景树后 | 初始化逻辑(只调用一次) |
_Process(double delta) | 每一帧 | 更新逻辑,delta 是上一帧的时间间隔 |
_PhysicsProcess(double delta) | 每个物理帧(固定 60fps) | 物理移动和碰撞相关逻辑 |
_ExitTree() | 节点离开场景树时 | 清理资源 |
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
GetParent() | Node | 获取父节点 |
GetChild(int index) | Node | 获取第 N 个子节点(从 0 开始) |
GetChildCount() | int | 获取子节点数量 |
GetNode<T>(string path) | T | 按路径获取节点,类型安全版本 |
GetNode(string path) | Node | 按路径获取节点(如 "Player/Sprite") |
AddChild(Node node) | void | 添加子节点 |
RemoveChild(Node node) | void | 移除子节点 |
QueueFree() | void | 延迟删除节点(安全的删除方式,会在帧末删除) |
GetTree() | SceneTree | 获取场景树,用于暂停、切换场景等 |
IsInsideTree() | bool | 节点是否在场景树中 |
HasNode(string path) | bool | 是否存在指定路径的节点 |
GetNodeOrNull<T>(string path) | T? | 安全获取节点(不存在时返回 null 而不是报错) |
PrintTree() | void | 在控制台打印节点树结构(调试用) |
GetGroups() | string[] | 获取节点所属的所有分组名称 |
AddToGroup(string group) | void | 将节点添加到分组 |
RemoveFromGroup(string group) | void | 将节点从分组中移除 |
代码示例
基础生命周期
C
using Godot;
public partial class GameManager : Node
{
public override void _Ready()
{
GD.Print("游戏管理器准备好了!");
}
public override void _Process(double delta)
{
// 每帧执行的逻辑
}
public override void _PhysicsProcess(double delta)
{
// 物理帧逻辑(固定时间步长)
}
}GDScript
extends Node
func _ready():
print("游戏管理器准备好了!")
func _process(delta):
# 每帧执行的逻辑
pass
func _physics_process(delta):
# 物理帧逻辑(固定时间步长)
pass节点操作
C
using Godot;
public partial class NodeOpsDemo : Node
{
private Node _player;
public override void _Ready()
{
// 获取子节点
_player = GetNode<Node>("Player");
// 安全获取(节点不存在时不会报错)
var optional = GetNodeOrNull<Node>("OptionalNode");
// 获取父节点
var parent = GetParent();
// 遍历所有子节点
foreach (Node child in GetChildren())
{
GD.Print($"子节点: {child.Name}");
}
// 添加分组
AddToGroup("enemies");
}
}GDScript
extends Node
var _player: Node
func _ready():
# 获取子节点
_player = $Player
# 安全获取(节点不存在时不会报错)
var optional = get_node_or_null("OptionalNode")
# 获取父节点
var parent = get_parent()
# 遍历所有子节点
for child in get_children():
print("子节点: ", child.name)
# 添加分组
add_to_group("enemies")场景切换
C
using Godot;
public partial class SceneManager : Node
{
public void GoToMainMenu()
{
GetTree().ChangeSceneToFile("res://scenes/main_menu.tscn");
}
public void RestartGame()
{
GetTree().ReloadCurrentScene();
}
}GDScript
extends Node
func go_to_main_menu():
get_tree().change_scene_to_file("res://scenes/main_menu.tscn")
func restart_game():
get_tree().reload_current_scene()