This document is about: QUANTUM 2
SWITCH TO

このページは編集中です。更新が保留になっている可能性があります。

Unityのアセット

概要

Quantum は Unity で利用可能な各アセットタイプに対して、 ScriptableObject ベースのラッパーパーシャルクラスを生成します。このようなラッパーのベースとなるクラスが AssetBase です。AssetBase のインスタンスを管理するメインクラスは UnityDB と呼ばれます。QuantumはUnityで利用できる各アセットに対して、ScriptableObjectベースのラッパーパーシャルクラスを生成します。このラッパーのベースクラスはAssetBaseです。AssetBaseインスタンスを管理するメインクラスは、UnityDBという名前です。

editing a data asset
Unityのデータアセットのプロパティを編集
Quantum SDKは、各アセットに固有のGUIDを生成します。

起動時に、シミュレーションに全ての利用可能なアセットのAssetGuidsを知らせる必要があります。

知らせる方法は以下の通りです。

  • エディター内:

    1. QuantumEditorSettings.AssetSearchPaths で定義された場所(デフォルトでは Assets/Resources/DB )から収集したすべての AssetBase アセットです。
    2. AssetBase には、AssetGuidAssetBase を実行時に読み込むために必要な情報を含む生成されたエントリーがあります。
    3. エントリーは QuantumEditorSettings.AssetResourcePath で定義された AssetResourceContainer アセットに保存されます(デフォルトでは Assets/Resources/AssetResources.asset です)。
  • ランタイム時:

    1. 最初に UnityDB のいずれかのメンバーが使用されると、Resources.Load を使ってAssetResourceContainer が 読み込まれます (QuantumEditorSettings.AssetResourcePath に基づいています)。
    2. エントリーのリストは、各アセットを動的に読み込むために必要な情報とともに、シミュレーションの IResourceManager を初期化するために使用されます。

現在データベースの一部となっているAsset Objectのリストを参照するには、Quantum/Show AssetDB InspectorおよびWindow/Quantum/AssetDB Inspectorメニュー項目からアクセス可能なAssetDB Inspectorを使用します。

Finding Quantum Assets in Unity scripts

ユーザーが作成したすべてのコンクリートクラスには、Unity側で作成された対応するクラスが与えられ、実際のUnityスクリプタブルオブジェクトとしてインスタンス化を有効にすることができるようになります。

例:CharacterDataと名前のついてQuantumアセットはUnityではCharacterDataAssetという名前の付いたクラスが与えられます。ここには必ずAssetという言葉がサフィックスとして追加されます。Unityクラスには常に、シミュレーション固有のフィールドにアクセスするためQuantumクラスにキャストされうるAssetObjectというプロパティが含まれます。

Unity側のアセットを探すには、UnityDBクラスを使用します。以下では、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
**2019 より前の Unity バージョンでのみ必要です。** QuantumEditorSettings で Addressables を有効にします。 あるいは、`QUANTUM_ADDRESSABLES` および `QUANTUM_ADDRESSABLES_WAIT_FOR_COMPLETION` を定義します (Addressables 1.17 以降の場合)。

AssetBase を上記のいずれかの方法で動的に読み込むために、特別な手順は必要ありません。各アセットの読み込み方法の詳細は AssetResourceContainer に格納されています。この情報は、シミュレーションが Frame.FindAsset を呼び出したとき、または UnityDB.FindAsset を呼び出したときにアクセスされ、適切な読み込み方法が使用されるように導かれます。 上記のメソッドを使用すれば、AssetBaseを動的に読み込めるようにするためにその他の手順は不要です。各アセットを読み込む際の詳細は、AssetResourceContainerに保存されています。この情報は、シミュレーションがFrame.FindAssetを呼んだ場合、またはUnityDB.FindAssetが呼ばれた場合に、適切な読み込みメソッドを使用する必要が生じた際にアクセスされます。

  • アセットが Resource フォルダにある場合、Resources API を使用して読み込まれます。 アセットがResourceフォルダ内にある場合、アセットはResourcesAPIを使用して読み込まれます。
  • アセットにアドレスがある場合(明示的または暗黙的)、Addressables API を使用して読み込まれます。 アセットにアドレスがある場合(明示的または暗黙的)、アセットはAddressablesAPIを使用して読み込まれます。
  • アセットがアセットバンドルに属している場合(明示的または暗黙的に)、AssetBundle API を使用してアセットを読み込もうと試みます。 アセットがアセットバンドルに属する場合(明示的または暗黙的)、AssetBundleAPIを使用したアセットの読み込みが試行されます。 アセットのリスト(AssetResourceContainer)自体を動的にするためには、いくつかの追加コードが必要です。詳細については、Updating Quantum Assets At Runtime の項を参照してください。 アセットのリスト(AssetResourceContainer)を動的にするには、コードの追加が必要です。詳細な情報は、ランタイム時にQuantumアセットを更新セクションを参照してください。

