热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

乐元素CTO凌聪-基于cocos2d-x二次开发的自有引擎方案分享

主持人:接下来请乐元素CTO凌聪发言。他们的方案已经做到很高的层次了,上次我在他们公司蹭场,所以就邀请他过来跟大家分享,他也比较慷慨的就答应了。凌聪:我想讲的内容里面有很多为什

主持人:接下来请乐元素CTO凌聪发言。他们的方案已经做到很高的层次了,上次我在他们公司蹭场,所以就邀请他过来跟大家分享,他也比较慷慨的就答应了。

 

凌聪:我想讲的内容里面有很多为什么,前面我们听到ARM和英特尔几位先生讲的东西都太高精尖了,我们讲一个接地气的东西,我们讲作为一个开发商当时为什么会选择自己在Cocos2D-X引擎里面,可能是造文字,可能是造我们自己的引擎,接下来也会讲一下整体我们的架构设计,然后是一个Q&A环节。


首先我们为什么会选择Cocos2D-X?我们其实从2011年开始,我们开始了第一个游戏,就是我们的水族箱的发布,我们从4月份开始做了6个月,当时我们选择的就是Cocos2D iPhone,也导致我们后来做了很多的移植工作才能在Android上跑起来。接下来我们又选择了HTML5,当时没有Cocos2D HTML5的技术,要不然的话很可能就成功了。后来我们又用了Flash Air Port,接下来的才是Cocos2D-X,其实我们前面经历了很多种技术。我们在Cocos2D-X之后也尝试了另外一种技术,就是Conora,我们比较早的接触,觉得这种语言可以控制,后面是Unity。

 

这么多种技术,最后我们为什么决定选择技术框架还是用Cocos2D-X呢?我们主要有几个方面的考虑。首先还是跨平台,现在我们看到Android的市场其实比iOS市场要大,特别在国内。所以在韩国已经大幅超越iOS,在日本也在赶超。全世界除了欧美之外,可能其他国家都是Android会比iOS大。在这种情况下,跨平台是肯定需要做的,所以我们选择的技术肯定是跨平台的进行。我们考虑到性能,当时Air Port和HTML5测试出来性能还是比较差,我们有一个游戏叫《我的王国》,基本上把所有的动画都阉割了才能上线,当时的版本我记得是3.1或者是3.2。HTML5其实也是出现了一个性能的问题,我们其实当时做了一个小小的游戏,但是觉得那个管的速度,就是那个用户体验其实并不那么好。最后是可控性,就是说我们在选择一个技术方案的话一定要可控,比如说我们当时选择Flash Air Port,我们有些优化根本就无法做,它的性能怎么样我们就怎么样,我们没有办法控制。比如说我要做国内平台,我要做很多SDK无法接,我要做优化无法做,可控性非常差,于是我们就选择了Cocos2D-X,这个是开源的框架,性能很好,也跨平台,所以这个就是我们当时的选择。

 

为什么脚本化?这个议题也是一把鼻涕一把泪。更新的问题,Google是非常好的平台,随便你搞,你可以更新代码,可以更新素材,但是更新很快,两小时一更新,除了Class不能更新以外,其他的都可以更新。但是iOS需要5天时间,这是更新,还不是提交,提交应该是15天以上,审核周期特别之长。另外就是多版本维护,如果你需要提交审核的话,肯定会涉及到多版本维护的问题,因为有些人就是不爱更新,如果我玩很多游戏,我看到更新的话都点No。我现在iPhone上有124个更新没有更新了,我的Android上我也不知道有多少没有更新了,我就是不爱更新。不爱更新的话,多版本就是一个很大的问题。特别是联网游戏,像我们的水族箱要维护7、8个版本。另外iOS和Android是没有办法做增量更新的,Google可以做增量更新,比如说你的APP包,只有你的SO文件发生了更新,你的素材文件没有更新,他不会下载你的素材文件,只会下更新的东西,这个就是要增量更新,据说QQ是支持增量更新了。但是国内很多市场和iOS是需要全包下来的,假如说50几兆的包下次还会下50几兆,会阻碍很多人更新。我们现在打包工具做了大包和小包,小包就是仅留那些第一次启动需要的素材的那些包我们叫小包,大包是指我把所有的素材全部打到一个APK或者一个IPA里面的包我们叫大包,肯定是需要包含所有的分辨率的。这样的话,包括所有的分辨率就会变得非常之大,比如一个iPhone5的,一个iOS的设备现在支持960×640,1036×640,108×68,在iPad上非常大,非常多。你要支持这么多分辨率的话,你的存储和你的带宽都很大。

 

