地图模块的相关的优化

手头在做一个大型在线MMORPG的地图模块部分,遇到很多优化问题,记录下来给以后的自己看看。。。

首先是大地图方面,地图是背景大概为 3000*3000 ,或许更大。 整张图片在3M左右。

已国内用户的平均网速来说,大概要下载 15 秒左右。 显然用户是不能忍受黑屏15秒的。

于是采用了分块加载,将地图切成 100 块,每块 大小在 30KB。 一般25块可以将用户当前的屏幕填满。 那么显然的,填充满用户的屏幕还需要大概4秒。

4秒的黑屏显然也是不靠谱的。 于是首先截取原图的 1/10 作为模糊图,大小为30KB. 那么用户进入游戏后,首先加载模糊图,用户可以在进入游戏的瞬间,就能看到 模糊的全图。 之后再加载分块图,将模糊区域进行填充。

用户在移动的过程中,随时以用户为中心,25块的加载周围的地图区块。但是,当用户移动的足够快速,那么在区块加载成功的瞬间,会有卡顿现象。
于是我检查了代码。

首先将一个区块为一个bitMap,一百个区块为一百个bitmap的方法改写为使用一个bitMap,使用bitMap.bitmapData.draw 将区块直接 绘制在一张bitmap上。经过测试后,效果改善,但还是有卡顿。

然后采用 bitMap.bitMapData.copyPixels 的方式进行像素拷贝。发现 像素拷贝 和 绘制像素 的花费时间差距在 0.001秒左右,几乎可以忽略。

之后采用 bitMap.bitMapData.setPixels 使用 byteArray 进行单一像素的填充。其效率也和之前差不多。于是觉得卡顿问题并非主要是由填充方面引起的。

于是,想着和地图滚动相关的还有 镜头跟随 方面,于是找到相关代码,将位移量全部修改为 2的倍数。效果略微改善。

最后降帧率从60fps 降低为 30fps ,同时降低滚动速度,降低卡顿。

其最终占用率为:
原地不动:CPU 0%
地图滚动: CPU 25%
地图滚动+加载区块: CPU 31%

看到这么高的数据,难道是我自己代码太烂?于是打开目前几个主流同类型页游
<傲剑> 地图中,只有玩家自己 CPU:26%
有10个其他玩家 CPU:48%
有其他玩家+加载区块 CPU”56%
<诛神> 的情况差不多。

但是本着对完美的追求,打算采用卡马克卷轴算法,进行可视范围优化,在之前的个人demo中,占用率可降低10%左右。

卡马克看来也坑爹了,卡马克在加载无限地图的时候,可以很好的保持内存的占用量减少。但是其代价是巨大的CPU开销。即使地图在不滚屏的时候也要占用10%左右的CPU.

之后又尝试了全屏scrollRect的方式,提示也是不够的说。

最终决定使用 强制GC+放弃缓动+A*优化+多队列并行改为多队列等待+双缓冲+无变化不重绘+单render驱动

其最终占用率为:
原地不动:CPU 0%
地图滚动: CPU 5%
地图滚动+加载区块: CPU 5%
启动到运行,内存变化不超过5M,基本满意了。

不知道为嘛,主程一直很反对使用全屏重绘,强烈要求使用区域性区块显示。
没办法,谁叫人家是老大呢,于是我根据摄像头位置,遍历所有的区块,把所有摄像头可视区域的区块都显示出来,摄像头不可视的区域的区块全部移除。
嘛~ =。= 这周~当主程同屏放上200个avatar后,fps掉了一半。
想想,毕竟一共有 784 个区块,虽然只有当摄像头移动超过1个区块大小后才遍历,不过全是遍历的次数多了些。
于是改进一下,不遍历所有区块来知道哪些区块在附近了。 由于区块的x,y都是区块大小的倍数。可以直接通过偏移区块宽高值去获取到。
于是通过计算摄像头中心点位置,左右,上下偏移4格做显示和移除。 现在每次遍历只需要遍历47块就够了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注