cocos2dx 实现flappybird

前两天在博客园看到网友实现的一个网页版的flappy bird,挂在360游戏平台,玩了一会儿得分超低,就很想自己做一个。刚好这两天炫舞的活都清了,就弄一下玩玩。

效果图

布局类GameScene.h

#ifndef GAMESCENE_BIRD
#define  GAMESCENE_BIRD

#include "cocos2d.h"

#include "Box2D/Box2D.h"

#include "SimpleAudioEngine.h"
USING_NS_CC;
class Cbird;
class CPipe;
class CGameScene :public cocos2d::CCLayer
{
public:
     CCSprite * _background;
    /* CPipe * _pipe;*/
     CCSpriteBatchNode * _gameBatchNode;
     Cbird * m_bird;
    /* CCArray *m_pipes;*/
     CPipe *_pipes;
    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();  

    // there's no 'id' in cpp, so we recommand to return the exactly class pointer
    static cocos2d::CCScene* scene();

    // a selector callback
    void menuCloseCallback(CCObject* pSender);

    // implement the "static node()" method manually
    CREATE_FUNC(CGameScene);

    virtual void ccTouchesBegan(CCSet* pTouches, CCEvent* event);
    virtual void ccTouchesEnded(CCSet* pTouches, CCEvent* event);
    void update(float dt);
    void startGame (CCObject* pSender);
private:
    enum{        
        GAMEREAD=0,
        GAMEOVER,
        BIRDFLY,
        BIRDDIE,
    };
    enum{
        TAG_LOGO,
        TAG_OVER,
        TAG_BUTTON,
        TAG_BESTSCORE,
        TAG_CURRSCORE,
    };
    int m_gamestate;
};
#endif

GameScene.cpp

#include "GameScene.h"
#include "Bird.h"
#include "Pipe.h"
using namespace cocos2d;


cocos2d::CCScene* CGameScene::scene()
{
    CCScene * scene = NULL;
    do 
    {
        // 'scene' is an autorelease object
        scene = CCScene::create();
        CC_BREAK_IF(! scene);

        // 'layer' is an autorelease object
        CGameScene *layer = CGameScene::create();
        CC_BREAK_IF(! layer);

        // add layer as a child to scene
        scene->addChild(layer);
    } while (0);

    // return the scene
    return scene;
}