调试是比较困难的,调试工具都不一样,Android是很麻烦,后面也会讲到。一般我们开发都是在一个调试神器上开发,但是并不代表你的程序在iOS和Android上顺利,因为种种的资源调用,各种各样的性能切换都会导致崩溃,所以有时候C++的调试还是需要的。在调试的过程当中我们经常会发现,我不知道是ARM的问题还是什么问题,Context有些变量会发生变化,调试的值,或者是看到的值是不对的,这个我们经常发现。另外是真机调试,真机调试其实我们觉得特别麻烦。在iOS上就必须用MAC去编译、部署和测试,我们没有那么多的设备,另外我们也看到了,很多人对MAC操作系统其实不熟悉,绝大多数开发人员还是在Windows上开发的。Android上如果用C++开发,就是基本上编译、部署、调试全部写脚本,我现在写了一堆脚本,就是为了搞Android。Eclipse最近对NDK有了一些支持,但是还是不好,特别是Debugging,在Gdb在Windows下是有问题的,Gdb在Windows上不能中断,这是很大的问题。

 

接下来还有一个C++的问题,就是Crash,我们50%的联调全部放在Crash上面,这是一个制定的一个上线标准,我们上线的只有只允许5%的Crash Rate在5千分钟之内。另外Crash我们引用技术,其实都大量的用了云技术,而是用云技术池,它崩溃的时候,如果引用技术出错了,是很难找到那个崩溃源在哪里。基本上都要重新的回顾,才能找到那个问题。在优化的版本里面,Context和Stack经常会丢,大家特别清楚,经常会出现这个问题。因此我们是尽量的想把这个C++做一个框架,稳定了,然后尽量让以后的开发人员少写C++。

 

这么多的脚本语言选择,为什么选择Lua呢?因为它简单,那个代码整个的Lua非常短小精悍,好像只有不到500K的代码,非常可观,非常可控,要改什么东西就可以直接改。另外非常轻,很多东西都可以用,所以我们觉得这个语言还是挺好用的。再就是我们看到国内的市场商业化最成熟的是Cocos2D-X+Lua的方案,今天早晨王哲也演示了,这个的确是我们当时选型的一个观察。

 

接下来我会讲一下我们在这里面做了哪些改造。我们选择了Cocos2D-X+Lua,当时我们的版本可能是用了比较老的版本,我们是用2.0.4,有一得项目是2.0.2,没有这么先进的技术。所以我们当时做的还没有出来,我们当时这个CocoStudio还没有,所以我们当时自己做了很多工作。首先就是第三方库的集成,大家都知道,其实Lua、OC、Java,这三个应该是套起来非常顺畅的,比如说Lua Java就是一个Lua到Java的互调,谁调谁都非常方便,所以我们就做了Lua和Java的集成。我们有一个同事在前天做了OC的集成,改开源件,把很多的技术分享了。其实我们也会把OC和Lua放起来,大家不用写该死的C函数封装,这都会节省大家的工作量。如果我知道有人已经做完了这个集成的话,我就不用做这个了,这个是因为当时不知道,所以我们做了LuaJit换成Lua5.1,当时提高了5到6倍的性能,是非常夸张的。后来在LuaJit在某些手机上,好像i910这个手机上,LuaJit有些问题,所以我们把LuaJit的特性放在了Android上,不然的话就是60倍,很快。

 

