節點與場景實體

本指南將說明如何獲取節點、建立節點、將節點新增為子節點,以及如何用程式碼實體化場景。

也參考

請參閱 編輯實體 教學,進一步瞭解 Godot 處理場景實體化的方法。

取得節點

你可以透過呼叫 Node.get_node() 方法來取得節點的參考。要讓這個方法正常運作,該子節點必須已經存在於場景樹中。在父節點的 _ready() 函式中取得節點可以保證這一點。

舉例來說,如果你有如下的場景樹,並且想在腳本中取得 Sprite2D 和 Camera2D 節點的參考。

../../_images/nodes_and_scene_instances_player_scene_example.webp

你可以使用以下程式碼來達成。

var sprite2d
var camera2d

func _ready():
    sprite2d = get_node("Sprite2D")
    camera2d = get_node("Camera2D")

請注意,取得節點時是使用節點名稱,而非型別。上述範例中的「Sprite2D」與「Camera2D」都是該節點在場景中的名稱。

../../_images/nodes_and_scene_instances_sprite_node.webp

如果你在「場景」面板中將 Sprite2D 節點重新命名為 Skin,那就必須在腳本中將取得該節點的程式碼更改為 get_node("Skin")

../../_images/nodes_and_scene_instances_sprite_node_renamed.webp

節點路徑

在取得節點參考時,不只限於直接子節點。get_node() 方法支援路徑,有點像是在檔案總管中操作,使用斜線分隔各節點。

以下列範例場景為例,腳本掛載在 UserInterface 節點上。

../../_images/nodes_and_scene_instances_ui_scene_example.webp

要取得 AnimationPlayer 節點,可以使用以下程式碼。

var animation_player

func _ready():
    animation_player = get_node("ShieldBar/AnimationPlayer")

備註

和檔案路徑一樣,可以使用「..」取得父節點。不過,最佳實踐是避免這樣做,以維持良好的封裝性。你也可以讓路徑以斜線開頭,代表這是絕對路徑,此時最上層節點會是「/root」,也就是應用程式預設的根視窗。

語法糖

在 GDScript 中,你可以使用兩個速記法來簡化你的程式碼。第一個是在成員變數前加上 @onready 標註,這樣變數會在 _ready() 回呼前自動初始化。

@onready var sprite2d = get_node("Sprite2D")

此外,也可以用美元符號「$」作為 get_node() 的簡寫。只要將「$」放在你想取得的節點名稱或路徑前即可。

@onready var sprite2d = $Sprite2D
@onready var animation_player = $ShieldBar/AnimationPlayer

建立節點

要從程式碼建立節點,只需像其他類別型資料一樣呼叫 new() 方法即可。

你可以將新建立的節點參考存入變數,然後用 add_child() 把它加入為腳本掛載節點的子節點。

var sprite2d

func _ready():
    var sprite2d = Sprite2D.new() # Create a new Sprite2D.
    add_child(sprite2d) # Add it as a child of this node.

要刪除節點並釋放其記憶體,可以呼叫它的 queue_free() 方法。這會將節點排入佇列,在本幀處理結束後刪除。屆時,Godot 會把該節點從場景移除並釋放記憶體資源。

sprite2d.queue_free()

在呼叫 sprite2d.queue_free() 之前,遠端場景樹看起來如下。

../../_images/nodes_and_scene_instances_remote_tree_with_sprite.webp

當引擎釋放該節點後,遠端場景樹就不會再顯示這個精靈了。

../../_images/nodes_and_scene_instances_remote_tree_no_sprite.webp

你也可以呼叫 free() 立即銷毀節點,但需謹慎使用,因為所有對該節點的參考會立即變成 null。除非你確定這樣做沒問題,否則建議用 queue_free()

釋放節點時也會同時釋放其所有子節點。因此,若要刪除場景樹的整個分支,只需釋放最上層的父節點即可。

場景實體化

場景是可以重複產生多份副本的範本。這個動作稱為「實體化」,在程式碼中實體化場景需分兩個步驟:

  1. 從本地磁碟載入場景。

  2. 將載入的 PackedScene 資源產生實體。

var scene = load("res://my_scene.tscn")

預先載入場景可以提升使用者體驗,因為載入動作會在編譯器讀取腳本時發生,而不是在執行階段才載入。這個功能僅支援 GDScript。

var scene = preload("res://my_scene.tscn")

此時,scene 仍是一個打包場景資源,而不是節點。要建立實際的節點,需呼叫 PackedScene.instantiate()。這個方法會回傳一個節點樹,可以作為目前節點的子節點使用。

var instance = scene.instantiate()
add_child(instance)

這種兩步驟的方式好處是可以維持場景資源已載入的狀態,隨時快速產生新實體。例如可用於即時生成多個敵人或子彈。