This document is about: QUANTUM 2
SWITCH TO

This page is a work in progress and could be pending updates.

Assets in Unity

概述

針對在Unity中可用的各個資產類型,Quantum生成一個以ScriptableObject為基礎的包裝部分類別。針對該包裝的基礎類別是AssetBase。管理AssetBase執行個體的主要類別稱為UnityDB

editing a data asset
從Unity編輯一個資料資產的屬性。
Quantum SDK將針對各個資產生成唯一的GUID。

所有可用的資產的AssetGuids必須在模擬開始時為模擬所知。

實現這一點的過程是:

  • 在編輯器中:

    1. QuantumEditorSettings.AssetSearchPaths中定義的位置收集的所有AssetBase資產。(預設為Assets/Resources/DB)。
    2. 各個AssetBase有一個被生成的輸入項目,其含有AssetGuid以及在運行階段時載入AssetBase所需的資訊。
    3. 輸入項目被儲存到QuantumEditorSettings.AssetResourcePath中定義的AssetResourceContainer資產之中(預設為Assets/Resources/AssetResources.asset)。
  • 在運行階段:

    1. 第一次使用任何UnityDB成員時,使用Resources.Load載入AssetResourceContainer(基於QuantumEditorSettings.AssetResourcePath)。
    2. 使用輸入項目清單以初始化模擬的IResourceManager及動態地載入各個資產所需的資訊。

為了瀏覽目前的資料庫的一部分的資產物件的清單,使用資產DB偵測器視窗,可透過Quantum/Show AssetDB InspectorWindow/Quantum/AssetDB Inspector選單項目來取用。

在Unity指令碼中尋找Quantum資產

使用者建立的每個實體資產類別都取得一個在Unity側生成的相對應的類別,以啟用它們的具現化,如實際的Unity可指令碼物件。

為了舉例說明:一個名為CharacterData的Quantum資產在Unity中取得一個名為CharacterDataAsset的類別,其中單字Asset始終是被新增的尾碼。Unity類別總是含有一個名為AssetObject的屬性,其可被投放到Quantum類別,以存取模擬特定欄位。

使用UnityDB類別,以在Unity側中尋找資產。這裡是一個Quantum資產宣告的一個完整的程式碼片段,以及如何在Unity上存取其欄位的方式:

在Quantum側:

C#

// in any .qtn file:
asset CharacterData;

// in a .cs file:
public unsafe partial class CharacterData
{
    public FP MaximumHealth;
}

在Unity側:

C#

var characterDataAsset = UnityDB.FindAsset<CharacterDataAsset>(myAssetRef.Id);
var characterData = characterDataAsset.Settings;
FP maximumHealth = characterData.MaximumHealth;

資源、可定址及資產套件

Quantum永不硬參照到AssetBase資產。這啟用了任何動態內容傳遞的使用。以下載入資產的方法立即可用:

  • 資源
  • 可定址(需要明確地被啟用)
  • 資產套件(作為一個概念證明,因為資產套件要求高度自訂,及針對各個專案的方法)
enabling addressables
在Quantum編輯器設定中啟用可定址。或者定義`QUANTUM_ADDRESSABLES`及`QUANTUM_ADDRESSABLES_WAIT_FOR_COMPLETION`(針對可定址1.17或更新的版本)。

動態地使用上述任何方法來讓AssetBase成為可載入時,不需要任何額外的步驟。如何載入各個資產的細節儲存於AssetResourceContainer之中。當一個模擬調用Frame.FindAsset,或當調用UnityDB.FindAsset時,將存取這個資訊,以使用一個合適的載入方法。

  • 如果一個資產是在一個Resource資料夾之中,將使用Resources API載入它。
  • 如果一個資產有一個地址(明確或隱含),將使用Addressables API載入它。
  • 如果一個資產屬於一個資產套件(明確或隱含),將會嘗試使用AssetBundle API載入它。

為了使資產清單(AssetResourceContainer)成為動態,需要一些額外的程式碼;請參見在運行階段更新Quantum資產章節以取得更多資訊。

使用者指令碼可以透過使用AssetRef類型(比如AssetRefSimulationConfig)而非AssetBase參照(比如SimulationConfig)來避免硬參照,以參照Quantum資產。

