分享一款cocos2d-x横版格斗教程,包括打怪以及人物的移动等等,目前我使用的是最新版:cocos2d-x-3.0alpha1,开发环境为win7+vs2012。这个游戏demo是在网上看到的,觉得挺有意思,网上也已经有很多了文章和例子了,不过基本上都是用cocos2d-x较早的版本实现的,本文使用cocos2d-x 3.0重新实现了一遍。cocos2d-x 3.0更新了一些API,加入了c++ 11特性。我们将要学习精灵动作切换和保存、碰撞检测、简单的机器人AI、3.0新功能的使用等等,最终效果如下图:
1. 创建项目
切换到tools\project-creator目录下,shift+右键,打开命令提示符窗口,输入:
python create_project.py -p PompaDroid -k com.alexzhou.pompadroid -l cpp
项目目录如下图:
双击cocos2d-x-3.0\projects\PompaDroid\proj.win32\PompaDroid.sln,打开项目。
2. 下载游戏所需资源文件:http://download.csdn.net/detail/zhoujianghai/6880595
使用Tiled打开pd_tilemap.tmx,就可以看到游戏的整个地图:
根据地图,我们可以得到以下信息:
1.地图分成两层:Wall(墙)和Floor(地板),关闭每个层的透明度可以查看每层的构成。
2.每个瓦片都是32*32,地图瓦片数100×10(宽x高)。
3.从下往上数,前三行瓦片是可以行走的。
3. 添加地图
创建GameLayer类,代码如下:
- GameLayer.h
- class GameLayer : public cocos2d::Layer
- {
- public:
- GameLayer();
- ~GameLayer();
- virtual bool init();
- CREATE_FUNC(GameLayer);
- private:
- cocos2d::TMXTiledMap *m_pTiledMap;
- };
- GameLayer.cpp
- GameLayer::GameLayer()
- :m_pTiledMap(NULL)
- {
- }
- GameLayer::~GameLayer()
- {
- }
- bool GameLayer::init()
- {
- bool ret = false;
- do {
- CC_BREAK_IF( !Layer::init());
- m_pTiledMap = TMXTiledMap::create("pd_tilemap.tmx");
- this->addChild(m_pTiledMap, -10);
- ret = true;
- } while(0);
- return ret;
- }
接着创建场景类GameScene:
- GameScene.h
- class GameScene
- {
- public:
- static cocos2d::Scene* createScene();
- };
- GameScene.cpp
- Scene* GameScene::createScene()
- {
- auto scene = Scene::create();
- auto gameLayer = GameLayer::create();
- scene->addChild(gameLayer, 0);
- return scene;
- }
- bool AppDelegate::applicationDidFinishLaunching() {
- // initialize director
- auto director = Director::getInstance();
- auto eglView = EGLView::getInstance();
- director->setOpenGLView(eglView);
- eglView->setDesignResolutionSize(480, 320, ResolutionPolicy::SHOW_ALL);
- // turn on display FPS
- director->setDisplayStats(false);
- // set FPS. the default value is 1.0/60 if you don't call this
- director->setAnimationInterval(1.0 / 60);
- // create a scene. it's an autorelease object
- auto scene = GameScene::createScene();
- // run
- director->runWithScene(scene);
- return true;
- }
因为这里资源分辨率是480×320,所以在main.cpp中设置宽高为480×320效果最好。
编译运行项目会看到地图已经显示出来了,效果如下:
现在cocos2d-x横版格斗教程的地图上啥也没有,太单调了,那就创造一个英雄吧。
4. 添加英雄
英雄的资源文件是pd_sprites.pvr.ccz,可以使用TexturePacker打开,如下图:
英雄有5种状态:
1. 空闲(站着不动时)
2. 行走
3. 攻击
4. 被攻击
5. 死亡
每个状态都对应一组动画,因为英雄不可能同时处于多种状态下,所以我们要考虑的是如何实现状态切换,然后播放状态对应的动画。
这里当英雄处于空闲状态时,只能切换到行走、攻击、受伤状态,不会还没受伤就死亡了,当英雄死亡后,就不能切换到其他四种状态了。
创建BaseSprite类,作为精灵的基类:
- BaseSprite.h
- typedef enum {
- ACTION_STATE_NONE = 0,
- ACTION_STATE_IDLE,
- ACTION_STATE_WALK,
- ACTION_STATE_ATTACK,
- ACTION_STATE_HURT,
- ACTION_STATE_DEAD
- }ActionState;
- class BaseSprite : public cocos2d::Sprite
- {
- public:
- BaseSprite();
- ~BaseSprite();
- void runIdleAction();
- void runWalkAction();
- void runAttackAction();
- void runHurtAction();
- void runDeadAction();
- CC_SYNTHESIZE_RETAIN(cocos2d::Action*, m_pIdleAction, IdleAction);
- CC_SYNTHESIZE_RETAIN(cocos2d::Action*, m_pWalkAction, WalkAction);
- CC_SYNTHESIZE_RETAIN(cocos2d::Action*, m_pAttackAction, AttackAction);
- CC_SYNTHESIZE_RETAIN(cocos2d::Action*, m_pHurtAction, HurtAction);
- CC_SYNTHESIZE_RETAIN(cocos2d::Action*, m_pDeadAction, DeadAction);
- CC_SYNTHESIZE(ActionState, m_currActionState, CurrActionState);
- cocos2d::CallFunc* createIdleCallbackFunc();
- protected:
- static cocos2d::Animation* createAnimation(const char* formatStr, int frameCount, int fps);
- private:
- bool changeState(ActionState actionState);
- };
- BaseSprite.cpp
- BaseSprite::BaseSprite():
- m_pIdleAction(NULL),
- m_pWalkAction(NULL),
- m_pAttackAction(NULL),
- m_pHurtAction(NULL),
- m_pDeadAction(NULL),
- m_currActionState(ACTION_STATE_NONE)
- {
- }
- BaseSprite::~BaseSprite()
- {
- CC_SAFE_RELEASE_NULL(m_pIdleAction);
- CC_SAFE_RELEASE_NULL(m_pWalkAction);
- CC_SAFE_RELEASE_NULL(m_pAttackAction);
- CC_SAFE_RELEASE_NULL(m_pHurtAction);
- CC_SAFE_RELEASE_NULL(m_pDeadAction);
- }
- void BaseSprite::runIdleAction()
- {
- if(changeState(ACTION_STATE_IDLE))
- {
- this->runAction(m_pIdleAction);
- }
- }
- void BaseSprite::runWalkAction()
- {
- if(changeState(ACTION_STATE_WALK))
- {
- this->runAction(m_pWalkAction);
- }
- }
- void BaseSprite::runAttackAction()
- {
- if(changeState(ACTION_STATE_ATTACK))
- {
- this->runAction(m_pAttackAction);
- }
- }
- void BaseSprite::runHurtAction()
- {
- if(changeState(ACTION_STATE_HURT))
- {
- this->runAction(m_pHurtAction);
- }
- }
- void BaseSprite::runDeadAction()
- {
- if(changeState(ACTION_STATE_DEAD))
- {
- this->runAction(m_pDeadAction);
- }
- }
- Animation* BaseSprite::createAnimation(const char* formatStr, int frameCount, int fps)
- {
- Array *pFrames = Array::createWithCapacity(frameCount);
- for(int i = 0; i < frameCount; ++ i)
- {
- const char* imgName = String::createWithFormat(formatStr, i)->getCString();
- SpriteFrame *pFrame = SpriteFrameCache::getInstance()->getSpriteFrameByName(imgName);
- pFrames->addObject(pFrame);
- }
- return Animation::createWithSpriteFrames(pFrames, 1.0f / fps);
- }
- bool BaseSprite::changeState(ActionState actionState)
- {
- if(m_currActionState == ACTION_STATE_DEAD || m_currActionState == actionState)
- {
- return false;
- }
- this->stopAllActions();
- this->m_currActionState = actionState;
- return true;
- }
- CallFunc* BaseSprite::createIdleCallbackFunc()
- {
- return CallFunc::create(CC_CALLBACK_0(BaseSprite::runIdleAction, this));
- }
现在该创建咱们的英雄类Hero了:
- Hero.h
- class Hero : public BaseSprite
- {
- public:
- Hero();
- ~Hero();
- bool init();
- CREATE_FUNC(Hero);
- };
- Hero.cpp
- Hero::Hero()
- {}
- Hero::~Hero()
- {}
- bool Hero::init()
- {
- bool ret = false;
- do {
- CC_BREAK_IF( !this->initWithSpriteFrameName("hero_idle_00.png") );
- Animation *pIdleAnim = this->createAnimation("hero_idle_%02d.png", 6, 12);
- this->setIdleAction(RepeatForever::create(Animate::create(pIdleAnim)));
- Animation *pWalkAnim = this->createAnimation("hero_walk_%02d.png", 7, 14);
- this->setWalkAction(RepeatForever::create(Animate::create(pWalkAnim)));
- Animation *pAttackAnim = this->createAnimation("hero_attack_00_%02d.png", 3, 20);
- this->setAttackAction(Sequence::create(Animate::create(pAttackAnim), BaseSprite::createIdleCallbackFunc(), NULL));
- Animation *pHurtAnim = this->createAnimation("hero_hurt_%02d.png", 3, 12);
- this->setHurtAction(Sequence::create(Animate::create(pHurtAnim), BaseSprite::createIdleCallbackFunc(), NULL));
- Animation *pDeadAnim = this->createAnimation("hero_knockout_%02d.png", 5, 12);
- this->setDeadAction(Sequence::create(Animate::create(pDeadAnim), Blink::create(3, 9), NULL));
- ret = true;
- } while(0);
- return ret;
- }
- Hero类比较简单,就是初始化各种动作。
- 我们来修改GameLayer类,加载精灵图片所需的资源。
- 在GameLayer.h中添加:
-
- CC_SYNTHESIZE_READONLY(Hero*, m_pHero, Hero);
- float m_fScreenWidth;
- float m_fScreenHeight;
- cocos2d::Point m_origin;
- cocos2d::SpriteBatchNode *m_pSpriteNodes;
- 在GameLayer.cpp的init函数中添加:
-
- auto visibleSize = Director::getInstance()->getVisibleSize();
- this->m_origin = Director::getInstance()->getVisibleOrigin();
- this->m_fScreenWidth = visibleSize.width;
- this->m_fScreenHeight = visibleSize.height;
- SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pd_sprites.plist");
- m_pSpriteNodes = SpriteBatchNode::create("pd_sprites.pvr.ccz");
- this->addChild(m_pSpriteNodes);
- m_pHero = Hero::create();
- m_pHero->setPosition( m_origin + Point(100, 100) );
- m_pHero->runIdleAction();
- m_pHero->setZOrder(m_fScreenHeight - m_pHero->getPositionY());
- m_pSpriteNodes->addChild(m_pHero);
现在编译运行项目,就可以看到一个骚包在屏幕上晃来晃去了:
OK,cocos2d-x横版格斗教程就到此为止了,