bool CGameScene::init()
{
    bool bRet = false;
    do 
    {
        this->setTouchEnabled(true);
        //设置游戏背景
        CCSprite * bg = CCSprite::create("bird_bg.png");
        bg->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width * 0.5f, CCDirector::sharedDirector()->getWinSize().height * 0.5f));
        this->addChild(bg, 0);

        //CCSpriteFrameCache(精灵帧缓存)主要用来存放CCSpriteFrame,它没有提供特别的属性,而是提供一系列用于管理CCSpriteFrame的方法
        CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("bird.plist","bird.png");
        _gameBatchNode = CCSpriteBatchNode::create("bird.png", 200);
        this->addChild(_gameBatchNode, 1);

        CCSprite * repeat;

        _background = CCSprite::createWithSpriteFrameName("bird_bg.png");
        _background->setAnchorPoint(ccp(0,0));
        _gameBatchNode->addChild(_background, 0);

        repeat = CCSprite::createWithSpriteFrameName("bird_bg.png");
        repeat->setAnchorPoint(ccp(0,0));
        repeat->setPosition(ccp(repeat->getContentSize().width - 1, 0));
        _background->addChild(repeat, 0);

        repeat = CCSprite::createWithSpriteFrameName("bird_bg.png");
        repeat->setAnchorPoint(ccp(0,0));
        repeat->setPosition(ccp(2 * (repeat->getContentSize().width - 1), 0));
        _background->addChild(repeat, 0);


        //设置水管
    /*    _pipe =new CPipe;
        _pipe->SetLayer(_gameBatchNode);

        m_pipes = CCArray::arrayWithCapacity(4);*/
        _pipes = new CPipe[4];
        for(int i = 0;i < 4;i ++){
            _pipes[i].init();
            _pipes[i].SetLayer(_gameBatchNode);
        }


        //加入logo
        CCSprite* _intro = CCSprite::createWithSpriteFrameName("bird_logo.png");
        _intro->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width * 0.5f, CCDirector::sharedDirector()->getWinSize().height * 0.7f));
        _intro->setTag(TAG_LOGO);
        _gameBatchNode->addChild(_intro, 10);

        //加入gamgover logo
        CCSprite* _over = CCSprite::createWithSpriteFrameName("bird_gameover.png");
        _over->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width * 0.5f, CCDirector::sharedDirector()->getWinSize().height * 0.7f));
        _over->setTag(TAG_OVER);
        _over->setVisible(false);
        _gameBatchNode->addChild(_over, 10);

        //add menu
        CCSprite * menuItemOn;
        CCSprite * menuItemOff;
        //菜单有两个状态,平时展示的样子和点击的样子
        menuItemOn = CCSprite::createWithSpriteFrameName("bird_start_btn.png");
        menuItemOff = CCSprite::createWithSpriteFrameName("brid_start_btn_pressed.png");
        //New Game 菜单
        CCMenuItemSprite * starGametItem = CCMenuItemSprite::create(
            menuItemOff,
            menuItemOn,
            this,
            //这个最重要,点击菜单调用系统哪个方法
            menu_selector(CGameScene::startGame));

        CCMenu*_mainMenu = CCMenu::create( starGametItem, NULL);//创建菜单
        _mainMenu->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width * 0.5f, CCDirector::sharedDirector()->getWinSize().height * 0.5f));
        _mainMenu->setTag(TAG_BUTTON);
        this->addChild(_mainMenu,10);

        CCLabelBMFont* bestscore = CCLabelBMFont::create("0", "font.fnt");
        bestscore->setPosition(CCPoint(CCDirector::sharedDirector()->getWinSize().width / 15, CCDirector::sharedDirector()->getWinSize().height / 4 * 3));        
        bestscore->setVisible(false);
        bestscore->setTag(TAG_BESTSCORE);
        this->addChild(bestscore,10);

        CCLabelBMFont* currscore = CCLabelBMFont::create("0", "font.fnt");
        currscore->setPosition(CCPoint(CCDirector::sharedDirector()->getWinSize().width / 15, CCDirector::sharedDirector()->getWinSize().height / 4 * 3));        
        currscore->setVisible(false);
        currscore->setTag(TAG_CURRSCORE);
        this->addChild(currscore,10);

        m_bird = Cbird::create();
        CC_BREAK_IF(! m_bird);

        // Place the sprite on the center of the screen
        //pSprite->setPosition(ccp(size.width/2, size.height/2));

        // Add the sprite to HelloWorld layer as a child layer.
        _gameBatchNode->addChild(m_bird, 100);

        bRet = true;
        this->schedule(schedule_selector(CGameScene::update));
        m_gamestate = GAMEREAD;
    } while (0);

    return bRet;
}

void CGameScene::menuCloseCallback( CCObject* pSender )
{
   CCDirector::sharedDirector()->end();
}

void CGameScene::ccTouchesBegan( CCSet* pTouches, CCEvent* event )
{
}

void CGameScene::ccTouchesEnded( CCSet* pTouches, CCEvent* event )
{
    if (m_gamestate == BIRDFLY)
    {
        m_bird->SetFlyUp();
    }
}
void CGameScene::update(float dt)
{
    //if (_pipe)
    //{
    //    _pipe->update(dt);
    //}
    //CPipe * pipe = (CPipe *)(m_pipes->objectAtIndex(0));
    //if (pipe)
    //{    
    _pipes[0].StartGame();
    for(int i = 0;i <3;i ++){
        //CPipe * _pipe = (CPipe *)(m_pipes->objectAtIndex(i));
        //CPipe * _pipe2 = (CPipe *)(m_pipes->objectAtIndex(i+1));
        if (_pipes[i].isStart())
        {
            if (_pipes[i].getPositionX()+213<=_pipes[i+1].getPositionX())
            {
                _pipes[i+1].StartGame();
            }
        }
    }
    if (m_bird->getPositionY()<=0)
    {
        m_gamestate = BIRDDIE;
    }
    if (m_gamestate == BIRDFLY)
    {
        for(int i = 0;i <4;i ++){
            _pipes[i].update(dt);
        }
    }
    for(int i = 0;i <4;i ++){
        if(_pipes[i].CheckCollision(m_bird->getPositionX(), m_bird->getPositionY()))
        {
            m_gamestate = BIRDDIE;

            _gameBatchNode->getChildByTag(TAG_LOGO)->setVisible(false);
            _gameBatchNode->getChildByTag(TAG_OVER)->setVisible(true);
            this->getChildByTag(TAG_BUTTON)->setVisible(true);
            break;
        }
    }

    CCLabelBMFont* scoreSprite = (CCLabelBMFont*)this->getChildByTag(TAG_BESTSCORE);
    CCString* s = CCString::createWithFormat("%d", CPipe::GetScore());
    scoreSprite->setString(s->getCString());
    //}

}

