【Unity】実行中に指定したアセットをロードする

Resources.Loadはゲーム実行中に動的にメモリにアセットをロードする機能になります
ResourcesフォルダはUnityのアセットフォルダの下に位置し、その中に置かれたアセットはゲーム中に動的にロード可能な状態で保持されます。Resources.Loadメソッドを使って、これらのアセットにアクセスし、インスタンス化することができます。

Resourcesの使用方法(動的にPrefabをロードして、インスタンスを作る場合)

フォルダ構造

UnityプロジェクトのAssetsフォルダ内に「Resources」という名前のフォルダを作成します。Resourcesフォルダは、複数作成することが可能で、サブフォルダも利用できます。

アセットのロード

Resources.Loadメソッドを使用して、Resourcesフォルダ内のアセットをロードします。このメソッドは、アセットのパスを引数として取り、アセットの型をジェネリックパラメータとして指定します。

var prefab = Resources.Load<GameObject>("PrefabName");

アセットのインスタンス化

ロードしたアセットは、Instantiateメソッドを用いてシーン中に配置することができます。

Instantiate(prefab);

サンプル

Resources.Loadを使用してアセットを動的にロードする簡単な例を以下に示します。この方法は、プロジェクト内の「Resources」フォルダに保存されているテクスチャ、オーディオクリップ、プレハブなどのアセットをロードするのに便利です

using UnityEngine;

public class LoadAssetExample : MonoBehaviour
{
    void Start()
    {
        // Resourcesフォルダからアセットをロード
        GameObject prefab = Resources.Load<GameObject>("MyPrefab");

        // ロードしたプレハブをインスタンス化
        if (prefab != null)
        {
            Instantiate(prefab, Vector3.zero, Quaternion.identity);
        }
        else
        {
            Debug.LogError("プレハブが見つかりません!");
        }
    }
}

説明

Resources.Load

この関数はUnityプロジェクトの「Resources」フォルダからアセットをロードします。Resources.Loadに渡されるパスは「Resources」フォルダに対して相対的であり、ファイル拡張子は含まれません。

Instantiate

プレハブが正常にロードされた場合(つまり、nullでない場合)、原点(Vector3.zero)で回転なし(Quaternion.identity)でインスタンス化されます。

エラー処理

ロードしたアセットがnullの場合をチェックすることにより、アセットが存在しない場合やパスが正しくない場合にランタイムエラーを防ぐことができます。

このコードが正しく動作するためには、UnityプロジェクトのAssetsディレクトリ内に「Resources」というフォルダを作成し、「MyPrefab」がそのフォルダ直下に存在する必要があります。

シーン構成

Resourcesのメリット

Resources.Loadを使用する主なメリットは、アセットを動的にロードする柔軟性が得られる点です。この機能は、特に以下のような状況で有効です:

メモリの効率的な使用

ゲームが大量のアセットを使用する場合、すべてをシーンに事前に読み込むとメモリ消費が大きくなります。Resources.Loadを使用すると、必要なタイミングでのみアセットをロードし、不要になったアセットをアンロードすることが可能です。これにより、メモリの使用を最適化できます。

遅延ロードによる起動時間の短縮

アプリケーションの起動時にすべてのアセットをロードすると、起動時間が長くなる可能性があります。Resources.Loadを使用すると、実際に必要になるまでアセットのロードを遅延させることができるため、初期のロード時間を短縮できます。

条件に基づくアセットのロード

プレイヤーの進行状況や選択に基づいて、特定のアセットだけをロードする必要がある場合に便利です。たとえば、プレイヤーが特定のレベルに到達したときにのみ特定の敵やアイテムをロードするといった使い方ができます。

リソースの統合管理

Resourcesフォルダ内にアセットを集約することで、プロジェクトのリソース管理を一元化できます。これにより、アセットの整理やアップデートが容易になります。

Resourcesのデメリット

ビルドサイズの増加

Resourcesフォルダ内の全アセットは、たとえ使用されていなくてもビルドに含まれます。これにより、最終的なアプリケーションのサイズが不必要に大きくなる可能性があります。

ランタイム時のオーバーヘッド

動的にアセットをロードすると、ランタイム時のパフォーマンスに影響を与える可能性があります。特に大きなアセットを頻繁にロードする場合、ゲームのパフォーマンスに悪影響を及ぼすことがあります。

これらのメリットとデメリットを考慮した上で、Resources.Loadの使用を検討することが重要です。特定のケースにおいては、Asset BundlesやAddressablesなど他のアセット管理方法が適切な場合もあります。

代替手段(Addressable)

前述した通り、大規模なプロジェクトやより詳細なアセット管理が必要な場合は、Asset BundlesAddressablesといったより進んだアセット管理システムの使用を検討することが推奨されます。これらのシステムは、Resourcesに比べてより柔軟で効率的なアセットの管理と配布を可能にします。

Resourcesシステムはその利便性から小規模プロジェクトやプロトタイピングには非常に便利ですが、プロジェクトのスケールが大きくなるにつれて、より洗練されたアセット管理方法に移行することが推奨されます


Addressables
システムを使用してアセットを動的にロードするためのサンプルコードを作成します。AddressablesはUnityのアセット管理システムで、リソースの効率的なロードとアンロードを提供し、特に大規模なプロジェクトに適しています。

Addressablesをセットアップする

