基于cocos2d-x的游戏客户端优化
cocos2d-x并不是一个适合网游客户端(mmo)的游戏引擎,越是大型游戏,这个小引擎就越无法驾驭(虽然它非常受欢迎)。 之前我在原来的公司使用的是自主研发的C3引擎,已经对外开放(尚未开源),后面如果我有提到c3引擎,那么指的就是这个2.5d游戏引擎。
我想起我上个月刚离职的时候,c3的首席研究员(应该也是引擎圈内的一个大牛)对我说cocos2d-x没有什么技术含量,我还不以为然,当时我想的是,如果我自己开发一个游戏,首选必然是cocos2d-x。但是真正到新的公司接触了使用cocos2d-x开发的一个类似神仙道的mmo才感觉cocos2d-x对于一个mmo引擎来说,差的很多。与c3相比,差就差在几年,十余款mmo,上千位开发者的检验。虽然cocos2d-x的开发社区很庞大,但是它适合初学者去开发一个愤怒的小鸟、水果忍者,并不适合一个网游公司去开发一个mmo。虽然基于cocos2d-x有很多不错的mmo,比如忘仙、神仙道。但是我认为那是一群牛x的开发者通过自己的努力弥补了cocos2d-x的不足。
可以认为我不是一个牛人,但是一个团队能有一个牛人就已经万幸了,能有两个就可遇而不可求了,一个好的游戏引擎比如c3正是被我们这些普通开发者来使用,它可以不次时代,可以不面向对象,但是它会非常易于使用,并且非常难被误用。
牢骚发完了,下面是具体的优化:
1、去掉libxml2,改用rapidxml来解析xml文件。 rapidxml简直是一个大杀器,解析xml的速度甚至比纯文本解析和json格式还要快。其解析速度比libxml2快5倍,即便cocos2d-x中使用的是sax模型,而rapidxml是dom模型,使用rapidxml依然要快非常多。我们的游戏是所有配置文件都用xml来描述,其实大可不必,但是为了跟网页版本配置统一,方便今后的维护,暂时没有对配置格式进行修改。而cocos2d-x底层对xml使用最频繁的地方就是Plist文件的解析了。ios平台下还好,NSDictionary速度也很快(但是依然比rapidxml慢一倍),但是android下效果就非常明显了。游戏启动时间大大缩短。 所以,为什么cocos2d-x还要用libxml2呢?
2、游戏资源打包。 这个虽然是可以自己扩展的,但是却是需要引擎提供支持的。因为所有的图片读取都是属于引擎的内部代码。 当然不是所有的游戏都需要资源打包,但是一个实用(mmo向)的游戏引擎这个是必然要考虑的。 这一块儿牵扯到很多东西,比如游戏资源更新,资源读取规则,读取失败后的异常处理,多线程加载时的同步机制等等。
3、修改CCAssert,增加日志记录功能。 作为一个游戏引擎,cocos2d-x内部代码很不健壮,很多资源不存在或者是不小心的误用都会让程序挂掉。 这个对一个mmo来说是不可接受的。 CCAssert原来是一个简单的assert,这个在ios和android下就直接挂掉了,后面虽然修改为CCMessageBox的提示,但是依然不够方便,因为这些弹出框都很卡很慢。接触过mmo客户端开发的应该都有体会资源不存在是经常发生的事情,尤其是大家一起开发功能的时候,资源总是最后才正确且完整。 这个时候记录个log不就完了。而cocos2d-x却并没有提供任何Log记录功能(实际文件Log而不是开发时用的CCLog)。 而引擎内部有大量的Assert,断定文件一定是存在的,断定某个配置一定是正确的,断定某个Frame一定是存在的,这个造成的问题就是一旦有配置错误,那么程序很可能就崩溃掉了。而作为一个mmo,尤其是已经对外发布的情况下,这个时候出现表现异常(比如图片不显示)而不是崩溃会更加合理。
4、资源异步加载。虽然cocos2d-x有提供Texture的资源异步加载,但是这并不够用。 我们修改为这样的形式,CCSpriteCache缓存图片的时候异步加载图片,这个时候可以获取到正确的CCSprite,只不过里面的CCTexture并没有附上一个正确的纹理id,当图片加载完毕,这个id就正确了,那么CCSprite在下一次Draw的时候自然就会渲染出正确的图片(这里要做下判断,如果纹理id不正确那么就不进行渲染操作)。 还有需要注意的就是只有一个线程加载图片是不够用的,根据需要可能要开3~5个线程来加载图片,才会起到异步加载图片的最佳体验。 当然,如果仅仅是怕加载图片卡主主线程而不关心加载速度,那么就不需要这么麻烦了。
5、添加一个快速渲染的CCFont,无论是哪个平台生成字形纹理的过程都是非常慢的。如果一个mmo中有大量的文本、聊天等等,光生成字形的时间可能就要500~600ms,那这个游戏给人的感觉就是时不时一卡一卡的。 这个新的CCFont思路非常简单,生成字形的时候一个文字一个文字的进行生成,把生成的字形保存到一个512*512的纹理上,然后渲染的时候取这个生成好的字形进行绘制。
6、计划中: 人物图片使用骨骼动画切片处理,这个其实应该比什么js脚本更应该加到引擎内部。这个要提供的不仅仅是代码的支持,这个是从生产到结果的一站式技术支持。 不能引导生产流程的引擎不能说是游戏引擎,不能成为生产线的游戏引擎不能说是游戏引擎。
优化进行中。。。。。。。
最后再牢骚下,我敢打赌cocos2d-x的js脚本支持并不是一个正确的选择,如果是吸引html的开发者,我勉强认同cocos2d-html5,但是说实话,用html来开发网页游戏在几年内都不会是一个正确选择。而cocos2d-html5更像是给html开发人员的玩具,并且悲剧的是这个玩具还有些难,大多数html开发者无法掌握这个玩具,只能用它写写斗地主之类的小游戏。有能力用它写出捕鱼达人的开发者要么是顶尖的html开发者,要么会像我一样更习惯用c++来写代码。
正确的跨网页平台方向应该是像c3或者是unity3d一样,内部使用llvm把c++代码直接编译成flash或html5代码,这样现有的游戏只要经过非常简单的移植就可以在网页上面跑了。像unity3d那样支持js固然不错,但是这个不是必须的,我如果用unity3d,我选择脚本语言会是c#而不会是js,相信很多游戏开发者都会做出这样的选择。所以cocos2d-x费了那么大力气搞js,完全是走弯路了。有这个时间还不如把发布做好,把c#支持加进来(不加也无所谓,lua也凑合,就比c#慢几倍而已)。如果cocos2d-x不能在mmo相关功能上提供更多的支持的话,那么它对我而言就是一个玩具,而不是一个强力武器