我们做了自己的工具,第一个就是IDE。相信大家如果用Lua开发的很多人,都用了一个IDE去做调试器,我们觉得需要一个IDE,因为很多的程序员从Flash做,很多程序员还是离不开IDE。另外就是调试器,我跟很多同行也聊过,当时我们觉得,其实我们还是需要有调制器,能能输出变量,能够设断点,能够跟踪。所以的话,其实也不是我们自己做的,我们改造了一个调试器,把它变成IDE+调试器。当时没有CocoStudio,可能有CocosBuilder,但是感觉不好用,我们自己做了一个UI编辑器,也是开源的,我们在CS5上面搞了一个开源的插件,这个是做了我们的UI编辑器和谷歌动画编辑器这两个。我们做了一个TTF字体导出工具,我们做游戏经常涉及到一些TTF的字体,这个字体如果把整个字体包嵌入进去是很大的,一个包可能是5到6兆,但是你可能只用到了200个字,200个字除以6千,只要1/30的体积就可以嵌入进去。大家都知道,Android上的包,如果你把一个5兆的字体文件嵌入进去的话,整个体积就会大很多。做TTF的目的就是把你该用的字体抽出来不该用的字体就扔掉。我们其实很多时候,特别是IPG游戏,我们聊天的时候用的都是系统字,我们在渲染的时候可能用TTF去做场景的字体,或者是做菜单的字体。

 

接下来讲一下我们的框架,底层就是Cocos2D-X。我们Android的部分主要做几方面,包括跟渲染相关的,其实就是把刚才讲的导出的文件我们自己改,把导出的文件放进来,把输出的东西导进来。另外是本地化,比如说不同的语言可能要不同的素材,不同的文案,那就是本地化。我们资源管理后面会重点讲,是一个很复杂的框架,可能比Cocos2D-X资源管理要复杂得多。另外是Utils类,其实主要就是文件等,主要是两个,我觉得还是比较好的,一个是配置管理,我们其实是C和Java和Lua都统一支持的配置管理。另外一个就是包括版本、设备,就是跟游戏内容物外的外部设备的环境,这个也是Java、Lua和C全部是通用的。接下来就是网络库,我们的网络是基于CURL的,当然这个我也希望CURL加上HTPS的支持,包括Facebook用的图片地址全是HTPS的。另外我们会有自己的脚本引擎扩展,刚才讲了,我们会集成一大堆的接口。后面两个是我们自己做的比较兴奋的,一个是Crash,我们自己做了Crash分析,我们把用户的Crash都搜集到我们这儿,我们可以进行分析,把它的堆栈排序,然后找到用户Crash最多的地方。日志管理就不用讲了,还有就是内存混淆,比如说我们的神器,相信做休闲游戏的人都碰到过这个东西,主要就是改内存,就像我们以前用的改内存的工具一样,然后发现两个内存的不同点改掉,如果你的游戏数据读到那个内存的话就误以为他有那么多钱了,把存进去的东西加密,拿出来的时候解密。

 

第三方介入,如果我们当时有Plugin-X可能就不至于做了。但是我觉得Plugin-X那个接口还有待商榷,比如说跟Facebook集成的时候,它有非常多的接口,他们的改造也非常快。你如果是都用那个统一的接口,很多接口是无法接的。比如它的高传播性的接口,那都是非常特殊的接口。所以我们其实接了一堆的接口,包括91、UC,各种各样的系统,SNS,包括支付,Plugin-X应该提供APP和Google的支付,包括Notification,包括DC,包括我们的广告几分墙,包括Log Tracker,包括CI Service,这是第三方集成的库。接下来就是Develop tools,这里面包括IDE无、调试工具、自动化Build脚本和打包工具。其实大家觉得在Android比iOS难调,其实我觉得不是,Android比iOS好调太多了,直接用一大堆的命令,把所有的东西改掉,甚至把SO改掉都可以,所以我写了大概20几个脚本,就是关于Android的调试。

 

刚才讲到了一个非常重要的框架,就是我们的脚本引擎的扩展。脚本引擎的扩展也讲到,我们传统的所有的Cocos2D-X以及我们开发的接口,我们都可以通过Tolua++,接下来我们可以用iOS API和3rd Party API,他们要兼顾到Lua,需要C++分一成,我们不需要,我们就搞Lua,所以我们都会用非跨语言的技术去做。我先把我们的游戏给大家看一下,这个就是我们的Lua调试器,其实是基于一个开源项目去改的,这是我们工程师改出来的。我们也可以演示一下一个游戏,我们看到这个游戏启动的时候,有一个断点断进来了,就是说在启动的时候,这个Lua已经连到我们的游戏的调试器里面来了。在这里面我们可以设断点,在它停止的时候可以设置。我们设了一个断点,开始游戏就会进入到这个地方了。这个时候进入到第一行,后面都黑了。我这个是跟刚才一样的,我们可以设断点,可以继续执行,我们现在继续执行。这个游戏现在发布在台湾,在大陆还没上。我们进入游戏,看到这个断点已经设在这儿了,这个就是我们的调试器,可以支持真机调试,可以支持我们的设备上的调试,包括这边我们可以那所有的理论变量,这个刚才演示的是我们一个调试器。

 

