Unity 场景加载和资源加载

一个游戏往往都是由很多场景组成的,例如会有主界面场景、战斗场景…等,不同的场景也是由若干的资源组合而成,在游戏的制作过程中,场景和资源的加载是不可或缺的。不管是场景还是资源都会涉及到加载的问题,在什么时候进行场景或资源的加载?场景的加载和资源的加载如何区分?加载时是使用同步的方式还是异步的方式?…

场景加载

在需要切换到新场景时,就会涉及到场景加载。Unity场景加载分为同步加载和异步加载。

提到场景的跳转,在Unity中想要实现场景转换的前置工作就是将涉及到加载的场景添加到Scenes In Build中。
操作流程:
1、选中File中的Build Settings

2、在Scenes In Build中添加场景

Unity中常用的场景加载相关方法

1、加载场景(同步、异步)

同步加载场景 SceneManager.LoadScene();

此方法的第一个参数可以使用场景的名称(输入名称时要使用字符串)或者在Scenes In Build中对应的数字编号。
此方法的第二个参数是枚举变量,对应的枚举类型是LoadSceneMode,这个枚举类型只有两个值

(1)当给第二个参数赋值LoadSceneMode.Single时,这个加载场景方法就会使得当前游戏中有且仅有我们给定的场景(第一个参数传入的场景)会被加载。
(1)当给第二个参数赋值LoadSceneMode.Additive时,会让我们给定的场景加载,并让这个场景与当前已经加载的场景同时显示。

这种同步的场景加载方式存在一个问题,就是当加载的场景很大很复杂时,加载速度就会变慢,而且加载时会出现卡顿,为了解决这个问题,Unity提供了一个新的方法。

异步加载场景 SceneManager.LoadSceneAsync();

此方法有返回值i,返回值的类型时AsyncOperation,我们可以通过接收这个返回值来跟踪场景的加载进度。

AsyncOperation.isDone 
// 这个是用来判断加载是否完成。这个属性是加载完并且跳转成功后才会变成完成。
AsyncOperation.allowSceneActivation 
// 这个是加载完后,是否允许跳转,当为false时,即使场景加载完了,也不会跳转。
AsyncOperation.progress 
// 这个时表示加载场景的进度。实际上的值时 0 - 0.9, 当值为0.9的时候,场景就已经加载完成了。

需要注意的是,SceneManager.LoadSceneAsync() 方法也可以在普通的方法中调用,但这样做会导致阻塞主线程,从而导致应用程序在加载期间出现卡顿或无响应的情况。所以异步加载场景更推荐卸载协程中使用。

2、获取当前场景 SceneManager.GetActiveScene();

通常使用这个方法是为了进行后续获取信息的一些操作,例如

// 获取当前场景
Scene scene = SceneManager.GetActiveScene();
// 场景名称
Debug.log(scene.name);
// 场景是否已经加载
Debug.log(scene.isLoaded);
// 场景路径
Debug.log(scene.path);
// 场景索引
Debug.log(scene.buildIndex);

3、获取调用场景对象所指向的场景中的所有游戏物体

Scene scene = SceneManager.GetActiveScene();
GameObject[] gos = scene.GetRootGameObjects();

以上都是针对场景的方法,下面介绍一些针对场景管理类而言的方法

4、获得当前加载的场景数量

Debug.log(SceneManager.sceneCount);

这个变量可以获取到当前加载的场景的数量,场景并非在同一时间只能存在一个,它是可以多个叠加起来的。

5、创建一个新的场景

// 方法中的参数是新场景的名称
Scenee scene = SceneManager.CreateScene("newScene"); 

6、卸载场景

// 参数是要卸载的场景的场景名
SceneManager.UnloadSceneAsync(newScene);

卸载这个场景后,场景及其对应的场景文件都会被删除。

分析LoadSceneAsync相关问题

这里之所以将LoadSceneAsync单独拿出来分析,是因为Unity异步加载场景的这个方法确实存在一些小坑,不便于使用者使用。

1、SceneManager.LoadSceneAsync()并不是真正上的后台加载,它是在每一帧加载一些资源;
2、将allowSceneActivation设置为false后,Unity中就只会加载到90%,剩下的要等到allowSceneActivation设置为true才加载。加载到90%时,我们人为控制让其进度条的值为100%,实际并没有加载完成,所以会卡顿;
3、floa类型转int类型的转换规则:值会向零舍入,1.99会返回1,0.9会返回0,所以我这的进度条直接从0到100,就是这个原因,一直返回的是0。

类型转换的规则:
当在int(假设int是32位的)、float和double格式之间进行强制类型转换时,原则如下:
1.从 int 转换成 float,数字不会溢出,但是可能被舍入。
2.从 int、float 转换成 double,能够保留精确的数值。因为 double 有更大的范围和更高的精度(有效位数)。
3.从 double 转换成 float,因为 float 范围要小一些,所以值可能溢出成 +∞ 或 -∞。另外由于float精度较小,还可能被舍入。
4.从 float、double 转换成 int,值将会向零舍入。如1.999会被转成1,-1.999会被转成-1。同时值可能会溢出。

资源加载

资源加载和场景加载类似,也存在同步加载和异步加载。使用Unity开发游戏的过程中,资源的加载一直都是需要重点关注的。

Unity提供的资源加载方式

Unity一共提供了5种资源加载的方式,分别是
1、Resources(只能加载Resources目录中的资源)
2、AssetBundle(只能加载AB资源,当前设备允许访问的路径都可以)
3、WWW(可以加载任意处资源,包括项目外资源(如远程服务器))
4、AssetDatabase(只能加载Assets目录下的资源,但只能用于Editor)
5、UnityWebRequest(可以加载任意处资源,是WWW的升级版本)

同步加载和异步加载的意义和优缺点

既然资源加载有同步和异步两种方式,那必然是因为两者各有优劣,那么了解两者的差异,我们才可以在开发中灵活使用。

1、同步:并不是按字面意思的同时或一起,而是指协同步调,协助、相互配合。是按先后顺序执行在发出一个功能调用时,在没有得到返回结果之前一直在等待,不会继续往下执行。

同步的优点:管理方便,资源准备好可以及时返回。缺点:没有异步快。

2、异步:刚好和同步相反,也就是在发出一个功能调用时,不管没有没得到结果,都继续往下执行,异步加载至少有一帧的延迟

异步的优点:速度快与主线程无关。缺点:调用比较麻烦,最好的做法是使用回调。

Unity中Resource常用的资源加载相关方法

1、同步加载资源 Resources.Load();

(1)读取文件时的根目录是 Assets/Resources,所有资源文件都放在该文件夹下,命令中的路径从 Resources 文件夹里开始写。
(2)用 / 表示子文件夹。
(3)读取的文件不要加文件的后缀。
(4)Load 后 <> 中写入读取的类型。

2、异步加载资源 Resources.LoadAsync<>();

Resources 异步加载就是内部新开一个线程进行资源加载,不会造成主线程卡顿。

注意:异步加载不能马上得到加载的资源,至少要等一帧。

比较常用的异步加载资源的方式,一个是事件监听实现异步加载,另一个是协程实现异步加载。两种方式各有优劣,事件监听的方式实现异步加载,优势是写法简单,但是有一定局限性,只能在资源加载结束后进行处理,这实际上属于“线性加载”。协程的方式实现异步加载,优势是可以在协程中处理复杂逻辑(比如,同时加载多个资源、进度条更新等),但相应的编写逻辑会更为复杂,这实际上是类似于“并行加载”。

加载的过渡(加载界面)
不论是场景还是资源,在异步加载的时候,都会存在一个问题,当资源在异步加载的过程中,会存在可能资源未加载完成就切换场景的情况,这样一来就会导致表现效果不好。
Q:资源异步加载的时候怎么解决表现问题?
A:一般来说,最简单的处理方式就是使用UI遮挡一下(加载界面),再有比较常用的方式,就是其他主页点击按钮后先跳转到加载页面场景, 同时异步加载要跳转到的场景。

具体实现加载界面的方法很多,网上的文档也很多,这里就不过多赘述,下面提供几个相关链接以供参考:
1、http://t.csdn.cn/VTTvA
2、http://t.csdn.cn/wlmwq
3、http://t.csdn.cn/h6Pnn

参考文档:
1、https://blog.csdn.net/ChinarCSDN/article/details/82914541
2、http://t.csdn.cn/NfaMx
3、http://t.csdn.cn/wqenA

猜你喜欢

转载自blog.csdn.net/ProSWhite/article/details/132600551
今日推荐