Contents
  1. 1. 环境准备
  2. 2. 环境搭建
  3. 3. 游戏设计
  4. 4. 软件构建
    1. 4.1. 语言选择
    2. 4.2. 程序框架
    3. 4.3. 逻辑开发
    4. 4.4. 游戏UI
    5. 4.5. 游戏场景与tilemap
    6. 4.6. 游戏数据
    7. 4.7. 屏幕适配问题
    8. 4.8. 浅析内存管理
    9. 4.9. 物理引擎
  5. 5. 广告和SNS接入
  6. 6. 测试 & 发布
  7. 7. 一点兼容性问题
  8. 8. 总结

最近业余时间和同事合作在做一款休闲游戏,主要是先来试试水,能不能带来收入什么的倒是在其次。

考虑到成本问题,毫无疑问的选择了现在2d游戏中最风靡的cocos2dx引擎。

第一次这么正经的做手游,虽然是小制作,但坚持到现在也深有感触,要把任何一件事情完成好都是不容易的。

以为以前没有cocos2dx方面的经验,甚至可以说手游制作的经验也几乎没有,制作过程还是蛮磨人,从开始到现在,断断续续的做了两个来月,索性也都坚持下来了。

我把这段时间经历的一些印象深刻的问题简单写写,做个记录。

环境准备

windows 8.1 x64
cocos2dx 3.2 alpha
visual studio 2012
最新版的:adt + ndk + ant + jdk
python 2.7
cocos studio 1.5.0.0
tiled
virtual box 4.3.x
mac os x 10.8.4 + xcode 5.1.1
魅族MX3小机机一台(测试机)
豌豆荚(为了获得手机驱动)

环境搭建

虽然上面列的东西很多,不过基本上都是围绕cocos2dx 3.x来用的,我是3.0才开始接触cocos2dx貌似它和2.x相比安装步骤来说已经简化很多了。但目前网上查到的资料多数是2.x的,有点烦。

新手可能经常在这个地方搞的很疲惫,但是对于经常用第三方库的人来说也没怎么麻烦,其实解压cocos2dx后找到README按步骤做一下就可以了,然后你如果发现自己机子上还没py、adt、ndk之类的,依次把它们准备好。

顺带一提,到3.0这个版本的时候,python还必须用2.7的,python3x仍然会有些语法不兼容,不知道现在改了没。

大致按README做好之后:

cocos new MyGame -p com.your_company.mygame -l cpp -d NEW_PROJECTS_DIR

这样就得到一个自己的游戏工程啦(README上有此步骤),如果是windows用户,只要打开里面的sln,编译一下基本上就可以运行demo了。

由于cocos2dx 3.x中用了很多C++11的feature,IDE最好用vs2012之后的版本。

游戏设计

这些做好之后就可以真正开始进行游戏制作了。

就算作为个人或mini team开发,种代码前最好也先稍加设计下,这样就比较容易把握工作进度,以及不容易在制作的时候同时纠结于设计,需求过度膨胀以及自我迷失=。=。

另外虽然小制作应当轻装简行是没错,不过一些设计和制作过程的规划最好还是落实到文档。项目规划的问题有时间单独写写,这里先不展开了。

软件构建

这是游戏制作程序部分的正题了。

语言选择

由于cocos2dx支持JS、Lua、C++这几种语言,结合语言特点综合考虑采用哪种语言开发。

JS我不熟,Lua和C++相比我觉得大多数情况是Lua更合适,理由是开发效率高。因为cocos2dx主框架是由C++写成,所以第一次用cocos2dx的时候不妨先用C++,方便熟悉引擎大小机制。

程序框架

因为cocos2dx已经提供基本的游戏框架了,这部分需要我们自己发挥的地方已经不多了。

结合官方文档和默认生成的代码,很容易具体开发从何处入手:

入口:AppDelegate
场景:Scene(由开发者自己实现各种各样的scene)
场景组件:Layer(主要提供组管理的机制)和各种Node(基本要素)
场景切换:Director

很显然一个简单的游戏基本上只需要自己自己实现几个Scene,添加一些Layer和Node进来,再找个合适的地方用Director进行切换即可。

