Godot 的核心抽象:一切游戏对象都是树中的节点。Node(scene/main/node.h,GDCLASS(Node, Object))提供树结构、通知驱动的回调、组、输入路由;SceneTree(scene/main/scene_tree.h:89,继承 MainLoop)驱动每帧更新。

Node

全部状态收在 Data 结构(node.h:199-299):parent/owner/name/tree/viewport/depth/index、HashMap<StringName,Node*> children + children_cache、组数据、进程组与优先级、process/physics_process/input 位域、ready_notified 等。

通知常量(node.h:455-518)

ENTER_TREE=10, EXIT_TREE=11, READY=13, PAUSED=14, PHYSICS_PROCESS=16, PROCESS=17, PARENTED=18, UNPARENTED=19, SCENE_INSTANTIATED=20, POST_ENTER_TREE=27, DISABLED/ENABLED=28/29;另有窗口(1002+)、OS(2009+)、编辑器(9001+)区段。

生命周期传播

  • _propagate_enter_tree(node.cpp:341-389):继承 tree/depth → viewport = 自身 cast_to<Viewport> 或继承父 → 注册组 → 发 ENTER_TREE → emit tree_entered → tree->node_added(this) → 递归子节点
  • _propagate_ready(node.cpp:323-339):先递归子节点(自底向上 ready) → POST_ENTER_TREE → 首次发 READY 并 emit ready
  • READY 处理(node.cpp:255-280):先按 GDVIRTUAL_IS_OVERRIDDEN 自动开启对应 process/input 标志,再 GDVIRTUAL_CALL(_ready)
  • PREDELETE(node.cpp:282-287):清理 owner/owned、从父移除、递归 memdelete 子节点;非主线程释放树内节点会被 cancel_free 拦截

回调全部走通知 + GDVIRTUAL:_ready/_process/_physics_process/_input/_notification 等(node.h:433-444),与 object-model 的通知机制一致。

路径与组

  • get_node 语法(node.cpp:1922-1982):.. 父、%Name 唯一名(查 owned_unique_nodes,回退 owner)、普通名查 children HashMap;绝对路径先上溯到根
  • 组:add_to_group/remove_from_group/is_in_group;persistent 组随场景保存;SceneTree 按组广播通知/调用(见下)
  • queue_free() 转 SceneTree::queue_delete(帧末统一释放)
  • 暂停:ProcessMode INHERIT/PAUSABLE/WHEN_PAUSED/ALWAYS/DISABLED(node.h:79-85)

SceneTree 主循环

成员:Window *root(:133,即主窗口,继承 Viewport)、current_scene、paused、group_map、delete_queue、process_groups(含默认进程组)。

  • physics_process(scene_tree.cpp:639-671):flush 变换通知 → emit physics_frame → viewport picking → _process(true) → MessageQueue flush → timers/tweens → _flush_delete_queue
  • process(scene_tree.cpp:688-791):multiplayer poll → emit process_frame → _process(false) → 场景切换冲刷 → timers/tweens → delete queue
  • _process_group(scene_tree.cpp:1183-1242):按 process_priority 排序、拷贝列表防遍历中增删、跳过暂停节点、发 PROCESS 通知
  • 线程组:SUB_THREAD 组经 _process_groups_thread 派发工作线程(scene_tree.cpp:1244)
  • 组调用:call_group_flagsp/notify_group_flags,GROUP_CALL_REVERSE/DEFERRED/UNIQUE(UNIQUE 经 unique_group_calls 去重)
  • 信号:tree_changed、scene_changed、node_added/node_removed、process_frame、physics_frame
  • set_pause(scene_tree.cpp:1132):同步停/启 PhysicsServer2D/3D 并下发通知

场景切换

change_scene_to_file → change_scene_to_packed → change_scene_to_node(scene_tree.cpp:1705-1724):移除旧场景记 prev_scene_id,新场景存 pending_new_scene_id;下一帧 process() 中 _flush_scene_change(:1677)memdelete 旧场景、挂载新场景、emit scene_changed。

场景序列化:PackedScene

SceneState : RefCounted(scene/resources/packed_scene.h:38-244)是核心:

  • 索引池:names/variants/node_paths/id_paths(属性值即 Variant,见 variant)
  • NodeData{parent,owner,type,name,instance,index,properties[],groups[]}(:58-73)
  • ConnectionData 序列化信号连接(:83-91)
  • base_scene_idx 支持场景继承
  • instantiate(GenEditState)(:165)按池还原节点;延迟属性(DeferredNodePathProperties)处理 NodePath 依赖
  • GenEditState:DISABLED/INSTANCE/MAIN/MAIN_INHERITED(编辑器区分主场景编辑态)

PackedScene : Resource(:248-296,扩展名 .scn)仅持有 Ref<SceneState> state;set_bundled_scene(Dictionary) 是文本/二进制格式的交换表示。

Viewport 与输入

Viewport : Node(scene/main/viewport.h:96)持 RenderingServer 视口与 texture_rid;Window 继承 Viewport,SceneTree::root 即 Window*。输入经 _vp_input<viewport_id> 组路由(node.cpp:171-182);GUI 输入在 Viewport::_gui_input_event(viewport.cpp:1931)。渲染侧见 rendering。

相关