转自:http://philon.cn/post/cocos2d-x-3.0-zhi-zuo-heng-ban-ge-dou-you-xi
cocos2d-x: v3.0-alpha-pre
Windows环境: Windows8 + Visual Studio 2012
Linux环境: Ubuntu12.04 + gcc 4.7.2
Android环境: Android Studio v0.1 + Mi2 + MIUIv5
老早知道cocos2d-x出3.0的预览版了,据说变化很大(更牛x了),但对于我这个初学者而言依然努力保持一颗蛋定的心,目前手上拥有的是2.0.3的版本并已经完成了PompaDroid
(在英文教程中名为《PompaDroid》不过网上有人发布了的应用叫旋风小子)的开发和适配工作,而那也是一个月之前的事了。。。。今天脑子一热跑去cocos2d-x的官网上了解了一下3.0alpha版的内容,果然很牛逼,于是果断下载并彻头彻尾的改造了手上的《PompaDroid》代码,一来为了熟悉cocos2d-x3.0,二来巩固一下之前的学习并做个学习笔记,温故而知新嘛~
先来看个之前做出来的效果:
闲聊一下,其实这次3.0版本吸引我的地方除了各种性能提升的传说之外,主要有两点:
取消了各种类、宏的CC前缀,例如CCSprite变为了Sprite,老实说我很不喜欢之前那种类似匈牙利的命名方式,总觉得既然有cocos2d这个namespace了干嘛还要画蛇添足的在每个类前面加个CC呢?我不知道是不是cocos2d-iPhone的传统(懒得研究),但真心不喜欢这个CC前缀。
加入了2.5D的支持,这个纯属个人喜好,因为在我脑子了已经勾勒出了一两个游戏,而且都是2.5d才能更好的表达游戏的效果(3d人物+2d场景的效果很炫,目前正苦逼的练习手绘+photoshop)
扯远了,进入正题,横版格斗游戏《PompaDroid》的制作过程
新建工程
使用create-multi-platform-projects.py
纳尼!!!之前的install-templates-msvc.bat
呢,没有模版怎么在vs里新建工程??查阅了一番文档后发现其实从2.1.4开始,所有cocos2dx项目都用create-multi-platform-projects.py脚本来创建了(唉,落伍啊)。于是乎:
$ python create-multi-platform-projects.py -p PompaDroid -k cn.philon.pompadroid -l cpp
完成之后得到这样一个目录:
目录 | 说明 |
---|---|
Classes | 用于存放游戏的各种类各种实现各种算法(总之我想说的是.h和.cpp) |
proj.xxx | 即是各个平台的相应工程项目 |
Resources | 游戏中所用到的资源全在这里 |
Wonderful!!我很喜欢这样的目录结构,简单明了。
接下来先从Windows平台开始吧,进入proj.win32并打开PompaDroid.sln
在解决方案中有6个项目:
项目 | 说明 |
---|---|
PompaDroid | 很明显,需要我们实现的游戏项目 |
libBox2D | 物理引擎(这里用不到,不管它) |
libchipmunk | 貌似和box2d一样是物理引擎 |
libcocos2d | 这个就不用解释了 |
libCocosDenshion | 音频引擎(我没在游戏里加入音效) |
libExtensions | 扩展库,具体参考这里 |
依照惯例,cocos2dx新工程里会有个HelloWorld实例,展开cyclone-kid\Classes就可以看到了,果断编译运行,一切ok!
好了,删除HelloWorld.h和HelloWorld.cpp文件,开始实现CycloneKid的代码吧!
首先点击这里下载所需的美术资源,解压放到Resources目录下。
GameScene
一款游戏中会有很多个场景(Scene):主菜单、游戏、游戏结束、过场动画等等,由于只是学习,我仅做了主游戏场景(GameScene),该场景包涵两个图层(Layer):游戏层和操作层。
顾名思义,游戏层主要负责游戏的内容(地图的渲染,各个精灵的调度等);而操作层负责响应触摸(前进、后退、攻击等操作)。
因此根据上图所示,我们需要建立三个类,GameScene
GameLayer
OptionLayer
务必把类文件建立在Classes目录下,方便之后夸平台编译
GameScene.h
class GameScene : public cocos2d::Scene{ public: GameScene(); ~GameScene(); virtual bool init(); CREATE_FUNC(GameScene); CC_SYNTHESIZE(GameLayer*, _gameLayer, GameLayer); CC_SYNTHESIZE(OptionLayer*, _optionLayer, OptionLayer);};
GameLayer.h
class GameLayer : public cocos2d::Layer{ public: GameLayer(); ~GameLayer(); virtual bool init(); CREATE_FUNC(GameLayer);};
OptionLayer.h
class OptionLayer : public cocos2d::Layer{ public: OptionLayer(); ~OptionLayer(); virtual bool init(); CREATE_FUNC(OptionLayer);};
1. GameLayer
GameLayer主要有背景地图(map)
、主角(hero)
、机器人若干(robots)
人组成。
1.1 瓦片地图
在Resources/pd_tilemap.tmx
便是背景地图资源,tile即瓦片的意思,整个背景地图有若干个32*32像素的图片组成,像瓦片一样,cocos2dx是支持.tmx文件的,因此在GameLayer.h文件中声明一个私有变量_map
,用于游戏的背景地图。
GameLayer.h
private: cocos2d::TMXTileMap *_map;
新建GameLayer.cpp文件,实现游戏层
GameLayer.cpp
using namespace cocos2d;GameLayer::GameLayer(){}GameLayer::~GameLayer(){}bool GameLayer::init(){ bool ret = false; do { CC_BREAK_IF(!Layer::init()); _map = TMXTiledMap::create("pd_tilemap.tmx"); this->addChild(_map); ret = true; } while(0); return ret;}
游戏层已经有地图了,现在只差把游戏层添加到场景中,新建GameScene.cpp,实现游戏场景的内容:
GameScene.cpp
GameScene::GameScene(){ }GameScene::~GameScene(){ }bool GameScene::init(){ bool ret = false; do { CC_BREAK_IF(!Scene::init()); // 游戏层初始化 _gameLayer = GameLayer::create(); this->addChild(_gameLayer, 0); ret = true; } while (0); return ret;}
编译并运行一下!
在编译中我的环境会出现两个警告:
现默认库“LIBCMT”与其他库的使用冲突;请使用 /NODEFAULTLIB:library
在属性-->配置属性-->链接器-->输入-->忽略特定库:增加LIBCMT即可;忽略“/EDITANDCONTINUE”(由于“/SAFESEH”规范)
在属性-->配置属性-->链接器-->高级-->映像具有安全异常处理程序:改为“否”即可。
1.2 动作精灵
主角和机器人的资源包涵在pd_sprites.plist
与pd_sprites.pvr.ccz
当中,打开pd_sprites.plist文件可以看到很多hero_xx_xx.png
和robot_xx_xx.png
,这些便是主角英雄和机器人的动作序列图片。从plist文件中可以清楚的看到,不论是“hero”还是“robot”都具备了idle
空闲、attack
攻击、walk
行走、knockout
(被)击倒、hurt
受伤这五个动作,因此需要建立一个动作类ActionSprite
来统一实现动作播放。
如上图所示,我们需要新建三个类ActionSprite
、Hero
、Robot
,其中ActionSprite既然是“动作精灵”所以需要继承cocos2d的Sprite类。
原本我想ActionSprite类只负责调用精灵每个动作的动画,精灵的“攻击力”、“生命值”、“移动”等属性方法放到另一个新的类当中管理,但为了省事我还是决定把这些内容完全塞到ActionSprite当中(尽管我知道这是一种灾难,但是。。。让bug来得更猛烈些吧!谁让我懒呢)。
首先,新建三个类ActionSprite
、Hero
、Robot
ActionSprite.h
// 根据pd_sprites.plist得到,动作精灵有五种状态typedef enum { ACTION_STATE_NONE = 0, ACTION_STATE_IDLE, ACTION_STATE_WALK, ACTION_STATE_ATTACK, ACTION_STATE_HURT, ACTION_STATE_KNOCKOUT,} ActionState;class ActionSprite : public cocos2d::Sprite{ public: ActionSprite(); ~ActionSprite(); void idle(); void walk(cocos2d::Point direction); void attack(); void hurt(int damage); void knockout(); // 定义每个状态动作的get/set方法 CC_SYNTHESIZE_RETAIN(cocos2d::Action*, _idleAction, IdleAction);