那么框架层面需要自己发挥的地方在哪里呢?

答案是根据需求而定,你把需求划分为多少个Scene?每个Scene做哪些Layer?每个Layer里需要放什么东西?明确这些问题后,开始建立初步的逻辑框架。

另外,如果场景组件之间有比较复杂的交互,则建议在逻辑层实现一个Observer模型作为游戏的事件系统,貌似引擎上是没有提供这个的,否则不管是耦合关系上还是开发效率上都比较难处理好。

逻辑开发

逻辑开发主要涉及几个基本点:逻辑对象的生成、销毁、游戏事件的响应、定时事件。处理好这些逻辑就写的差不多啦。

我们把这些过程代入到cocos2dx的框架里:

逻辑对象的生成:

虽然上面提到游戏基本要素在cocos2dx里是Node类,但Node作为所有游戏元素的公共基类很少直接去用它,另外cocos2dx提供了不少更接地气的类,比如Sprite,需要显示图片的游戏单位可以考虑集成这个类。

cocos2dx中对象的创建是让我觉得比较困惑的地方,按照官方文档和官方DEMO的说法,貌似是给每个类定义中通过CREATE_FUNC(CLASS)宏来创建一个无参的create函数,再自己添加一个init函数进行初始化。

但实际开发中很多逻辑对象的创建是“有条件的”,即需要给参数,但我并没有找到处理这种需求的“官路子”,于是这个事情变得麻烦起来。

我最后的解决办法当然还是放弃使用CREATE_FUNC+init组合,改用C++的构造函数来做了。实际上我看了下CREATE_FUNC这个实现,反正也没做多少事,而且附近确实没有处理带参创建的方式了。强行用这个机制的话真的是有一种脱裤子放屁的感觉。

这么做的一个隐藏问题就是,CREATE_FUNC里包含了一个this->autorelease()的操作,必须在构造函数中加回来,否则会在运行时出现一些小问题,这个后面再提。

创建完逻辑对象后我们还需要把它放到场景中,可以直接加入到场景或者放到一个layer中,再把layer放到场景,根据管理需要。

不管是直接还是间接的方式进入当前正在运行的场景,都会触发onEnter,如果有“入场处理”的需求(比如角色出生表现),可以在实现类的时候override一下onEnter。

不过这里又涉及到一个坑点,override onEnter的时候务必记得先调用基类的onEnter(Base::onEnter()),否则会导致一些引擎相关的状态不正常从而导致表现异常。

逻辑对象的销毁:

因为cocos2dx有个强制的内存管理机制,使得cocos2dx对象的内存基本上不需要手动管理了。自建对象可以选择继承ref从而使用相同的机制或者手动管理。

内存管理的细节问题下面再讲。

游戏事件的响应:

常见的需求比如A对象被touch后消息,然后B对象上显示的数字+1,或者A对象死亡后场景中所有运动着的对象都要静止下来之类的。

为了减少对象之间的偶尔,当然可以先从对象把消息向上路由传递到scene,再由scene级联下发给各个对象,再各个对象自己解决自己的问题。

但为了实现这种通信机制,需要对某个消息在每个对象上都实现一个调用。或者再抽象一下,所有的消息共用一个调用,通过MsgID来区分。

都不是太理想选择,总之复杂的事件需求还是自己实现一个Observer比较好。

另外就是如何接收到外部事件的问题,常见的就是用EventListenerTouchOneByOne来作为输入。

定时事件:

定时事件大概是大多数游戏都会用到的功能,cocos2dx中做法很简单,提供了scheduleXXX系列函数,可以灵活的控制,但必须是“active”的对象才会触发,即一般来讲它必须在当前场景中。

游戏UI

和大多数引擎一样,cocos2dx有程序绘制UI的接口,但为了规范流程,特意下了个cocos studio试了下他们的UI编辑器。

这个编辑器还是很容易上手的,用过adobe或者u3d之类的软件基本上看一下就会。

需要稍微了解下的就是程序里如何解析UI export文件,网上稍微找下资料了解一下也很快解决了。

主要就是要添加一下cocosgui和cocostudio的库,剩余的部分用cocostudio.h提供的接口就容易就完成了,做起来还是非常简便的。