ユーザースクリプトは、Quantumアセットを参照する際に、AssetBase参照(例:SimulationConfig)の代わりに AssetRef 型(例:AssetRefSimulationConfig)を用いて、ハードリファレンスを回避することができます。 Quantumアセットを参照する際、AssetBase参照(たとえばSimulationConfig)の代わりにAssetRef型(たとえばAssetRefSimulationConfig)を使用すれば、ユーザースクリプトはハード参照を回避できます。

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でアセットをドラッグアンドドロップ

アセットインスタンスを追加し、シミュレーション内からFrameクラスで検索しても、システムはそれ以上のことはできません。このため、アセットインスタンスにデータベースへの参照を持たせ、Unity エディター内でそれらの参照をドラッグアンドドロップできるようにすることで、利便性の高いソリューションが生まれました。

よくある使い方としては、ビルド前の RuntimePlayer クラスを拡張して、プレイヤーが選択した特定の CharacterSpec アセットへの AssetRef を含めることです。生成されたタイプセーフな asset_ref 型は、アセットや他の設定オブジェクト間の参照をリンクするために使用されます。 よくある利用法としては、ビルド前のRuntimePlayerクラスを拡張し、プレイヤーが選択した特定のCharacterSpecアセットにAssetRefを含めることです。生成された型セーフな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インスペクタに表示され、スロットにアセットをドラッグ&ドロップすることで入力することができます。 このスニペットでは、asset_refフィールドを生成し、このフィールドはCharacterSpec型のアセットへのリンクのみを受容します。このフィールドはUnityインスペクタ―に表示され、アセットをスロットにドラッグアンドドロップすることで入力できます。

drag & drop asset
Asset refプロパティは、Quantumスクリプト可能なオブジェクトのタイプセーフスロットとして表示されます。 アセット参照プロパティは、Quantumスクリプト可能オブジェクトへの型セーフスロットとして表示されます。

マップアセット・ベイキングパイプライン

Quantumでカスタムデータを生成するためのもう一つのエントリーポイントは、マップベーキングパイプラインです。MapAssetMap アセットの AssetBase ベースラッパーです。

Map アセットは Quantum シミュレーションに必要なもので、Navmeshes や静的コライダーなどの基本情報が含まれています。追加のカスタムデータは、カスタムアセットスロットに置かれたアセットの一部として保存することができます。カスタムアセットには、初期化時や 実行時に使用する静的データを格納することができます。典型的な例としては、位置、スポーンタイプなどのスポーンポイントデータの配列があります。

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) {

  }
}

Addressable アセットのプリロード

Quantum では、アセットが同期的に読み込み可能である必要があります。

v1.16以降

1.17以前のAddressablesバージョンでは、シミュレーション開始前にプリロードするか、UnityのSyncAddressablesサンプルを使用する以外に、Addressableアセットを同期的に読み込む手段はありませんでした。

v1.17以前

WaitForCompletion は Addressables 1.17 で追加され、アセットを同期して読み込む機能が追加されました。Quantum でこれを有効にするには、 QUANTUM_ADDRESSABLES_USE_WAIT_FOR_COMPLETION を定義するか、 QuantumEditorSettings アセットの Build Features セクションのトグル を使用します。

同期読み込みも可能ですが、プリロードの方が望ましい場合もあります。 QuantumRunnerLocalDebug.cs スクリプトは、これを実現する方法を示しています。

