这个小的游戏代码可以使我们理解常见的cocos的概念,从场景,精灵,图层,到导演,回调函数,更新函数,再到设置物理世界,设置精灵刚体。不得不说cocos博大精深,不过有个大家一直在意的问题,就是cocos版本更新太快,有些东西不能使用或者使用错误。个人建议去看cocos官网的版本更新信息和去官网论坛提问或者加群讨论,这样更利于大家提高! 上代码!代码大部分都有注释,如有问题可以提问!
游戏由三个场景构成,HelloWorldScene,GameScene,GameOver。
HelloWorldScene是初始场景
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
//#include "Land.h"
USING_NS_CC;
class HelloWorld : public cocos2d::Layer
{
void scrollLand(float dt);
Sprite* land1;
Sprite* land2;
public:
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::Scene* createScene();
//virtual void update(float delta);
void myupdate(float delta);
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// a selector callback
void menuCloseCallback(cocos2d::Ref* pSender);
//void scrollLand(float dt);
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld);
};
#endif // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h"
#include "SceneOne.h"
#include"GameScene.h"
#include "SimpleAudioEngine.h"
USING_NS_CC;
using namespace CocosDenshion;
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//
// 1. super init first
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
SimpleAudioEngine::getInstance()->preloadEffect("die.mp3");
SimpleAudioEngine::getInstance()->preloadEffect("hit.mp3");
SimpleAudioEngine::getInstance()->preloadEffect("point.mp3");
SimpleAudioEngine::getInstance()->preloadEffect("swooshing.mp3");
SimpleAudioEngine::getInstance()->preloadEffect("wing.mp3");
/
// 2. add a menu item with "X" image, which is clicked to quit the program
// you may modify it.
// add a "close" icon to exit the progress. it's an autorelease object
/
// 3. add your codes below...
// add a label shows "Hello World"
// create and initialize a label
auto label = Label::createWithTTF("Start_Scene", "fonts/Marker Felt.ttf", 24);
// position the label on the center of the screen
label->setPosition(Vec2(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - label->getContentSize().height));
// add the label as a child to this layer
// this->addChild(label, 1);
// add "HelloWorld" splash screen"
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("game.plist");
auto background = Sprite::createWithSpriteFrameName("bg.png");
// position the sprite on the center of the screen
background->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
// add the sprite as a child to this layer
this->addChild(background, 0);
auto bird = Sprite::createWithSpriteFrameName("bird1.png");
auto animation = Animation::create();
for (int i = 1; i <= 3; ++i)
{
char szName[100] = { 0 };
sprintf(szName, "bird%d.png", i);
auto _sprite = Sprite::createWithSpriteFrameName(szName);
animation->addSpriteFrame(_sprite->getSpriteFrame());
}
animation->setDelayPerUnit(1.5f / 14.0f);
animation->setRestoreOriginalFrame(true);
auto action = Animate::create(animation);
auto swing = MoveBy::create( 0.5f,Vec2(0, 10));
bird->runAction(RepeatForever::create(action));
bird->runAction(RepeatForever::create(Sequence::create(swing,swing->reverse(),NULL)));
bird->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
this->addChild(bird, 10);
auto flappybird = Sprite::createWithSpriteFrameName("bird_logo.png");
flappybird->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y+3*flappybird->getContentSize().height));
this->addChild(flappybird, 100);
/*auto land1 = Sprite::createWithSpriteFrameName("land.png");
land1->setPosition(Vec2(visibleSize.width / 2 + origin.x,visibleSize.height/2-background->getPositionY()+land1->getContentSize().height));
this->addChild(land1, 100);
auto land1move = MoveBy::create(3.0f, Vect(land1->getContentSize().width, 0));
auto land2 = Sprite::createWithSpriteFrameName("land.png");
land2->setPosition(Vec2(visibleSize.width / 2 + origin.x-land1->getContentSize().width, visibleSize.height / 2 - background->getPositionY() + land1->getContentSize().height));
this->addChild(land2, 100);
auto land2move = MoveBy::create(3.0f, Vect(land2->getContentSize().width, 0));
land1->runAction(land1move);
land2->runAction(land2move);*/
land1 = Sprite::createWithSpriteFrameName("land.png");
land1->setAnchorPoint(Point::ZERO);
land1->setPosition(Point::ZERO);
this->addChild(land1, 10); //置于最顶层
land2 = Sprite::createWithSpriteFrameName("land.png");
land2->setAnchorPoint(Point::ZERO);
land2->setPosition(Point::ZERO);
this->addChild(land2, 10);
//this->schedule(schedule_selector(HelloWorld::scrollLand), 0.01f);
//land = Land::create();
//land->setPosition(Vec2(visibleSize.width, visibleSize.height));
//this->addChild(land, 100);
auto start_bt = Sprite::createWithSpriteFrameName("start_btn.png");
auto pressed_bt = Sprite::createWithSpriteFrameName("start_btn_pressed.png");
auto closeItem = MenuItemSprite::create(
start_bt,
pressed_bt,
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
closeItem->setPosition(Vec2(visibleSize.width / 2 + origin.x,
visibleSize.height / 2 - background->getPositionY() +3* closeItem->getContentSize().height));
// create menu, it's an autorelease object
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 101);
//this->scheduleUpdate();//使用update()函数来更新
this->schedule(schedule_selector(HelloWorld::myupdate));//使用自定义函数来更新
return true;
}
void HelloWorld::menuCloseCallback(Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
return;
#endif
auto scene = GameScene::createScene();
auto transition = TransitionFade::create(1, scene);
// run
Director::getInstance()->replaceScene(transition);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
/*void HelloWorld::scrollLand(float dt)
{
this->land1->setPositionX(this->land1->getPositionX() - 2.0f);
this->land2->setPositionX(this->land1->getPositionX() + this->land1->getContentSize().width - 2.0f);
if (this->land2->getPositionX() == 0) {
this->land1->setPositionX(0);
}
}
void HelloWorld::update(float delta)
{
int posLand1 = land1->getPositionX();
int posLand2 = land2->getPositionX();
int speed = 1;
posLand1 -= speed;
posLand2 -= speed;
auto landsize = land2->getContentSize();
if (posLand1 < -landsize.width / 2+142)
{
posLand2 = landsize.width / 2;
posLand1 = landsize.width + landsize.width / 2;
}
if (posLand2 < -landsize.width / 2+142)
{
posLand1 = landsize.width / 2;
posLand2 = landsize.width + landsize.width / 2;
}
land1->setPositionX(posLand1);
land2->setPositionX(posLand2);
}*/
void HelloWorld::myupdate(float delta)
{
int posLand1 = land1->getPositionX();
int posLand2 = land2->getPositionX();
int speed = 1;
posLand1 -= speed;
posLand2 -= speed;
auto landsize = land2->getContentSize();
if (posLand1 < -landsize.width / 2 + 142)
{
posLand2 = 0;
posLand1 = landsize.width + 0;
}
if (posLand2 < -landsize.width / 2 + 142)
{
posLand1 = 0;
posLand2 = landsize.width + 0;
}
land1->setPositionX(posLand1);
land2->setPositionX(posLand2);
}
接下来是游戏核心的GameScene代码:
#pragma once
#include "cocos2d.h"
//一些全局常量
const int BIRD_RADIUS = 15; //小鸟半径
const int PIPE_HEIGHT = 320;//半根管道长度
const int PIPE_WIDTH = 52; //管道宽度
const int PIPE_SPACE = 100; //上下管之间的缝隙
const int PIPE_INTERVAL = 170;//横向两根管子之间的间距,288/2+52/2
const int WAIT_DISTANCE = 380;//等待距离
enum GAME_STATUS //游戏状态,准备,开始,结束
{
GAME_READY,
GAME_START,
GAME_OVER
};
class GameScene :public cocos2d::Layer
{
public:
static cocos2d::Scene* createScene();
virtual bool init();
CREATE_FUNC(GameScene);
void update(float dt);
void scrollLand(float dt);
void setPhysicWorld(cocos2d::PhysicsWorld *world);
virtual bool onContactBegin(const cocos2d::PhysicsContact& contact);
virtual bool onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event);
virtual void onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *event);
void createPipes();
int getRandomHeight();
void gameStart();
void gameOver();
void gameRetart(Ref *sender);
void gamePanelAppear();
private:
cocos2d::Sprite *birdSprite; //小鸟
cocos2d::RepeatForever *swingAction; //小鸟的晃动动画
cocos2d::LabelTTF *scoreLabel; //计分
cocos2d::Sprite *land1, *land2; //地板
cocos2d::Vector<cocos2d::Node*> pipes; //管道,用容器装起来
cocos2d::PhysicsWorld *m_physicWorld; //游戏层物理世界
GAME_STATUS gameStatus; //游戏状态变量
int score, bestScore; //游戏当前分数和最好分数
int touchX; //触摸点横坐标
};
#include "GameScene.h"
#include "SimpleAudioEngine.h"
#include "HelloWorldScene.h"
#include "GameOver.h"
USING_NS_CC;
using namespace CocosDenshion;
Scene* GameScene::createScene()
{
//创建游戏场景
auto gameScene = Scene::createWithPhysics(); //用物理世界初始化场景
gameScene->getPhysicsWorld()->setGravity(Vec2(0, -700)); //设置重力场,重力加速度可以根据手感改小点
//添加主游戏层
auto gameLayer = GameScene::create();
gameLayer->setPhysicWorld(gameScene->getPhysicsWorld()); //绑定物理世界
gameScene->addChild(gameLayer);
return gameScene;
}
bool GameScene::init()
{
if (!Layer::init())
return false;
Size visibleSize = Director::getInstance()->getVisibleSize();
Point visibleOrigin = Director::getInstance()->getVisibleOrigin();
//初始化游戏状态
gameStatus = GAME_READY;
score = 0;
//添加游戏背景
Sprite *backGround = Sprite::createWithSpriteFrameName("bg.png");
backGround->setPosition(visibleOrigin.x + visibleSize.width / 2, visibleOrigin.y + visibleSize.height / 2);
this->addChild(backGround);
//logo
auto gameLogo = Sprite::createWithSpriteFrameName("bird_logo.png");
gameLogo->setPosition(visibleOrigin.x + visibleSize.width / 2, visibleOrigin.y + visibleSize.height / 2 + 100);
gameLogo->setName("logo");
this->addChild(gameLogo);
//添加管子
createPipes();
//小鸟
birdSprite = Sprite::create();
birdSprite->setPosition(visibleOrigin.x + visibleSize.width / 3, visibleOrigin.y + visibleSize.height / 2);
this->addChild(birdSprite);
auto birdAnimation = Animation::create();
birdAnimation->setDelayPerUnit(0.2f);
birdAnimation->addSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("bird1.png"));
birdAnimation->addSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("bird2.png"));
birdAnimation->addSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("bird3.png"));
auto birdAnim = Animate::create( birdAnimation);
birdSprite->runAction(RepeatForever::create(birdAnim)); //挥翅动画
auto up = MoveBy::create(0.4f, Point(0, 8));
auto upBack = up->reverse();
if (gameStatus == GAME_READY)
{
swingAction = RepeatForever::create(Sequence::create(up, upBack, NULL));
birdSprite->runAction(swingAction); //上下晃动动画
}
//小鸟绑定刚体
auto birdBody = PhysicsBody::createCircle(BIRD_RADIUS); //将小鸟当成一个圆,懒得弄精确的轮廓线了
birdBody->setDynamic(true); //设置为可以被物理场所作用而动作
birdBody->setContactTestBitmask(1); //必须设置这项为1才能检测到不同的物体碰撞
birdBody->setGravityEnable(false); //设置是否被重力影响,准备画面中不受重力影响
birdSprite->setPhysicsBody(birdBody); //为小鸟设置刚体
//添加两个land
land1 = Sprite::createWithSpriteFrameName("land.png");
land1->setAnchorPoint(Point::ZERO);
land1->setPosition(Point::ZERO);
this->addChild(land1, 10); //置于最顶层
land2 = Sprite::createWithSpriteFrameName("land.png");
land2->setAnchorPoint(Point::ZERO);
land2->setPosition(Point::ZERO);
this->addChild(land2, 10);
//设置地板刚体
Node *groundNode = Node::create();
auto groundBody = PhysicsBody::createBox(Size(visibleSize.width, land1->getContentSize().height));
groundBody->setDynamic(false);
groundBody->setContactTestBitmask(1);
groundNode->setAnchorPoint(Vec2::ANCHOR_MIDDLE); //物理引擎中的刚体只允许结点锚点设置为中心
groundNode->setPhysicsBody(groundBody);
groundNode->setPosition(visibleOrigin.x + visibleSize.width / 2, land1->getContentSize().height / 2);
this->addChild(groundNode);
//设置界面顶部刚体
Node * UpgroundNode = Node::create();
auto UpgroudBody = PhysicsBody::createBox(Size(visibleSize.width, 1));
UpgroudBody->setDynamic(false);
UpgroudBody->setCategoryBitmask(1);
UpgroundNode->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
UpgroundNode->setPhysicsBody(UpgroudBody);
UpgroundNode->setPosition(visibleOrigin.x + visibleSize.width / 2, visibleSize.height+0.5f);
this->addChild(UpgroundNode);
//记分牌,在最外层,这里懒得弄图片文字了^_^
scoreLabel = LabelTTF::create("0", "Felt", 35);
scoreLabel->setPosition(visibleOrigin.x + visibleSize.width / 2, visibleOrigin.y + visibleSize.height / 2 + 200);
scoreLabel->setVisible(false); //一开始隐藏
this->addChild(scoreLabel);
//添加碰撞监测
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(GameScene::onContactBegin, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
//添加触摸监听
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = CC_CALLBACK_2(GameScene::onTouchBegan, this);
touchListener->onTouchEnded = CC_CALLBACK_2(GameScene::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
return true;
}
//设置层的物理世界
void GameScene::setPhysicWorld(PhysicsWorld *world)
{
m_physicWorld = world;
}
//游戏开始
void GameScene::gameStart()
{
gameStatus = GAME_START;
score = 0;//重置分数
scoreLabel->setString(String::createWithFormat("%d", score)->getCString());
this->getChildByName("logo")->setVisible(false); //logo消失
scoreLabel->setVisible(true); //计分开始
this->scheduleUpdate();//启动默认更新
this->schedule(schedule_selector(GameScene::scrollLand), 0.01f); //启动管子和地板滚动
birdSprite->stopAction(swingAction); //游戏开始后停止上下浮动
birdSprite->getPhysicsBody()->setGravityEnable(true); //开始受重力作用
}
//游戏结束
void GameScene::gameOver()
{
gameStatus = GAME_OVER;
//获取历史数据
bestScore = UserDefault::getInstance()->getIntegerForKey("BEST");
if (score > bestScore)
{
bestScore = score; //更新最好分数
UserDefault::getInstance()->setIntegerForKey("BEST", bestScore);
}
SimpleAudioEngine::getInstance()->playEffect("hit.mp3");
//游戏结束后停止地板和管道的滚动
this->unschedule(schedule_selector(GameScene::scrollLand));
}
//碰撞监测
bool GameScene::onContactBegin(const PhysicsContact& contact)
{
if (gameStatus == GAME_OVER) //当游戏结束后不再监控碰撞
return false;
gameOver();//如果游戏状态不是GAMEOVER就调用gameOver函数来设置碰撞后游戏结束的信息
return true;
}
//触摸监听
bool GameScene::onTouchBegan(Touch *touch, Event *event)
{
switch (gameStatus)
{
case GAME_OVER:
break;
case GAME_READY:
{
gameStart();
birdSprite->getPhysicsBody()->setVelocity(Vec2(0, 100)); //给一个向上的初速度
SimpleAudioEngine::getInstance()->playEffect("wing.mp3");
//这里也要写,不然touchx的值是未知值,负无穷,导致bug
touchX = touch->getLocation().x;
}
break;
case GAME_START:
{
auto curVelocity = birdSprite->getPhysicsBody()->getVelocity();
birdSprite->getPhysicsBody()->setVelocity(Vec2(0, 100 > (curVelocity.y + 500) ? (curVelocity.y + 500) : 100)); //向上的速度受下降影响
SimpleAudioEngine::getInstance()->playEffect("wing.mp3");
//开上帝视角,留个后门,嘿嘿
touchX = touch->getLocation().x;
}
break;
default:
break;
}
return true;
}
void GameScene::onTouchEnded(Touch *touch, Event *event)
{
//当触摸点滑动超过100,分数瞬间涨100
if (touch->getLocation().x - touchX > 100)
{
score += 100;
scoreLabel->setString(String::createWithFormat("%d", score)->getCString());
SimpleAudioEngine::getInstance()->playEffect("point.mp3");
}
}
//地板滚动自定义计时器回调
void GameScene::scrollLand(float dt)
{
Size visibleSize = Director::getInstance()->getVisibleSize();
//两个图片循环移动
land1->setPositionX(land1->getPositionX() - 1.0f);
land2->setPositionX(land1->getPositionX() + land1->getContentSize().width - 2.0f);
if (land2->getPositionX() <= 0)
land1->setPosition(Point::ZERO);
//管子滚动
for (auto &singlePipe : pipes)
{
singlePipe->setPositionX(singlePipe->getPositionX() - 1.0f);//每次向左移动一个单位
if (singlePipe->getPositionX() < -PIPE_WIDTH / 2)//如果管子完全移除了界面
{
singlePipe->setPositionX(visibleSize.width + PIPE_WIDTH / 2);//设置管子从界面右侧进入
singlePipe->setPositionY(getRandomHeight());//Y的位置设置为随机值
singlePipe->setName("newPipe"); //每次重设一根管子,标为new
}
}
}
//获取随机高度,用于管道
int GameScene::getRandomHeight()
{
auto size = Director::getInstance()->getVisibleSize();
//使得单根管子纵向坐标在屏幕中心点-(40~270)中间随机波动,这个是自己试出来的
return size.height / 2 - 40 - CCRANDOM_0_1() * (270 - 40);
}
//创建管道
void GameScene::createPipes()
{
//同屏幕出现的只有两根管子,放到容器里面,上下绑定为一根
for (int i = 0; i < 2; i++)
{
auto visibleSize = Director::getInstance()->getVisibleSize();
Sprite *pipeUp = Sprite::createWithSpriteFrameName("pipe_up.png");
Sprite *pipeDown = Sprite::createWithSpriteFrameName("pipe_down.png");
Node *singlePipe = Node::create();
//给上管绑定刚体
auto pipeUpBody = PhysicsBody::createBox(pipeUp->getContentSize());
pipeUpBody->setDynamic(false);
pipeUpBody->setContactTestBitmask(1);
pipeUp->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
pipeUp->setPhysicsBody(pipeUpBody);
//给两个管子分开设置刚体,可以留出中间的空隙使得小鸟通过
//给下管绑定刚体
auto pipeDownBody = PhysicsBody::createBox(pipeDown->getContentSize());
pipeDownBody->setDynamic(false);
pipeDownBody->setContactTestBitmask(1);
pipeDown->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
pipeDown->setPhysicsBody(pipeDownBody);
pipeUp->setPosition(0, PIPE_HEIGHT + PIPE_SPACE);//上面管子设置在Y为管子的高度和管子空隙高度之和(相对于父节点,也就是singlePipe)
singlePipe->addChild(pipeUp);
//下面管子pipeDown没有设置位置,就是设置在默认位置(0,0)
singlePipe->addChild(pipeDown); //pipeDown默认加到(0,0),上下合并,此时singlePipe以下面的管子中心为锚点,此时singlePipe由两个管子组合而成
singlePipe->setPosition(i*PIPE_INTERVAL + WAIT_DISTANCE, getRandomHeight()); //设置初始位置,X方向为等待距离和管子间隔之和,Y设置为随机位置
singlePipe->setName("newPipe");
this->addChild(singlePipe); //把两个管子都加入到层
pipes.pushBack(singlePipe); //两个管子先后添加到容器
}
}
//默认的更新函数
void GameScene::update(float dt)
{
//当游戏开始时,判断得分,这个其实也可以写在其他地方,比如管子滚动的更新函数里面或者触摸监测里面
if (gameStatus == GAME_START)
{
for (auto &pipe : pipes)
{
if (pipe->getName() == "newPipe") //新来一根管子就判断
{
if (pipe->getPositionX() < birdSprite->getPositionX())
{
score++;
scoreLabel->setString(String::createWithFormat("%d", score)->getCString());
SimpleAudioEngine::getInstance()->playEffect("point.mp3");
pipe->setName("passed"); //标记已经过掉的管子
}
}
}
}
//小鸟的旋转
auto curVelocity = birdSprite->getPhysicsBody()->getVelocity();
birdSprite->setRotation(-curVelocity.y*0.1 - 20); //根据竖直方向的速度算出旋转角度,逆时针为负
auto visibleSize = Director::getInstance()->getVisibleSize();
if (birdSprite->getPositionY() <= land1->getContentSize().height + BIRD_RADIUS )
{
birdSprite->stopAllActions(); //小鸟挂了就不能再扇翅了
birdSprite->setRotation(70); //设置为嘴朝下,顺时针70度旋转
birdSprite->getPhysicsBody()->setDynamic(false); //设置为不动了
SimpleAudioEngine::getInstance()->playEffect("die.mp3");
this->unscheduleUpdate(); //在小鸟掉到地面上再停止默认更新
gamePanelAppear(); //弹出记分牌
}
}
//加入记分板和重玩菜单
void GameScene::gamePanelAppear()
{
Size size = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
//用node将gameoverlogo和记分板绑在一起
Node *gameOverPanelNode = Node::create();
auto gameOverLabel = Sprite::createWithSpriteFrameName("gameover.png");
gameOverPanelNode->addChild(gameOverLabel);
auto panel = Sprite::createWithSpriteFrameName("board.PNG");//注意这里是大写PNG,原图片用什么后缀这里就用什么,区分大小写
gameOverLabel->setPositionY(panel->getContentSize().height); //设置一下坐标
gameOverPanelNode->addChild(panel);
//记分板上添加两个分数
auto curScoreTTF = LabelTTF::create(String::createWithFormat("%d", score)->getCString(), "Arial", 20);
curScoreTTF->setPosition(panel->getContentSize().width - 40, panel->getContentSize().height - 45);
curScoreTTF->setColor(Color3B(255, 0, 0));
panel->addChild(curScoreTTF);
auto bestScoreTTF = LabelTTF::create(String::createWithFormat("%d", bestScore)->getCString(), "Arial", 20);
bestScoreTTF->setPosition(panel->getContentSize().width - 40, panel->getContentSize().height - 90);
bestScoreTTF->setColor(Color3B(0, 255, 0));
panel->addChild(bestScoreTTF);
this->addChild(gameOverPanelNode);
gameOverPanelNode->setPosition(origin.x + size.width / 2, origin.y + size.height);
//滑入动画
gameOverPanelNode->runAction(MoveTo::create(0.5f, Vec2(origin.x + size.width / 2, origin.y + size.height / 2)));
SimpleAudioEngine::getInstance()->playEffect("swooshing.mp3");
//添加菜单
auto start_bt = Sprite::createWithSpriteFrameName("start_btn.png");
auto pressed_bt = Sprite::createWithSpriteFrameName("start_btn_pressed.png");
auto restartItem = MenuItemSprite::create(start_bt, pressed_bt,NULL,this, menu_selector(GameScene::gameRetart));//调用重新开启游戏函数
restartItem->setPosition(Vec2(size.width / 2 + origin.x,
size.height / 2 - 1.5* restartItem->getContentSize().height));
auto menu = CCMenu::createWithItem(restartItem);
menu->setPosition(Vec2::ZERO);
this->addChild(menu,10);
}
//游戏重新开始
void GameScene::gameRetart(Ref *sender)
{
//重新回到初始画面
auto gameScene = GameOver::createScene();//切换到GameOver场景
Director::getInstance()->replaceScene(gameScene);
}
#ifndef __GAMEOVER_H__
#define __GAMEOVER_H__
//#include "Box2D/Box2D.h"
#include "cocos2d.h"
USING_NS_CC;
class GameOver : public cocos2d::Layer
{
void scrollLand(float dt);
Sprite *land1;
Sprite *land2;
//b2World *world;
public:
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::Scene* createScene();
virtual void update(float delta);
void myupdate(float delta);
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// a selector callback
void menuReStartCallback(cocos2d::Ref* pSender);
void menuGameOverCallback(cocos2d::Ref* pSender);
//void scrollLand(float dt);
// implement the "static create()" method manually
CREATE_FUNC(GameOver);
};
#endif // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h"
#include "SceneOne.h"
#include "GameOver.h"
#include "GameScene.h"
USING_NS_CC;
Scene* GameOver::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = GameOver::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
bool GameOver::init()
{
if (!Layer::init())
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
auto label = Label::createWithTTF("GameOver_Scene", "fonts/Marker Felt.ttf", 24);
label->setPosition(Vec2(origin.x + visibleSize.width / 2,
origin.y + visibleSize.height - label->getContentSize().height));
//this->addChild(label);
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("game.plist");//使用plist文件来加载精灵帧
auto background = Sprite::createWithSpriteFrameName("bg.png");//使用精灵帧名字来初始化背景
background->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
this->addChild(background, 0);
auto gameoverSprite = Sprite::createWithSpriteFrameName("gameover.png");//设置gameover图标
gameoverSprite->setPosition(Vec2(visibleSize.width/2,2*visibleSize.height/3));
this->addChild(gameoverSprite, 1);
auto start_bt = Sprite::createWithSpriteFrameName("start_btn.png");//初始化两个按钮精灵
auto pressed_bt = Sprite::createWithSpriteFrameName("start_btn_pressed.png");
//设置菜单精灵,并调用重启游戏回调函数
auto reStartItem = MenuItemSprite::create(
start_bt,
pressed_bt,
CC_CALLBACK_1(GameOver::menuReStartCallback, this));
reStartItem->setPosition(Vec2(visibleSize.width / 2 + origin.x,
visibleSize.height / 2 - background->getPositionY() + 3 * reStartItem->getContentSize().height));
auto menu = Menu::create(reStartItem, NULL);//使用菜单精灵创建菜单
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 101);
auto GameOverlabel = Label::createWithTTF("EXIT", "fonts/arial.ttf", 24);//设置退出菜单,调用退出游戏回掉函数
auto gameOverItem = MenuItemLabel::create(GameOverlabel,CC_CALLBACK_1(GameOver::menuGameOverCallback,this));
gameOverItem->setPosition(Vec2(visibleSize.width / 2 + origin.x,
visibleSize.height / 2 - background->getPositionY() + 4 * gameOverItem->getContentSize().height));
auto gameovermenu = Menu::create(gameOverItem, NULL);
gameovermenu->setPosition(Vec2::ZERO);
this->addChild(gameovermenu, 101);
return true;
}
void GameOver::menuReStartCallback(Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.", "Alert");
return;
#endif
auto scene = GameScene::createScene();//初始化游戏场景
auto transition = TransitionFade::create(1, scene);
// run
Director::getInstance()->replaceScene(transition);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
void GameOver::menuGameOverCallback(cocos2d::Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.", "Alert");
return;
#endif
Director::getInstance()->end();//直接退出
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
void GameOver::scrollLand(float dt)
{
this->land1->setPositionX(this->land1->getPositionX() - 2.0f);
this->land2->setPositionX(this->land1->getPositionX() + this->land1->getContentSize().width - 2.0f);
if (this->land2->getPositionX() == 0) {
this->land1->setPositionX(0);
}
}
void GameOver::update(float delta)
{
int posLand1 = land1->getPositionX();
int posLand2 = land2->getPositionX();
int speed = 1;
posLand1 -= speed;
posLand2 -= speed;
auto landsize = land2->getContentSize();
if (posLand1 < -landsize.width / 2 + 142)
{
posLand2 = landsize.width / 2;
posLand1 = landsize.width + landsize.width / 2;
}
if (posLand2 < -landsize.width / 2 + 142)
{
posLand1 = landsize.width / 2;
posLand2 = landsize.width + landsize.width / 2;
}
land1->setPositionX(posLand1);
land2->setPositionX(posLand2);
}
void GameOver::myupdate(float delta)
{
int posLand1 = land1->getPositionX();
int posLand2 = land2->getPositionX();
int speed = 1;
posLand1 -= speed;
posLand2 -= speed;
auto landsize = land2->getContentSize();
if (posLand1 < -landsize.width / 2 + 142)
{
posLand2 = landsize.width / 2;
posLand1 = landsize.width + landsize.width / 2;
}
if (posLand2 < -landsize.width / 2 + 142)
{
posLand1 = landsize.width / 2;
posLand2 = landsize.width + landsize.width / 2;
}
land1->setPositionX(posLand1);
land2->setPositionX(posLand2);
}
参考博文:http://blog.csdn.net/u012234115/article/details/40487557
APK下载地址:https://github.com/Tingmaobaobei/Fly_Bird-1/blob/22d3739f0c635548f3e51848e674424d8f01a58d/bin/debug/android/happybird-debug.apk;
源码下载地址:https://github.com/Tingmaobeobei/Fly_Bird/commit/22d3739f0c635548f3e51848e674424d8f01a58d
图片资源下载地址:https://github.com/Tingmaobeobei/Fly_Bird/commit/cbc061673883db1824d5bec76753b8eaa9150039