《flappy bird》是由来自越南的独立游戏开发者Dong Nguyen所开发的作品,游戏中玩家必须控制一只小鸟,跨越由各种不同长度水管所组成的障碍,而这只鸟其实是根本不会飞的……所以玩家每点击一下小鸟就会飞高一点,不点击就会下降,玩家必须控制节奏,拿捏点击屏幕的时间点,让小鸟能在落下的瞬间跳起来,恰好能够通过狭窄的水管缝隙,只要稍一分神,马上就会失败阵亡。
图片资源提取后使用PS5 处理,Zwoptex 重新打包。
======================================================================================
开发环境:
Cocos2d-x cocos2d-x-2.2.1
MacBook Pro 13' 10.9
Xcode 5.0.2
iPhone5 IOS 7.0.4
======================================================================================
一、效果图
二、小鸟的实现
//
// Bird.h
// Flappy
//
// Created by yuzai on 14-2-12.
//
//
#ifndef __Flappy__Bird__
#define __Flappy__Bird__
#include "cocos2d.h"
#include "Box2D/Box2D.h"
using namespace cocos2d;
class Bird:public cocos2d::CCNode
{
public:
Bird(void);
virtual ~Bird(void);
virtual void onEnter();
virtual void onExit();
CREATE_FUNC(Bird);
b2Body* m_pBody;//物理
private:
CCSprite *body;
};
#endif /* defined(__Flappy__Bird__) */
三、物理世界搭建
//
// GameLayer.h
// Flappy
//
// Created by yuzai on 14-2-12.
//
//
#ifndef __Flappy__GameLayer__
#define __Flappy__GameLayer__
#include "cocos2d.h"
#include "Box2D.h"
#include "Bird.h"
using namespace cocos2d;
class GameLayer:public cocos2d::CCLayer
{
public:
GameLayer(void);
~GameLayer(void);
//背景
CCSprite *bg;
//路
CCSprite *land1;
CCSprite *land2;
//水管
CCSprite *pipe1;
CCSprite *pipe2;
CCSprite *pipe3;
CCSprite *pipe4;
Bird *bird;
void setBackgroud(unsigned int bg);
CREATE_FUNC(GameLayer);
virtual bool init();
virtual void update(float time);
void initPhysics();
private:
b2World* world;//定义物理世界
b2BodyDef groundBodyDef;//定义物体(世界的)
};
#endif /* defined(__Flappy__GameLayer__) */
//
// GameLayer.cpp
// Flappy
//
// Created by yuzai on 14-2-12.
//
//
#include "GameLayer.h"
#define PTM_RATIO 32.0 //设定每32像素为一米
GameLayer::GameLayer(void)
{
}
GameLayer::~GameLayer(void)
{
CC_SAFE_DELETE(world);
}
bool GameLayer::init()
{
if (!CCLayer::init())
{
return false;
}
//屏幕宽高比 首先 适配IPHONE5
CCSize frameSize = CCEGLView::sharedOpenGLView()->getFrameSize();
float scales = (float) frameSize.width/ 288;
CCSize winSize=CCDirector::sharedDirector()->getWinSize();
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("res/default.plist");
CCSpriteFrame *bg1Frame=CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("bg_day.png");
bg=CCSprite::create();
bg->setAnchorPoint(ccp(0, 0));
bg->setDisplayFrame(bg1Frame);
bg->setScale(scales);
bg->setPosition(ccp(0,0));
addChild(bg);
//2.陆地
CCSpriteFrame *landFrame=CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("land.png");
land1=CCSprite::create();
land1->setAnchorPoint(ccp(0, 0));
land1->setDisplayFrame(landFrame);
land1->setScale(scales);
land1->setPosition(ccp(0, 0));
addChild(land1,1);
land2=CCSprite::create();
land2->setAnchorPoint(ccp(0, 0));
land2->setDisplayFrame(landFrame);
land2->setScale(scales);
land2->setPosition(ccp(frameSize.width, 0));
addChild(land2,1);
//3.添加小鸟
bird=new Bird();
bird->setPosition(winSize.width/2,winSize.height/2);
bird->setScale(scales);
addChild(bird,2);
//4.水管
//5.物理世界
this->initPhysics();
// Define the dynamic body.
//Set up a 1m squared box in the physics world
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;//小鸟是运动的 所有设置为动态刚体
bodyDef.position.Set(bird->getPositionX()/PTM_RATIO,bird->getPositionY()/PTM_RATIO);//转化真实世界坐标 Pix/PTM_RATIO
bodyDef.userData=bird;
bird->m_pBody=world->CreateBody(&bodyDef);
// Define another box shape for our dynamic body.
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(0.5f,0.5f);//These are mid points for our 1m box
// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
fixtureDef.restitution=0.8f;
bird->m_pBody->CreateFixture(&fixtureDef);
scheduleUpdate();
return true;
}
//改变背景
void GameLayer::setBackgroud(unsigned int bg)
{
switch (bg) {
case 1:
{
}
break;
default:
break;
}
}
void GameLayer::update(float time){
//land移动逻辑
CCSize frameSize = CCEGLView::sharedOpenGLView()->getFrameSize();
float dif=4;
land1->setPosition(ccp(land1->getPositionX()-dif,land1->getPositionY()));
land2->setPosition(ccp(land2->getPositionX()-dif,land2->getPositionY()));
if (land2->getPositionX()<0) {
float temp=land2->getPositionX()+frameSize.width;
land1->setPosition(ccp(temp,land2->getPositionY()));
}
if (land1->getPositionX()<0) {
float temp=land1->getPositionX()+frameSize.width;
land2->setPosition(ccp(temp,land1->getPositionY()));
}
float32 timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;
world->Step(timeStep, velocityIterations, positionIterations);
b2Vec2 position = bird->m_pBody->GetPosition();
float32 angle = bird->m_pBody->GetAngle();
for (b2Body *body=world->GetBodyList(); body!=NULL; body=body->GetNext()) {
Bird *bir=(Bird*)body->GetUserData();
if (bir!=NULL) {
bir->setPosition(ccp(position.x*PTM_RATIO, position.y*PTM_RATIO));
bir->setRotation(CC_RADIANS_TO_DEGREES(body->GetAngle())*-1);
}
}
printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle);
}
//初始化物理引擎的方法
void GameLayer::initPhysics()
{
//0.屏幕大小
CCSize winSize=CCDirector::sharedDirector()->getWinSize();
//1.重力向量
b2Vec2 gravity=b2Vec2(0.0f, -10.0f);//模拟真实世界
world = new b2World(gravity);
//2.设置是否持续物理模拟
world->SetAllowSleeping(true);
world->SetContinuousPhysics(true);
//3.设置世界盒子的位置
// Define the ground body. 定义 边缘刚体
groundBodyDef.position.Set(0,0); // bottom-left corner
// Call the body factory which allocates memory for the ground body
// from a pool and creates the ground box shape (also from a pool).
// The body is also added to the world.
//所有的b2Body都由b2World示例创建
b2Body* groundBody = world->CreateBody(&groundBodyDef);
// Define the ground box shape.//创建边缘刚体
b2PolygonShape groundBox;
b2FixtureDef boxShapeBox;
boxShapeBox.shape=&groundBox;
//屏幕宽高比 首先 适配IPHONE5
CCSize frameSize = CCEGLView::sharedOpenGLView()->getFrameSize();
float scales = (float) frameSize.width/ 288;
//定义物体边界
// bottom 112*scales 设置的是地面的高度
groundBox.SetAsBox(winSize.width/PTM_RATIO,112*scales/PTM_RATIO, b2Vec2(0, 0), 0);
groundBody->CreateFixture(&groundBox,0);
// top
groundBox.SetAsBox(winSize.width/PTM_RATIO, 0, b2Vec2(0, winSize.height/PTM_RATIO), 0);
groundBody->CreateFixture(&groundBox,0);
// left
groundBox.SetAsBox(0, winSize.height/PTM_RATIO, b2Vec2(0, 0), 0);
groundBody->CreateFixture(&groundBox,0);
// right
groundBox.SetAsBox(0, winSize.height/PTM_RATIO, b2Vec2(winSize.width/PTM_RATIO, 0), 0);
groundBody->CreateFixture(&groundBox,0);
}
注:代码迭代随时有变动