.entry-content ul, .entry-content ol {padding: 0 0 0 10px; }
写这个系列主要为了记录和总结使用Cocos2d-x JSB和Cocos2d-html5做游戏开发的过程中遇到的问题和解决方案。
Cocos2d-x JSB和Cocos2d-html5的跨平台原理
先引用cocos2dx官方wiki的一张图:
cocos2d-x JSB
Cocos2d-x js binding(JSB)和Cocos2d-x lua binding一样,是Cocos2dx的一部分。它们构建在原来的cocos2d-x c++代码之上,通过脚本解释引擎让我们可以用脚本语言编写游戏逻辑。JSB的js引擎为firefox的spidermonkey,它可移植性非常好,经常被用作嵌入式的js脚本引擎。不过spidermonkey的性能是不如V8的,那为什么不用V8呢?据官方论坛的解释是V8官方没有IOS的支持。JSB的主要组成是spidermonkey加一堆自动生成的binding代码,这些binding代码完成了将cocos2dx c++里地类和方法注册到js的脚本运行环境中。比如js中的cc.Sprite.createWithSpriteFrameName会通过binding代码调用到c++里的CCSprite::createWithSpriteFrameName,除了CCSize CCPoint这样的栈变量,js里地每一个cc.Xxx变量都对应这一个C++ CCXxx实例,其生命周期也由C++控制,而不是js的垃圾回收机制。
Cocos2d-html5
Cocos2d-html5和JSB不太一样,他运行在浏览器环境中,整个引擎用js完全重写,使用WebGL和Canvas作为图形引擎,但是API和JSB完全兼容,这样就能实现一套代码既能运行在IOS、Android(Cocos2dx JSB),又能运行在浏览器里(Cocos2d-html5)。但是目前Cocos2d-html5在移动浏览器上不能使用WebGL,只能使用canvas,canvas的性能在一些机型上有很大问题,这对游戏设计带来很大的限制,后面再详细说这个问题。
为什么选择Cocos2d-x JSB + Cocos2d-html5: The Good Part
网上有很多关于Cocos2d-x JSB和Cocos2d-x lua binding孰优孰劣的讨论,比如这里,我主要说一下我们项目的情况。
javascript作为动态脚本语言处理游戏逻辑非常顺手。语法上的灵活性大大增加了开发效率。
内建的array和object类型,配合underscore.js库,使得各种数组、map操作非常方便;
有了first-class function使得实现callback非常简单自然;
动态更新,由于javascript代码和spider monkey字节码的平台无关性,游戏逻辑可以动态从服务器更新,绕过了重新发布新版本的繁琐步骤,给bugfix和活动运营带来很大的便利;
无需编译,改完代码直接刷新浏览器就能调试大大节省了时间,firebug或者chrome dev tools都能很轻松地实现断点调试,另外有webstorm、aptana这样优秀的IDE让代码编写非常顺畅,这方面lua就很弱了。
公司主要focus在轻游戏上,移动web浏览器(微信浏览器)是轻游戏的一个重要分发和传播平台,所以游戏需要有html5版本。用Cocos2d-x JSB + Cocos2d-html5使得平台原生版本和html5版本可以共用一套代码,降低开发成本。这点是lua-binding办不到的。这也是我们选择js的最主要原因。
我们游戏的Server端使用nodejs和,这样就是所谓的full-stack javascript。服务器和客户端可以共用object model和部分游戏逻辑代码。mongoose <-> json-rpc <-> client,整个数据交换的流程中,数据都是以相同的json model存储,完全统一,避免了各种转换带来的理解上的困难。
得益于nodejs,js的开源社区非常活跃,可以从社区中获得丰富的工具和类库支持。比如grunt,通过grunt实现了开发过程中所有费力的脏活自动化,比如纹理合并优化、游戏打包发布等等。
开发流程优化。用Cocos2d-html5快速制作原型,通过浏览器很方便的让大家试玩,验证游戏可玩性,立项后相对平滑部署到其他平台。
Cocos2d-x JSB和Cocos2d-html5的问题:The Not-So-Good Part
我们的游戏目一开始用Cocos2d-html5做demo,一切非常顺利。立项后尝试让游戏通过JSB跑在IOS上,开始遇到各种问题,当时对JSB理解也不够,解决问题很慢,立项后的前两周被JSB的各种问题搞得焦头烂额,一度开始认为选择Cocos2d-x JSB也许是个错误。把集中不同问题都解决过一遍之后项目开发才回归到正常节奏。总结一下,大概有以下几种问题(我会在下一篇blog里详细列出遇到的所有问题)
1. Cocos2d-x JSB和Cocosd-html5的API不兼容
这类问题数量最多,但相对也比较好解决。
一种是名字不同,比如CCSprite::setFlipX在html5里 cc.Sprite.setFlippedX,JSB还是setFlipX。
还有一种是某个类或者方法C++里有,但是JSB里没有binding,这个需要在binding生成的配置文件中加上,或者手动改binding代码。
js里没有私有成员的概念的,所有的成员都可以被外部访问,这使得h5版本里可以绕开getter/setter直接修改属性。但是这在JSB里就会报错,因为JSB没有暴露私有成员。
Cocos2d-html5的canvas模式和WebGL模式也有差异,canvas模式下所有3D相关的功能都无法使用,比如CCXxxTiles3D以及相关的transition。
2. JSB使用的坑
这个问题其实可以和API不兼容归为一类。单独拿出来说是因为这种问题难以调试,非常令人抓狂。这类问题的根本原因在于js相对lua而言是比较复杂的,整个解释器编译完有3M大,所以引入一些语言的坑是难免的,这也是很多人推崇lua binding对JSB敬而远之的原因。最典型的问题是对象生命周期和内存管理。Cocos2d-html5里,内存管理完全有js的gc控制,只要有可达引用就不会被gc掉。但是在JSB里情况就复杂了,普通的js object也是由垃圾回收器管理,而引擎的组件(主要是CCNode的所有子类)的生命周期还是由C++的引用计数机制和autorelease pool来控制。这就导致了对象在html5和JSB里销毁的时机是不一样的,一般是JSB早于html5,由此产生了很多只在JSB里出现的“Invalid Native Object”问题。
3. 引擎实现bug
任何引擎都有bug,但是cocos2d-html5里的bug还是略多了点,JSB里一些人工binding的代码也有不少bug,需要时刻关注cocos2dx的github repo和官方论坛。我遇到好几个bug都在3.0的branch fix了,但是2.2.x里一直都还有,不得不手动merge。
4. 性能问题
移动浏览器的WebGL支持目前都还不咋地,所以Cocos2d-html5在移动浏览器上只支持Canvas模式。前面提到了Cocos2d-html5 canvas在移动浏览器上有性能问题,这里详细说一下。我们的游戏帧率是60,在iphone 5s draw call数量到达200之后可以感觉到丢帧,iphone 4就直接卡死了,用SpriteBatchNode优化以及将屏幕外的sprite invisible后,iphone4和iphone5的都能流畅跑起来,但是一放粒子特效立马降到20帧以下。Android的情况更惨,很多机型的浏览器没有canvas硬件加速,只能跑个几帧。
JSB的性能基本上是没什么问题的,因为和cocos2d-x c++比较渲染都是由原生的opengles完成,花费的时间也就一样。不同的是游戏逻辑部分的js的性能是c++的1/5到1/10,这一般不会带来性能问题,除非游戏逻辑中有非常密集的计算和大型for循环。我们游戏里会实时创建游戏地图,每次创建800个对象,每个对象是一个sprite+一个物理刚体,在ipad2上,每次生成地图时都能感觉到卡顿,后来把地图生成拆分到每一帧中解决了这个问题。
所以结论是Cocos2d-html5在移动端目前只能做一些对显示效果要求不高的休闲游戏,比如问答、2D解谜之类,这类游戏在手机上既可以通过移动浏览器、微信分享分发html5的网页版本,又可以通过应用市场分发JSB的app版本。而复杂一点的游戏就只有JSB的app版本了。
上面的问题确实让我们一开始花了不少时间填坑,但总体来说Cocos2d-x JSB + Cocos2d-html5的跨平台开发模式可以满足我们游戏的要求。我们比较在乎html5版本,所以目前来说Cocos2d-html5是最佳的选择。
原文链接:
http://boundary.cc/2014/02/cocos2d-x-jsb-cocos2d-html5-game-development-1-choice-of-engine/