4.AssetReference类指定资源加载

4.资源加载基础-指定资源加载


4.1 知识点

资源准备

我们准备一些常用的各类型的资源

  • GameObject预设体
  • 精灵图片
  • 图集
  • 贴图
  • 材质球
  • 配置文件(json、xml、txt、2进制)
  • Lua脚本
  • 音效
  • Animator Controller 动画状态机控制文件
  • 场景

AssetReference资源标识类

  • 命名空间:using UnityEngine.AddressableAssets;

  • AssetReference资源标识相关类

    • AssetReference: 通用资源标识类,可用于加载任意类型资源
    • AssetReferenceAtlasedSprite: 图集资源标识类
    • AssetReferenceGameObject: 游戏对象资源标识类
    • AssetReferenceSprite: 精灵图片资源标识类
    • AssetReferenceTexture: 贴图资源标识类
    • AssetReferenceTexture2D
    • AssetReferenceTexture3D
    • AssetReferenceT<T>: 指定类型标识类
  • 通过不同类型标识类对象的声明,可以在Inspector窗口中筛选关联的资源对象。

    public AssetReference assetReference;
    public AssetReferenceAtlasedSprite assetReferenceAtlasedSprite;
    public AssetReferenceGameObject assetReferenceGameObject;
    public AssetReferenceSprite assetReferenceSprite;
    public AssetReferenceTexture assetReferenceTexture;
    
    public AssetReferenceT<AudioClip> assetReferenceTAudioClip;
    public AssetReferenceT<RuntimeAnimatorController> assetReferenceTRuntimeAnimatorController;
    public AssetReferenceT<TextAsset> assetReferenceTTextAsset;
    
    public AssetReferenceT<Material> assetReferenceTMaterial;
    
    public AssetReference AssetReferenceScene;
    


加载资源

  • 引用命名空间:using UnityEngine.ResourceManagement.AsyncOperations;

  • 注意:

    • 所有Addressables加载相关都使用异步加载。
    • 现在加载资源时的模式不要是Use Existing Build(requires built groups),因为这是从AB包模式中加载,建议选择Simulate Groups(advanced)模拟
  • 加载后有两种方式判断是否加载成功和得到加载资源

    • 通过事件函数传入的参数AsyncOperationHandle.Status == AsyncOperationStatus.Succeeded判断加载是否成功 并且创建AsyncOperationHandle.Result(建议)
    • 通过资源标识类对象AssetReference.IsDone判断 并且创建AssetReference.Asset

AssetReference.LoadAssetAsync 异步加载可寻址资源 返回异步操作处理者AsyncOperationHandle对象

AsyncOperationHandle.Completed 完成回调添加监听函数 进行对完成事件的监听

AsyncOperationHandle.Status 异步加载状态 一般判断是否成功

AsyncOperationHandle.Result 异步加载出来的资源


// AssetReference.LoadAssetAsync 异步加载可寻址资源 返回异步操作处理者AsyncOperationHandle对象
AsyncOperationHandle<GameObject> asyncOperationHandle = assetReference.LoadAssetAsync<GameObject>();

// 对AsyncOperationHandle对象的Completed完成回调添加监听函数 对完成进行事件监听
// 回调有一个AsyncOperationHandle<TObject>类型的参数 TObject是要加载的资源的类型 比如现在是GameObject
asyncOperationHandle.Completed += OnAsyncOperationHandleCompleted;
// 加载成功后的回调函数
private void OnAsyncOperationHandleCompleted(AsyncOperationHandle<GameObject> asyncOperationHandle)
{
    // 加载成功后 使用加载的资源
    // 判断是否加载成功
    if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
    {
        Instantiate(asyncOperationHandle.Result);
    }
}

一步到位的写法 不得出AsyncOperationHandle对象并使用Lambda表达式直接添加Completed成功回调

AssetReference.IsDone 判断资源是否加载

AssetReference.Asset 加载出来的资源

