节点什么时候准备好:生命周期
理解 _ready、_process 与 _physics_process,避免在错误时刻访问对象。
01不是每个函数都由你直接调用
一些函数是引擎约定的回调:节点进入场景树触发 _enter_tree();完成初始准备后触发 _ready();普通帧更新进入 _process(delta);固定物理步进入 _physics_process(delta)。你重写这些函数,让引擎在合适时机调用。
02先父后子与先子后父
进入场景树通常是父节点先进入,再到子节点;首次准备完成的回调则先到子节点,再到父节点。因此父节点的 _ready() 适合连接已经存在的子节点。@onready 变量会推迟到节点准备阶段初始化,避免脚本刚创建时就找尚未进入树的孩子。
03可运行观察实验
extends Node
@export var label_name: String = "未命名"
func _enter_tree() -> void:
print(label_name, " enter")
func _ready() -> void:
print(label_name, " ready")
func _exit_tree() -> void:
print(label_name, " exit")- 创建父 Node 和一个子 Node;给两者都挂这个脚本。
- 在 Inspector 中分别把 label_name 设为 parent 和 child。
- F6 后查看输出,预测 enter 和 ready 顺序;停止时再看 exit。
04把代码放进正确的更新循环
与物理移动有关的逻辑优先放在 _physics_process。只是视觉变化的效果通常考虑 _process 或动画系统。delta 是相邻更新之间经过的秒数;是否乘 delta 取决于 API 的单位约定,不是看到运动就机械相乘。CharacterBody2D 的 velocity 表示速度,move_and_slide() 内部处理时间步。
05让输出记录回答:这一行究竟执行了几次
生命周期容易被背成一串名字,却没有变成调试能力。沿用父子节点实验,在纸上先写四张卡片:父进入、子进入、子就绪、父就绪。运行后按输出顺序摆卡片,接着给场景再添加第二个子节点,预测它会插在哪里。此时不要给每帧回调添加大量 print,否则初始化的几行输出会被淹没。
再增加一个普通函数 reset_practice,让它只打印“执行重置”。把这个函数的调用放在一个按钮回调中,按两次按钮。你应该能分清:进入树与准备完成由引擎触发;重置由你的代码明确调用。按钮按下两次不会重新执行整个场景的初始化。若每次按钮都出现 ready 日志,应调查是不是重新实例化了节点,而不是把这种现象理解为 ready 天生会反复执行。
06三个初始化位置,各自适合放什么
可以把角色准备工作分成三类。第一类是不依赖场景的初始数值,例如速度默认值,可以直接写在变量声明里。第二类是查找已经摆好的子节点,适合用 @onready 保存引用。第三类是多个部件之间的连接与首次界面刷新,可以放在 _ready 中。@onready 变量会在该节点的 _ready 方法之前初始化,它不是一种自动修复错误路径的功能。
给练习 Label 改名,再运行引用它的脚本。若引用失败,等得更久也不会把错误名字变正确;应检查实际节点路径。如果是在代码中稍后才创建 Label,则应在创建后传递引用,不能假设启动时的 @onready 未来会自动再查一遍。不要把同一个变量同时标成 @export 和 @onready:前者期待编辑器赋值,后者又在准备阶段初始化,容易覆盖你以为已经配置好的内容。
07按时间单位选择更新方式,而不是机械乘 delta
先给每个量补上单位,再写计算。透明度变化可以表示为“每秒增加多少”,自己累加时就需要考虑经过的秒数;角色 velocity 已经表示速度,而 move_and_slide 按物理时间步处理移动,不能把同一时间因素算两遍。把“速度”“每帧位移”“持续秒数”混在一起,是帧率变化后行为不同的常见原因。
练习时做两项观察:持续移动一段时间,记录大致路程;打开和关闭对话,记录哪些更新应该停止、哪些仍应继续。先明确对象的职责,再决定控制某个脚本的行为还是暂停整棵树。你的验收记录应写出每段逻辑为什么放在那个回调、调用次数由谁决定。仅仅没有红色报错,不能证明更新时机符合体验目标。
动手后,再勾选
不是“我看懂了”,而是你在独立练习里做出并检查过。
换一个情景,你会怎么判断?
父节点首次 _ready() 通常发生在何时?
用自己的话,留一条笔记
可以写“我之前以为……,现在发现……”,或者记录还没解决的问题。
↗回到资料核对
本课是解释与练习,不替代对应版本的官方手册。网页实验不运行 Godot;未标明实机验证的代码,仍需在独立工程中检查。
标记已读不会自动勾选实作,也不代表游戏功能已经完成。