使用Unity开发安卓游戏怎么进行性能优化?

姓名:雷潇 16030110083 

转载自:http://www.gameres.com/475425.html

【嵌牛导读】绝地求生这款游戏优化很差大家都有所耳闻,那么优化游戏就成了大家所关注的东西,首先如何优化最贱的游戏。

【嵌牛鼻子】游戏的优化,绘制函数,资源利用

【嵌牛提问】怎么进行性能优化游戏?

【嵌牛正文】引言

几周前,我开始写一款叫Sky Blocks的游戏,使用Unity引擎并且发布在了安卓手机上,如果你有时间可以在Google Play上下载体验一下。

在写这个游戏的过程中,我遇到的问题大部分都是性能方面的。下面我来介绍一下这款游戏,以及性能问题的解决方案。

这款游戏混合了《俄罗斯方块》和《太空入侵者》这两个游戏的玩法。玩家将方块尽量的摆成一条线,方块会从下往上运动,最后停在屏幕的最顶端,但是不会想《俄罗斯方块》那样连成线以后就立即消失。你有60秒的时间摆出尽量多的线,时间一到就会有UFO入侵你完成的防御工事,一旦它们将你的防御都摧毁以后就会攻打地球,当地球的生命值为零游戏就结束了。

这游戏听上去挺简单的,但要做好还得下些功夫,不过,这样才有意思,非常有意思!

写代码前一定要计划好

写代码之前一定要计划好,这非常重要。我在开始开发Sky Blocks之前就没有想好要做什么,没有考虑清楚游戏的玩法。在正式开发Sky Blocks之前我走了一些冤枉路,我用JavaScript和HTML5写了一个《俄罗斯方块》游戏,后来又用C#将其移植到Unity,但是在移植的过程中没有考虑二维和三维的区别,仅仅是复制粘贴的做法,遇到碰撞检测的bug也只是做了小幅的调整。

因为没有简单的在每次刷新时更新整个游戏面板,所以我将整个面板都布满一个最简单的方块,这些方块用来作为背景网格定位。每次网格刷新时都会将所有方块销毁然后重新实例化,对于我来说,这样做已经很不错了,在电脑上运行的很流畅。

一般,一个面板上会有20行10列的网格,有可能会不断地有200个背景方块需要渲染、销毁、重建。另外,还会有不断增加的防御线(10个方块每行),每个方块都会有自己的材料,每个材料都会绘制。假如,一个游戏面板上有150-200个方块需要渲染,那么,就会调用大约200次的绘制函数。

如果我在动手之前有明确的计划,我就会发现这么做游戏是不会运行太久,有可能就会在一开始就省去我大部分时间。

解决

在动手之前画一个草图是一个好主意,这样就可以通过整体分析找到哪些内容是不变的?这些内容有什么不同?在Sky Blocks这游戏中是游戏面板、防御线和UFO。

游戏面板用来控制游戏,包括可移动的方块和已经锁定住的静态方块。

防御线由10个方块组成并排在一条线上。UFO都是由网格组成,它们可以在防御线上面移动。抓住这几点,我就接近成功了!

减少绘制函数调用

我之前也提到过,我的实现方式会大量调用绘制函数。当在安卓设备(三星galaxy S4)上运行游戏,随着游戏内容越来多,我发现游戏变得越来越卡了。    为了让游戏运行流畅,我首先考虑减少绘制函数的调用次数。我在网上查相关资料,绘制函数会消耗多少资源?怎么造成的?该怎么优化?    意识到效率问题,我不能出一个好的测试方案,找到一些测例会对CPU和GPU造成严重的压力就行。一些测例没有太大的影响,但有些则会让我的帧率变得很低。

影响效率的问题还是比较容易发现,其根源就是不同的方块有不同的材质。

要减少绘制函数的调用就得减少object的数量和材质数量。

因此,我写了一段代码用来生成一个网格,这个网格就可以替代原来有200个立方体组成的游戏面板。然后,我用顶点着色的方法替代贴图方法。最后,我将材质的着色器换成在网上找到的一个不发光的顶点着色。现在我将所有重复的绘制函数调用都减少为只调用一次!

对于防御线的处理,我用了类似的方法。我将所有材质都替换成了不发光的顶点着色,我没将它们用一个网格代替,而是保留了10个立方体,因为,替换了材质就已经不再多次调用绘制函数了。

非常遗憾,我事先没有准备,所以这里没有提供优化前后的区别对比图片。下面是一个已经优化好的游戏截图:

上图目前这个方块只调用了一次绘制函数(Batches:20、SetPass calls:20),之前提到每个方块由4-5个立方体组成,这个方块就处理了4次。

现在,已经放置了两个方块,但处理次数只增加了一次。若是之前的版本,每激活一个方块中的一个立方体都会处理一次。

