👌

Addressablesのハンドル管理を任せたい(Unity)

2023/04/17に公開約2,600字

はじめに

Unity の Addressables クラスはとても便利なのですが、ハンドルを取得したり解放しないといけなかったりと大変です。また、メインのコードが冗長になります。
少しでも楽をするべく、ハンドルの管理を任せるクラスを作成してみました。

初学者による記事なのでご参考までに。
また、つっこみなど頂けましたら幸いです。

使い方

public class Sample : MonoBehaviour
{
    void Start()
    {
        GameObjectInstantiater instantiater =
	    GetComponent<GameObjectInstantiater>();

        GameObject gameObject = instantiater.Instantiate(
            address: "address",
            vector3: Vector3.zero,
            quaternion: Quaternion.identity);
    }
}

説明

フィールドに Dictionary を使用し、Addressables アセットのアドレスをキーにして各ハンドルを登録します。
すでに読み込み済みのハンドルが指定された場合は新たに読み込まず、Dictionary からハンドルを指定してインスタンス化します。
アタッチされたオブジェクトが破棄されると、Dictonary に登録していたハンドルをまとめて解放します。
MonoBehaviour を継承しているため、オブジェクトにアタッチしてください。

GameObjectInstantiater クラス

GameObjectInstantiater.cs
#nullable enable

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

/// <summary>
/// Addressables アセットのインスタンス化を行う。
/// </summary>
public class GameObjectInstantiater : MonoBehaviour
{
    // 読み込んだハンドルを登録するフィールド。
    private static Dictionary<
        string, AsyncOperationHandle<GameObject>> _loadedHandles = new();

    private void OnDestroy()
    {
        // 読み込み済みのハンドルをまとめて解放する。
        UnloadHandles();
    }

    /// <summary>
    /// Addressables アセットに登録済みのオブジェクトをインスタンス化する。
    /// </summary>
    /// <param name="address">アセットのアドレス</param>
    /// <param name="vector3">インスタンス化する位置</param>
    /// <param name="quaternion">インスタンス化する向き</param>
    /// <returns>インスタンス化した GameObject</returns>
    public GameObject Instantiate(
        string address, Vector3 vector3, Quaternion quaternion)
    {
        GameObject gameObject = LoadHandle(address).WaitForCompletion();
        return Instantiate<GameObject>(gameObject, vector3, quaternion);
    }

    /// <summary>
    /// ハンドルの読み込みを行う。
    /// すでに読み込み済みであれば新たに読み込まず、読み込み済みのハンドルを返す。
    /// </summary>
    private AsyncOperationHandle<GameObject> LoadHandle(string address)
    {
        if (_loadedHandles.ContainsKey(address))
        {
            return _loadedHandles[address];
        }
        else
        {
            AsyncOperationHandle<GameObject> handle =
                Addressables.LoadAssetAsync<GameObject>(address);
            _loadedHandles.Add(address, handle);
            return handle;
        }
    }

    /// <summary>
    /// 読み込み済みのハンドルをまとめて解放する。
    /// </summary>
    private void UnloadHandles()
    {
        foreach (AsyncOperationHandle<GameObject> handle in _loadedHandles.Values)
        {
            Addressables.Release(handle);
        }
    }
}

Discussion

ログインするとコメントできます