Cocos2d-x 2.3.3版 FlappyBird

48 篇文章 0 订阅
33 篇文章 0 订阅

https://blog.csdn.net/wwj_748/article/details/37742559

本篇博客基于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\tools\project-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来为我们创建一个看似比较真实的世界。

[cpp]  view plain  copy
  1. // -10表示重力加速度方向为向下  
  2.     world = new b2World(b2Vec2(0, -10));  


[cpp]  view plain  copy
  1. // 模拟物理世界  
  2.     // Box2D建议的迭代次数是速度阶段8次,位置阶段3次  
  3.     world->Step(dt, 8, 3);  

3. 如何添加小鸟到物理世界

小鸟在Cocos2d-x就是一个Sprite(精灵),我们知道精灵是需要添加到层当中的,我们还要设置我们小鸟在物理世界的刚体。关于Box2d相关的概念,笔者在这里不详细说,读者可以自己找百度老师,学习更多关于Box2d的知识。
我们定义以下方法:
[cpp]  view plain  copy
  1. /** 
  2. * 添加小鸟 
  3. * 
  4. */  
  5. void HelloWorld::addBird()  
  6. {  
  7.     // 创建小鸟  
  8.     bird = B2Sprite::create("bird.png");  
  9.     // 获取内容大小  
  10.     CCSize size = bird->getContentSize();  
  11.   
  12.     // 刚体属性  
  13.     b2BodyDef bodyDef;  
  14.     // 动态刚体  
  15.     bodyDef.type = b2_dynamicBody;  
  16.     // 设置初始位置  
  17.     bodyDef.position = b2Vec2(screenSize.width/2/RATIO, screenSize.height/2/RATIO);  
  18.     // 创建一个小鸟刚体  
  19.     b2Body *birdBody = world->CreateBody(&bodyDef);  
  20.   
  21.     // 隐形形状  
  22.     b2PolygonShape birdShape;  
  23.     // 设置为盒子,参数为内容的半宽半高  
  24.     birdShape.SetAsBox(size.width/2/RATIO, size.height/2/RATIO);  
  25.   
  26.     // 材料属性  
  27.     b2FixtureDef birdFixtureDef;  
  28.     // 形状  
  29.     birdFixtureDef.shape = &birdShape;  
  30.     // 添加地表物体  
  31.     birdBody->CreateFixture(&birdFixtureDef);  
  32.   
  33.     // 设置度量比例  
  34.     bird->setPTMRatio(RATIO);  
  35.     // 设置小鸟刚体  
  36.     bird->setB2Body(birdBody);  
  37.     // 添加小鸟到层中  
  38.     addChild(bird);  
  39.   
  40. }  


4. 如何添加地板

地板跟小鸟也是类似的,只是设置地板刚体的类型为静态的,因为它相对静止的也不受重力影响。
[cpp]  view plain  copy
  1. /** 
  2. * 添加地板 
  3. */  
  4. void HelloWorld::addGround()  
  5. {  
  6.     // 地板精灵  
  7.     B2Sprite *ground = B2Sprite::create("ground.png");  
  8.     // 得到地板内容的大小  
  9.     CCSize size = ground->getContentSize();  
  10.   
  11.     // 用于初始化刚体在物理世界的一些属性,比如位置,类型  
  12.     b2BodyDef bDef;  
  13.     // 静态的刚体  
  14.     bDef.type = b2_staticBody;  
  15.     // 设置位置  
  16.     bDef.position = b2Vec2(size.width/2/RATIO, size.height/2/RATIO);  
  17.     // 创建刚体  
  18.     b2Body *groundBody = world->CreateBody(&bDef);  
  19.   
  20.     // 形状  
  21.     b2PolygonShape groundShape;  
  22.     // 设置为矩形  
  23.     groundShape.SetAsBox(size.width/2/RATIO, size.height/2/RATIO);  
  24.     // 材料定制器  
  25.     b2FixtureDef groundFixtureDef;  
  26.     // 设置形状  
  27.     groundFixtureDef.shape = &groundShape;  
  28.     // 创建定制器  
  29.     groundBody->CreateFixture(&groundFixtureDef);  
  30.     // 为精灵设置刚体  
  31.     ground->setB2Body(groundBody);  
  32.     // 设置度量比例  
  33.     ground->setPTMRatio(RATIO);  
  34.     // 添加地板到层当中  
  35.     addChild(ground);  
  36.   
  37. }  

5. 添加水管

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

