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