godot-nodes-scenes

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Godot Nodes & Scenes (4.x)

Godot 节点与场景(4.x版本)

Compose games from nodes and scenes, instance them at runtime, and access the tree without crashing on freed or missing nodes. Targets Godot 4.3+.
基于节点与场景构建游戏,在运行时实例化它们,并在访问场景树时避免因节点已释放或缺失导致崩溃。适用于**Godot 4.3+**版本。

When to use

适用场景

  • Use when structuring
    .tscn
    scenes, choosing how to break a feature into nodes, instancing a
    PackedScene
    (bullets, enemies, UI), or setting up autoload singletons.
  • Use when debugging
    get_node()
    /
    $Path
    returning
    null
    , or "Attempt to call on a previously freed instance".
When not to use: GDScript language/syntax →
godot-gdscript
; signal-based decoupling →
godot-signals-groups
; physics bodies/collisions →
godot-physics
.
  • 适用于构建.tscn场景、选择如何将功能拆分为节点、实例化
    PackedScene
    (如子弹、敌人、UI),或配置自动加载单例时。
  • 适用于调试
    get_node()
    /
    $Path
    返回
    null
    ,或“尝试调用已释放实例”错误时。
不适用场景:GDScript语言/语法相关问题请参考
godot-gdscript
;基于信号的解耦请参考
godot-signals-groups
;物理体/碰撞相关问题请参考
godot-physics

Core workflow

核心工作流程

  1. Model with composition. A scene is a tree of nodes saved as
    .tscn
    . Build small, single-purpose scenes (Player, Bullet, Enemy) and compose larger scenes from them. Favor adding child nodes over deep inheritance.
  2. Make a scene reusable by giving its root a script and exposing
    @export
    config. Save it; it becomes a
    PackedScene
    you can instance many times.
  3. Instance at runtime with
    preload
    /
    load
    scene.instantiate()
    add_child(instance)
    . Set position/state after adding (or before, both work).
  4. Access nodes safely. Use
    @onready var x = $Path
    for fixed children; use unique names (
    %Name
    ) for nodes deep in the tree; never assume a node still exists.
  5. Use autoloads for global state/services (game state, audio, scene switching) — registered in Project Settings > Globals (Autoload), accessible by name everywhere.
  6. Free nodes with
    queue_free()
    and guard later access with
    is_instance_valid()
    .
  1. 基于组合建模。场景是保存为.tscn格式的节点树。创建小型、单一用途的场景(如玩家、子弹、敌人),并通过组合这些小场景构建更大的场景。优先添加子节点,而非使用深度继承。
  2. 让场景可复用:为场景根节点添加脚本并暴露
    @export
    配置项。保存后,该场景会成为可多次实例化的
    PackedScene
  3. 运行时实例化:通过
    preload
    /
    load
    加载场景 → 调用
    scene.instantiate()
    创建实例 → 使用
    add_child(instance)
    将实例添加到场景树。可在添加前后设置位置/状态(两种方式都可行)。
  4. 安全访问节点:对于固定子节点,使用
    @onready var x = $Path
    ;对于树中深层节点,使用唯一名称(
    %Name
    );永远不要假设节点仍然存在。
  5. 使用自动加载管理全局状态/服务(如游戏状态、音频、场景切换)—— 在项目设置>全局(自动加载)中注册,可通过名称在任意位置访问。
  6. 使用
    queue_free()
    释放节点
    ,并在后续访问时通过
    is_instance_valid()
    验证节点有效性。

Patterns

实践模式

1. Instance a scene at runtime

1. 运行时实例化场景

gdscript
extends Node2D

const BULLET := preload("res://bullet.tscn")   # preload: loaded at compile time

func shoot(at: Vector2, dir: Vector2) -> void:
    var bullet := BULLET.instantiate()         # create an instance of the scene
    bullet.global_position = at
    bullet.direction = dir                      # set exported/public state
    add_child(bullet)                           # now it's in the tree and runs
gdscript
extends Node2D

const BULLET := preload("res://bullet.tscn")   # preload: loaded at compile time

func shoot(at: Vector2, dir: Vector2) -> void:
    var bullet := BULLET.instantiate()         # create an instance of the scene
    bullet.global_position = at
    bullet.direction = dir                      # set exported/public state
    add_child(bullet)                           # now it's in the tree and runs

2. Safe node access: $, get_node_or_null, and unique names

2. 安全节点访问:$、get_node_or_null与唯一名称

gdscript
@onready var label: Label = $UI/Label            # $ is sugar for get_node("UI/Label")
@onready var health_bar: ProgressBar = %HealthBar # % = scene-unique name (rename-proof)

func update() -> void:
    var optional := get_node_or_null("Maybe/Missing")  # returns null instead of erroring
    if optional:
        optional.queue_free()
gdscript
@onready var label: Label = $UI/Label            # $ is sugar for get_node("UI/Label")
@onready var health_bar: ProgressBar = %HealthBar # % = scene-unique name (rename-proof)

func update() -> void:
    var optional := get_node_or_null("Maybe/Missing")  # returns null instead of erroring
    if optional:
        optional.queue_free()