[cpp]  view plain  copy
  1. / 添加运动的水管  
  2. void HelloWorld::addBar(float dt) {  
  3.     // 随机生成偏移量  
  4.     float offset = -rand() %5;  
  5.   
  6.     // 创建向下水管的精灵  
  7.     B2Sprite *down_bar = B2Sprite::create("down_bar.png");  
  8.     // 得到水管的大小  
  9.     CCSize down_bar_size = down_bar->getContentSize();  
  10.   
  11.     // 下水管  
  12.     b2BodyDef down_bar_body_def;  
  13.     // 运动学物体,但不受重力影响  
  14.     down_bar_body_def.type = b2_kinematicBody;  
  15.     // 设置下水管的位置  
  16.     down_bar_body_def.position = b2Vec2(screenSize.width/RATIO + 2, down_bar_size.height/RATIO/2 +offset);  
  17.     // 线性速度,从右往左移动  
  18.     down_bar_body_def.linearVelocity = b2Vec2(-5,0);  
  19.     // 创建刚体  
  20.     b2Body *down_bar_body = world->CreateBody(&down_bar_body_def);  
  21.   
  22.     // 隐形形状  
  23.     b2PolygonShape down_bar_shape;  
  24.     // 设置为盒子,参数为内容的半宽半高  
  25.     down_bar_shape.SetAsBox(down_bar_size.width/2/RATIO, down_bar_size.height/2/RATIO);  
  26.     // 声明定制器  
  27.     b2FixtureDef down_bar_fixture_def;  
  28.     // 定制器形状  
  29.     down_bar_fixture_def.shape = &down_bar_shape;  
  30.     // 为刚体创建定制器  
  31.     down_bar_body->CreateFixture(&down_bar_fixture_def);  
  32.   
  33.     // 设置精灵刚体  
  34.     down_bar->setB2Body(down_bar_body);  
  35.     // 设置度量  
  36.     down_bar->setPTMRatio(RATIO);  
  37.   
  38.     // 上水管  
  39.     B2Sprite *up_bar = B2Sprite::create("up_bar.png");  
  40.     // 获得内容大小  
  41.     CCSize up_bar_size = up_bar->getContentSize();  
  42.   
  43.     b2BodyDef up_bar_body_def;  
  44.     // 运动学物体,但不受重力影响  
  45.     up_bar_body_def.type = b2_kinematicBody;  
  46.     // 设置水管位置  
  47.     up_bar_body_def.position = b2Vec2(screenSize.width/RATIO+2, down_bar_size.height/RATIO+offset+2+up_bar_size.height/2/RATIO);  
  48.     up_bar_body_def.linearVelocity = b2Vec2(-5, 0);  
  49.     b2Body *up_bar_body = world->CreateBody(&up_bar_body_def);  
  50.   
  51.     // 隐形形状  
  52.     b2PolygonShape up_bar_shape;  
  53.     // 设置为盒子形状,参数为半宽半高  
  54.     up_bar_shape.SetAsBox(up_bar_size.width/2/RATIO, up_bar_size.height/2/RATIO);  
  55.     b2FixtureDef up_bar_fixture_def;  
  56.     up_bar_fixture_def.shape = &up_bar_shape;  
  57.     up_bar_body->CreateFixture(&up_bar_fixture_def);  
  58.     up_bar->setB2Body(up_bar_body);  
  59.     up_bar->setPTMRatio(RATIO);  
  60.   
  61.     barContainer->addChild(down_bar);  
  62.     barContainer->addChild(up_bar);  
  63.   
  64. }  

6. 添加碰撞检测

这里需要说一下如何让小鸟运动,我们需要设置屏幕的监听事件,并且让小鸟有一个向上的线性速度,点击屏幕的时候小鸟向上运动,松开则下坠。
我们需要重写方法:
[cpp]  view plain  copy
  1. virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);  

实现:
[cpp]  view plain  copy
  1. // 触摸事件开始  
  2. void HelloWorld::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent) {  
  3.     bird->getB2Body()->SetLinearVelocity(b2Vec2(0, 5));  
  4. }  

接下来讲碰撞检测,这个我们同样也要设置监听器,我们设置的是物理世界的事件监听。
[cpp]  view plain  copy
  1. // 添加碰撞监听  
  2.     world->SetContactListener(this);  


然后重写以下方法:
[cpp]  view plain  copy
  1. virtual void BeginContact(b2Contact* contact);  

[cpp]  view plain  copy
  1. void HelloWorld::BeginContact(b2Contact *contact) {  
  2.     // 发生碰撞,则弹出对话框  
  3.     if (contact->GetFixtureA()->GetBody()->GetUserData() == bird ||  
  4.         contact->GetFixtureB()->GetBody()->GetUserData() == bird) {  
  5.             stopGame();  
  6.             CCMessageBox("游戏失败","游戏失败");  
  7.     }  
  8.   
  9. }  