AssetBase の読み込み情報をベイクする

AssetResourceContainerScriptableObject で、各 AssetBase を読み込んで AssetGuids にマッピングするための情報を含んでいます。

N.B.: `AssetBase` is not a Quantum asset itself.

メニューオプション Quantum > Generate Asset Resources を使用するか、QuantumEditorSettings.AssetSearchPaths のいずれかにあるアセットをインポートするたびに、AssetResourceContainerQuantumEditorSettings.AssetResourcePath で指定した場所に完全に再作成されます。

AssetResourceContainer の作成時に、任意の QuantumEditorSettings.AssetSearchPaths にある各 AssetBase はグループに割り当てられます。デフォルトでは、次の3つのグループが存在します。

  • ResourcesGroup
  • AssetBundlesGroup
  • AddressablesGroup

アセットをどのグループに割り当てるかを決定するプロセスは、下図のとおりです。

assetresourcecontainer generation
アセットにグループを割り当てるフロー。

以下の場合、アセットはAddressableであるとみなされます。

  • アドレスが割り当てられている。
  • その親フォルダのいずれかがAddressableである。
  • 他のAddressableアセットの中にネストされている場合。

同じロジックが、アセットが Asset Bundle の一部であるかどうかを決定する際にも適用されます。

アセットをインポートするときに AssetBase をベイクしないようにするには、QuantumEditorSettings.UseAssetBasePostprocessor のチェックボックスをオフにします。

Quantum Assets をビルドで更新する

外部CMSからデータアセットを提供することは可能です。これは、既にリリースされたゲームに対して、プレイヤーがアップデートしなければならない新しいビルドを作成することなく、バランス調整のアップデートを提供する場合に特に有用です。

このアプローチでは、キャラクターのスペック、マップ、NPCのスペックなど、データ駆動型の側面に関する情報を含むバランス調整シートを、ゲームのビルド自体から独立して更新することができます。この場合、ゲームクライアントは常にCMSサービスに接続し、アップデートがあるかどうかを確認し、(必要であれば)オンラインマッチを開始または参加する前にゲームデータを最新バージョンにアップグレードしようとします。

既存アセットの更新

Addressable または Asset Bundle を使用することをお勧めします。Addressable または Asset Bundle の一部である AssetBase は、適切なメソッドを使用して実行時に読み込まれます。

ゲームシミュレーション中にアセットをダウンロードすることによる、予測できない遅延スパイクを避けるために、アセットをダウンロードし、プリロードすることを検討してください。Addressable Assetsのプリロード](#preloading_addressable_assets)

新しいアセットを追加

エディタで生成される AssetResourceContainer には、その作成時に存在したすべてのアセットのリストが含まれます。もし、プロジェクトの動的コンテンツに、新しいビルドを作成せずに新しい Quantum アセットを追加する場合、リストを更新する方法を実装する必要があります。

これを達成するために推奨される方法は、部分的な UnityDB.LoadAssetResourceContainerUser メソッドの拡張を使用することです。最初のシミュレーションを開始するとき、あるいは UnityDB メソッドを呼び出すとき、Quantum は AssetResourceContainer を読み込もうと試みます。デフォルトでは、AssetResourcesContainerQuantumEditorSettings.AssetResourcePath にある Resource であると仮定されます。この挙動をオーバーライドするには、UnityDB.LoadAssetResourceContainerUser を実装する必要があります。

実装例

まず、AssetResourceContainerResources フォルダから移動する必要があります。これは、QuantumEditorSettings.AssetResourcePathを設定することで行います。

assetresourcecontainer path override

次に、新しい AssetResourceContainer は Addressable にする必要があります。

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);
  }
}
This is a simplified implementation and, depending on project's needs, some management of the `AsyncOperationHandle` returned by `Addressables.LoadAssetAsync` may need to be added.

DynamicAssetDB による新しいアセットの追加

新しいアセットを決定論的な方法で作成できる場合、DynamicAssetDB を使用することができます。ダイナミックアセット](./assets-simulation#dynamic_assets)

Back to top