void CGameScene::startGame (CCObject* pSender) {
    m_gamestate = BIRDFLY;
    _gameBatchNode->getChildByTag(TAG_LOGO)->setVisible(false);
    _gameBatchNode->getChildByTag(TAG_OVER)->setVisible(false);
    this->getChildByTag(TAG_BUTTON)->setVisible(false);
    m_bird->ResetBird();
    m_bird->GameStart();
    for(int i = 0;i <4;i ++){
        _pipes[i].ReSetPositionX();
        _pipes[i].GameOver();
    }

    CCLabelBMFont* scoreSprite = (CCLabelBMFont*)this->getChildByTag(TAG_BESTSCORE);
    scoreSprite->setVisible(true);
}

水管Pipe类

#ifndef _PIPE_
#define  _PIPE_
#include "cocos2d.h"
#include "GameScene.h"
USING_NS_CC;
class CPipe:public CCObject{
private:
    CCSprite* m_upipe;
    CCSprite* m_dpipe;
    int relativeHight;
    enum{
        PLYAYING=0,
        OVER,
    };
    int m_gamestate;
    float updatetime;
    bool canaddscore;
public:
    CPipe();
    ~CPipe();
    void ReSetPositionX();
    void update(float times);
    bool CheckCollision(int x, int y);
    void StartGame();
    void GameOver();
    void SetLayer(CCSpriteBatchNode* layer);
    float getPositionX();
    bool isStart();
    void init();
    static int GetScore();
};
#endif

#include "Pipe.h"
static int m_score = 0;
CPipe::CPipe()
:m_gamestate(OVER),
updatetime(0.0),
canaddscore(false)
{
    //生成随机数
    float rheight = CCRANDOM_MINUS1_1();
    //设置上水管
    m_upipe = CCSprite::createWithSpriteFrameName("obstacle_up.png");
    m_upipe->setAnchorPoint(ccp(0,0));
    m_upipe->setPosition(ccp(852,306+rheight*100));
    m_upipe->retain();
    //设置下水管
    m_dpipe = CCSprite::createWithSpriteFrameName("obstacle_down.png");
    m_dpipe->setAnchorPoint(ccp(0,1));
    m_dpipe->setPosition(ccp(852,206+rheight*100));
    m_dpipe->retain();
    //this->schedule(schedule_selector(CPipe::update));
}

CPipe::~CPipe()
{    


}

void CPipe::ReSetPositionX()
{
    //生成随机数
    float rheight = CCRANDOM_MINUS1_1();
    m_upipe->setPosition(ccp(852,306+rheight*100));
    m_dpipe->setPosition(ccp(852,206+rheight*100));
    canaddscore = true;
}

void CPipe::update( float times )
{
    //updatetime +=dt;
    //if (updatetime >= 0.4)
    //{
    //    updatetime = 0.0;
    //}
    if (m_gamestate == PLYAYING)
    {
        int pox = m_upipe->getPositionX()-3;
        if (pox <=-52)
        {
            pox = 852;
            ReSetPositionX();
        }
        m_upipe->setPositionX(pox);
        m_dpipe->setPositionX(pox);
        if ( m_upipe->getPositionX()<CCDirector::sharedDirector()->getWinSize().width*0.36f-52&&canaddscore)
        {
            m_score++;
            canaddscore = false;
        }

    }
}

bool CPipe::CheckCollision( int x, int y )
{
    if (x<m_upipe->getPositionX()+52&&x>m_upipe->getPositionX())
    {
        if (y>m_upipe->getPositionY()||y<m_dpipe->getPositionY())
        {
            return true;
        }
    }
    return false;
}

void CPipe::StartGame()
{
    m_gamestate = PLYAYING;
}

void CPipe::GameOver()
{
    m_gamestate = OVER;
    m_score = 0;
}

void CPipe::SetLayer( CCSpriteBatchNode* layer )
{
    layer->addChild(m_upipe, 10);
    layer->addChild(m_dpipe, 10);
}

float CPipe::getPositionX()
{
    return m_dpipe->getPositionX();
}

bool CPipe::isStart()
{
    return m_gamestate==PLYAYING;
}