防御线也是同一种模式,但实际上有10个四边形,它们采用顶点着色法并且共享材质。这个例子中,我们没必要将防御线做成一个网格来绘制,因为,Unity会通过“Saved by batching”来自动处理这个问题。

UFO比较棘手。每一个UFO都由上中下三块网格组成,因为,我想让UFO的外观是随机组成的。UFO的每一部分包含3-4个材质,那么一个UFO很有可能就会调用12-17次绘制函数,而实际上会调用17-30次。会有2-3个UFO同时出现在屏幕上,那么就会调用50-100次绘制函数,该死!

对于这点,我迫切的想要减少绘制函数的调用次数,所以我在网上找到了一个脚本,它可以将这些网格合并为一个。但是这个脚本不可以处理材质的问题,于是我最终将UFO都着成一个颜色,这样UFO变得非常丑。我手动改了一下那个脚本,现在UFO可以绘制最多2种颜色了。来看看行得通吗?现在只调用了30次绘制函数,但是我也不确定运行效率是否真的有所提升,不过至少我将每个UFO绘制函数的调用次数减少到了10次以下。

减少绘制函数的调用次数是不是适合所有的情况呢?当然不是。如果你可以减少当然最好,但是对于有些非常棘手的部分,只有通过牺牲显示效果来提升效率。

现在,对于绘制函数调用次数的优化,我已经从150-200次减少到了75-90次,还是很不错的!

最后,轮到UFO发射的激光,它们也都是单独的材质,当UFO进入狂暴状态时,绘制函数需要调用30-40次。非常幸运,这次只需要建立一个原始的四边形,它使用不发光的顶点着色法,这样,所有的激光只需要调用一次绘制函数,即使是UFO都进入了狂暴状态。

现在,游戏中所有的绘制函数减少到了30-45次,不错不错!剩下的就是UI中的绘制函数了,但是UI的处理我没有找到好的办法,不过我还是非常满意现在的效率了,现在游戏比之前运行得流畅许多。

UFO还是占了一部分绘制函数,但是考虑到已经从30减少到了不到10次,还是有很大进步。

一个首要的原则就是使用尽量少的材质,如果可以,最好共享材质而不是每一个都实例化,这样,会减少很多绘制函数调用次数。

资源只加载一次

在我的一些代码中,我使用了一些Resource.Load函数,但是由于Unity不会将已经加载的资源缓存下了,所以游戏运行中就会反复加载资源,这样非常消耗效率。我之前就会把激光的材质反复加载,这样虽然不会在PC上有什么影响,但是在安卓设备上就不行了。

为了避免反复加载游戏资源,我建立了一个静态的Dictionary(资源名称为Key,资源为value),当我要用某个资源的时候我会先去查询字典中是否有对应的Key,若是没有才会加载资源,反之,我就直接用缓存的资源。

避免多次调用Instantiate函数

我没有考虑过GameObject.Instantiate函数的开销,在代码中大量的使用了它,我本以为这个函数的开销也就和new一个类对象一样,但是,我错了!在GameObject的新建与销毁时都比较消耗CPU。然而,我在实现UFO攻击的时候就遇到了这个问题,每当UFO开火时都会新建一个激光束,然后再非常短的时间内又将其销毁,这样,在短短1.5秒内就有可能调用20-40次新建与销毁函数。太棒了!我终于找到UFO攻击时性能不高的原因了。

解决这个问题的方法就是做一个对象池。我构建了一个空的对象池,当我需要新建激光束的时候,我会先去检查对象池中是否已经存在,如果存在,改变一下它的位置与血量就可以直接用了。

如果对象池中没有我想要的,我就会像之前一样新建一个。当在需要销毁这个对象时,我并没有直接销毁,而是又将其交还给对象池,然后将其设置为非激活状态。通过对象池的方法,在UFO攻击的时候CPU的开销降低了25-30%!

总结

绘制函数开销非常大,你应该尽量减少调用次数。减少材质数量可以非常有效的减少绘制函数调用。少用不同的贴图,可以将多张贴图烘培在一个图集里面。如果时2D游戏就少用光照,甚至可以像我这样做,不要光照只用色彩描述就可以了。着色器不要带有参数,而是用不发光的顶点着色,我这个项目中就是这样做的。以上这些可以大大减少绘制函数的调用次数。如果你觉得这样视觉效果达不到你的要求,你可以试试增加一些网格。

Instantiate函数非常慢,所以尽量少用它。在游戏一开始你可以将大部分你经常需要用到的对象构建好放在对象池中,要用的时候只需要将其激活。

绘制函数和Instantiate函数并不是唯一优化对象,绘制函数销耗CPU和GPU,Instantiate函数消耗CPU。

如果你有一个非常精细的模型或者一个过程非常耗时,这时减少绘制函数并不能起到什么作用。优化CPU的消耗时重中之重,你可以梳理你的代码,看看是否有大量重复执行的内容,然后想办法优化它们。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容