标签:场景树
-
多 SceneTree 的可行性:为什么插件里不能随便 new MainLoop
SceneTree 表面上是可替换的 MainLoop,但渲染、输入、视口、单例注册全围绕"一棵树"假设搭建;要第二棵树,官方给的答案是 SubViewport 而不是第二个 SceneTree。
-
组(Group)系统:SceneTree 里的组哈希表
add_to_group 背后是两份哈希表的双写,get_nodes_in_group 的遍历顺序由 HashSet 决定而不稳定——这篇把组系统的存储结构、开销和适用边界讲清楚。
-
节点树的挂接与脱离:add_child() 背后做了什么
add_child 一行代码背后是命名冲突消解、树内通知级联、process 标志传播三件事,这篇读 scene/main/node.cpp 的 _add_child_nocheck 与 _propagate 家族,讲清挂接的完整成本。
-
场景切换的正确姿势:change_scene_to_file 的内部行为
change_scene_to_file 是同步拆旧建新——旧 current_scene 被立即摘除并释放,从物理回调里直接调会触发 locked 报错;这篇把 _change_scene 的每一步和延迟切换的正确写法讲清楚。
-
NOTIFICATION 全家桶:ENTER_TREE / EXIT_TREE / READY 的顺序保证
把 Node 的通知编号体系、Object::notification 的分发路径、reversed 参数的含义一次讲清,顺带解释为什么这套机制不用 C++ 虚函数。
-
Node 的 owner 与持久化:场景保存时哪些节点会被写盘
owner 字段决定一个节点在保存场景时被写进哪份 PackedScene;它只影响序列化、不影响运行时查找,运行时 add_child 出来的节点 owner 为 null,天然不会被保存。
-
call_deferred 与消息队列:延迟调用的实现与 flush 时机
call_deferred 不是定时器,是把 Callable 塞进一条全局 FIFO 消息队列;队列在一帧的固定时点上被 flush,回调运行期改树是主要用途,队列满了引擎会直接崩。
-
NodePath 的解析与缓存:get_node 每次调用都重新解析吗
NodePath 在构造时就完成了字符串切分,get_node 的成本在逐级子节点查找而不在解析;引擎不缓存查找结果,所以高频路径要用 @onready 变量把引用钉住。
-
_process 与 _physics_process 的时序关系:同一帧里谁先谁后
从 Main::iteration 的固定步长累加器出发,讲清一个渲染帧里物理迭代和 _process 的先后、delta 各自怎么算,以及 144Hz 屏配 60Hz 物理时的步数抖动和插值平滑。
-
unique_name_in_owner 与 %NodePath:百分号语法糖背后的查找表
百分号写法不是路径简写,而是一套挂在 owner 上的 StringName 哈希表,查询 O(1) 且不受节点深度影响——这篇从 set_unique_name_in_owner 的注册逻辑追到 get_node_or_null 的分支。
-
process_priority 排序:同一帧内节点的执行顺序
process_priority 决定同一帧里 _process 的调用次序,优先级相同时按挂接顺序稳定排队——这篇讲 SceneTree 处理组的排序插入、线程组机制,以及什么时候真的需要调优先级。
-
SceneTree 的 MainLoop 循环:一帧到底发生了什么
从 main/main.cpp 的 Main::iteration() 一路追到 SceneTree::process(),弄清固定物理帧和渲染帧是怎么在一帧里被排好队的。
-
Window 节点与 Viewport 的关系:4.x 把窗口做成节点解决了什么
4.x 让 Window 继承 Viewport 并进入场景树,窗口从此是一等节点:多窗口管理、per-window 渲染缓冲、子窗口嵌入都能用节点语义表达,代价是 Viewport 的类职责被拉宽。
-
pause 模式:process_mode 与 SceneTree.paused——暂停游戏时哪些节点还在跑
paused 只是一道布尔闸门,真正决定节点停不停的是沿 owner 链向上解析出的有效 process_mode;物理服务器不停步、动画默认停——把这两条边界想清楚,暂停逻辑就没什么神秘的了。
-
Node2D 与 CanvasItem:全局变换的脏标记传播
CanvasItem 用脏标记加惰性求值维护全局变换:改动只向上冒泡置位、计算只在读取时发生;理解了传播规则,才能解释为什么频繁改 transform 的 2D 游戏不必每帧全树重算矩阵。
-
PackedScene::instantiate:场景实例化的完整链路
一个 .tscn 文件 instantiate 成活节点树要经历取字符串表、建对象、递归子场景、刷属性、连信号五步,owner 在实例化时被重新赋值——这篇按 scene_state.cpp 的代码走一遍。
-
Control 的布局通知:NOTIFICATION_RESIZED 何时触发
Control 的尺寸变化分两条路:anchor 变化同步触发 RESIZED,容器重排则走延迟的 SORT_CHILDREN;两条路的时机差异决定了自定义 UI 代码该把逻辑挂在哪个通知里。
-
Node 的 _ready 与 _process 调用链源码分析
从 add_child 到 NOTIFICATION_READY,再从 set_process 的标志位到 GDVIRTUAL_CALL 进脚本虚函数,把两个最常用的生命周期回调在 4.2 源码里的完整链路走通。