Resources同步加载
作用
- 通过代码动态加载Resources文件夹下指定路径的资源
- 避免繁琐的拖曳操作
常见的资源类型
- 预设体对象 - GameObject
- 音效文件 - AudioClip
- 文本文件 - TextAsset
- 图片文件 - Texture
- 其他类型
预设体对象加载需要实例化,因为他要显示到场景中。其他资源加载一般直接使用
资源同步加载 - 普通方法
在一个工程中Resources文件夹可以有多个,通过API加载时,会自己去这些同名的Resources文件夹中去找资源。打包时,Resources文件夹力的内容都会打包到一起。
1.预设体对象
第一步:要去加载预设体资源文件(本质上就是加载的配置数据,然后存在内存中)
Object obj = Resources.Load("Cube");
第二步:如果要在场景上创建预设体,一般是加载文件过后,然后实例化
Instantiate(obj);
2.音效文件
第一步:加载数据
//加载Music文件夹下的audio音频文件
Object obj = Resources.Load("Music/audio");
第二步:使用数据。我们不需要实例化音效切片,只需要把数据赋值到正确的脚本上即可
//audioSource 是 AudioSource 对象
audioSource.clip = obj as AudioClip;
audioSource.Play();
3.文本文件
支持的格式:.txt, .xml, .bytes, .json, .html, .csv 。常用的格式就是前4种。
//加载Txt文件夹下的test.txt文件
TextAsset ta = Resources.Load("Txt/test") as TextAsset;
//可以直接打印文本内容
print(ta.text);
//也可以打印字节数组
print(ta.bytes);
4.图片
//加载Tet文件夹下的jpg图片文件,可以将tex 赋值给RawImage
Texture tex = Resources.Load("Tet/jpg") as Texture;
5.其他类型
略
6.资源同名问
Resources.Load加载同名资源,因为该API加载资源的 时候只需要资源名字即可,不需要类型,所以会有无法准确加载出想要的内容的问题。
解决方法:使用另外的API
1.加载指定类型资源
//可以通过typeof指定类型
Texture tex = Resources.Load("Tet/jpg", typeof(Texture)) as Texture;
TextAsset ta = Resources.Load("Tet/jpg", typeof(TextAsset)) as TextAsset;
2.加载同名所有资源
Object[] objs = Resources.LoadAll("Tet/jpg");
//TODO:遍历处理。性能低,不推荐
资源加载 - 泛型方法
//一步到位
Texture tex = Resources.Load<Texture>("Tet/jpg");
Resources异步加载
如果我们同步加载过大的资源可能会造成程序卡顿。卡顿原因就是因为从硬盘读取数据到内存中是需要进行计算的,越大的资源耗时越长,就会造成掉帧卡顿。Reesources异步加载就是内部新开一个线程进行资源加载,不会造成主线程卡顿。
异步加载方法
异步加载不能马上得到加载的资源,至少要等一帧
1.通过异步加载中的完成事件监听,使用加载的资源
//Unity在内部就会开一个线程进行资源下载
ResourceRequest rq = Resources.LoadAsync<Texture>("Tex/jpg");
//监听资源下载结束事件
rq.completed += LoadEnd;
//加载完成方法
private void LoadEnd(AsyncOperation operation)
{
print("Load End!");
tex = (operation as ResourceRequest).asset as Texture;
}
AsyncOperation 是ResourceRequest的父类
2.通过协程使用加载的资源
//1.声明一个迭代器方法
IEnumerator Load()
{
//迭代器函数,当遇到yield return 时,就会停止执行之后的代码,然后协程协调器(StartCoroutine)通过得到的返回值去判断何时执行后面的步骤
ResourceRequest rq = Resources.LoadAsync<Texture>("Tex/jpg");
//Unity 自己知道该返回值(ResourceRequest rq)意味着你在异步加载资源,且会在资源加载完成后,执行后面的代码
//ResourceRequest 继承于 AsyncOperation 继承于
YieldInstruction;
//WaitForSeconds 同样继承于 YieldInstruction
//所以这里yield return rq是完全没问题的!!
yield return rq;
tex = rq.asset as Texture;
}
//2.调用协程
StartCoroutine(Load());
//迭代器的第二种写法
IEnumerator Load()
{
//这里可以同时加载多个资源,然后可以判断所有资源都加载完成后再执行下一步
ResourceRequest rq = Resources.LoadAsync<Texture>("Tex/jpg");
while (!rq.isDone)
{
//打印进度
print(rq.progress);
//如果没有加载完,下一帧继续执行循环
yield return null;
}
tex = rq.asset as Texture;
}
总结
1.完成事件监听异步加载
好处:写法简单
坏处:只能再资源结束后进行处理。有点类似”线性加载“。
2.协程异步加载
好处:可以在协程中处理复杂的逻辑,比如同时加载多个资源,比如进度条更新等
坏处:写法稍显麻烦。类似于“并行加载”
Resources卸载资源
Resources重复加载资源会浪费内存吗?
答案:不会。
Resources加载一次资源后,该资源就一致放在内存中作为缓存,第二次加载时发现有缓存数据会直接取出来,所以多次重复加载不会浪费内存。但是会对性能有影响,因为每次加载都需要去查找资源然后取出,会伴随一些性能的消耗。
如何手动释放缓存中的资源
1.卸载指定资源
使用Resources.UnloadAsset 方法。但是该方法不能释放GameObject对象,因为它会用于实例化对象。它只能用于释放一些不需要实例化的内容的内存,比如:图片,音效以及文本等等 。一般情况下很少单独使用。
//卸载图片资源。如果卸载GameObject会报错,哪怕这个GameObject没有实例化。
Resources.UnloadAsset(tex);
2.卸载未使用的资源
一般在过场景时和GC一起使用
Resources.UnloadUnusedAssets();
GC.Collect();