【Unity】ResourcesフォルダからAddressableに切り替える

2023年5月10日

アドレス指定可能型アセットシステム(Addressable Asset System)

Addressable Asset Systemは、"アドレス “によってアセットをロードする簡単な方法を提供します。コンテンツパックの作成と展開を簡素化することで、アセット管理のオーバーヘッドを処理します。

アドレス指定型アセットシステムは、非同期ロードを使用して、あらゆる場所からのロードと、あらゆる依存関係のコレクションをサポートします。直接参照、従来のアセットバンドル、リソースフォルダのいずれを使用している場合でも、アドレス指定可能なアセットは、ゲームをよりダイナミックにするためのシンプルな方法を提供します。

アセットとは?

アセットとは、ゲームやアプリを作成するために使用するコンテンツのことです。アセットには、プレハブ、テクスチャ、マテリアル、オーディオクリップ、アニメーションなどがあります。

アドレスとは?

アドレスは、何かが存在する場所を特定するものです。例えば、携帯電話に電話をかけると、電話番号が住所として機能します。相手が家にいても、職場にいても、パリにいても、ピッツバーグにいても、電話番号でつながることができるのです。

アドレス指定可能なアセットとは?

あるアセットが「アドレス指定可能(addressable)」とマークされると、そのアドレス指定可能なアセットはどこからでも呼び出すことができるようになります。そのアドレス指定可能なアセットがローカルプレーヤーに存在しようが、コンテンツ配信ネットワークに存在しようが、システムはそれを探し出し返します。アドレスを介して単一のアドレス指定可能なアセットをロードすることも、定義したカスタマイズされたグループラベルを使用して多数のアドレス指定可能なアセットをロードすることも可能です。

なぜ必要になるのか?

従来、コンテンツを効率的にロードするためにゲームアセットを構造化することは困難でした。

アドレス指定可能なアセットを使用すると、反復サイクルが短縮され、アプリケーションの設計、コーディング、およびテストに多くの時間を割くことができるようになります。アドレス指定可能なアセットでは、アセットがアドレス指定可能であることを確認し、それをロードします。

アドレス指定可能なアセットシステムは、どのような問題を解決するのでしょうか?

開発サイクル

アドレスでコンテンツを参照することは、非常に効率的です。アドレスの参照により、コンテンツは単に検索されるだけです。コンテンツを最適化するために、コードを変更する必要はありません。

依存性の管理

アドレスでコンテンツを返すだけでなく、そのコンテンツの依存関係もすべて返します。アセット全体の準備が整った時点で通知されるため、コンテンツが返される前にメッシュ、シェーダー、アニメーションなどがすべてロードされます。

メモリ管理

アドレスはアセットをロードするだけでなく、アンロードも行います。参照は自動的にカウントされ、堅牢なプロファイラーが潜在的なメモリ問題を発見するのに役立ちます。

コンテンツのパッキング

:システムは複雑な依存関係の連鎖をマッピングして理解するため、アセットの移動や名前の変更があっても、バンドルの効率的なパッキングを可能にします。アセットをローカルとリモートの両方に展開することで、ダウンロードコンテンツ(DLC)やアプリケーションサイズの縮小を容易に準備することができます。

既存のゲームの移行ついてはどうですか?

Addressable Asset Systemは、直接参照、Resourceフォルダ、Asset Bundleのいずれを使用しても、アップグレードのための移行経路を提供します。

Resourcesフォルダからの移行

Resourcesサンプルの作成

Addressable Assets packageのインストール

WindowメニューのPackageManagerからAddressablesをインストールします

Resourceフォルダにアセットのサンプルを保存

今回はサンプルとしてプレファブを作っておきます

動的にゲームオブジェクトロードして生成するコード

実行中にリソースフォルダからロードしてシーンに登場させます

using UnityEngine;

public class LoadPrefab : MonoBehaviour
{
    void Start()
    {
        var cube = Resources.Load<GameObject>("Cube");
        Instantiate(cube);
    }
}

シーンの構成

新しくゲームオブジェクトを作成して、スクリプトをアタッチします

実行結果

アドレス指定可能型アセットシステムへの移行

Cubeプレファブを選択して、Addressableにします

プレファブアセットの保存場所を移動する旨のメッセージが出ますので、Yesを選択します

Resources_movedフォルダが自動作成されてプレファブが移動されています
もちろん、このまま実行してもエラーになります

スクリプトの更新

using UnityEngine;
using UnityEngine.AddressableAssets;

public class LoadPrefab : MonoBehaviour
{
    async void Start()
    {
        var cube = Addressables.LoadAssetAsync<GameObject>("Cube");
        await cube.Task;
        Instantiate(cube.Result);
    }
}

このコードはUnityのAddressable Assetsを使用して、アセットバンドルからプレハブをロードし、インスタンス化する方法を示しています。

usingステートメントでUnityエンジンとAddressable Assetsをインポートします。

LoadPrefabクラスはMonoBehaviourを継承しています。

Start()メソッドは、UnityのライフサイクルイベントであるStart時に自動的に呼び出されます。

asyncキーワードは、このメソッドが非同期であることを示します。

Addressables.LoadAssetAsyncメソッドは、アセットバンドルから指定されたアセットのロードを開始します。この場合、Cubeプレハブをロードします。

awaitキーワードは、ロードが完了するまでcube.Taskが待機することを示します。

Instantiateメソッドは、ロードされたプレハブをインスタンス化して、シーンに表示します。

したがって、このコードは、アセットバンドルからCubeプレハブを非同期でロードし、完了したらシーンに表示します。

実行結果

移行前と同様、実行時にプレファブからインスタンスが作成されるようになります

おまけ

エラー処理つき

以下は、LoadPrefabクラスのリファクタリングしたコードです。このコードは、読みやすく保守性が高くなっています。

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class LoadPrefab : MonoBehaviour
{
    [SerializeField] private string prefabName;

    private async void Start()
    {
        var prefabHandle = Addressables.LoadAssetAsync<GameObject>(prefabName);
        await prefabHandle.Task;

        if (prefabHandle.Status == AsyncOperationStatus.Succeeded)
        {
            Instantiate(prefabHandle.Result);
        }
        else
        {
            Debug.LogError($"Failed to load prefab {prefabName}");
        }
    }
}

このコードでは、以下の点が変更されています。

  • usingステートメントにUnityEngine.ResourceManagement.AsyncOperationsが追加されています。これにより、非同期操作の状態を確認できます。
  • Cubeという文字列が、インスペクターから設定可能なprefabName変数に変更されています。
  • Instantiateメソッドが条件分岐に入れられ、ロードに失敗した場合はDebug.LogErrorを出力するようになっています。

進捗の確認

簡易的なものになりますが参考まで

using System.Collections;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class LoadPrefab : MonoBehaviour
{
    AsyncOperationHandle<GameObject> cube;

    async void Start()
    {
        StartCoroutine(Progress());

        await GetAndCreateCube();
    }

    private IEnumerator Progress()
    {
        while (!cube.IsValid())
        {
            Debug.Log("not");
            yield return null;
        }

        while (true)
        {
            if (cube.IsDone)
            {
                break;
            }
            Debug.Log(cube.GetDownloadStatus().Percent);
            yield return null;
        }
    }


    private async Task GetAndCreateCube()
    {
        cube = Addressables.LoadAssetAsync<GameObject>("Cube");
        await cube.Task;
        Instantiate(cube.Result);
    }
}

Addressable,Unity

Posted by hidepon