C#

public class TestScript : MonoBehaviour {
  // hard reference
  public SimulationConfigAsset HardRef;
  // soft reference
  public AssetRefSimulationConfig SoftRef;

  void Start() {
    // depending on the target asset's settings, this call may result in
    // any of the supported loading methods being used
    SimulationConfigAsset config = UnityDB.FindAsset<SimulationConfigAsset>(SoftRef.Id);
  }
}

在Unity中拖放資產

從模擬系統之中新增資產執行個體及透過 類別搜尋它們,只能做到如此。方便的解決方案是能夠讓資產執行個體指向資料庫參照,並且在Unity編輯器中拖放這些參照。

一個常見的使用是擴展預先組建的RuntimePlayer類別,以包含一個AssetRef到一個玩家所選擇的一個特定的CharacterSpec資產。將使用被生成的及對於類型安全的asset_ref類型來在資產或其他組態物件之間連接參照。

C#

// this is added to the RuntimePlayer.User.cs file
namespace Quantum {
  partial class RuntimePlayer {
    public AssetRefCharacterSpec CharacterSpec;

    partial void SerializeUserData(BitStream stream) {
      stream.Serialize(ref CharacterSpec);
    }
  }
}

這個程式碼片段將允許生成asset_ref欄位,其只接受一個到類型CharacterSpec的資產的一個連結。這個欄位將在Unity偵測器中顯示,並且可以透過拖放一個資產到槽來填入。

drag & drop asset
針對Quantum可指令碼的物件,資產參照屬性顯示為對於類型安全的槽。

地圖資產內嵌管道

在Quantum中針對生成自訂資料的另一個入口,是地圖內嵌管道。MapAsset是針對Map資產的以AssetBase為基礎的包裝。

Quantum模擬要求Map資產,其含有基本的資訊,比如導航網格及靜態碰撞器;額外的自訂資料可以保存為放置在其自訂資產槽中的資產的一部分——這可以是任何自訂資料資產的一個執行個體。自訂資產可用於儲存初始化時或在運行階段時使用的任何靜態資料。一個典型的例子是繁衍點資料的一個陣列,比如位置、被繁衍的類型等等。

為了使一個Unity場景與一個MapAsset相關聯,MapData MonoBehaviour元件需要在場景之中在一個GameObject上被呈現。當MapData.Asset指向一個有效的MapAsset,內嵌流程將發生。預設下,當一個場景被儲存或當進入遊玩模式時,Quantum自動地內嵌導航網格、靜態碰撞器及場景原型;可在QuantumEditorSettings中更改這個行為。

為了指派一個自訂程式碼片段,讓其在每次內嵌發生時被調用,建立一個繼承於抽象MapDataBakerCallback類別的類別。

C#

public abstract class MapDataBakerCallback {
  public abstract void OnBake(MapData data);
  public abstract void OnBeforeBake(MapData data);
  public virtual void OnBakeNavMesh(MapData data) { }
  public virtual void OnBeforeBakeNavMesh(MapData data) { }
}

然後覆寫強制性OnBake(MapData data)OnBakeBefore(MapData data)方法。

C#

public class MyCustomDataBaker: MapDataBakerCallback {
  public void OnBake(MapData data) {
    // any custom code to live-load data from scene to be baked into a custom asset
    // generated custom asset can then be assigned to data.Asset.Settings.UserAsset
  }
  public void OnBeforeBake(MapData data) {

  }
}

預先載入可定址資產

Quantum需要資產可被同步地載入。

第1.16版或更舊版本

在可定址版本1.17版之前的版本,除了在模擬開始之前預先載入,或使用Unity的SyncAddressables範例,沒有其他方法可以同步地載入可定址資產。

第1.17版或更新版本

在可定址1.17版中新增了WaitForCompletion,其新增了同步地載入資產的能力。為了針對Quantum啟用它,請定義QUANTUM_ADDRESSABLES_USE_WAIT_FOR_COMPLETION或在QuantumEditorSettings資產的Build Features段落中使用切換。

雖然同步載入是可能的,但在某些情況下,預先載入資產仍然可能是更好的方法;QuantumRunnerLocalDebug.cs指令碼展示了如何達成這點。

內嵌資產基礎載入資訊