这个调试器是基于Zerobrane,用于调试性能是很低的,主要是每一次因为Lua调试的原理是每执行一个都会调用这个,就相当于每运行一个语句都会去调用很复杂的调试语句一次。我们做了一个改善,就是把调试的断点设到了C,我们通过C去过滤断点,我们把那个断点的性能提高了120倍,使得我们这个是全世界最快的一个Lua调试器。另外我们现在的改善是支持了我们的Symbols以及文件快速定位,就是我们的函数文件的快速定位,这个是仿照做的一个功能。还有一个功能是Push to Device,我们可以直接Push到设备上去,可以很方便的把改过的代码直接Push过去。在我们的Zerobrane里面,其实我们是支持智能提示的,可以给大家看一下。这可以把这个智能提示过去了,这是我们一个简单的改造。Push to Device这个原理是什么?首先我们简单介绍一下这个原理,我们做了iOS和Android和Windows的Stub,会告诉哪个文件是改变了,接下来Debugger就把这个文件退过去,就关闭文件,这是Push to Device的过程。调试是主动的发起一个连接,这边告诉他连接成功,今后要查询什么数据,发送什么指令,包括Stub那些指令都会直接通过Debugger发送一个命令,之后包括日志和断点,都是往这边去发的,只要到了一个断点,就会通过这个端口去通知Debugger,这个大概是Push to Device的一个原理。

 

后面讲一下Resource Manager,我们要保证更新一定要Transaction。假设我们更新过程当中来了一个电话,结果用户把这个进程中断了,之后你的包没有解完,可能剩下5、6兆没解,直接第二次进入的时候直接就挂了,这样的话是很有问题的。所以我们的更新一定要实施Transaction,一定是完整性的,如果更新不完整就不要更新。我们要增量更新,我们不会去包更新,比如我下载一个东西,这个东西比如说一个图片资源,我不可能把整个图片资源都下载下来,整个50几兆,肯定要去做增量更新。我们需要做按需下载,按需下载主要是按功能模块去下载,比如我们经常遇到这样一个场景,就是进入到一个场景的时候,这个场景可能有几个背景,有几个人物。我进这个场景的时候,就需要所有的素材全部是完整的才进,不然的话进去就崩。分辨率匹配,刚才我讲了,就是下包的问题,下包的时候如果是说我们这个包,比如说我为了Android的设备设了三个分辨率的包,这样的话,如果是高端机,我是1280×720的话,我可能就下这样的素材就行了,我不用下载另外两个素材。根据我们以前的经验,基本上是可以省1/2的资源量。属于是说你是一个480×620的,你这个包就非常小,可能就是1/6的素材量,不用把所有的素材都下载下来。另外一个就是我们后来做的按需加载,比如我们到了一个全幅的里面去,里面有人骑马,有人骑骆驼,有人骑条龙,这些素材我都没用,因为我是刚进游戏的。这个时候我没有素材,我就需要到网络上去下载,下完素材之后回写到这里,这是一个功能需求。另外一个比如说我们的休闲游戏里面有很多Facebook的头像,这些Facebook的头像我当时本地没有,我需要到外面去下载。下载完了之后显示过来,因为我不想这些用户进来的时候,因为这些用户头像卡住了。这个时候我就需要按需下载,就是我先建立起来,然后之后再回写,按需下载的功能就是这些。要支持资源加密,比如说我们的Lua这些脚本混淆都有可能破了,所以我们必须要做资源加密,包括编译,包括我们对素材原码进行一个加密,都要做资源加密,做完了之后就是资源解密的问题了。针对中国市场还有一个需要做的就是APK更新,因为很多市场是没有下载的途径的,需要去做APK的更新。

 

