Меняем материал в Skybox с помощью Coroutine
В проекте создаем сцену с тремя кнопками. Кнопки будут менять материал скайбокса.

Также создаем три материала с Shader Skybox/Panoramic, материалам назначаем серый, зеленый и оранжевый цвета.
В инспекторе у каждого материала ставим галку “Addressables”.
На сцену добавляем объект ManagerForSkyBox содержащий скрипт Manager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class Manager : MonoBehaviour
{
[SerializeField] private List<AssetReference> _skyboxMaterials; //созданные нами материалы
private AsyncOperationHandle operationHandle; //переменная определяющая статус и результат операции
public void SetSkybox(int skyboxIndex)
{
StartCoroutine(SetSkynoxInternal(skyboxIndex));
}
private IEnumerator SetSkynoxInternal(int skyboxIndex)
{
if (operationHandle.IsValid()) // если конкретный материал уже загружался - очищаем
{
Addressables.Release(operationHandle);
}
AssetReference skyboxMaterialReference = _skyboxMaterials[skyboxIndex]; //Ссылка на адресуемый актив в нашем случае на материал по индексу
operationHandle = skyboxMaterialReference.LoadAssetAsync<Material>(); // operationHandle назначаеем результат асинхронной загрузки
yield return operationHandle; // ждем окончания результата
RenderSettings.skybox = (Material)operationHandle.Result; // меняем материал скайбокса и приводим типы
}
void OnDestroy()
{
Addressables.Release(operationHandle);
}
}
В обьекте ManagerForSkyBox компоненту Manager в List _skyboxMaterials добавляем материалы.
Кнопки на сцене будут вызывать метод SetSkybox с различными индексами.
Теперь можно запустить проект и увидеть как меняется материал скайбокса в зависимости от нажатой кнопки.
В приведенном выше примере нужно обратить внимание на:
Addressables.Release(operationHandle);
Поскольку LoadAssetAsync , не возвращает загруженные активы напрямую, Вместо этого она возвращает объект AsyncOperationHandle. который является как результатом операции, счетчиком, так и способом освобождения как результатов, так и самого объекта операции. Необходимо сохранять объект дескриптора так долго, как мы хотим использовать результаты. В зависимости от ситуации, это может быть один кадр, до конца уровня или даже все время существования приложения.
В данном случае мы можем несколько раз нажимать кнопку с загружающую один ресурс
если не очищать дискриптор, он будет выдавать сообщение об ошибке, так как объект уже загружен.
В противном случае Как только мы выполним Addressables.Release(operationHandle)
доступ к материалу будет утерян. Нужно обратить внимание на то, что дискриптор является общим счетчиком и в случае выполнения Addressables.Release(operationHandle) мы потеряем доступ к загруженному ресурсу, только тогда, когда все дескрипторы на сцене выполнили Addressables.Release(operationHandle)
Поэтому На практике нужно выполнять Addressables.Release(operationHandle) в OnDestroy()
void OnDestroy()
{
Addressables.Release(operationHandle);
}
Меняем спрайт в Image с помощью Coroutine
загружаем в проект любой спрайт. Будем назначать его о объекту типа “image” в рантайме.
На сцену добавляем объект типа “image”, и объект ManagerForSprite содержащий скрипт Manager2.cs
Механизм загрузки такой же как с материалами но свернутый в более краткую форму
using System.Collections;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.UI;
public class Manager2 : MonoBehaviour
{
[SerializeField] private AssetReference _sptite; //спрайт который будем назначать в _image
[SerializeField] private Image _image; //объект которому будем менять спрайт
AsyncOperationHandle<Sprite> handle; // явно типизированный хендл
private IEnumerator Start()
{
handle = _sptite.LoadAssetAsync<Sprite>();
yield return handle;
if (handle.Status == AsyncOperationStatus.Succeeded)
{
Sprite sprite = handle.Result;
//спрайт загружен и готов к использованию
_image.sprite = sprite;
}
else
{
Addressables.Release(handle);
}
}
void OnDestroy()
{
Addressables.Release(handle);
}
}
Результат выполнение программы:

Меняем спрайт в Image с помощью асинхронного метода
using System.Collections;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.UI;
public class Manager2 : MonoBehaviour
{
[SerializeField] private AssetReference _sptite; //спрайт который будем назначать в _image
[SerializeField] private Image _image; //объект которому будем менять спрайт
AsyncOperationHandle<Sprite> handle; // явно типизированный хендл
private async void Start2()
{
handle = _sptite.LoadAssetAsync<Sprite>();
await handle.Task;
if (handle.Status == AsyncOperationStatus.Succeeded)
{
Sprite sprite = handle.Result;
//спрайт загружен и готов к использованию
_image.sprite = sprite;
}
else
{
Addressables.Release(handle);
}
}
void OnDestroy()
{
Addressables.Release(handle);
}
}
Рекомендуется пользоваться асинхронным методом, так как в случае если объект станет неактивным – корутина прервется.
Создание объекта из префаба. Полный метод
Создадим префаб куба
На сцену добавляем объект ManagerForPrefab содержащий скрипт Manager3.cs
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class Manager3 : MonoBehaviour
{
[SerializeField] private AssetReference _prefab; //префаб который будем инстанциировать в сцене
AsyncOperationHandle<GameObject> handle; // явно типизированный хендл
private async void Start()
{
handle = _prefab.LoadAssetAsync<GameObject>();
await handle.Task;
if (handle.Status == AsyncOperationStatus.Succeeded)
{
GameObject gameObjectPrefab = handle.Result;
Instantiate(gameObjectPrefab);
}
else
{
Addressables.Release(handle);
}
}
void OnDestroy()
{
Addressables.Release(handle);
}
}
Создание объекта из префаба. Краткий метод
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class Manager3 : MonoBehaviour
{
[SerializeField] private AssetReference _prefab; //префаб который будем инстанциировать в сцене
private void Start()
{
_prefab.InstantiateAsync();
}
}
Создание объекта с помощью адресса префаба
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class Manager3 : MonoBehaviour
{
private async void Start()
{
AsyncOperationHandle<GameObject> handle = Addressables.LoadAssetAsync<GameObject>("Assets/Prefabs/Cube.prefab");
await handle.Task;
if (handle.Status == AsyncOperationStatus.Succeeded)
{
GameObject gameObjectPrefab = handle.Result;
Instantiate(gameObjectPrefab);
}
}
void OnDestroy()
{
Addressables.Release(handle);
}
}
Загрузка Scene c с помощью Addressables
Создадим новую сцену “New Scene”
В первой сцене добавляем объект ManagerForScene содержащий скрипт Manager4.cs. Добавляем кнопку по которой будем менять сцены
using UnityEngine;
using UnityEngine.AddressableAssets;
public class Manager4 : MonoBehaviour
{
[SerializeField] private AssetReference _scene;
public void LoadScene()
{
_scene.LoadSceneAsync();
}
}
к кнопке смены сцены привязываем функцию LoadScene()