3. An autoload singleton (global game state)

3. 自动加载单例(全局游戏状态)

gdscript
undefined
gdscript
undefined

game_state.gd — add in Project Settings > Globals > Autoload as "GameState".

game_state.gd — add in Project Settings > Globals > Autoload as "GameState".

extends Node
var score := 0 signal score_changed(value: int)
func add_score(points: int) -> void: score += points score_changed.emit(score) # any scene can: GameState.score_changed.connect(...)
undefined
extends Node
var score := 0 signal score_changed(value: int)
func add_score(points: int) -> void: score += points score_changed.emit(score) # any scene can: GameState.score_changed.connect(...)
undefined

4. Change the running scene

4. 切换运行场景

gdscript
func go_to_level_2() -> void:
    # Swaps the current scene for another. Frees the old scene tree.
    get_tree().change_scene_to_file("res://levels/level_2.tscn")
    # Or, with a preloaded PackedScene:
    # get_tree().change_scene_to_packed(LEVEL_2)
gdscript
func go_to_level_2() -> void:
    # Swaps the current scene for another. Frees the old scene tree.
    get_tree().change_scene_to_file("res://levels/level_2.tscn")
    # Or, with a preloaded PackedScene:
    # get_tree().change_scene_to_packed(LEVEL_2)

Pitfalls

常见陷阱

  • $Path
    /
    get_node()
    return
    null
    or error
    when the path is wrong or the node isn't in the tree yet. Use
    @onready
    , verify the path matches the scene, or use
    get_node_or_null()
    for optional nodes.
  • Renaming a node breaks
    $Path
    .
    Use unique names (
    %Name
    , set via right-click
    Access as Unique Name) so deep references survive renames and reparenting.
  • free()
    mid-frame can crash
    other code still using the node. Prefer
    queue_free()
    (deletes at end of frame) and check
    is_instance_valid(node)
    .
  • Setting child state before
    add_child()
    is fine, but
    _ready()
    on the child only runs after it enters the tree — don't expect its
    @onready
    vars before that.
  • Autoload order matters: autoloads are added before the main scene, in list order. An autoload can't depend on the main scene existing yet.
  • instance()
    was renamed
    to
    instantiate()
    in Godot 4.
    preload
    runs at parse time (path must be constant);
    load
    runs at runtime (path can be a variable).
  • change_scene_to_file()
    is deferred
    , not immediate — Godot swaps and frees the old scene at the end of the current frame. Any code after the call still runs against the old tree, and
    get_tree().current_scene
    isn't the new scene until next frame. Don't read the new scene's nodes on the same line; do it from the new scene's
    _ready()
    .
  • $Path
    /
    get_node()
    返回
    null
    或报错
    :当路径错误或节点尚未加入场景树时会出现此问题。使用
    @onready
    、验证路径是否与场景匹配,或对可选节点使用
    get_node_or_null()
  • 重命名节点会破坏
    $Path
    :使用唯一名称
    %Name
    ,通过右键>设为唯一名称访问),这样深层引用在节点重命名或重新父化后仍然有效。
  • 帧中调用
    free()
    可能导致崩溃
    :如果其他代码仍在使用该节点,会引发崩溃。优先使用
    queue_free()
    (在帧末尾删除节点),并通过
    is_instance_valid(node)
    检查节点有效性。
  • add_child()
    前设置子节点状态
    是可行的,但子节点的
    _ready()
    仅在加入场景树后才会运行——在此之前不要依赖其
    @onready
    变量。
  • 自动加载顺序很重要:自动加载项会按列表顺序在主场景之前添加。自动加载项不能依赖主场景的存在。
  • instance()
    已重命名
    :在Godot 4中,
    instance()
    改名为
    instantiate()
    preload
    在解析时运行(路径必须为常量);
    load
    在运行时运行(路径可为变量)。
  • change_scene_to_file()
    是延迟执行
    ,而非立即生效——Godot会在当前帧末尾切换并释放旧场景。调用后的任何代码仍会基于旧场景树运行,且
    get_tree().current_scene
    要到下一帧才会指向新场景。不要在调用同一行读取新场景的节点;应在新场景的
    _ready()
    中进行操作。

References

参考资料

  • For scene inheritance,
    owner
    /ownership when saving scenes from code, groups vs unique names, and node-path edge cases, read
    references/tree-and-instancing.md
    .
  • 关于场景继承、代码保存场景时的
    owner
    /所有权、组与唯一名称的对比,以及节点路径的边缘情况,请阅读
    references/tree-and-instancing.md

Related skills

相关技能

  • godot-gdscript
    — language, lifecycle, and
    @onready
    .
  • godot-signals-groups
    — decouple instanced scenes from their spawner.
  • godot-resources
    — share data between instances without duplicating it.
  • save-systems
    — persist scene/game state across runs.
  • godot-gdscript
    — 语言、生命周期与
    @onready
    相关内容。
  • godot-signals-groups
    — 将实例化场景与其生成器解耦。
  • godot-resources
    — 在实例间共享数据而不重复复制。
  • save-systems
    — 在多次运行间持久化场景/游戏状态。