AssetResourceContainer是一個ScriptableObject,其含有如何載入各個AssetBase及對應它們到AssetGuids的資訊。

請注意: `AssetBase`本身並不是一個Quantum資產。

每次使用選單選項Quantum > Generate Asset Resources或匯入在QuantumEditorSettings.AssetSearchPaths的其中之一的一個資產時,將在QuantumEditorSettings.AssetResourcePath所特定的位置完整地重新建立AssetResourceContainer

在建立AssetResourceContainer時,位於任何QuantumEditorSettings.AssetSearchPaths中的各個AssetBase將被指派到一個群組。預設存在三個群組:

  • ResourcesGroup
  • AssetBundlesGroup;以及,
  • AddressablesGroup

以下圖表展示了決定一個資產被指派到哪個群組的過程。

assetresourcecontainer generation
指派一個資產到一個群組的流程。

一個資產被認為是可定址的 前提是

  • 它被指派一個地址;
  • 其任何的上層資料夾都是可定址的;或是,
  • 它巢狀於另一個可定址的資產。

同樣的邏輯適用於決定一個資產是否屬於一個資產套件的一部分。

為了在匯入資產時停用內嵌AssetBase,請取消勾選QuantumEditorSettings.UseAssetBasePostprocessor

在組建中更新Quantum資產

一個外部CMS可以提供資料資產;這在提供平衡更新到一個已經發布的遊戲時特別有用,而不需要建立一個玩家必須更新的新組建。

這個方法允許含有關於由資料驅動的方面的資訊,比如角色規格、地圖、NPC規格等等的資訊的平衡表,獨立地從遊戲組件被更新。在這個情況下,遊戲客戶端將總是嘗試連接到CMS服務,檢查那裡是否有更新,並且(如果需要的話)在開始或加入線上對戰之前,升級它們的遊戲資料到最新版本。

更新已存在的資產

建議使用可定址或資產套件,因為這些都是開箱即用的。任何屬於一個可定址或屬於一個資產套件的一部分的AssetBase將使用適合的方法在運行階段被載入。

為了避免在遊戲模擬時下載資產而產生的不可預測的延隔高峰,請考慮在此下載及預先載入您的資產: 預先載入可定址的資產.

新增新的資產

在編輯器中生成的AssetResourceContainer將含有在其建立時所呈現的所有資產的清單。如果一個專案的動態內容包含新增新的Quantum資產而不建立一個新的組建,則需要執行一個方法以更新該清單。

為了達成這個,建議的方法是透過一個部分UnityDB.LoadAssetResourceContainerUser方法的擴展。當第一個模擬開始或任何UnityDB方法被調用時,Quantum將嘗試載入AssetResourceContainer。預設是假設AssetResourcesContainer是一個資源並且位於QuantumEditorSettings.AssetResourcePath。為了覆寫這個行為,UnityDB.LoadAssetResourceContainerUser需要被執行。

實例執行方式

首先,AssetResourceContainer需要被移出Resources資料夾之外。透過設定QuantumEditorSettings.AssetResourcePath來完成這個動作:

assetresourcecontainer path override

第二,新的AssetResourceContainer需要被做成一個可定址:

addressable assetresourcecontainer

最後,程式碼片段執行部分方法:

C#

partial class UnityDB {
  static partial void LoadAssetResourceContainerUser(ref AssetResourceContainer container) {
    var path = QuantumEditorSettings.Instance.AssetResourcesPath;

#if UNITY_EDITOR
    if (!UnityEditor.EditorApplication.isPlaying) {
      container = UnityEditor.AssetDatabase.LoadAssetAtPath<AssetResourceContainer>(path);
      Debug.Assert(container != null);
      return;
    }
#endif

    var op = Addressables.LoadAssetAsync<AssetResourceContainer>(path);
    container = op.WaitForCompletion();
    Debug.Assert(container != null);
  }
}
這是一個簡化的執行方式,並且根據專案的需要,可能需要新增由`Addressables.LoadAssetAsync`傳回的`AsyncOperationHandle`的一些管理。

以動態資產DB來新增新的資產

如果新的資產可以在一個確定性的方式下被建立,可使用此處所討論的DynamicAssetDB動態資產.

Back to top