// 一步到位的写法 不得出AsyncOperationHandle对象并使用Lambda表达式直接添加Completed成功回调
// 注意要注释掉上面的加载,因为重复加载会报错
// 调用 LoadAssetAsync 方法时,如果目标资源已经被加载过,并且该加载操作返回的 OperationHandle 已经暴露出来,那么再次调用加载就会引发错误。
assetReference.LoadAssetAsync<GameObject>().Completed += (asyncOperationHandle) =>
{
    // 加载成功后使用
    // 1.通过事件函数传入的参数AsyncOperationHandle.Status == AsyncOperationStatus.Succeeded判断加载是否成功 并且创建AsyncOperationHandle.Result
    // 2.通过资源标识类对象AssetReference.IsDone判断 并且创建AssetReference.Asset

    // 使用传入的参数(建议)
    // 判断是否加载成功
    if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
    {
        GameObject cube = Instantiate(asyncOperationHandle.Result);
    }

    // 使用标识类创建
    // if(assetReference.IsDone)
    // {
    //     Instantiate(assetReference.Asset);
    // }
};

注意重复加载会报错

异步加载场景

AssetReference.LoadSceneAsync 异步加载场景 添加Completed回调

// AssetReference.LoadSceneAsync 异步加载场景 添加Completed回调
AssetReferenceScene.LoadSceneAsync().Completed += (asyncOperationHandle) =>
{
    // 初始化场景的一些信息
    print("场景加载结束");
};

释放资源

AssetReference.ReleaseAsset 释放资源

直接调用释放资源代码不合理
因为可能没加载成功就释放了 最好卸载加载成功后且用完了再释放 应该卸载加载成功的回调中

// assetReference.ReleaseAsset();

注意:

  • 执行释放资源方法后,资源标识类中的资源会置空,但是AsyncOperationHandle类中的对象不为空
  • 释放资源不会影响场景中被实例化出来的对象,但是会影响使用的资源。
  • 比如实例化GameObject后再释放不受影响。因为用的是预制体的配置文件
  • 但是赋值材质后释放在AB包模式下会丢失材质。因为赋值后用的是资源对象。
assetReference.LoadAssetAsync<GameObject>().Completed += (asyncOperationHandle) =>
{
    if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
    {
        GameObject cube = Instantiate(asyncOperationHandle.Result);

        // 一定资源加载过后 使用完后 再去释放
        assetReference.ReleaseAsset();

        // 异步加载材质球
        assetReferenceTMaterial.LoadAssetAsync().Completed += (materialAsyncOperationHandle) =>
        {
            // 材质球赋值给加载出来的cube
            cube.GetComponent<MeshRenderer>().material = materialAsyncOperationHandle.Result;

            // 如果释放材质球 这样会造成使用这个资源的对象 资源丢失(简单模式和模拟AB包模式看不出来,真正的AB包模式下会丢失)
            assetReferenceTMaterial.ReleaseAsset();

            // 异步加载传入对象的资源 释放资源后不会清空引用
            print(materialAsyncOperationHandle.Result);

            // 这个是 资源标识类的资源 释放资源后会置空
            print(assetReferenceTMaterial.Asset);
        };
    }
};

直接实例化对象

AssetReference.InstantiateAsync 异步实例化对象

// InstantiateAsync方法有一些重载调整位置角度等
// 相当于帮我们自己LoadAssetAsync且添加Completed回调中实例化对象的事给做了
// 只适用于想要实例化的对象 才会直接使用该方法 一般都是GameObject预设体
assetReferenceGameObject.InstantiateAsync();

自定义标识类

继承AssetReferenceT<T>类

自定义类 继承AssetReferenceT类 即可自定义一个指定类型的标识类
比如class AssetReferenceAudioClip : AssetReferenceT
该功能主要用于Unity2020.1之前,因为之前的版本不能直接使用AssetReferenceT泛型字段 Unity2020.1之后的版本其实没必要

public class AssetReferenceAudioClip : AssetReferenceT<AudioClip>
{
    public AssetReferenceAudioClip(string guid) : base(guid)
    {
    }
}

总结

  1. 我们可以根据自己的需求选择合适的标识类进行资源加载。
  2. 资源加载和场景加载都是通过异步进行加载。
  3. 需要注意异步加载资源使用时必须保证资源已经被加载成功了,否则会报错。

4.2 知识点代码

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

public class AssetReferenceAudioClip : AssetReferenceT<AudioClip>
{
    public AssetReferenceAudioClip(string guid) : base(guid)
    {
    }
}

