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)
    {
    }
}
总结
- 我们可以根据自己的需求选择合适的标识类进行资源加载。
- 资源加载和场景加载都是通过异步进行加载。
- 需要注意异步加载资源使用时必须保证资源已经被加载成功了,否则会报错。
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
 
            