网页游戏性能优化最佳实践:延迟策略
网页游戏,尤其是多人同时在线的即时战斗webgame,性能优化是开发过程中、开发后期必然遇到的问题。历经磨难,总结出了一个最佳实践:延迟策略。其实说白了,就一句话:不要在一帧里做太多事。然后展开总结一下。
理解Flash Player的异步单线程
首先我们应该理解Flash Player的异步单线程机制。当然,最近刚出现的新版本FP的多线程API除外。FP的单线程表现在,我们可以控制的线程只有一个,这个线程可以以帧循环来表现出来。跑道模型告诉我们,每帧都会运行一些代码,然后进行渲染。那么哪些代码在哪一帧执行?这是通过事件机制来支撑的。通过“异步”地派发事件,来完成动画的渲染。例如我们在某个时刻创建一个Loader对象,并下载一张图片。这时主线程继续执行,FP会创建新的线程,来完成下载,然后派发一个Event.COMPLETE事件,通知主线程做处理。
插一句,这一点有点像JavaScript的运行机制。JavaScript也是单线程来运行代码,把代码分割成小的代码片段,一点一点执行。Ajax异步请求,就好比Flash里的Loader,只不过Ajax XMLHttpRequest是浏览器直接开放的接口,Flash Loader是浏览器插件开放的接口而已。
网页游戏的动画实现
网页游戏中通常会添加ENTER_FRAME事件,每帧去检测数据的变更,然后完成各种功能和动画。这就好比一个故事,有两条“时间线”,一条是数据,一条是执行。我们随时改变数据,然后等待下一个ENTER_FRAME去执行,来完成动画。例如我们给角色的当前动作设置成“行走”,那么下一帧进入的时候,用一些代码把角色位图换成行走,直接赋值bitmapdata即可。
性能瓶颈的起因和优化
假如某一个ENTER_FRAME的处理需要太长的时间,超过了一帧的时间,那么性能瓶颈就来了。下面的代码可以说明问题:
private function onEnterFrame(e:Event):void { frameCount++; trace(frameCount, flash.utils.getTimer() + "ms"); // so heavy for (var i:int = 0; i < 100000; i ++) { var s:Sprite = new Sprite(); addChild(s); } }
输出:
1 324ms 2 1833ms 3 3019ms 4 4569ms 5 7344ms
每帧的间隔都超过了1秒……方法执行之间太长,而FP又是单线程,这就导致ENTER_FRAME事件不能按照原定的时间去派发。帧的时间被撑开,导致帧频降低。人眼能分辨的最小时间片约为100ms,按这样计算的话,按最好的“数据”和“执行”的协调情况,帧频降低到10,必然会感觉卡。
显而易见,解决办法来了。不要在一帧里干太多事儿!在一般的情景中,例如其他玩家的出现、怪物行走等,实时性要求并不高。一个很常见的例子就是,刚进入一个场景,而周围有50只怪物。服务器会把50只怪物的信息一次性通通发给前端,而我们如果在一帧内完成50只怪物的初始化和渲染,恐怕这一帧要撑大了。我们可以把这些怪物缓存起来,再监听一个ENTER_FRAME事件,每帧处理5只怪物。
再插一句,这里又有点像JavaScript。JS里setInterval之后,如果某个代码片段执行时间过长,那么设置的interval就不准了。一样一样的。
结论
帧频25的情况下,一帧的时间只有宝贵的40ms。这要求我们每一毫秒都不能滥用。平时我们说的那些AS3语言方面的性能,例如用移位来取整,用Vector代替Array,往往不是性能的瓶颈所在。把大量操作分割成若干部分延时处理,是网页游戏性能优化的最佳实践。
本文转载自:http://jsfox.cn/blog/webgame/webgame-cpu-optimization-method-lazy-render-stratogy.html