| 版权声明:本文为博主原创文章,未经博主允许不得转载。
这个是游戏的核心部分:(FlyBird游戏重中之重)
- 创建一个物理世界(世界设置重力加速度)
- 在物理世界中添加一个动态的刚体(小鸟)
- 在物理世界中添加一个静态的刚体(地板)和一个顶部边界(Edge)
- 在物理世界中添加一对浮动的刚体(Pipe),并设置线速度
- 设置每次点击屏幕小鸟上升的加速度
- 碰撞检测,判断游戏是否结束
下面贴上代码:
GamePlay.h
#ifndef _GAME_PLAY_H_ #define _GAME_PLAY_H_ #define PTM_RATIO 32 #include "cocos2d.h" #include "Box2DBox2D.h" #include "SimpleAudioEngine.h" //背景音乐平台控制 #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) #define MUSIC_FILE "music/background.wav" #elif (CC_TARGET_PLATFORM == CC_PLATFORM_BLACKBERRY || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX) #define MUSIC_FILE "music/background.ogg" #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) #define MUSIC_FILE "music/background.caf" #else #define MUSIC_FILE "music/background.mp3" #endif // CC_PLATFOR_WIN32 USING_NS_CC; using namespace CocosDenshion; class GamePlay : public cocos2d::Layer, public b2ContactListener { private: cocos2d::Sprite* backgroundA; cocos2d::Sprite* backgroundB; cocos2d::Sprite* ready; cocos2d::Sprite* tutorial; cocos2d::Sprite* bird; cocos2d::Sprite* land; cocos2d::Sprite* num; cocos2d::Sprite* upPipe; cocos2d::Sprite* downPipe; cocos2d::Sprite* pipeContainer; cocos2d::Sprite* model; cocos2d::Sprite* gameEnd; cocos2d::LabelTTF* score; cocos2d::LabelTTF* best; cocos2d::MenuItemImage* play; cocos2d::MenuItemImage* exit; b2World* world; b2Body* birdBody; b2Body* landBody; b2Body* downBody; b2Body* upBody; int bestScore; int times = 0; private: void replaceBackground(int); void tipInformation(); void addBird(); void addLand(); void addPipe(float dt); void gameBegin(float dt); void gameOver(); void timeAnimate(); void upperBoundary(); //int birdSelect(float); public: static cocos2d::Scene* createScene(); virtual bool init(); void initPhysicsWorld(); virtual void update(float); /// Called when two fixtures begin to touch. virtual void BeginContact(b2Contact* contact); /** Callback function for multiple touches began. * * @param touches Touches information. * @param unused_event Event information. * @js NA */ virtual void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event); void goPlay(cocos2d::Ref* pSender); void goExit(); CREATE_FUNC(GamePlay); }; #endif // _GAME_PLAY_H_
GamePlay.cpp
#include "GamePlay.h" #include "GameUnit.h" #include "GameData.h" unit u3; cocos2d::Scene* GamePlay::createScene() { auto scene = Scene::create(); auto layer = GamePlay::create(); scene->addChild(layer); return scene; } bool GamePlay::init() { if (!Layer::init()) { return false; } SimpleAudioEngine::getInstance()->playBackgroundMusic(MUSIC_FILE, true); this->initPhysicsWorld(); this->replaceBackground(1); this->tipInformation(); this->upperBoundary(); this->addLand(); this->addBird(); this->timeAnimate(); //this->addPipe(); //设置多点触屏事件的监听器 auto listener = EventListenerTouchAllAtOnce::create(); listener->onTouchesBegan = CC_CALLBACK_2(GamePlay::onTouchesBegan, this); //注册监听器 _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); //设置物理世界监听 world->SetContactListener(this); scheduleOnce(schedule_selector(GamePlay::gameBegin), 3); //scheduleUpdate(); return true; } void GamePlay::initPhysicsWorld() { //设置重力加速度为9.8;方向向下 b2Vec2 gravity; gravity.Set(0.0f, -9.8f); //创建一个新的物理世界 world = new b2World(gravity); //设置是否允许物体休眠 world->SetAllowSleeping(true); //连续物理测试,防止发生非子弹特性的物体发生穿透现象 world->SetContinuousPhysics(true); } void GamePlay::timeAnimate() { num = Sprite::create("bird/n1.png"); num->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 2, u3.winOrigin().y + (4 * u3.winSize().height) / 5)); num->setScale(2); auto repeat = Repeat::create(Animate::create(u3.gameAnimate(4)), 1); num->runAction(repeat); this->addChild(num, 1); } void GamePlay::replaceBackground(int flag) { switch (flag) { case 1: backgroundA = Sprite::create("background/light.png"); backgroundA->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 2, u3.winOrigin().y + u3.winSize().height / 2)); backgroundA->setScale(u3.scaleX(backgroundA, u3.winSize()), u3.scaleY(backgroundA, u3.winSize())); this->addChild(backgroundA, 0); break; case 2: backgroundB = Sprite::create("background/night.png"); backgroundB->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 2, u3.winOrigin().y + u3.winSize().height / 2)); backgroundB->setScale(u3.scaleX(backgroundB, u3.winSize()), u3.scaleY(backgroundB, u3.winSize())); this->addChild(backgroundB, 0); break; default: break; } } void GamePlay::tipInformation() { ready = Sprite::create("logo/text_ready.png"); ready->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 2, u3.winOrigin().y + u3.winSize().height - 3*ready->getContentSize().height)); ready->setScale(2); this->addChild(ready, 1); tutorial = Sprite::create("logo/tutorial.png"); tutorial->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 2, u3.winOrigin().y + u3.winSize().height / 2)); tutorial->setScale(2); this->addChild(tutorial, 1); //exit exit = MenuItemImage::create( "button/exit_f.png", "button/exit_b.png", CC_CALLBACK_0(GamePlay::goExit, this) ); Menu* menu = Menu::create(exit, NULL); menu->setPosition(Vec2(u3.winOrigin().x + exit->getContentSize().width / 2, u3.winOrigin().y + exit->getContentSize().height / 2)); this->addChild(menu, 7); } void GamePlay::addBird() { bird = Sprite::create("bird/littleBird.png"); bird->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 3, u3.winOrigin().y + u3.winSize().height - 5 * (ready->getContentSize().height))); bird->setScale(1.5); auto repeat = RepeatForever::create(Animate::create(u3.gameAnimate(1))); bird->runAction(repeat); this->addChild(bird, 1); //创建刚体 b2BodyDef birdBodyDef; birdBodyDef.type = b2_dynamicBody; birdBodyDef.position.Set(bird->getPosition().x / PTM_RATIO, bird->getPosition().y / PTM_RATIO); //将刚体,精灵与世界关联起来 birdBody = world->CreateBody(&birdBodyDef); birdBody->SetUserData(bird); //定义一个盒子 b2PolygonShape birdBox; birdBox.SetAsBox(bird->getContentSize().width / 3 / PTM_RATIO, bird->getContentSize().height / 3 / PTM_RATIO); //夹具 b2FixtureDef fixtureDef; //设置夹具的形状 fixtureDef.shape = &birdBox; birdBody->CreateFixture(&fixtureDef); } void GamePlay::update(float dt) { world->Step(dt, 8, 3); for (b2Body* bb = world->GetBodyList(); bb; bb = bb->GetNext()) { if (bb->GetUserData() != nullptr) { Sprite* sprite = (Sprite*)bb->GetUserData(); //设置精灵的当前的位置,通过取得精灵的位置乘上相应的像素,这里的PTM_RATIO为32个像素为1m,就可以判断出精灵的位置处于物理世界的何处 sprite->setPosition(Vec2(bb->GetPosition().x*PTM_RATIO, bb->GetPosition().y*PTM_RATIO)); //设置精灵的角度偏转 sprite->setRotation(0); } } } void GamePlay::onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event) { birdBody->SetLinearVelocity(b2Vec2(0, 5)); //birdBody->SetLinearVelocity(b2Vec2(1, 5)); } //添加地面 void GamePlay::addLand() { //地板也是物理世界的一个刚体,是一个静态的刚体 land = Sprite::create("background/land.png"); land->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 2, u3.winOrigin().y + land->getContentSize().height / 2)); land->setScaleX(u3.winSize().width / 1.5*land->getContentSize().width); land->setScaleY(u3.winSize().height / (land->getContentSize().height * 3)); this->addChild(land, 4); //创建刚体 b2BodyDef landBodyDef; landBodyDef.type = b2_staticBody; landBodyDef.position.Set(u3.winSize().width / 2 / PTM_RATIO, land->getPosition().y / PTM_RATIO); landBody = world->CreateBody(&landBodyDef); landBody->SetUserData(land); b2PolygonShape landShape; landShape.SetAsBox(u3.winSize().width / 2 / PTM_RATIO, backgroundA->getContentSize().height / 2 / PTM_RATIO); //1.4*land->getContentSize().height / PTM_RATIO b2FixtureDef landFixtureDef; landFixtureDef.shape = &landShape; landBody->CreateFixture(&landFixtureDef); } void GamePlay::upperBoundary() { b2BodyDef upperBodyDef; //左下角 upperBodyDef.position.Set(0, 0); //创建地面物体 b2Body* upperBody = world->CreateBody(&upperBodyDef); //定义一个有边的形状 b2EdgeShape upperBox; //顶部边界线 upperBox.Set(b2Vec2(0, u3.winSize().height / PTM_RATIO), b2Vec2(u3.winSize().width / PTM_RATIO, u3.winSize().height / PTM_RATIO)); upperBody->CreateFixture(&upperBox, 0); } void GamePlay::addPipe(float dt) { times++; float randPipe = -rand() % 3; //down bar downPipe = Sprite::create("pipe/down.png"); downPipe->setScaleY(u3.winSize().height / (downPipe->getContentSize().height*1.5)); this->addChild(downPipe, 3); b2BodyDef downBodyDef; downBodyDef.position = b2Vec2(u3.winSize().width / PTM_RATIO + 2, downPipe->getContentSize().height / 2 / PTM_RATIO + randPipe); // + land->getContentSize().height / PTM_RATIO downBodyDef.type = b2_kinematicBody; //修改速度可以提升游戏的难度 downBodyDef.linearVelocity = b2Vec2(-2, 0); downBody = world->CreateBody(&downBodyDef); downBody->SetUserData(downPipe); b2PolygonShape downShape; downShape.SetAsBox(downPipe->getContentSize().width / 2 / PTM_RATIO, 1.6*downPipe->getContentSize().height / PTM_RATIO); b2FixtureDef downPipeFixture; downPipeFixture.shape = &downShape; downBody->CreateFixture(&downPipeFixture); upPipe = Sprite::create("pipe/upPipe.png"); upPipe->setScaleY(u3.winSize().height / (upPipe->getContentSize().height*1.5)); this->addChild(upPipe, 3); b2BodyDef upBodyDef; upBodyDef.position = b2Vec2(u3.winSize().width / PTM_RATIO + 2, downPipe->getContentSize().height / PTM_RATIO + randPipe + 3 +2*upPipe->getContentSize().height / PTM_RATIO); // upBodyDef.type = b2_kinematicBody; //修改速度可以提升游戏的难度 upBodyDef.linearVelocity = b2Vec2(-2, 0); upBody = world->CreateBody(&upBodyDef); upBody->SetUserData(upPipe); b2PolygonShape upShape; upShape.SetAsBox(upPipe->getContentSize().width / 2 / PTM_RATIO, 1.6*upPipe->getContentSize().height / PTM_RATIO); b2FixtureDef upPipeFixture; upPipeFixture.shape = &upShape; upBody->CreateFixture(&upPipeFixture); } void GamePlay::gameOver() { //显示Game Over的Logo gameEnd = Sprite::create("logo/gameOver.png"); gameEnd->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 2, u3.winOrigin().y + u3.winSize().height - 3*gameEnd->getContentSize().height)); gameEnd->setScale(2); this->addChild(gameEnd, 5); //显示奖章牌 model = Sprite::create("logo/score_panel.png"); model->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 2, u3.winOrigin().y + u3.winSize().height / 2)); model->setScale(u3.winSize().width / 1.5 / model->getContentSize().width, u3.winSize().height / 4.5 / model->getContentSize().height); this->addChild(model, 5); //奖章 Sprite* award = Sprite::create("logo/medals1.png"); award->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 2 - model->getContentSize().width*0.6, u3.winOrigin().y + u3.winSize().height / 2)); award->setScale(3); this->addChild(award, 6); //显示成绩 score = LabelTTF::create("0", "Arial", 16); score->setPosition(Vec2(u3.winOrigin().x + (u3.winSize().width / 3) * 2, u3.winOrigin().y + u3.winSize().height / 2 + award->getContentSize().height)); this->addChild(score, 7); //设置字体的颜色为黑色,并将成绩显示在panel面板上 score->setColor(Color3B(0, 0, 0)); score->setString(__String::createWithFormat("%5d", times - 1)->getCString()); bestScore = GameData::getGameData(); best = LabelTTF::create("0", "Arial", 16); best->setPosition(Vec2(u3.winOrigin().x + (u3.winSize().width / 3) * 2, u3.winOrigin().y + u3.winSize().height / 2 - 1.5*award->getContentSize().height)); this->addChild(best, 7); best->setColor(Color3B(0, 0, 0)); best->setString(__String::createWithFormat("%5d", bestScore - 1)->getCString()); GameData::keepGameData(times); unscheduleUpdate(); unschedule(schedule_selector(GamePlay::addPipe)); } void GamePlay::gameBegin(float dt) { ready->setVisible(false); tutorial->setVisible(false); num->setVisible(false); scheduleUpdate(); //修改时间可以提升游戏的难易程度 schedule(schedule_selector(GamePlay::addPipe), 2); } void GamePlay::BeginContact(b2Contact* contact) { if (contact->GetFixtureA()->GetBody() == birdBody || contact->GetFixtureB()->GetBody() == birdBody) { this->gameOver(); play = MenuItemImage::create( "button/play.png", "button/play.png", CC_CALLBACK_1(GamePlay::goPlay, this) ); play->setPosition(Vec2(u3.winOrigin().x + u3.winSize().width / 2, u3.winOrigin().y + u3.winSize().height / 3)); Menu* menu = Menu::create(play, NULL); menu->setPosition(Vec2::ZERO); menu->setScale(1.5); this->addChild(menu, 6); } } void GamePlay::goPlay(cocos2d::Ref* pSender) { times = 0; Director::getInstance()->replaceScene(TransitionFadeTR::create(1, GamePlay::createScene())); } void GamePlay::goExit() { times = 0; unscheduleUpdate(); unschedule(schedule_selector(GamePlay::addPipe)); Director::getInstance()->end(); }
函数功能详见:http://www.cnblogs.com/geore/p/5800009.html
效果图: