游戏关卡是酱紫加载的,你造吗?
游戏属于实时交互程序,需要每秒渲染若干帧(例如30帧),让用户感觉画面和操作是连续的。而从硬盘中加载游戏资源往往是一个比较长时间的过程(至少不能在1 / 30秒内加载完),所以需要显示加载游戏的过渡画面,本文将对常见的关卡过渡画面及其对应的资源加载方式进行分析。
1 同步加载方案
游戏之所以看起来是连续的,是因为每秒渲染若干帧(例如30帧),如果使用同步I/O的方式加载资源,那么在资源加载完成之前,由于没有渲染,画面自然持续不变了。当然,游戏要加载的资源很可能并不只是一个文件,所以在从硬盘读取一个文件了以后有个机会渲染画面,所以有以下两种资源的同步加载方案:
1.1 显示静态画面
所有资源加载完了以后,进入下一关卡。加载资源的时候画面是卡死的,一般在关卡载入时间较短的时候,才会选择这种方法。
1.2 显示进度条
虽然采用同步I/O的方式加载资源时不能进行渲染,但是可以在单个资源加载结束以后渲染一帧。例如OGRE的资源管理系统提供了回调接口ResourceGroupListener(观察者模式),在载入资源的时候通知各种事件,可以利用这个事件绘制进度条。
使用这种方式显示进度条,会有明显的卡顿现象,因为单个资源加载了才刷新画面。好处就是充分利用CPU,节约加载时间,同时还可以显示进度条。个人感觉PC上的许多游戏就是采用这种方式(当然也有可能是下面2.2的方法)。
2 异步加载方案
如果在一个关卡运行的时候,采用异步I/O的方式在另一个线程中加载资源,那么用户则感觉不到关卡的加载时间,或看到流畅的加载关卡的动画(而不是静态画面或者很卡的进度条)。
2.1 简单的异步I/O加载资源
假设玩家当前所在关卡为关卡A,下一关卡为关卡B,那么玩家还在A关卡的时候,就异步加载关卡B的内容,这样在玩家进入关卡B的时候就不需要等待。
这种做法比较简单,但是在游戏中几乎见不到,主要有以下两个原因:
1、内存资源是很宝贵的,尤其是在游戏机上,而这种方法会比原先多消耗近一倍的内存;
2、对于非线性关卡的游戏,这个方法不适用。
2.2 使用显示进度条的过渡场景
假设玩家当前所在关卡为关卡A,下一关卡为关卡C,可以先加载过渡场景:关卡B。关卡B中采用异步I/O的方式加载关卡C,并绘制加载进度。由于关卡B的内容比较少,所以从关卡A到关卡B的时间非常短,玩家接下来就会看到关卡B中流畅显示的进度条和加载动画了。
Unity3D中使用这种方法加载关卡的实现看雨松MOMO的博客:Unity3D研究院之异步加载游戏场景与异步加载游戏资源进度条(三十一)
个人感觉很多手机游戏采用的是这种方法,体验感好;至于PC上的很多游戏我不太确定是采用这种方法还是1.2的方法,因为如果将负责渲染的线程优先级降低,负责加载资源的线程优先级提高,这样加载的速度会提高,但是进度条和过渡动画会有明显的卡顿。
2.3 Air Lock(阻隔室)
上一个方法玩家仍旧需要等待,只是出现关卡间的过渡动画和进度条,相比静态画面,体验感更好。如果使用Air Lock(阻隔室),则能够让玩家感觉不到等待时间,同时又不像2.1的方法那样浪费内存。
在制作关卡的时候,可以将关卡分为一大一小两部分,小的一部分为阻隔室;在加载关卡的时候,先加载阻隔室,然后再异步加载关卡的其他内容。加载期间,别让玩家在阻隔室闲下来,可以让玩家简单的走过一条通道,或者执行更有趣的任务。由于阻隔室比较小,所以加载很快,玩家感觉关卡的间隔不明显;等到玩家在阻隔室中玩了一段时间后,可以直接进入下一场景而无需等待。
XBOX的《光环》采用了类似的方法,不过总体感觉使用这种方法的游戏不是太多。
3 总结
若关卡比较简单,可以采用1.1的方法;若关卡比较复杂,加载时间长,则需要使用1.2或2.2的方法,给用户相关提示。2.3的方法比较有意思,但是需要在关卡的设计上下功夫。