前两天在博客园看到网友实现的一个网页版的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=,
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 (); // 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, ); //CCSpriteFrameCache(精灵帧缓存)主要用来存放CCSpriteFrame,它没有提供特别的属性,而是提供一系列用于管理CCSpriteFrame的方法
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("bird.plist","bird.png");
_gameBatchNode = CCSpriteBatchNode::create("bird.png", );
this->addChild(_gameBatchNode, ); CCSprite * repeat; _background = CCSprite::createWithSpriteFrameName("bird_bg.png");
_background->setAnchorPoint(ccp(,));
_gameBatchNode->addChild(_background, ); repeat = CCSprite::createWithSpriteFrameName("bird_bg.png");
repeat->setAnchorPoint(ccp(,));
repeat->setPosition(ccp(repeat->getContentSize().width - , ));
_background->addChild(repeat, ); repeat = CCSprite::createWithSpriteFrameName("bird_bg.png");
repeat->setAnchorPoint(ccp(,));
repeat->setPosition(ccp( * (repeat->getContentSize().width - ), ));
_background->addChild(repeat, ); //设置水管
/* _pipe =new CPipe;
_pipe->SetLayer(_gameBatchNode); m_pipes = CCArray::arrayWithCapacity(4);*/
_pipes = new CPipe[];
for(int i = ;i < ;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, ); //加入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, ); //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,); CCLabelBMFont* bestscore = CCLabelBMFont::create("", "font.fnt");
bestscore->setPosition(CCPoint(CCDirector::sharedDirector()->getWinSize().width / , CCDirector::sharedDirector()->getWinSize().height / * ));
bestscore->setVisible(false);
bestscore->setTag(TAG_BESTSCORE);
this->addChild(bestscore,); CCLabelBMFont* currscore = CCLabelBMFont::create("", "font.fnt");
currscore->setPosition(CCPoint(CCDirector::sharedDirector()->getWinSize().width / , CCDirector::sharedDirector()->getWinSize().height / * ));
currscore->setVisible(false);
currscore->setTag(TAG_CURRSCORE);
this->addChild(currscore,); 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, ); bRet = true;
this->schedule(schedule_selector(CGameScene::update));
m_gamestate = GAMEREAD;
} while (); 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[].StartGame();
for(int i = ;i <;i ++){
//CPipe * _pipe = (CPipe *)(m_pipes->objectAtIndex(i));
//CPipe * _pipe2 = (CPipe *)(m_pipes->objectAtIndex(i+1));
if (_pipes[i].isStart())
{
if (_pipes[i].getPositionX()+<=_pipes[i+].getPositionX())
{
_pipes[i+].StartGame();
}
}
}
if (m_bird->getPositionY()<=)
{
m_gamestate = BIRDDIE;
}
if (m_gamestate == BIRDFLY)
{
for(int i = ;i <;i ++){
_pipes[i].update(dt);
}
}
for(int i = ;i <;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 = ;i <;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=,
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 = ;
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(,));
m_upipe->setPosition(ccp(,+rheight*));
m_upipe->retain();
//设置下水管
m_dpipe = CCSprite::createWithSpriteFrameName("obstacle_down.png");
m_dpipe->setAnchorPoint(ccp(,));
m_dpipe->setPosition(ccp(,+rheight*));
m_dpipe->retain();
//this->schedule(schedule_selector(CPipe::update));
} CPipe::~CPipe()
{ } void CPipe::ReSetPositionX()
{
//生成随机数
float rheight = CCRANDOM_MINUS1_1();
m_upipe->setPosition(ccp(,+rheight*));
m_dpipe->setPosition(ccp(,+rheight*));
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()-;
if (pox <=-)
{
pox = ;
ReSetPositionX();
}
m_upipe->setPositionX(pox);
m_dpipe->setPositionX(pox);
if ( m_upipe->getPositionX()<CCDirector::sharedDirector()->getWinSize().width*0.36f-&&canaddscore)
{
m_score++;
canaddscore = false;
} }
} bool CPipe::CheckCollision( int x, int y )
{
if (x<m_upipe->getPositionX()+&&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 = ;
} void CPipe::SetLayer( CCSpriteBatchNode* layer )
{
layer->addChild(m_upipe, );
layer->addChild(m_dpipe, );
} 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(,));
m_upipe->setPosition(ccp(,+rheight*));
m_upipe->retain();
//设置下水管
m_dpipe = CCSprite::createWithSpriteFrameName("obstacle_down.png");
m_dpipe->setAnchorPoint(ccp(,));
m_dpipe->setPosition(ccp(,+rheight*));
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(,))
,_screenSize(CCDirector::sharedDirector()->getWinSize())
,gravity()
{
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,/* _nextPosition.y*/)); //_height = 228;
//_width = 180;
_height = ;
_width = ;
CCAnimation* animation;
//创建一个空白的序列帧动画信息
animation = CCAnimation::create(); //CCSpriteFrame对应的就是帧,将CCSpriteFrame添加到CCAnimation生成动画数据,
//用CCAnimation生成CCAnimate(就是最终的动画动作),最后可以用CCSprite执行这个动作。
CCSpriteFrame * frame;
int i;
//共有3帧,这里用for循环将对应的序列图加入到动画中
for(i = ; i <= ; i++) {
char szName[] = {};
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(-);
//由这个动画信息创建一个序列帧动画
m_NormalAnimation = CCAnimate::create(animation);
//保存这个动画
m_NormalAnimation->retain(); this->runAction(m_NormalAnimation);
m_fallAnimation = CCEaseOut::create(CCRotateTo::create(0.4f, ), 0.4);
m_fallAnimation->retain();
this->runAction(m_fallAnimation);
// update
//scheduleUpdate();
this->schedule(schedule_selector(Cbird::update));
return ;
} 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 ;
}
gravity = ;
CCFiniteTimeAction *action = CCJumpTo::create(0.5f, CCPointMake(this->getPositionX(),this->getPositionY()+),,); CCFiniteTimeAction *actionss = CCSpawn::create(
action,
//CCRotateTo::create(0.25f,-45),
//CCSequence::create(
CCSequence::actions(CCEaseIn::create(CCRotateTo::create(0.25f, -), 0.4),CCEaseOut::create(CCRotateTo::create(0.25f, ), 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 ;
} void Cbird::update(float dt)
{
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
switch (m_state)
{
case PlayerFalling:
// update bird positionY
if (this->getPositionY() > && this->getPositionY() < winSize.height)
{
//velocity -= gravity; this->setPositionY(this->getPositionY() -gravity);
gravity += 0.3;
}
break;
case PlayerDying:
// update bird positionY
if (this->getPositionY() > && 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,/* _nextPosition.y*/));
gravity = ;
return ;
}
源码地址:Download