考虑到管理方便,我们让一个ui成为一个layer。

直觉上比之前公司项目的ui制作起来方便。

游戏场景与tilemap

cocostudio提供了一个sceneeditor,不过这次没用上,这个编辑器主要处理场景表现相关的(摆放各种物件和效果),并且支持结合tilemap来用。

由于没再SceneEditor上看到任何添加障碍信息的工具,所以我猜测应该是把刷障碍的功能托付给tilemap。

对于制作tilemap,官方推荐了一个叫做tiled的免费工具,它支持简单的格子地图制作,刷障碍我觉得算是灵活运用它的基本功能而产生能力——不是工具直观提供的。

因为这次对场景的要求不高,所以直接在tiled上完成了地图和障碍。

程序中解析tilemap的方式是和解析ui差不多的,api也由cocostudio.h提供。

关于tilemap的制作可以稍微参考下这两篇:

http://www.raywenderlich.com/39113/cocos2d-x-tile-map-tutorial-part-1
http://www.raywenderlich.com/40544/cocos2d-x-tile-map-tutorial-part-2

游戏数据

完整的游戏经常一般会涉及大量的数据和游戏记录,对于这个问题,cocos2dx是这么做的:

如果只是记录少量特殊数据的话(比如历史最高),可以用UserDefault这个类来保持到xml中,这也是最简单的解决办法。否则视情况要改用file的方式做。

因为这次做的游戏体量很小,没有用到额外的数据表,基本配置直接抽到一个config.h放起来了(因为工程小,编译的代价也不算大)。

但看到cocostudio是有提供DataEditor的,实际上我觉得应该归类成一个转表工具…可以方便的把excel之类格式的数据转换成易于读取的cocos2dx兼容格式,虽然没用过,但是猜测解析起来和前面几个应该都是差不多的。

屏幕适配问题

cocos2dx上做屏幕适配比11年的时候用坑爹的libgdx简单太多了,简单的处理的方式只要在程序里设置好一个标准大小,之后所有的UI、场景制作都以此为标准做就行了,在不同设备上运行时可以选择让它自动缩放适配。

glview->setDesignResolutionSize(1920, 1080, ResolutionPolicy::EXACT_FIT);

浅析内存管理

cocos2dx对象内存管理是我觉得这个引擎做的还不够好的地方,对开发者而言基本上是个绕不开的坎,就你非得了解里面是怎么工作的,不然要想把一个游戏从头到尾开发出来而不遇到相关问题,太难了…

因为cocos2dx的内存管理机制用不用你是没得选的…所以通常来说,除非是完全自己实现的类(包括基类),其它的采用的都是统一的自动回收机制。

我已知的自动回收的机制都是基于引用计数技术的,cocos2dx也不例外。当你用到的时候(cocos2dx中最常见的addChild的情况)进行引用计数+1,不用的时候(同理,是removeChild)计数-1这样。

cocos2dx中为了处理起来更简单,对没用到的对象下一帧进行释放:一个对象初始给的refcnt是1,如果设置了autorelease,则会在下一帧时对计数进行一次性-1,从而触发delete this。

这里又会涉及到对autorelease()函数和自动回收的理解问题,如果你认为构造对象时不调用autorelease就可以完全手动管理了,这是错的。

不调用autorelease最大的区别就是让对象初始带了一个计数而已…add和remove仍然和使得计数改变,计数为0时依然会自动回收…

所以在cocos2dx下管理内存务必要知道这些事实。

物理引擎

cocos2dx 3.x一个比较好的改进就是把chipmunk和box2d进行封装,向上提供了一个统一的物理接口。

虽然确实好用了许多,不过实际应用的时候还是有些地方不得不debug+source code才能看明白问题。

比如说,物理引擎的大小计算和逻辑大小是独立的,不是动态可变的(改变逻辑size物理size不会同步改变,只能重新创建)。

比如,使用物理引擎之前需要在场景初始化时调用initWithPhysics,其实它给你加了个schedule用来更新物理世界,不知情的情况下如果你做了stopallschedule之类的事情或者override了update调用并且没有调用基类update,就会出现一些让你很难理解的事情。

