👌

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

2023/04/17に公開

はじめに

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

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

使い方

public class Sample : MonoBehaviour
{
    AddressablesInstantiater instantiater = new();

    void Start()
    {
        GameObject gameObject = instantiater.Instantiate(
            address: "address",
            vector3: Vector3.zero,
            quaternion: Quaternion.identity);
    }
    
    void OnDestroy()
    {
        // 使用後はハンドルを解放する。
        instantiater.Dispose();
    }
}

説明

フィールドに Dictionary を使用し、Addressables アセットのアドレスをキーにして各ハンドルを登録します。
すでに読み込み済みのハンドルが指定された場合は新たに読み込まず、Dictionary からハンドルを指定してインスタンス化します。
使用後は Dispose メソッドを実行し、読み込んだハンドルを解放してください。

実装

AddressablesInstantiater.cs
#nullable enable

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


/// <summary>
/// Addressables アセットのインスタンス化を行う。
/// 使用後は必ずすべてのハンドルを破棄する必要がある。
/// </summary>
public class AddressablesInstantiater : IDisposable
{
    // 読み込んだハンドルを登録するフィールド。
    private readonly Dictionary<string,
        AsyncOperationHandle<GameObject>> _loadedHandles = new();


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

        return UnityEngine.Object.Instantiate(
            gameObject,
            position ?? Vector3.zero,
            direction ?? Quaternion.identity);
    }


    /// <summary>
    /// 読み込み済みのハンドルをすべて破棄する。
    /// </summary>
    public void Dispose()
    {
        foreach (AsyncOperationHandle<GameObject> handle
            in _loadedHandles.Values)
        {
            Addressables.Release(handle);
        }
    }


    /// <summary>
    /// ハンドルの読み込みを行う。
    /// </summary>
    private AsyncOperationHandle<GameObject> LoadHandle(string address)
    {
        AsyncOperationHandle<GameObject> handle =
            Addressables.LoadAssetAsync<GameObject>(address);

        _loadedHandles.Add(address, handle);
        return handle;
    }
}

Discussion