Cocos2d-x3.5 设计Fly_bird(飞行的小鸟)并打包成APK文件

这个小的游戏代码可以使我们理解常见的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));
	panel->addChild(curscoreTTF);
	auto bestscoreTTF = LabelTTF::create(String::createWithFormat("%d",bestscore)->getCString(),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,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);  
	 
}



最后是GameOver场景,可以退出游戏或者继续游戏:


#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",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,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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


    本文实践自 RayWenderlich、Ali Hafizji 的文章《How To Create Dynamic Textures with CCRenderTexture in Cocos2D 2.X》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.1.4进行学习和移植。在这篇文章,将会学习到如何创建实时纹理、如何用Gimp创建无缝拼接纹
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@163.com微信公众号:HopToad 欢迎转载,转载标注出处:http://blog.csdn.netotbaron/article/details/424343991.  软件准备 下载地址:http://cn.cocos2d-x.org/download 2.  简介2.1         引用C
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从Cocos2D-x官网上下载,进入网页http://www.cocos2d-x.org/download,点击Cocos2d-x以下的Download  v3.0,保存到自定义的文件夹2:从python官网上下载。进入网页https://www.python.org/downloads/,我当前下载的是3.4.0(当前最新
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发引擎,易学易用,支持多种智能移动平台。官网地址:http://cocos2d-x.org/当前版本:2.0    有很多的学习资料,在这里我只做为自己的笔记记录下来,错误之处还请指出。在VisualStudio2008平台的编译:1.下载当前稳
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《最强大脑》娱乐节目。将2048改造成一款挑战玩家对数字记忆的小游戏。邮箱:appdevzw@163.com微信公众号:HopToadAPK下载地址:http://download.csdn.net/detailotbaron/8446223源码下载地址:http://download.csdn.net/
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试以QtCreatorIDE来进行CMake构建。Cocos2d-x3.X地址:https://github.com/cocos2d/cocos2d-x1.打开QtCreator,菜单栏→"打开文件或项目...",打开cocos2d-x目录下的CMakeLists.txt文件;2.弹出CMake向导,如下图所示:设置
 下载地址:链接:https://pan.baidu.com/s/1IkQsMU6NoERAAQLcCUMcXQ提取码:p1pb下载完成后,解压进入build目录使用vs2013打开工程设置平台工具集,打开设置界面设置: 点击开始编译等待编译结束编译成功在build文件下会出现一个新文件夹Debug.win32,里面就是编译
分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net前言上次用象棋演示了cocos2dx的基本用法,但是对cocos2dx并没有作深入的讨论,这次以超级马里奥的源代码为线索,我们一起来学习超级马里奥的实
1. 圆形音量button事实上作者的本意应该是叫做“电位计button”。可是我觉得它和我们的圆形音量button非常像,所以就这么叫它吧~先看效果:好了,不多解释,本篇到此为止。(旁白: 噗。就这样结束了?)啊才怪~我们来看看代码:[cpp] viewplaincopyprint?CCContro
原文链接:http://www.cnblogs.com/physwf/archive/2013/04/26/3043912.html为了进一步深入学习贯彻Cocos2d,我们将自己写一个场景类,但我们不会走的太远,凡是都要循序渐进,哪怕只前进一点点,那也至少是前进了,总比贪多嚼不烂一头雾水的好。在上一节中我们建
2019独角兽企业重金招聘Python工程师标准>>>cocos2d2.0之后加入了一种九宫格的实现,主要作用是用来拉伸图片,这样的好处在于保留图片四个角不变形的同时,对图片中间部分进行拉伸,来满足一些控件的自适应(PS: 比如包括按钮,对话框,最直观的形象就是ios里的短信气泡了),这就要求图
原文链接:http://www.cnblogs.com/linji/p/3599478.html1.环境和工具准备Win7VS2010/2012,至于2008v2版本之后似乎就不支持了。 2.安装pythonv.2.0版本之前是用vs模板创建工程的,到vs2.2之后就改用python创建了。到python官网下载版本2.7.5的,然后
环境:ubuntu14.04adt-bundle-linux-x86_64android-ndk-r9d-linux-x86_64cocos2d-x-3.0正式版apache-ant1.9.3python2.7(ubuntu自带)加入环境变量exportANDROID_SDK_ROOT=/home/yangming/adt-bundle-linux/sdkexportPATH=${PATH}:/$ANDROID_SDK_ROOTools/export
1开发背景游戏程序设计涉及了学科中的各个方面,鉴于目的在于学习与进步,本游戏《FlappyBird》采用了两个不同的开发方式来开发本款游戏,一类直接采用win32底层API来实现,另一类采用当前火热的cocos2d-x游戏引擎来开发本游戏。2需求分析2.1数据分析本项目要开发的是一款游
原文链接:http://www.cnblogs.com/linji/p/3599912.html//纯色色块控件(锚点默认左下角)CCLayerColor*ccc=CCLayerColor::create(ccc4(255,0,0,128),200,100);//渐变色块控件CCLayerGradient*ccc=CCLayerGradient::create(ccc4(255,0,0,
原文链接:http://www.cnblogs.com/linji/p/3599488.html//载入一张图片CCSprite*leftDoor=CCSprite::create("loading/door.png");leftDoor->setAnchorPoint(ccp(1,0.5));//设置锚点为右边中心点leftDoor->setPosition(ccp(240,160));/
为了答谢广大学员对智捷课堂以及关老师的支持,现购买51CTO学院关老师的Cocos2d-x课程之一可以送智捷课堂编写图书一本(专题可以送3本)。一、Cocos2d-x课程列表:1、Cocos2d-x入门与提高视频教程__Part22、Cocos2d-x数据持久化与网络通信__Part33、Cocos2d-x架构设计与性能优化内存优
Spawn让多个action同时执行。Spawn有多种不同的create方法,最终都调用了createWithTwoActions(FiniteTimeAction*action1,FiniteTimeAction*action2)方法。createWithTwoActions调用initWithTwoActions方法:对两个action变量初始化:_one=action1;_two=action2;如果两个a
需要环境:php,luajit.昨天在cygwin上安装php和luajit环境,这真特么是一个坑。建议不要用虚拟环境安装打包环境,否则可能会出现各种莫名问题。折腾了一下午,最终将环境转向linux。其中,luajit的安装脚本已经在quick-cocos2d-x-develop/bin/中,直接luajit_install.sh即可。我的lin
v3.0相对v2.2来说,最引人注意的。应该是对触摸层级的优化。和lambda回调函数的引入(嗯嗯,不枉我改了那么多类名。话说,每次cocos2dx大更新。总要改掉一堆类名函数名)。这些特性应该有不少人研究了,所以今天说点跟图片有关的东西。v3.0在载入图片方面也有了非常大改变,仅仅只是