前两天在博客园看到网友实现的一个网页版的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