7. 本文总结

以上内容就是开发一款FlappyBird的简单Demo,读者可以在这个的基础上实现更丰富的功能,笔者觉得不想一步到位把所有东西介绍完毕。最重要的还是思路,把基本的东西掌握了,然后就可以按照这样的思路去做一个这样的东西。
可以到以下地址下载源码:https://github.com/devilWwj/eoeFlappyBird

下面是完整实现:
HelloWorldScene.h
[cpp]  view plain  copy
  1. #ifndef __HELLOWORLD_SCENE_H__  
  2. #define __HELLOWORLD_SCENE_H__  
  3.   
  4. #include "cocos2d.h"  
  5. #include "Box2D\Box2D.h"// 引入Box2D物理引擎  
  6. #include "B2Sprite.h"     
  7.   
  8. // 定义物理世界的比例  
  9. #define RATIO 48.0f  
  10. class HelloWorld : public cocos2d::CCLayer,public b2ContactListener  
  11. {  
  12. public:  
  13.     // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone  
  14.     virtual bool init();    
  15.   
  16.     // there's no 'id' in cpp, so we recommend returning the class instance pointer  
  17.     static cocos2d::CCScene* scene();  
  18.       
  19.     // a selector callback  
  20.     void menuCloseCallback(CCObject* pSender);  
  21.       
  22.     // implement the "static node()" method manually  
  23.     CREATE_FUNC(HelloWorld);  
  24.        
  25.     virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);  
  26.      virtual void BeginContact(b2Contact* contact);  
  27.   
  28.     // 重写update方法  
  29.     virtual void update(float dt);  
  30.   
  31.     // 声明物理世界引用  
  32.     b2World *world;  
  33.     B2Sprite *bird;  
  34.     CCSize screenSize;  
  35.     CCSprite *barContainer;  
  36.   
  37. private:  
  38.     // 添加小鸟  
  39.     void addBird();  
  40.     // 初始化物理世界  
  41.     void initWorld();  
  42.     // 添加地板  
  43.     void addGround();  
  44.     // 添加水管  
  45.     void addBar(float dt);   
  46.     // 添加一个容器  
  47.     void addBarContainer();  
  48.     // 开始游戏  
  49.     void startGame(float dt);  
  50.     // 结束游戏  
  51.     void stopGame();  
  52. };  
  53.   
  54. #endif // __HELLOWORLD_SCENE_H__  

HelloWorldScene.cpp
[cpp]  view plain  copy
  1. #include "HelloWorldScene.h"  
  2.   
  3. USING_NS_CC;  
  4.   
  5. CCScene* HelloWorld::scene()  
  6. {  
  7.     // 'scene' is an autorelease object  
  8.     CCScene *scene = CCScene::create();  
  9.   
  10.     // 'layer' is an autorelease object  
  11.     HelloWorld *layer = HelloWorld::create();  
  12.   
  13.     // add layer as a child to scene  
  14.     scene->addChild(layer);  
  15.   
  16.     // return the scene  
  17.     return scene;  
  18. }  
  19.   
  20. // on "init" you need to initialize your instance  
  21. bool HelloWorld::init()  
  22. {  
  23.     //  
  24.     // 1. super init first  
  25.     if ( !CCLayer::init() )  
  26.     {  
  27.         return false;  
  28.     }  
  29.     // 获取屏幕大小  
  30.     screenSize = CCDirector::sharedDirector()->getVisibleSize();  
  31.     initWorld();  
  32.     addBird();  
  33.     addBarContainer();  
  34.     addGround();  
  35.   
  36.     // 设置可点击  
  37.     setTouchEnabled(true);  
  38.     //scheduleUpdate();  
  39.     //schedule(schedule_selector(HelloWorld::addBar), 1);  
  40.     // 3秒之后执行  
  41.     scheduleOnce(schedule_selector(HelloWorld::startGame),3);  
  42.     return true;  
  43. }  
  44.   
  45. /** 
  46. * 添加小鸟 
  47. * 
  48. */  
  49. void HelloWorld::addBird()  
  50. {  
  51.     // 创建小鸟  
  52.     bird = B2Sprite::create("bird.png");  
  53.     // 获取内容大小  
  54.     CCSize size = bird->getContentSize();  
  55.   
  56.     // 刚体属性  
  57.     b2BodyDef bodyDef;  
  58.     // 动态刚体  
  59.     bodyDef.type = b2_dynamicBody;  
  60.     // 设置初始位置  
  61.     bodyDef.position = b2Vec2(screenSize.width/2/RATIO, screenSize.height/2/RATIO);  
  62.     // 创建一个小鸟刚体  
  63.     b2Body *birdBody = world->CreateBody(&bodyDef);  
  64.   
  65.     // 隐形形状  
  66.     b2PolygonShape birdShape;  
  67.     // 设置为盒子,参数为内容的半宽半高  
  68.     birdShape.SetAsBox(size.width/2/RATIO, size.height/2/RATIO);  
  69.   
  70.     // 材料属性  
  71.     b2FixtureDef birdFixtureDef;  
  72.     // 形状  
  73.     birdFixtureDef.shape = &birdShape;  
  74.     // 添加地表物体  
  75.     birdBody->CreateFixture(&birdFixtureDef);  
  76.   
  77.     // 设置度量比例  
  78.     bird->setPTMRatio(RATIO);  
  79.     // 设置小鸟刚体  
  80.     bird->setB2Body(birdBody);  
  81.     // 添加小鸟到层中  
  82.     addChild(bird);  
  83.   
  84. }  
  85. // 初始化物理世界  
  86. void HelloWorld::initWorld()  
  87. {  
  88.     // -10表示重力加速度方向为向下  
  89.     world = new b2World(b2Vec2(0, -10));  
  90.     // 添加碰撞监听  
  91.     world->SetContactListener(this);  
  92. }   
  93.   
  94. // 更新  
  95. void HelloWorld::update(float dt)  
  96. {  
  97.     // 模拟物理世界  
  98.     // Box2D建议的迭代次数是速度阶段8次,位置阶段3次  
  99.     world->Step(dt, 8, 3);  
  100.     CCSprite *s;  
  101.   
  102.     // 遍历销毁  
  103.     for (b2Body *b = world->GetBodyList(); b!= NULL; b=b->GetNext()) {  
  104.         if (b->GetPosition().x<-3) {  
  105.             s = (CCSprite*)b->GetUserData();  
  106.             if (s != NULL) {  
  107.                 s->removeFromParent();  
  108.                 CCLog("Remove");  
  109.             }  
  110.             world->DestroyBody(b);  
  111.         }  
  112.     }  
  113. }  
  114.   
  115. /** 
  116. * 添加地板 
  117. */  
  118. void HelloWorld::addGround()  
  119. {  
  120.     // 地板精灵  
  121.     B2Sprite *ground = B2Sprite::create("ground.png");  
  122.     // 得到地板内容的大小  
  123.     CCSize size = ground->getContentSize();  
  124.   
  125.     // 用于初始化刚体在物理世界的一些属性,比如位置,类型  
  126.     b2BodyDef bDef;  
  127.     // 静态的刚体  
  128.     bDef.type = b2_staticBody;  
  129.     // 设置位置  
  130.     bDef.position = b2Vec2(size.width/2/RATIO, size.height/2/RATIO);  
  131.     // 创建刚体  
  132.     b2Body *groundBody = world->CreateBody(&bDef);  
  133.   
  134.     // 形状  
  135.     b2PolygonShape groundShape;  
  136.     // 设置为矩形  
  137.     groundShape.SetAsBox(size.width/2/RATIO, size.height/2/RATIO);  
  138.     // 材料定制器  
  139.     b2FixtureDef groundFixtureDef;  
  140.     // 设置形状  
  141.     groundFixtureDef.shape = &groundShape;  
  142.     // 创建定制器  
  143.     groundBody->CreateFixture(&groundFixtureDef);  
  144.     // 为精灵设置刚体  
  145.     ground->setB2Body(groundBody);  
  146.     // 设置度量比例  
  147.     ground->setPTMRatio(RATIO);  
  148.     // 添加地板到层当中  
  149.     addChild(ground);  
  150.   
  151. }  
  152.   
  153. // 触摸事件开始  
  154. void HelloWorld::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent) {  
  155.     bird->getB2Body()->SetLinearVelocity(b2Vec2(0, 5));  
  156. }  
  157.   
  158. // 添加运动的水管  
  159. void HelloWorld::addBar(float dt) {  
  160.     // 随机生成偏移量  
  161.     float offset = -rand() %5;  
  162.   
  163.     // 创建向下水管的精灵  
  164.     B2Sprite *down_bar = B2Sprite::create("down_bar.png");  
  165.     // 得到水管的大小  
  166.     CCSize down_bar_size = down_bar->getContentSize();  
  167.   
  168.     // 下水管  
  169.     b2BodyDef down_bar_body_def;  
  170.     // 运动学物体,但不受重力影响  
  171.     down_bar_body_def.type = b2_kinematicBody;  
  172.     // 设置下水管的位置  
  173.     down_bar_body_def.position = b2Vec2(screenSize.width/RATIO + 2, down_bar_size.height/RATIO/2 +offset);  
  174.     // 线性速度,从右往左移动  
  175.     down_bar_body_def.linearVelocity = b2Vec2(-5,0);  
  176.     // 创建刚体  
  177.     b2Body *down_bar_body = world->CreateBody(&down_bar_body_def);  
  178.   
  179.     // 隐形形状  
  180.     b2PolygonShape down_bar_shape;  
  181.     // 设置为盒子,参数为内容的半宽半高  
  182.     down_bar_shape.SetAsBox(down_bar_size.width/2/RATIO, down_bar_size.height/2/RATIO);  
  183.     // 声明定制器  
  184.     b2FixtureDef down_bar_fixture_def;  
  185.     // 定制器形状  
  186.     down_bar_fixture_def.shape = &down_bar_shape;  
  187.     // 为刚体创建定制器  
  188.     down_bar_body->CreateFixture(&down_bar_fixture_def);  
  189.   
  190.     // 设置精灵刚体  
  191.     down_bar->setB2Body(down_bar_body);  
  192.     // 设置度量  
  193.     down_bar->setPTMRatio(RATIO);  
  194.   
  195.     // 上水管  
  196.     B2Sprite *up_bar = B2Sprite::create("up_bar.png");  
  197.     // 获得内容大小  
  198.     CCSize up_bar_size = up_bar->getContentSize();  
  199.   
  200.     b2BodyDef up_bar_body_def;  
  201.     // 运动学物体,但不受重力影响  
  202.     up_bar_body_def.type = b2_kinematicBody;  
  203.     // 设置水管位置  
  204.     up_bar_body_def.position = b2Vec2(screenSize.width/RATIO+2, down_bar_size.height/RATIO+offset+2+up_bar_size.height/2/RATIO);  
  205.     up_bar_body_def.linearVelocity = b2Vec2(-5, 0);  
  206.     b2Body *up_bar_body = world->CreateBody(&up_bar_body_def);  
  207.   
  208.     // 隐形形状  
  209.     b2PolygonShape up_bar_shape;  
  210.     // 设置为盒子形状,参数为半宽半高  
  211.     up_bar_shape.SetAsBox(up_bar_size.width/2/RATIO, up_bar_size.height/2/RATIO);  
  212.     b2FixtureDef up_bar_fixture_def;  
  213.     up_bar_fixture_def.shape = &up_bar_shape;  
  214.     up_bar_body->CreateFixture(&up_bar_fixture_def);  
  215.     up_bar->setB2Body(up_bar_body);  
  216.     up_bar->setPTMRatio(RATIO);  
  217.   
  218.     barContainer->addChild(down_bar);  
  219.     barContainer->addChild(up_bar);  
  220.   
  221. }  
  222.   
  223. // 运动条的容器  
  224. void HelloWorld::addBarContainer()  
  225. {  
  226.     barContainer = CCSprite::create();  
  227.   
  228.     addChild(barContainer);  
  229. }  
  230.   
  231.   
  232. // 开始游戏  
  233. void HelloWorld::startGame(float dt) {  
  234.     scheduleUpdate();  
  235.     schedule(schedule_selector(HelloWorld::addBar),1);  
  236. }  
  237.   
  238. // 结束游戏  
  239. void HelloWorld::stopGame() {  
  240.     unscheduleUpdate();  
  241.     unschedule(schedule_selector(HelloWorld::addBar));  
  242.   
  243. }  
  244.   
  245. void HelloWorld::BeginContact(b2Contact *contact) {  
  246.     // 发生碰撞,则弹出对话框  
  247.     if (contact->GetFixtureA()->GetBody()->GetUserData() == bird ||  
  248.         contact->GetFixtureB()->GetBody()->GetUserData() == bird) {  
  249.             stopGame();  
  250.             CCMessageBox("游戏失败","游戏失败");  
  251.     }  
  252.   
  253. }  
  254.   
  255.   
  256. void HelloWorld::menuCloseCallback(CCObject* pSender)  
  257. {  
  258. #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)  
  259.     CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");  
  260. #else  
  261.     CCDirector::sharedDirector()->end();  
  262. #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)  
  263.     exit(0);  
  264. #endif  
  265. #endif  
  266. }  



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值