Cocos2d 之FlyBird开发---GamePlay类

|   版权声明:本文为博主原创文章,未经博主允许不得转载。

这个是游戏的核心部分:(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

效果图:

  

原文地址:https://www.cnblogs.com/geore/p/5800131.html