void CPipe::init()
{
    m_gamestate = OVER;
    //生成随机数
    float rheight = CCRANDOM_MINUS1_1();
    //设置上水管
    m_upipe = CCSprite::createWithSpriteFrameName("obstacle_up.png");
    m_upipe->setAnchorPoint(ccp(0,0));
    m_upipe->setPosition(ccp(852,306+rheight*100));
    m_upipe->retain();
    //设置下水管
    m_dpipe = CCSprite::createWithSpriteFrameName("obstacle_down.png");
    m_dpipe->setAnchorPoint(ccp(0,1));
    m_dpipe->setPosition(ccp(852,206+rheight*100));
    m_dpipe->retain();
}

int CPipe::GetScore()
{
    return m_score;
}

小鸟类CBird

#ifndef _BIRD_
#define _BIRD_

#define BIRDFALLSPEED 4
#define BIRDGRAVITY 1
#include "cocos2d.h"
#include "GameScene.h"
USING_NS_CC;

typedef enum
{
    playerRead,//等待游戏开始
    PlayerFlying,//主角在往上飞
    PlayerFalling,//主角在降落
    PlayerDying//主角死亡

} PlayerState; 

class Cbird:public CCSprite{
    CCAction * m_flyAnimation;
    CCAction * m_fallAnimation;
    CCAction * m_NormalAnimation;
    bool m_isfalling;
    PlayerState m_state;
    CCSize _screenSize;
public:
    //定义变量,并且直接定义默认的get/set方法
    CC_SYNTHESIZE(CCPoint, _nextPosition, NextPosition);

    CC_SYNTHESIZE(float, _width, Width);

    CC_SYNTHESIZE(float, _height, Height);

    CC_SYNTHESIZE(CCPoint, _vector, Vector);
public: 
    Cbird();
    ~Cbird();
    static Cbird * create (void);
    static Cbird * ShareBird(void);
    bool InintBird();
    bool ResetBird();
    bool SetFlyUp();
    bool SetFall();
    void GameStart();
    void GameOver();
    inline void setSize() {
        _width = this->boundingBox().size.width;
        _height = this->boundingBox().size.height;
    }
private:
        void update(float dt);
        void flyactioncallback();
        float gravity;
};
#endif

#include "Bird.h"
static Cbird *instance = NULL;
Cbird::Cbird()
:_vector(ccp(0,0))
,_screenSize(CCDirector::sharedDirector()->getWinSize())
,gravity(2)
{
    m_isfalling = false;
    m_state = playerRead;
}

Cbird::~Cbird()
{
    CC_SAFE_RELEASE(m_flyAnimation);
    CC_SAFE_RELEASE(m_fallAnimation);
    CC_SAFE_RELEASE(m_NormalAnimation);
}

Cbird * Cbird::create( void )
{
    Cbird * bird = new Cbird();
    if (bird && bird->initWithSpriteFrameName("bird_hero1.png")) {
        bird->autorelease();
        bird->setSize();
        bird->InintBird();
        instance = bird;
        return bird;
    }
    CC_SAFE_DELETE(bird);
    return NULL;
}

bool Cbird::InintBird()
{
    //设置锚点
    this->setAnchorPoint(ccp(0.5f, 1.0f));
    this->setPosition(ccp(_screenSize.width * 0.36f,500/* _nextPosition.y*/));

    //_height = 228;
    //_width = 180;
    _height = 34;
    _width = 24;
    CCAnimation* animation;
    //创建一个空白的序列帧动画信息
    animation = CCAnimation::create();

    //CCSpriteFrame对应的就是帧,将CCSpriteFrame添加到CCAnimation生成动画数据,
    //用CCAnimation生成CCAnimate(就是最终的动画动作),最后可以用CCSprite执行这个动作。
    CCSpriteFrame * frame;
    int i;
    //共有3帧,这里用for循环将对应的序列图加入到动画中
    for(i = 1; i <= 3; i++) {
        char szName[100] = {0};
        sprintf(szName, "bird_hero%i.png", i);
        frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(szName);
        animation->addSpriteFrame(frame);
    }

    //设置每两帧间时间间隔
    animation->setDelayPerUnit(0.2f / 3.0f);
    //设置动画结束后是否保留动画帧信息
    animation->setRestoreOriginalFrame(false);
    //设置循环播放次数 (-1:无限循环)
    animation->setLoops(-1);
    //由这个动画信息创建一个序列帧动画
    m_NormalAnimation = CCAnimate::create(animation);
    //保存这个动画
    m_NormalAnimation->retain();


    this->runAction(m_NormalAnimation);
    m_fallAnimation = CCEaseOut::create(CCRotateTo::create(0.4f, 45), 0.4);
    m_fallAnimation->retain();
    this->runAction(m_fallAnimation);
    // update 
    //scheduleUpdate();
    this->schedule(schedule_selector(Cbird::update));
    return 1;
}

