[Unity] 從零開始的學習心得 #4 – Unity 與外部資源

unity-learning-totally-review-4

此篇文章是《從零開始的 Unity 學習心得》系列的第四篇文章,這個系列是記錄我對 Unity 的開發及學習心得,包含我用何種方式去理解 Unity 的運作,並且在我所知的範圍內盡可能說明相關原理與開發要點。完整系列的目錄可以參考:

在遊戲進行時載入資源 (Asset)

很多遊戲都會在啟動,或者在特定的時間點出現一個進度條,必須等待進度條跑完才能繼續遊戲,先不論怎麼實作進度條,來說說為何需要這個讀取檔案的步驟?

想想一些次世代的遊戲安裝於電腦中時,會佔用多少容量?10GB?20GB?還是更多?

對於這些誇張容量的遊戲,要求電腦一次性的啟動檔案是不切實際的;即使容量不到 1G 的小型遊戲,在不同設備與作業系統上也未必允許一次性地開啟所有資料。所以一般遊戲在啟動時只會讀取當前必要的部份檔案,然後等到遊戲進度到達需要更多檔案的時候,再讀取另一部分,同時將用不到的資料釋出,藉此降低電腦或設備的負擔,也是為在有限的設備上,盡可能做出最棒的遊玩效果。

Unity 的 Resources 資料夾

上篇文章有提過,Unity 會在啟動的時候開啟一個場景檔案(Scene)做為遊戲的初始點,並在需要的時候在讀取切換到不同的場景之中。除了場景之外,Unity 還有很多可以方法可以讀取資源檔案至遊戲中利用,其中最基本的便是 Resources 這功能。

Resources 是一個 Unity 的 API 類別,也是一個專案中特殊的資料夾。這個 API 可以讀取音訊、圖片等各式檔案,交給場景中的物件(GameObject)與組件(Component)利用,前提是這些檔案必須在專案中被放置到名為 Resources 的特別資料夾。

關於 Unity 特殊資料夾的參考資料:https://docs.unity3d.com/Manual/SpecialFolders.html

除了一般常見的檔案,還有一些透過 Resources 來讀取的 Unity 特殊資源:

  • Prefab
  • ScriptableObject

Prefab

Prefab 檔跟場景檔有個共通點,也是一個儲存物件與組件的檔案,不同的地方在於:場景是儲存一個絕對空間中的所有物件;Prefab是儲存一個局部的物件結構,以及其中的組件資訊。

Prefab 以單一個物件為根物件(Root GameObject),並在其下可以有無數個子物件(Child),以及被預先掛上的組件及其參數,整組儲存在外部儲存空間待命。Unity 執行 Resources.Load 將以根物件為讀取與辨識標的,將整份物件群複製到場景中進行後續利用。

當一組物件被儲存為 Prefab 後,可以被重複複製進場景中,作為一組有動態數量的複數物件,例如:子彈、怪物;也可以作為選擇性讀取的物件,節省場景重的物件數量,例如:可供選擇切換的各式武器、只會短暫使用 UI 介面。

利用場景讀取會長時間使用的固定物件,利用 Prefab 讀取會依情況有不同需求的局部物件,善用兩者的特性,可以節省場景的大小與數量、做出有彈性的物件結構,讓遊戲開發有更多的可能性。

補充

  1. 以優化角度來說,不建議用 Prefab 機制單次建立太巨大的結構,比如無縫地圖等。應該視情況從 Prefab 跟場景的 Additive 模式中擇一利用。
  2. 目前 Unity 不支援 Nested Prefab,但是有插件可以使用,或者自行實作相關的巢狀讀取機制。

ScriptableObject

在說明 ScriptableObject 之前,應該先理解 Unity 對於 Assets 有一套管理機制,用來避免同樣一份資源檔被重複讀取進記憶體。換句話說,預設情形下你在程式碼的兩處分別讀取了"某圖片檔案",Unity 會幫你"共用"資源,不會真的讀取兩次而造成浪費。

在腳本中控制的 Unity 類別:GameObject、Texture、Clip 等,都會在 Unity 底層對應到 Assets 管理機制中的某份 Asset 資源;而開發時自訂的一般類別(class)則不會有對應的資源,只是個資料組合。

而除了內建的圖片、音訊、遊戲物件等格式,ScriptableObject 便是 Unity 提供的自訂格式手段。繼承了 ScriptableObject 之後的類別會在 Assets 管理機制中有個對應的位置,也可以在開發階段儲存為一份在 Resources 中的檔案,並擁有資源共用的特性與好處。

一般來說,ScriptableObject 不是每個開發 Unity 專案時必要的手段,但是若要深入開發一些自訂 Editor 功能,會是一個值得研究部分。

網路資源

Unity 提供了 WWWUnityWebRequest 兩個類別用於網路下載,後者是較新的 API,可以透過 http 網路連線讀取線上資源,如:圖片、文字等。

配合網路下載,可以讓遊戲在不更新程式的情況下,增加更多可用的資源檔案;或者讓遊戲安裝檔本身瘦身,等到啟動遊戲後再獲取必要的資源更新。

很多的 App 會在初次啟動時更新大量的資源,檔案的數量可能動輒上百份,Unity 有個內建的 AssetsBundle 便是為此存在,可以打包用於下載的大量資源檔案,避免需要大量重複的使用 WWWUnityWebRequest,並有著自動檢查版本等特性。

不過我對 AssetsBundle 不熟。