资源管理的设计主要有这几个,我们有一个Resource Locator Version,接下来我们可能有很多Resource Locator,节先来就是APK/APP目录。后面简单讲讲增量更新,首先客户端将动态服务器去取当前的配置,这个客户端在本地校验一下当前的配置是不是最新的,如果不是最新的就去下载最新的配置。下载完最新的配置之后,再看看这个配置里面所要的资源,因为我们的资源全部是HTML5,所以看看这些资源在不在,如果资源不在就去下载资源。下载完资源就进入游戏,这是增量更新的框架流程。什么叫按需下载呢?就是发起端首先有一个接口,就是确认这些模块全部都在,查一下本地缓存,看看有没有,如果没有的话去下载资源,如果有的话直接回调。回调完了之后加载资源,非常简单。

 

Crash分析系统,一个Reporter,一个Breakpad,经过用户的同意之后,会有一个Task,这是一个线程,就把它扔到Crash Analysis Center,因为是一个集上的,我们不可能在远端搞一个集,所以会扔回到我们本地编译的一个Symbol的Center,最后是Log Tracker。我们的开发人员就可以通过最后的Log Tracker,可以看到所有的文件,所有的用户,包括这个Crash多少个都可以看到,这是我们完整的Crash分析。

 

接下来我们讲一讲Build,我们自己去做了一个Build管理,我们这个Build系统主要是用Hudson做的。我们支持的功能这边演示不了,给大家大概列一下,支持手机下载安装,什么叫手机下载安装呢?就是我手机访问这个网页就可以直接下载这个IPA或者是API进行安装,IPA是很麻烦的,以前我们在我们没有这个系统的时候,我们安装是怎么安装的呢?首先叫一个开发人员给我帮一台机器,测试人员跑过去,编一个脚本扔过去。结果我们测试人员有5个,这个开发人员一天基本上跑两个小时。做了这个东西之后,我们就可以直接从网上去下了,这个是很方便的。另外一个是新版本的下载提示,假设我们编译了一个新的版本之后,这个用户打开这个游戏,他就会收到一个提示说你有新版本了,请下载,他点击下载就自动安装更新包。这是我们Build系统最重要的功能之一。另外是Crash和日志采集和分析,刚才已经讲了,Crash和日志没有根本的太大的区别。Session time的分析,我们需要让我们的人员测试多长时间,去作为一个重要的指标。另外就是Crash也是根据Session time分析的。后面有两个CDN我们就过了。另外是Udid的检测,APP是非常麻烦的,做iOS,因为iOS有一个Udid的问题,如果不在这个List里面的话,其实是下载不了这个APP的。经常发现我们一些开发测试人员他无法下这个APP,原因就是Udid,所以我们也把这东西做进去了。可能今后我们会做一个脚本,现在还是通过手段去把APK提交上来,就是直接在这个CI,把这个东西发布到Google Play里面,这大概是我们整个的Build和CI的框架。我们可以看到,我们的Build脚本其实做了非常多的事,包括生成IPA、APK,生成下载文件,打包,基本上都是由这个脚本去做的。基本的模块,蓝颜色的部分基本上我们去做的模块。接下来我再讲一下我们用的工具,包括Dragon Bones,我们把引擎改了一改,支持我们需要的格式。接下来是Font eidtor,第三方的工具,我们其实是用了两个,包括Particle Design和Glyph Gesign。感谢开源项目,特别是Cocos2D-X,使我们能够很快的开发游戏。

 

做一些小广告,如果你想挑战自己,如果你想跟一帮有创造力,有想象力的人一起工作,如果你相信工程师能改变世界,就加入我们,谢谢大家!

 

问:我主要想问一下,你们会不会从服务器上下载Lua代码到用户的客户端上,如果有的话,实际上在苹果的Guideline里面是禁止这件事情的,你们是怎么考虑的?

凌聪:我相信很多的这么做。今天早晨我相信王哲也讲到这个事情了,我就不重复了。

 

问:我想请问一下Lua的加密和资源的加密具体的实现方式,我想请问一下你们这个东西能不能开源?

凌聪:加密非常简单,加密你用AES都可以,这个不是非常难的事,这个加密还是挺简单的,这个就是一句话,但是肯定是不能开源的。

 

问:我想问一下,提到了一个内存混淆,我想了解一下有没有相关的资料?

凌聪:没有,内存混淆是一个很大的,方法就是从里面解密拿出来,还有就是加密存进去,非常简单,就是内存混淆。


附上PPT下载:http://ishare.iask.sina.com.cn/f/36760375.html


推荐阅读
author-avatar
王尼玛的脑残粉
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有