本文同时也发布在我的博客:http://www.livoras.com/
转载请注明出处: http://www.livoras.com/post/23
Note:这篇文章是在做一个移动端HTML5小游戏《别碰钉子》时候写的一篇游戏方案分析文档。个人认为在移动端上做HTML5游戏最困难的点在于在性能上适配不同的手机浏览器。
现在比较主流做HTML5游戏的方式是用Canvas,用例如Phaser、Cocos-js之类的框架来做。在PC端上因为硬件比较好,性能问题不大。但是在移动端这种像素级别的Canvas操作上会遇到比较大的性能瓶颈,在性能上对不同浏览器(一般是不同Webkit新老版本)进行兼容和在PC端对不同版本的IE进行兼容难度相当。
本文分析了一个游戏不同的实现方案的性能上的区别,总结出一种实现高性能移动端HTML5游戏的方案:
- 使用DOM + JS控制CSS3属性开启3D加速实现动画
- 使用time-based动画算法替代一般的frame-based动画算法
用这种方式实现的HTML5游戏,可以不同手机浏览器的性能上达到一种体验基本一致的效果。微信扫一扫可玩:
下面是这种方案的出来的分析过程。
1. 前言
《别碰钉子》这个游戏其实相当于《Flappy Bird》游戏的一个改版,该游戏特点和如《神经猫》这类游戏不一样。这个游戏其实是对物理世界有模拟,无法单纯使用CSS3来实现。为了在不同移动平台浏览器上获取到比较良好的效果,对不同的技术方案进行可行性分析和性能测试,然后选择最佳方案以获得最佳体验效果。
该分析不针对任何游戏框架,因为游戏框架底层其实也是使用HTML5、CSS3等,分析直接针对不同方案最原始实现进行优化和测试,力求找出真正的性能瓶颈进行优化。
2. 可能技术方案以及初步分析
2. 1 方案一:Pure CSS3
描述:
使用纯原生CSS3的key-frames、translate、transition高性能CSS3属性来进行游戏动画的实现。
优点:
可以轻松开启3d GPU硬件加速,直接条跳过JavaScript解释器的性能瓶颈。移动平台上最流畅的动画实现方案。
缺点:
- CSS3的transition动画ease类型有限,这样使得模拟物理世界多变的动画变得困难,但是可以通过这个方案进行解决。
- 因为CSS3动画不通过JavaScript控制,无法对动画过程进行检测和逻辑操作,这使得物理世界的碰撞检测变得不可能。直接成为这个方案最大的硬伤,不排除有方案可以来实现这种不可能,有待探索。
- CSS3实现动画的开发效率会比JS实现同类动画开发效率要低。
2. 2 方案二:JavaScript + Canvas
描述:
使用JavaScript和Canvas进行动画的实现,由于移动平台的限制,基本不考虑WebGL。使用requestAnimationFrame + 逐帧渲染Canvas进行动画的实现。基本上游戏框架内部就采取这种实现,所以这里不讨论游戏框架的使用,直接讨论底层性能优化。
优点:
- 所有动画都是JS控制,可以对动画进行最精细的调控。
- 基本上可以做到任意能够想到的效果。
缺点:
- 因为Canvas是像素级的渲染,每次动画的实现其实是对画布的“擦除 + 重新渲染”。对于移动平台来说会有很大的计算压力,可能造成较大的性能瓶颈。
- 无法启动3d底层GPU加速,不能压榨渲染性能。
2. 3 方案三:JavaScript + CSS3
描述:
不使用Canvas进行游戏元素的渲染,而是使用DOM进行元素的实现。动画的实现采用这么一种方式:
- 用CSS3开启3D加速,使用translate进行元素位置的控制。
- 使用JS控制CSS3的translate属性进行动画的实现。
优点:
- 既能使用JavaScript对动画进行精细控制,又能使用3D硬件加速
缺点:
- 无法像Canvas那样做出非常绚丽的效果。
- 因为JS控制CSS3的方式实际操作的是DOM,一点元素多起来了,就会可能遇到一个非常大的性能瓶颈:DOM天生就非常慢。
- 游戏复杂程度高了,这种方案开发效率会比较低。
综上,第一种方案虽然效果最好,因为遇到较大的实现困难,直接排除;方案2和方案3值得探索,对它们进行一个性能上的测试,挑选最佳方案进行游戏的实现。
3. 技术方案性能分析
3. 1 性能相关环境因素
在分析之前先排除一个误区:移动端HTML5游戏和手机操作系统的关系。经过一系列在不同手机上同一浏览器的测试,同一手机上不同浏览器的测试。得出的现象是:在低级操作系统(2.3)下用好的浏览器也可以达到比较好的FPS,而在高级操作系统(4.4)中用低级浏览器可以获取到一个比较低FPS,如图:
Android 2.3, FPS:58
Android 4. 4, FPS:9
而同一个手机不通的浏览器也会有不一样的性能,小米2上用webkit build 为573.36的版本浏览器和534.30的版本浏览器居然是天壤之别:
小米2 webkit 573.36, FPS: 10
小米2 webkit 534.30, FPS: 62
而经过观察,在不同手机上的webkit的build版本相同的情况下,获取到的性能参数FPS是在同一个级别上的。在小米二和华webkit build的版本都为533.1的情况下,FPS基本都在10左右:
小米2, FPS:10
华为, FPS: 9
而在同一个build的Chrome上可以获取良好的50~60的FPS。
也就是说,在这个性能测例中,获取到结论是:一个游戏的执行效率和操作系统没有太大关系,而是和浏览器有关系。
注意:
- 该结论是不严谨的,仅代表在该测例情况下,并且由于没有足够多的垃圾测试手机,所以这只是一个推论。
- 这里简单地用webkit build版本来区分浏览器只是一种快捷方式,实际上,不能用webkit build版本来区分浏览器。同一个build的浏览器性能表现也可能有较大差异。
接下来的测试基于这个推论,在同一个测例性能表现较大的不同浏览器上,对表现较差的进行优化,减少性能表现差异。
3.2 方案性能测试和优化
一个方案的优秀与否参考两个标准:
- 页面的FPS
- 主观体验上动画流畅程度(10为满分,可参考PC端Chrome,主观判断)
针对方案2和3,做这么一个测试,做一个小人在页面上移动,遇到边界马上反弹,观察不同浏览器版本的FPS和体验的流畅程度。
3.2.1 方案二的测试和优化
用方案二(JavaScript + Canvas)方式编写了测试:http://livoras.github.io/blog/ca-move/ ,扫一扫可见效果:
在webkit build为537.36(下为浏览器一)的一个浏览器上获取到性能数据:
FPS: 10 流畅程度:3
在webkit build为534.30(下为浏览器二)的一个浏览器上获取到性能数据:
FPS:50~62 流畅程度:4
让人惊讶的是,两个浏览器在FPS表现较大,但是流畅度感受上差不多(比较卡)。而且,最大的差异在于,浏览器一(FPS较低)的小人的移动动作比浏览器二(FPS较大)的移动速度要慢得多。
经过研究发现,我们一般的动画算法是frame-based算法,也就是说我们每帧动画让小人移动的位移是一样的。假设我们一帧动画移动5px,在FPS为10的浏览器中一秒钟就移动 5 x 10 = 50px。而在FPS为60的浏览器中一秒钟就移动5 x 60 = 300px。
这就是为什么一些浏览器感觉特别卡(移动慢)的原因,因为我们浏览器的FPS不一样,我们的算法是frame-based的!而大多数框架的算法也是frame-based算法,例如Phaser就是这样。那怎么做到不同浏览器都可以做到统一的速度上的体验呢?把动画改成time-based算法即可。
time-based算法就是,小人的移动速度和FPS没有关系,而是直接和时间挂钩。以前我们是px/FPS,现在改为px/sec。也就是说在每一帧动画中基于过去的时间来计算移动的位置。详情可参考:
- http://viget.com/extend/time-based-animation
- http://blog.sklambert.com/using-time-based-animation-implement/
- http://codetheory.in/time-based-animations-in-html5-games-why-and-how-to-implement-them/
对上面的测例进行了算法上的优化,包括:
- Canvas清除不是整块画布,而是清除小人局部的画布。
- 使用time-based算法来实现动画。
修改完以后的测例:http://livoras.github.io/blog/ca-time-r/ ,扫一扫可见效果:
在浏览器一和浏览器二上效果卓然,两个浏览器达到统一的体验速度,也就是小人移动的速度是一样的。但是的动画体验上还是感觉到卡(体验5分左右),而我们在这个测例已经没有可以优化的地方(小人是直接使用drawImage,没有必要Pre-render优化)。
这就是我们在这个方案上能做到的优化。
3.2.2 方案三的测试
我们直接套用方案二的time-based Animation算法,用JavaScript控制CSS3的translate属性来进行动画的实现方案三,启动了3d加速(transform:tranlate3d),测例:http://livoras.github.io/blog/ca-css3-time-r/ ,扫一扫:
在webkit build为537.36(浏览器一)的一个浏览器上获取到性能数据: FPS:60+ 流畅程度:6
在webkit build为534.30(浏览器二)的一个浏览器上获取到性能数据: FPS:60+ 流畅程度:5
出现了让人惊讶的经过,原来只有FPS 10的浏览器一飙升到了60,而且流畅程度完爆了canvas的实现。而浏览器二保持原来的流畅程度和FPS。
3.2.3 测试结果
在条件相同的情况下,经过不同的手机上不同的浏览器测试后,方案三的体验流畅程度都比方案二的好,并且通过time-based animation算法,即使不同方案的实现都可以达到同一个速度(不是流畅程度)上的体验。
3.2.4 已知问题
- time-based算法在MX上会出现浏览器假死的状况。
4. 方案选择
根据测试,衡量各方面因素,最终采取的技术实现方案定为:
使用time-based animation算法,用JavaScript控制CSS3的translate属性开启3d硬件加速来实现游戏动画方案。
参考资料:
- http://www.slideshare.net/iiwork/high-performance-mobile-web-game-development-in-html5
- https://blog.safaribooksonline.com/2012/06/29/faster-mobile-gaming-with-css3/
- http://www.html5rocks.com/en/tutorials/canvas/performance/#disqus_thread
- http://jsperf.com/render-vs-prerender
- http://simonsarris.com/blog/427-increasing-performance-by-caching-paths-on-canvas
- http://kristerkari.github.io/adventures-in-webkit-land/blog/2013/03/08/dealing-with-svg-images-in-mobile-browsers/
- http://buildnewgames.com/dom-sprites/
- https://github.com/davidshimjs/collie-benchmark/wiki/Performance-Benchmark
- http://blogs.adobe.com/webplatform/2014/03/18/css-animations-and-transitions-performance/
- http://viget.com/extend/time-based-animation
- http://blog.sklambert.com/using-time-based-animation-implement/
- http://codetheory.in/time-based-animations-in-html5-games-why-and-how-to-implement-them/
- http://www.joelambert.co.uk/morf/
- http://jeremyckahn.github.io/blog/2013/07/28/60-fps-or-bust-dynamically-prerendering-css-animations/