bool Cbird::SetFlyUp()
{
    if (m_state == PlayerFlying)
    {
        this->stopAction(m_flyAnimation);
    }
    else if(m_fallAnimation)
        this->stopAction(m_fallAnimation);
    //CCAction *action1 = CCSpawn::create(
    //    CCMoveTo::create(0.25f,CCPointMake(this->getPositionX(),this->getPositionY()+30)),
    //    CCRotateTo::create(0.25f,-45),
    //    );
    //CCAction *action = CCSpawn::create(
    //    CCMoveTo::create(0.25f,CCPointMake(this->getPositionX(),this->getPositionY()+20)),
    //    CCRotateTo::create(0.25f,-45),
    //    NULL
    //    );

    //CCFiniteTimeAction *action = CCJumpTo::create(0.4f, CCPointMake(this->getPositionX(),this->getPositionY()),50,1);

    //CCAction *actions = CCSpawn::create(
    //    action,
    //    //CCRotateTo::create(0.25f,-45),
    //    CCSequence::create(
    //    CCEaseInOut::create(CCRotateTo::create(0.2f, 0), 2),
    //    CCEaseInOut::create(CCRotateTo::create(0.2f, 90), 2),
    //    NULL),
    //    NULL
    //    );

    //飞的动作
    if (m_state == playerRead||m_state == PlayerDying)
    {
        return 1;
    }
    gravity = 2;
    CCFiniteTimeAction *action = CCJumpTo::create(0.5f, CCPointMake(this->getPositionX(),this->getPositionY()+40),40,1);

    CCFiniteTimeAction *actionss = CCSpawn::create(
        action,
        //CCRotateTo::create(0.25f,-45),
        //CCSequence::create(
        CCSequence::actions(CCEaseIn::create(CCRotateTo::create(0.25f, -45), 0.4),CCEaseOut::create(CCRotateTo::create(0.25f, 0), 0.4),NULL),
    /*    CCCallFunc::create(this,callfunc_selector(Cbird::flyactioncallback)),  */
        //CCEaseInOut::create(CCRotateTo::create(0.2f, 90), 2),
        //NULL),
        NULL
        );
    CCFiniteTimeAction *actionin = CCEaseIn::create((CCActionInterval*)(actionss->copy()->autorelease()),0.5f);

    m_flyAnimation = CCSequence::create(  
        actionin,
        CCCallFunc::create(this,callfunc_selector(Cbird::flyactioncallback)), 
        NULL  
        );  
    m_flyAnimation->retain();
    this->runAction(m_flyAnimation);
    m_state = PlayerFlying;
    return 1;
}

void Cbird::update(float dt)
{
    CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    switch (m_state)
    {
    case PlayerFalling:
        // update bird positionY
        if (this->getPositionY() > 0 && this->getPositionY() < winSize.height)
        {
            //velocity -= gravity;

            this->setPositionY(this->getPositionY() -gravity);
            gravity += 0.3;
        }
        break;
    case PlayerDying:
        // update bird positionY
        if (this->getPositionY() > 0 && this->getPositionY() < winSize.height)
        {
            //velocity -= gravity;
            this->setPositionY(this->getPositionY() -gravity);
            gravity += 0.3;
        }
        break;
    case PlayerFlying:break;
    default:break;
    }
}

void Cbird::flyactioncallback()
{
    /*Cbird::ShareBird()->*/m_state = PlayerFalling;
    this->stopAction(m_flyAnimation);
    //m_fallAnimation = CCEaseIn::create(CCRotateTo::create(0.4f, 90), 2);
    //m_fallAnimation->retain();
    this->runAction(m_fallAnimation);
}

Cbird * Cbird::ShareBird( void )
{
    return instance;
}

void Cbird::GameStart()
{
    m_state = PlayerFalling;
}

void Cbird::GameOver()
{
    m_state = PlayerDying;
}

bool Cbird::ResetBird()
{
    this->setPosition(ccp(_screenSize.width * 0.36f,500/* _nextPosition.y*/));
    gravity = 2;
    return 1;
}

源码地址:Download

posted @ 2014-03-03 22:39  newShit  阅读(1259)  评论(0编辑  收藏