Autoload v.s. 一般節點
Godot 提供一個功能,可以自動在專案根節點載入節點,讓你能全域存取這些節點,達到單例(Singleton)的效果:請參閱 單例(自動載入)。這些自動載入的節點在你用 SceneTree.change_scene_to_file 切換場景時不會被釋放。
在本篇指南中,我們將學習如何使用 Autoload 功能,以及可以避免使用 Autoload 的一些技巧。
音訊截斷問題
其他的引擎鼓勵使用 Manager 類別,即一種用來管理許多全域存取物件功能的單例。託節點樹與訊號的福,Godot 中提供了許多方法來避免全域狀態。
舉例來說,假設我們在做一個平台遊戲,撿到金幣時需要播放音效,可用 AudioStreamPlayer 節點。但如果 AudioStreamPlayer 正在播放時又被呼叫,新的音效會中斷原本的聲音。
有一種解決方法是撰寫一個全域且自動載入的音訊管理員類別。這個類別要產生一個 AudioStreamPlayer 節點集區,然後在遇到音效播放要求的時候照順序讓每一個 AudioStreamPlayer 來播放。假設我們管這個類別叫 Sound ,則我們在專案任何一個地方都可以通過呼叫 Sound.play("coin_pickup.ogg") 來使用。這樣一來便在短期內解決了問題,但接著會引發更多的問題:
全域狀態 :現在,有一個物件必須要負責所有物件的資料。若
Sound類別發生錯誤,或是沒有可用的 AudioStreamPlayer,則所有呼叫 Sound 的節點都會壞掉。全域存取 :現在所有物件都能從任何地方呼叫
Sound.play(sound_path),所以要找到 Bug 的原因變得更加困難了。全域資源分配 :現在從一開始就有一個
AudioStreamPlayer節點集區,如果數量太少的話便會遇到 Bug,而數量太多的話則會佔用過多的記憶體。
備註
有關全域存取,問題在於,在本例中,任何地方的「所有」程式碼都有可能將錯誤的資料傳給 Sound Autoload。因此,發生問題時要尋找的範圍就變成了整個專案。
如果將程式碼保留在場景中,則只有一兩個程式碼可能會與音訊有關。
相較之下,如果每個場景都在自己內部保佑必要數量的 AudioStreamPlayer 的話,則這些所有的問題便解決了:
每個場景都管理自己的狀態資訊,所以當資料由問題的時候,就只會影響到單一場景。
每個場景都只存取自己的節點。所以當現在出現 Bug 時,就很容易找出是哪個節點的錯。
每個場景都只分配到所需數量的資源。
什麼時候該用 Autoload
GDScript 支援使用 static func 建立 static (靜態) 函式。 當與 class_name 結合使用時,(靜態函式)可以建立輔助函式程式庫,而無需建立實例來呼叫它們。 靜態函式也具有限制,它們不能引用成員變數、非靜態(non-static)函式或 self 。
自 Godot 4.1 起,GDScript 也支援使用 static var 宣告的「靜態」變數。這表示您現在可以在一個類別的不同實例之間共享變數,而不需要建立一個獨立的自動載入節點。
作用域更廣的系統 :若單例管理自己的資訊,且不會存取到其他物件的資料,則建立一個處理廣域資料的系統也不錯。例如,工作或對話系統。
備註
Autoload 並不完全同等與單例 (Singleton)。在 Autoload 中沒有方法可以防止再次實體化一個 Autoload 的節點。只能算是一種能不考慮遊戲節點架構以及目前執行的節點是什麼,就讓節點作為場景樹子節點自動載入的方法,例如,按 F6 鍵。
然後,就能取得自動載入的節點,例如有一個叫 Sound 的 Autoload,則可以呼叫 get_node("/root/Sound") 。