再比如,要在一个对象上绑定物理对象的时候,最好在这个对象的onEnter里或者之后做,否则大小和位置都容易出问题。

一些类似这样的问题基本上只有调试代码才能看明白(所以对于这个游戏引擎,想偷懒什么都不去弄明白就把游戏做下来真的是蛮难的,目前来说)。

一些基本的用法介绍可以稍微参考下这篇:http://blog.csdn.net/fansongy/article/details/14142323 (实际上也已经有点过时了,cocos3.x版本变化太快)

广告和SNS接入

个人小制作一般都是通过曝光率装点小钱啦,没广告的话就彻底是为了成就感劳动了。

广告怎么放才尽量不影响体验这个问题就不在这讨论啦,这里只谈下技术问题。

简单的办法就是找个大一点的广告提供商,下载他们的sdk按照教程整合到自己的项目里去啦,比如有米、百度网盟之类的。

SNS是和广告类似的处理方式,不过最近发现一个叫ShareSDK的东西,可以一次性搞定多个SNS平台,还没试不知道实际用起来如何。

测试 & 发布

cocos2dx发布版本是蛮容易的,在前期配置好环境的前提下只需要一条命令:

cocos deploy -s . -p win32 -m release

windows的测试就不说啦,因为可以直接从IDE启动,这样的测试成本是最低的,差不多搞定了之后再考虑真机测试。

android上的发布稍微麻烦点,要改下proj.android\jni\Android.mk这个文件,把需要编译的文件和用到的库加进来。测试就比较容易,装好手机驱动(装豌豆荚就是为了得到手机驱动)之后上面那条命令只要改下平台就可以。

ios的发布略麻烦,windows上面没办法用简单的办法办到,所以还是装个虚拟机(直接装真机上有风险,三思后行),网上找个教程在上面装个黑苹果,在xcode上进行测试和发布。

如果发布release版本,android还会涉及到应用程序签名的问题,网上随便找个教程弄一下就行。ios就只能花钱买了id然后按app标准上架流程来走了。

一点兼容性问题

实测发现一些情况下还是出现了功能异常的问题,其中典型的两个地方:

1、在Android开启ART模式的手机上
2、在ios模拟器上运行时

其中第2个因为实际上两个平台用了不同版本的cocos2dx(分别是3.2 alpha和 3.2 rc)还未确定是否和这有关。

但兼容性问题,总之要彻查原因我认为作为应用开发者多少是有点困难的,眼下还是看看怎样可以绕开雷区吧(就跟以前网站适配IE6似得 = =)。

总结

总的来说cocos2dx算是为常规游戏制作提供了相当完善的解决方案,也是难怪现在这么多游戏都用cocos2dx做(cocos2dx的英文主页比中文主页看起来高大上多了!)

这个引擎比以前用过的libgdx(仅支持android),HGE(仅windows)之类的成熟很多,目前来看毫无疑问是这这几个主流平台下一个比较好的选择吧。

和Unity3D相比,我觉得它主要的弱势除了在3d表现和制作方面不如u3d之外,编辑器也不如u3d来的强大(u3d可以很方便的制作插件从而对编辑器进行订制),不过毕竟它是免费的,而且单纯做2d的话,也省去了理解3d那么多的概念。

有点小瑕疵的地方,在现在看起来这么快速的迭代下相信也会逐渐完善起来吧。

至于网络的部分,这次完全没用到,以后用到再看有没有值得写的地方好了。

最后期待一下游戏上架的那天。

Contents
  1. 1. 环境准备
  2. 2. 环境搭建
  3. 3. 游戏设计
  4. 4. 软件构建
    1. 4.1. 语言选择
    2. 4.2. 程序框架
    3. 4.3. 逻辑开发
    4. 4.4. 游戏UI
    5. 4.5. 游戏场景与tilemap
    6. 4.6. 游戏数据
    7. 4.7. 屏幕适配问题
    8. 4.8. 浅析内存管理
    9. 4.9. 物理引擎
  5. 5. 广告和SNS接入
  6. 6. 测试 & 发布
  7. 7. 一点兼容性问题
  8. 8. 总结