Unity - 资源加载

631 阅读5分钟

Resources同步加载

作用

  1. 通过代码动态加载Resources文件夹下指定路径的资源
  2. 避免繁琐的拖曳操作

 

常见的资源类型

  1. 预设体对象 - GameObject
  2. 音效文件 - AudioClip
  3. 文本文件 - TextAsset
  4. 图片文件 - Texture
  5. 其他类型

预设体对象加载需要实例化,因为他要显示到场景中。其他资源加载一般直接使用

资源同步加载 - 普通方法

在一个工程中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的父类

image.png

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();

qrcode.jpg