Addressable Asset Systemのインストール

  1. Unity Editorのメニューバーから「Window」→「Package Manager」を選択します。
  2. 「Packages: Unity Registry」を選択し、「Addressables」を検索してインストールします。

キャプチャーは、Unity2022.3バージョンです
Unity2023バージョンでは構成が異なります

アセットをAddressableにする

  1. プロジェクトウィンドウでアセットを選択します。
  2. インスペクターパネルで「Address」フィールドにユニークなアドレス名(サンプルではMyPrefabAddress)を入力します。
    すでにResourcesフォルダにあるアセットを選択した場合、フォルダーから自動的に移動させられます
  3. 「Addressable」チェックボックスをオンにして、アセットをAddressablesシステムに追加します。

Addressablesを使用してアセットをロードするサンプルコード

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

public class LoadAssetWithAddressables : MonoBehaviour
{
    void Start()
    {
        // Addressablesシステムを使用してアセットを非同期でロードします。
        // "MyPrefabAddress"はAddressable Assetに設定したユニークなアドレスです。
        AsyncOperationHandle<GameObject> handle = Addressables.LoadAssetAsync<GameObject>("MyPrefabAddress");
        
        // ロードが完了した際に実行されるコールバックを設定します。
        handle.Completed += OnPrefabLoaded;
    }

    // ロードが完了した時に呼ばれるメソッド
    private void OnPrefabLoaded(AsyncOperationHandle<GameObject> handle)
    {
        // ロードの状態を確認し、成功している場合は以下を実行します。
        if (handle.Status == AsyncOperationStatus.Succeeded)
        {
            // ロードしたプレハブをシーンにインスタンス化します。
            // インスタンスは原点位置にデフォルトの回転で作成されます。
            GameObject prefabInstance = Instantiate(handle.Result, Vector3.zero, Quaternion.identity);
            Debug.Log("プレハブのロードとインスタンス化に成功しました。");
        }
        else
        {
            // ロードに失敗した場合はエラーメッセージをログに出力します。
            Debug.LogError("プレハブのロードに失敗しました。");
        }
    }
}

説明

LoadAssetAsync

Addressables.LoadAssetAsync<GameObject>は、指定したアドレス名のアセットを非同期でロードします。このメソッドは、ロードが完了するとAsyncOperationHandle<GameObject>を返します。

handle.Completed

Completedイベントを使用して、アセットのロードが完了したときのコールバックを登録します。ロードが成功したかどうかをチェックし、成功していればそのアセットをインスタンス化します。

非同期ロード

Addressablesは非同期操作を使用するため、ゲームのフレームレートに影響を与えずに大きなアセットをロードできます。

このサンプルは、シンプルなプレハブのロードとインスタンス化を示していますが、Addressablesシステムは依存関係の管理やアセットのバージョン管理も自動で行うため、より複雑なシナリオにも対応可能です。このシステムを使用することで、アセットのロードと管理を効率的に行うことができます。

詳細なエラー処理を行いたい場合

Addressable Asset Systemを使用している場合、例えばAddressableの名前(アセットのアドレス)を間違えたとき、例外エラーが発生する可能性があります。具体的には、指定したアドレスにアセットが存在しない場合、AsyncOperationHandleオブジェクトのOperationExceptionプロパティにエラー詳細が含まれます。このエラーは、ロードプロセスの完了時にCompletedイベントで捉えられ、適切に処理することができます。

エラー処理の具体例

以下のサンプルコードでは、Addressableの名前が間違っている場合に例外をキャッチし、それに応じた処理を行う方法を示しています。

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

public class LoadAssetWithErrorHandling : MonoBehaviour
{
    void Start()
    {
        // 存在しないAddressable名を指定してロードを試みる
        string addressableName = "NonExistentPrefabAddress";
        AsyncOperationHandle<GameObject> handle = Addressables.LoadAssetAsync<GameObject>(addressableName);
        handle.Completed += HandleCompleted;
    }

    private void HandleCompleted(AsyncOperationHandle<GameObject> handle)
    {
        if (handle.Status == AsyncOperationStatus.Succeeded)
        {
            // ロード成功時の処理
            Instantiate(handle.Result, Vector3.zero, Quaternion.identity);
            Debug.Log("アセットのロードとインスタンス化に成功しました。");
        }
        else if (handle.Status == AsyncOperationStatus.Failed)
        {
            // ロード失敗時の処理
            Debug.LogError($"アセットのロードに失敗しました。エラー詳細: {handle.OperationException.Message}");

            // リカバリ処理を呼び出す
            HandleLoadFailure();
        }
    }

    void HandleLoadFailure()
    {
        // ロード失敗のリカバリ処理をここに記述
        Debug.Log("リカバリ処理を実行中...");
        // ユーザーにエラーを通知するUIを表示する、リトライオプションを提供するなど
    }
}

エラー処理のポイント

  • OperationExceptionプロパティ: このプロパティを通じて、なぜロードに失敗したのかの詳細情報を取得できます。この情報を利用してユーザーへの通知やログ出力などを行います。
  • リカバリ処理: エラーが発生した場合、ただエラーをログに記録するだけでなく、ユーザーが理解しやすい形で通知したり、問題解決のためのアクションを提供することが重要です。

このように、Addressableの名前が間違っていた場合のエラーは、適切なエラーハンドリングを実装することで、ユーザーにとってより良い体験を提供するために利用することができます。

Unity

Posted by hidepon