🎮 节点是什么?

在 Godot 中,一切都是节点(Node)

  • 游戏场景(Scene)是节点树(Node Tree)。

  • 节点可以是可视的(如 Sprite3DMeshInstance),也可以是逻辑控制(如 TimerAnimationPlayer)。

🕑 节点生命周期核心流程

1️⃣ 创建(Instantiation)

  • 当你从代码 load() / preload() 一个场景或节点资源,并 instance() 它时,节点会被创建到内存中,但尚未加入场景树(SceneTree)

var enemy_scene = preload("res://Enemy.tscn")
var enemy = enemy_scene.instance()

此时,节点处于“脱离树”(not in tree)状态。


2️⃣ 添加到场景树(_enter_tree)

  • 当你用 add_child() 把节点挂到树上时,节点开始进入场景树:

    1. _enter_tree() 被调用(可重载)。

    2. 这个阶段,节点知道自己属于哪个树、父节点是谁、可访问其他在树中的节点。

add_child(enemy)  # enemy._enter_tree() 会被调用


3️⃣ 准备就绪(_ready)

  • 当所有的子节点都已经 enter_tree 完毕后,Godot 调用 _ready()

  • _ready() 是做初始化逻辑(如绑定信号、访问兄弟节点、启动动画等)的常用位置。

func _ready():
    print("节点准备就绪")

✅ 重要: _ready() 只在第一次加入场景树时调用,后续 remove_child 再 add_child,不会再次调用。


4️⃣ 每帧处理(_process / _physics_process)

  • 节点一旦处于活动状态,就会每帧执行:

    • _process(delta):每帧调用,和帧率相关。

    • _physics_process(delta):与物理帧同步(固定时间步长)。

只有 set_process(true)set_physics_process(true) 后才会调用(默认大多数节点是自动启用)。


5️⃣ 退出场景树(_exit_tree)

  • 当节点被从场景树移除(如 remove_child() 或场景关闭),Godot 会调用 _exit_tree()

  • 用于清理引用、取消连接信号、关闭定时器等。

func _exit_tree():
    print("节点已从树中移除")


6️⃣ 销毁(对象析构)

  • 当没有任何引用指向这个节点时,Godot 会自动释放内存。

  • 如果想主动销毁,用 queue_free()

    • 这会标记节点在当前帧末尾安全销毁(推荐做法)。

enemy.queue_free()


生命周期方法总结

方法

什么时候触发

典型用途

_init()

创建实例时

初始化脚本变量(构造函数)

_enter_tree()

节点加入场景树时

注册树依赖逻辑

_ready()

节点和子节点都加入场景树后

安全访问其他节点

_process(delta)

每帧

处理帧逻辑

_physics_process(delta)

每物理帧

处理物理逻辑

_exit_tree()

节点移出场景树时

清理资源、断开信号

queue_free()

标记销毁

释放资源


💡 常见易混点

  • _init()_ready() 的区别:

    _init() 是 GDScript 的构造器,执行时节点尚未与树绑定。

    _ready() 是节点已准备好后执行,适合需要访问其他节点的逻辑。

  • _enter_tree()_ready() 的区别:

    _enter_tree() 发生在加入树时,但不保证子节点已准备好。

    _ready() 保证所有子节点都已加入树。


📌 推荐实践

✅ 在 _ready() 中访问场景中的其他节点。

✅ 在 _exit_tree() 中断开信号连接,避免潜在崩溃。

✅ 用 queue_free() 而不是 free(),保证安全销毁。