Меняем материал в 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()

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *