Unity Addressables Helper

Unity Addressables Helper

I've been doing a lot of work with the Addressables package recently and I'm writing up an entire series on how to use and implement clever solutions.

Addressables is a fantastic framework that can:

  • Reduce memory pressure
  • Abstract and simplify the loading of both local and remote resources
  • Handle dependency loading and unloading
  • Help create clean, scalable game architectures

The caveat is that using Addressables is complicated, it requires good foundational knowledge of Unity, and introduces the complexities of asynchronous programming.

In this article I am introducing a simple helper class that hides some of this complexity and fits seamlessly into the coroutine pattern.

Let's assume that you've installed Addressables are starting to switch from hard references of GameObject prefab to weak references of AssetReference prefab. If you're already using and familiar with coroutines then you can use this helper to initiate the instantiation of an Addressable asset and wait for completion.


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

public static class AddressablesHelper
{

    public static WaitUntil Instantiate(AssetReference asset, Action<GameObject> callback)
    {
        return Instantiate(asset, null, Vector3.zero, Quaternion.identity, callback);
    }

    public static WaitUntil Instantiate(AssetReference asset, Transform parent, Action<GameObject> callback)
    {
        return Instantiate(asset, parent, Vector3.zero, Quaternion.identity, callback);
    }

    public static WaitUntil Instantiate(AssetReference asset,
                                                Transform parent,
                                                Vector3 position,
                                                Quaternion rotation,
                                                Action<GameObject> callback)
    {
        var handle = Addressables.InstantiateAsync(asset, position, rotation, parent);

        handle.Completed += handle =>
        {
            if (handle.Status == AsyncOperationStatus.Succeeded)
            {
                callback?.Invoke(handle.Result);
            }
            else
            {
                callback?.Invoke(null);
                Addressables.Release(handle);
            }
        };

        return new WaitUntil(() => handle.IsDone);
    }

}

Now you can weave these calls into your coroutines like this:


private IEnumerable Loading()
{
    yield return AddressablesHelper.Instantiate(menuPrefab, transform, (go) =>
        {
            Log.Info(name, "Loaded menu controller...");
            _menu = go.GetComponent<MenuController>();
        });

    _menu.ShowLoading();
}

The helper methods return a WaitUntil that is tied to the AsyncOperationHandle of the Addressables invocation. You pass in an Action or define it inline as I do in the above example.

This hides some of the pain from having to manage handles, the only thing to track is releasing the reference for this instantiated GameObject, which should be done via Addressables.ReleaseInstance() to ensure the asset is unloaded when there are no more references.


private void OnDestroy()
{
    Addressables.ReleaseInstance(_menu.gameObject);
}

More to come on Addressables, please subscribe to my newsletter if interested and comment your thoughts on this pattern.

Did you find this article valuable?

Support Steve Mcilwain by becoming a sponsor. Any amount is appreciated!