zoukankan      html  css  js  c++  java
  • Cocos2d-x 2.3.3版本 FlappyBird

    Cocos2d-x 2.3.3版本 FlappyBird


      本篇博客基于Cocos2d-x 2.3.3, 介绍怎样开发一款之前非常火的一款游戏FlappyBird。本篇博客内容大纲例如以下:
      1. 怎样创建Cocos2d-x 2.3.3 项目
      2. 初始化Box2d物理世界,并模拟物理世界
      3. 怎样加入小鸟到物理世界
      4. 怎样加入地板
      5. 加入水管
      6. 碰撞检測
      7. 本文总结

    效果图:

    1. 怎样创建Cocos2d-x 2.3.3

    本篇博客是基于Cocos2d-x 2.3.3,刚開始学习的人能够选择这个版本号学习,也能够从3.x版本号学习。但版本号差异较大。

    用命令行进入文件夹D:cocos2d-x-2.2.3 oolsproject-creator,敲入下面命令创建项目:
    python create_project.py -project FlappyBirdCpp -package com.wwj.flappybird -language cpp
    创建了名为FlappyBirdCpp的Cocos2d-x项目。包名为com.wwj.flappybird,开发语言为c++


    2. 初始化Box2d物理世界,并模拟物理世界

    Cocos2d-x使用了Box2d物理引擎来模拟物理世界,它还支持Chipmunk物理引擎。这里我们使用Box2d来为我们创建一个看似比較真实的世界。

    // -10表示重力加速度方向为向下
    	world = new b2World(b2Vec2(0, -10));


    // 模拟物理世界
    	// Box2D建议的迭代次数是速度阶段8次,位置阶段3次
    	world->Step(dt, 8, 3);

    3. 怎样加入小鸟到物理世界

    小鸟在Cocos2d-x就是一个Sprite(精灵),我们知道精灵是须要加入到层其中的。我们还要设置我们小鸟在物理世界的刚体。

    关于Box2d相关的概念。笔者在这里不具体说,读者能够自己找百度老师。学习很多其它关于Box2d的知识。

    我们定义下面方法:
    /**
    * 加入小鸟
    *
    */
    void HelloWorld::addBird()
    {
    	// 创建小鸟
    	bird = B2Sprite::create("bird.png");
    	// 获取内容大小
    	CCSize size = bird->getContentSize();
    
    	// 刚体属性
    	b2BodyDef bodyDef;
    	// 动态刚体
    	bodyDef.type = b2_dynamicBody;
    	// 设置初始位置
    	bodyDef.position = b2Vec2(screenSize.width/2/RATIO, screenSize.height/2/RATIO);
    	// 创建一个小鸟刚体
    	b2Body *birdBody = world->CreateBody(&bodyDef);
    
    	// 隐形形状
    	b2PolygonShape birdShape;
    	// 设置为盒子。參数为内容的半宽半高
    	birdShape.SetAsBox(size.width/2/RATIO, size.height/2/RATIO);
    
    	// 材料属性
    	b2FixtureDef birdFixtureDef;
    	// 形状
    	birdFixtureDef.shape = &birdShape;
    	// 加入地表物体
    	birdBody->CreateFixture(&birdFixtureDef);
    
    	// 设置度量比例
    	bird->setPTMRatio(RATIO);
    	// 设置小鸟刚体
    	bird->setB2Body(birdBody);
    	// 加入小鸟到层中
    	addChild(bird);
    
    }


    4. 怎样加入地板

    地板跟小鸟也是相似的。仅仅是设置地板刚体的类型为静态的。由于它相对精巧的也不受重力影响。

    /**
    * 加入地板
    */
    void HelloWorld::addGround()
    {
    	// 地板精灵
    	B2Sprite *ground = B2Sprite::create("ground.png");
    	// 得到地板内容的大小
    	CCSize size = ground->getContentSize();
    
    	// 用于初始化刚体在物理世界的一些属性。比方位置,类型
    	b2BodyDef bDef;
    	// 静态的刚体
    	bDef.type = b2_staticBody;
    	// 设置位置
    	bDef.position = b2Vec2(size.width/2/RATIO, size.height/2/RATIO);
    	// 创建刚体
    	b2Body *groundBody = world->CreateBody(&bDef);
    
    	// 形状
    	b2PolygonShape groundShape;
    	// 设置为矩形
    	groundShape.SetAsBox(size.width/2/RATIO, size.height/2/RATIO);
    	// 材料定制器
    	b2FixtureDef groundFixtureDef;
    	// 设置形状
    	groundFixtureDef.shape = &groundShape;
    	// 创建定制器
    	groundBody->CreateFixture(&groundFixtureDef);
    	// 为精灵设置刚体
    	ground->setB2Body(groundBody);
    	// 设置度量比例
    	ground->setPTMRatio(RATIO);
    	// 加入地板到层其中
    	addChild(ground);
    
    }

    5. 加入水管

    我们玩FlappyBird的时候,会知道水管高低不同,然后是从右往左运动的,这就须要我们随机设置上下两根水管的位置了,而且不停的加入水管。

    / 加入运动的水管
    void HelloWorld::addBar(float dt) {
    	// 随机生成偏移量
    	float offset = -rand() %5;
    
    	// 创建向下水管的精灵
    	B2Sprite *down_bar = B2Sprite::create("down_bar.png");
    	// 得到水管的大小
    	CCSize down_bar_size = down_bar->getContentSize();
    
    	// 下水管
    	b2BodyDef down_bar_body_def;
    	// 运动学物体,但不受重力影响
    	down_bar_body_def.type = b2_kinematicBody;
    	// 设置下水管的位置
    	down_bar_body_def.position = b2Vec2(screenSize.width/RATIO + 2, down_bar_size.height/RATIO/2 +offset);
    	// 线性速度,从右往左移动
    	down_bar_body_def.linearVelocity = b2Vec2(-5,0);
    	// 创建刚体
    	b2Body *down_bar_body = world->CreateBody(&down_bar_body_def);
    
    	// 隐形形状
    	b2PolygonShape down_bar_shape;
    	// 设置为盒子,參数为内容的半宽半高
    	down_bar_shape.SetAsBox(down_bar_size.width/2/RATIO, down_bar_size.height/2/RATIO);
    	// 声明定制器
    	b2FixtureDef down_bar_fixture_def;
    	// 定制器形状
    	down_bar_fixture_def.shape = &down_bar_shape;
    	// 为刚体创建定制器
    	down_bar_body->CreateFixture(&down_bar_fixture_def);
    
    	// 设置精灵刚体
    	down_bar->setB2Body(down_bar_body);
    	// 设置度量
    	down_bar->setPTMRatio(RATIO);
    
    	// 上水管
    	B2Sprite *up_bar = B2Sprite::create("up_bar.png");
    	// 获得内容大小
    	CCSize up_bar_size = up_bar->getContentSize();
    
    	b2BodyDef up_bar_body_def;
    	// 运动学物体。但不受重力影响
    	up_bar_body_def.type = b2_kinematicBody;
    	// 设置水管位置
    	up_bar_body_def.position = b2Vec2(screenSize.width/RATIO+2, down_bar_size.height/RATIO+offset+2+up_bar_size.height/2/RATIO);
    	up_bar_body_def.linearVelocity = b2Vec2(-5, 0);
    	b2Body *up_bar_body = world->CreateBody(&up_bar_body_def);
    
    	// 隐形形状
    	b2PolygonShape up_bar_shape;
    	// 设置为盒子形状,參数为半宽半高
    	up_bar_shape.SetAsBox(up_bar_size.width/2/RATIO, up_bar_size.height/2/RATIO);
    	b2FixtureDef up_bar_fixture_def;
    	up_bar_fixture_def.shape = &up_bar_shape;
    	up_bar_body->CreateFixture(&up_bar_fixture_def);
    	up_bar->setB2Body(up_bar_body);
    	up_bar->setPTMRatio(RATIO);
    
    	barContainer->addChild(down_bar);
    	barContainer->addChild(up_bar);
    
    }

    6. 加入碰撞检測

    这里须要说一下怎样让小鸟运动。我们须要设置屏幕的监听事件,而且让小鸟有一个向上的线性速度。点击屏幕的时候小鸟向上运动,松开则下坠。

    我们须要重写方法:
    virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);

    实现:
    // 触摸事件開始
    void HelloWorld::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent) {
    	bird->getB2Body()->SetLinearVelocity(b2Vec2(0, 5));
    }

    接下来讲碰撞检測,这个我们相同也要设置监听器,我们设置的是物理世界的事件监听。

    // 加入碰撞监听
    	world->SetContactListener(this);


    然后重写下面方法:
     virtual void BeginContact(b2Contact* contact);

    void HelloWorld::BeginContact(b2Contact *contact) {
    	// 发生碰撞,则弹出对话框
    	if (contact->GetFixtureA()->GetBody()->GetUserData() == bird ||
    		contact->GetFixtureB()->GetBody()->GetUserData() == bird) {
    			stopGame();
    			CCMessageBox("游戏失败","游戏失败");
    	}
    
    }


    7. 本文总结

    以上内容就是开发一款FlappyBird的简单Demo,读者能够在这个的基础上实现更丰富的功能,笔者认为不想一步到位把全部东西介绍完成。最重要的还是思路。把主要的东西掌握了,然后就能够依照这种思路去做一个这种东西。
    能够到下面地址下载源代码:https://github.com/devilWwj/eoeFlappyBird

    下面是完整实现:
    HelloWorldScene.h
    #ifndef __HELLOWORLD_SCENE_H__
    #define __HELLOWORLD_SCENE_H__
    
    #include "cocos2d.h"
    #include "Box2DBox2D.h"// 引入Box2D物理引擎
    #include "B2Sprite.h"	
    
    // 定义物理世界的比例
    #define RATIO 48.0f
    class HelloWorld : public cocos2d::CCLayer,public b2ContactListener
    {
    public:
        // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
        virtual bool init();  
    
        // there's no 'id' in cpp, so we recommend returning the class instance pointer
        static cocos2d::CCScene* scene();
        
        // a selector callback
        void menuCloseCallback(CCObject* pSender);
        
        // implement the "static node()" method manually
        CREATE_FUNC(HelloWorld);
    	 
    	virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);
    	 virtual void BeginContact(b2Contact* contact);
    
    	// 重写update方法
    	virtual void update(float dt);
    
    	// 声明物理世界引用
    	b2World *world;
    	B2Sprite *bird;
    	CCSize screenSize;
    	CCSprite *barContainer;
    
    private:
    	// 加入小鸟
    	void addBird();
    	// 初始化物理世界
    	void initWorld();
    	// 加入地板
    	void addGround();
    	// 加入水管
    	void addBar(float dt); 
    	// 加入一个容器
    	void addBarContainer();
    	// 開始游戏
    	void startGame(float dt);
    	// 结束游戏
    	void stopGame();
    };
    
    #endif // __HELLOWORLD_SCENE_H__
    

    HelloWorldScene.cpp
    #include "HelloWorldScene.h"
    
    USING_NS_CC;
    
    CCScene* HelloWorld::scene()
    {
    	// 'scene' is an autorelease object
    	CCScene *scene = CCScene::create();
    
    	// 'layer' is an autorelease object
    	HelloWorld *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 ( !CCLayer::init() )
    	{
    		return false;
    	}
    	// 获取屏幕大小
    	screenSize = CCDirector::sharedDirector()->getVisibleSize();
    	initWorld();
    	addBird();
    	addBarContainer();
    	addGround();
    
    	// 设置可点击
    	setTouchEnabled(true);
    	//scheduleUpdate();
    	//schedule(schedule_selector(HelloWorld::addBar), 1);
    	// 3秒之后运行
    	scheduleOnce(schedule_selector(HelloWorld::startGame),3);
    	return true;
    }
    
    /**
    * 加入小鸟
    *
    */
    void HelloWorld::addBird()
    {
    	// 创建小鸟
    	bird = B2Sprite::create("bird.png");
    	// 获取内容大小
    	CCSize size = bird->getContentSize();
    
    	// 刚体属性
    	b2BodyDef bodyDef;
    	// 动态刚体
    	bodyDef.type = b2_dynamicBody;
    	// 设置初始位置
    	bodyDef.position = b2Vec2(screenSize.width/2/RATIO, screenSize.height/2/RATIO);
    	// 创建一个小鸟刚体
    	b2Body *birdBody = world->CreateBody(&bodyDef);
    
    	// 隐形形状
    	b2PolygonShape birdShape;
    	// 设置为盒子。參数为内容的半宽半高
    	birdShape.SetAsBox(size.width/2/RATIO, size.height/2/RATIO);
    
    	// 材料属性
    	b2FixtureDef birdFixtureDef;
    	// 形状
    	birdFixtureDef.shape = &birdShape;
    	// 加入地表物体
    	birdBody->CreateFixture(&birdFixtureDef);
    
    	// 设置度量比例
    	bird->setPTMRatio(RATIO);
    	// 设置小鸟刚体
    	bird->setB2Body(birdBody);
    	// 加入小鸟到层中
    	addChild(bird);
    
    }
    // 初始化物理世界
    void HelloWorld::initWorld()
    {
    	// -10表示重力加速度方向为向下
    	world = new b2World(b2Vec2(0, -10));
    	// 加入碰撞监听
    	world->SetContactListener(this);
    } 
    
    // 更新
    void HelloWorld::update(float dt)
    {
    	// 模拟物理世界
    	// Box2D建议的迭代次数是速度阶段8次。位置阶段3次
    	world->Step(dt, 8, 3);
    	CCSprite *s;
    
    	// 遍历销毁
    	for (b2Body *b = world->GetBodyList(); b!= NULL; b=b->GetNext()) {
    		if (b->GetPosition().x<-3) {
    			s = (CCSprite*)b->GetUserData();
    			if (s != NULL) {
    				s->removeFromParent();
    				CCLog("Remove");
    			}
    			world->DestroyBody(b);
    		}
    	}
    }
    
    /**
    * 加入地板
    */
    void HelloWorld::addGround()
    {
    	// 地板精灵
    	B2Sprite *ground = B2Sprite::create("ground.png");
    	// 得到地板内容的大小
    	CCSize size = ground->getContentSize();
    
    	// 用于初始化刚体在物理世界的一些属性。比方位置,类型
    	b2BodyDef bDef;
    	// 静态的刚体
    	bDef.type = b2_staticBody;
    	// 设置位置
    	bDef.position = b2Vec2(size.width/2/RATIO, size.height/2/RATIO);
    	// 创建刚体
    	b2Body *groundBody = world->CreateBody(&bDef);
    
    	// 形状
    	b2PolygonShape groundShape;
    	// 设置为矩形
    	groundShape.SetAsBox(size.width/2/RATIO, size.height/2/RATIO);
    	// 材料定制器
    	b2FixtureDef groundFixtureDef;
    	// 设置形状
    	groundFixtureDef.shape = &groundShape;
    	// 创建定制器
    	groundBody->CreateFixture(&groundFixtureDef);
    	// 为精灵设置刚体
    	ground->setB2Body(groundBody);
    	// 设置度量比例
    	ground->setPTMRatio(RATIO);
    	// 加入地板到层其中
    	addChild(ground);
    
    }
    
    // 触摸事件開始
    void HelloWorld::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent) {
    	bird->getB2Body()->SetLinearVelocity(b2Vec2(0, 5));
    }
    
    // 加入运动的水管
    void HelloWorld::addBar(float dt) {
    	// 随机生成偏移量
    	float offset = -rand() %5;
    
    	// 创建向下水管的精灵
    	B2Sprite *down_bar = B2Sprite::create("down_bar.png");
    	// 得到水管的大小
    	CCSize down_bar_size = down_bar->getContentSize();
    
    	// 下水管
    	b2BodyDef down_bar_body_def;
    	// 运动学物体,但不受重力影响
    	down_bar_body_def.type = b2_kinematicBody;
    	// 设置下水管的位置
    	down_bar_body_def.position = b2Vec2(screenSize.width/RATIO + 2, down_bar_size.height/RATIO/2 +offset);
    	// 线性速度,从右往左移动
    	down_bar_body_def.linearVelocity = b2Vec2(-5,0);
    	// 创建刚体
    	b2Body *down_bar_body = world->CreateBody(&down_bar_body_def);
    
    	// 隐形形状
    	b2PolygonShape down_bar_shape;
    	// 设置为盒子。參数为内容的半宽半高
    	down_bar_shape.SetAsBox(down_bar_size.width/2/RATIO, down_bar_size.height/2/RATIO);
    	// 声明定制器
    	b2FixtureDef down_bar_fixture_def;
    	// 定制器形状
    	down_bar_fixture_def.shape = &down_bar_shape;
    	// 为刚体创建定制器
    	down_bar_body->CreateFixture(&down_bar_fixture_def);
    
    	// 设置精灵刚体
    	down_bar->setB2Body(down_bar_body);
    	// 设置度量
    	down_bar->setPTMRatio(RATIO);
    
    	// 上水管
    	B2Sprite *up_bar = B2Sprite::create("up_bar.png");
    	// 获得内容大小
    	CCSize up_bar_size = up_bar->getContentSize();
    
    	b2BodyDef up_bar_body_def;
    	// 运动学物体,但不受重力影响
    	up_bar_body_def.type = b2_kinematicBody;
    	// 设置水管位置
    	up_bar_body_def.position = b2Vec2(screenSize.width/RATIO+2, down_bar_size.height/RATIO+offset+2+up_bar_size.height/2/RATIO);
    	up_bar_body_def.linearVelocity = b2Vec2(-5, 0);
    	b2Body *up_bar_body = world->CreateBody(&up_bar_body_def);
    
    	// 隐形形状
    	b2PolygonShape up_bar_shape;
    	// 设置为盒子形状,參数为半宽半高
    	up_bar_shape.SetAsBox(up_bar_size.width/2/RATIO, up_bar_size.height/2/RATIO);
    	b2FixtureDef up_bar_fixture_def;
    	up_bar_fixture_def.shape = &up_bar_shape;
    	up_bar_body->CreateFixture(&up_bar_fixture_def);
    	up_bar->setB2Body(up_bar_body);
    	up_bar->setPTMRatio(RATIO);
    
    	barContainer->addChild(down_bar);
    	barContainer->addChild(up_bar);
    
    }
    
    // 运动条的容器
    void HelloWorld::addBarContainer()
    {
    	barContainer = CCSprite::create();
    
    	addChild(barContainer);
    }
    
    
    // 開始游戏
    void HelloWorld::startGame(float dt) {
    	scheduleUpdate();
    	schedule(schedule_selector(HelloWorld::addBar),1);
    }
    
    // 结束游戏
    void HelloWorld::stopGame() {
    	unscheduleUpdate();
    	unschedule(schedule_selector(HelloWorld::addBar));
    
    }
    
    void HelloWorld::BeginContact(b2Contact *contact) {
    	// 发生碰撞,则弹出对话框
    	if (contact->GetFixtureA()->GetBody()->GetUserData() == bird ||
    		contact->GetFixtureB()->GetBody()->GetUserData() == bird) {
    			stopGame();
    			CCMessageBox("游戏失败","游戏失败");
    	}
    
    }
    
    
    void HelloWorld::menuCloseCallback(CCObject* pSender)
    {
    #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
    	CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
    #else
    	CCDirector::sharedDirector()->end();
    #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    	exit(0);
    #endif
    #endif
    }
    


    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    HDU 2844 Coins(多重背包)
    HDU 4540 威威猫系列故事——打地鼠(DP)
    Codeforces Round #236 (Div. 2)
    FZU 2140 Forever 0.5
    HDU 1171 Big Event in HDU(DP)
    HDU 1160 FatMouse's Speed(DP)
    ZOJ 3490 String Successor
    ZOJ 3609 Modular Inverse
    ZOJ 3603 Draw Something Cheat
    ZOJ 3705 Applications
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4728244.html
Copyright © 2011-2022 走看看