public class Lesson04_资源加载基础_指定资源加载 : MonoBehaviour
{
    public AssetReference assetReference;
    public AssetReferenceAtlasedSprite assetReferenceAtlasedSprite;
    public AssetReferenceGameObject assetReferenceGameObject;
    public AssetReferenceSprite assetReferenceSprite;
    public AssetReferenceTexture assetReferenceTexture;

    public AssetReferenceT<AudioClip> assetReferenceTAudioClip;
    public AssetReferenceT<RuntimeAnimatorController> assetReferenceTRuntimeAnimatorController;
    public AssetReferenceT<TextAsset> assetReferenceTTextAsset;

    public AssetReferenceT<Material> assetReferenceTMaterial;

    public AssetReference AssetReferenceScene;

    void Start()
    {
        #region 知识点一 资源准备

        //我们准备一些常用的各类型的资源
        //1.GameObject预设体
        //2.精灵图片
        //3.图集
        //4.贴图
        //5.材质球
        //6.配置文件(json、xml、txt、2进制)
        //7.Lua脚本
        //8.音效
        //9.Animator Controller 动画状态机控制文件
        //10.场景

        #endregion

        #region 知识点二 Addressables中的资源标识类

        //命名空间:using UnityEngine.AddressableAssets;

        //AssetReference                通用资源标识类 可以用来加载任意类型资源
        //AssetReferenceAtlasedSprite   图集资源标识类
        //AssetReferenceGameObject      游戏对象资源标识类
        //AssetReferenceSprite          精灵图片资源标识类
        //AssetReferenceTexture         贴图资源标识类
        //AssetReferenceTexture2D
        //AssetReferenceTexture3D
        //AssetReferenceT<>             指定类型标识类

        //通过不同类型标识类对象的申明 我们可以在Inspector窗口中筛选关联的资源对象

        #endregion

        #region 知识点三 加载资源

        //注意:所有Addressables加载相关都使用异步加载

        //需要引用命名空间:using UnityEngine.ResourceManagement.AsyncOperations;

        //注意现在加载资源时的模式不要是Use Existing Build(requires built groups),因为这是从AB包模式中加载,建议选择Simulate Groups(advanced)模拟

        // // AssetReference.LoadAssetAsync 异步加载可寻址资源 返回异步操作处理者AsyncOperationHandle对象
        // AsyncOperationHandle<GameObject> asyncOperationHandle = assetReference.LoadAssetAsync<GameObject>();
        //
        // //对AsyncOperationHandle对象的Completed回调添加监听函数 对完成进行事件监听
        // //回调有一个AsyncOperationHandle<TObject>类型的参数 TObject是要加载的资源的类型 比如现在是GameObject
        // asyncOperationHandle.Completed += OnAsyncOperationHandleCompleted;

        // // 一步到位的写法 不得出AsyncOperationHandle对象并使用Lambda表达式直接添加Completed成功回调
        // // 注意要注释掉上面的加载,因为重复加载会报错
        // // 调用 LoadAssetAsync方法时,如果目标资源已经被加载过,并且该加载操作返回的 OperationHandle 已经暴露出来,那么再次调用加载就会引发错误。
        // assetReference.LoadAssetAsync<GameObject>().Completed += (asyncOperationHandle) =>
        // {
        //     //加载成功后使用
        //     //1.通过事件函数传入的参数AsyncOperationHandle.Status == AsyncOperationStatus.Succeeded判断加载是否成功 并且创建AsyncOperationHandle.Result
        //     //2.通过资源标识类对象AssetReference.IsDone判断 并且创建AssetReference.Asset
        //
        //     //使用传入的参数(建议)
        //     //判断是否加载成功
        //     if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
        //     {
        //         GameObject cube = Instantiate(asyncOperationHandle.Result);
        //         
        //         //一定资源加载过后 使用完后 再去释放
        //         assetReference.ReleaseAsset();
        //
        //         //assetReferenceTMaterial.LoadAssetAsync().Completed += (obj) =>
        //         //{
        //         //    cube.GetComponent<MeshRenderer>().material = obj.Result;
        //         //    //这样会造成使用这个资源的对象 资源丢失
        //         //    assetReferenceTMaterial.ReleaseAsset();
        //
        //         //    //这个异步加载传入对象的资源
        //         //    print(obj.Result);
        //         //    //这个是 资源标识类的资源
        //         //    print(assetReferenceTMaterial.Asset);
        //         //};
        //     }
        //
        //     //使用标识类创建
        //     //if(assetReference.IsDone)
        //     //{
        //     //    Instantiate(assetReference.Asset);
        //     //}
        // };

        //AssetReferenceTAudioClip已经指定了类型了 所以LoadAssetAsync就没有泛型了
        assetReferenceTAudioClip.LoadAssetAsync().Completed += (handle) =>
        {
            //使用音效
        };

        #endregion

        #region 知识点四 加载场景

        // // AssetReference.LoadSceneAsync 异步加载场景 添加Completed回调
        // AssetReferenceScene.LoadSceneAsync().Completed += (asyncOperationHandle) =>
        // {
        //     //初始化场景的一些信息
        //     print("场景加载结束");
        // };

        #endregion

        #region 知识点五 释放资源

        // AssetReference.ReleaseAsset 释放资源
        //直接调用不合理 因为可能没加载成功就释放了 最好卸载加载成功后且用完了再释放 应该卸载加载成功的回调中
        //assetReference.ReleaseAsset();

        //注意:
        //1.执行释放资源方法后,资源标识类中的资源会置空,但是AsyncOperationHandle类中的对象不为空
        //2.释放资源不会影响场景中被实例化出来的对象,但是会影响使用的资源。
        //比如实例化GameObject后再释放不受影响。因为用的是预制体的配置文件
        //但是赋值材质后释放在AB包模式下会丢失材质。因为赋值后用的是资源对象。

        assetReference.LoadAssetAsync<GameObject>().Completed += (asyncOperationHandle) =>
        {
            if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
            {
                GameObject cube = Instantiate(asyncOperationHandle.Result);

                //一定资源加载过后 使用完后 再去释放
                assetReference.ReleaseAsset();

                // 异步加载材质球
                assetReferenceTMaterial.LoadAssetAsync().Completed += (materialAsyncOperationHandle) =>
                {
                    //材质球赋值给加载出来的cube
                    cube.GetComponent<MeshRenderer>().material = materialAsyncOperationHandle.Result;

                    //如果释放材质球 这样会造成使用这个资源的对象 资源丢失(简单模式和模拟AB包模式看不出来,真正的AB包模式下会丢失)
                    assetReferenceTMaterial.ReleaseAsset();

                    //异步加载传入对象的资源 释放资源后不会清空引用
                    print(materialAsyncOperationHandle.Result);

                    //这个是 资源标识类的资源 释放资源后会置空
                    print(assetReferenceTMaterial.Asset);
                };
            }
        };

        #endregion

        #region 知识点六 直接实例化对象

        //AssetReference.InstantiateAsync 异步实例化对象
        //有一些重载调整位置角度等
        //相当于帮我们自己LoadAssetAsync且添加Completed回调中实例化对象的事给做了
        //只适用于 想要实例化的 对象 才会直接使用该方法 一般都是GameObject预设体
        assetReferenceGameObject.InstantiateAsync();

        #endregion

        #region 知识点七 自定义标识类

        //自定义类 继承AssetReferenceT<T>类 即可自定义一个指定类型的标识类
        //比如class AssetReferenceAudioClip : AssetReferenceT<AudioClip>
        //该功能主要用于Unity2020.1之前,因为之前的版本不能直接使用AssetReferenceT泛型字段
        //Unity2020.1之后的版本其实没必要

        #endregion

        #region 知识点八 总结

        //1.我们可以根据自己的需求选择合适的标识类进行资源加载
        //2.资源加载和场景加载都是通过异步进行加载
        //3.需要注意异步加载资源使用时必须保证资源已经被加载成功了,否则会报错

        #endregion
    }

    private void OnAsyncOperationHandleCompleted(AsyncOperationHandle<GameObject> asyncOperationHandle)
    {
        //加载成功后 使用加载的资源嘛
        //判断是否加载成功
        if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
        {
            Instantiate(asyncOperationHandle.Result);
        }
    }
}

4.3 练习题

尝试自己将各种资源类型都加载一次



转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