懶骨頭(http://blog.csdn.net/iamlazybone QQ:124774397 )
《Flappy Bird》
關於這個遊戲骨頭不多說了
直接開始學習吧(山寨不好聽)
正好前段時間看了幾個DEMO拿這個遊戲練練手
開搞!
報環境:
vs2013+cocos2dx3.0beta2
首先下載apk,找到資源檔,裁剪幾個圖片:
用指令碼建立一個空的Cocos2dx項目
建立一個Scene類
#include "cocos2d.h"#include "Obstacle.h"class FlyBirdGame :public cocos2d::Layer{public:static cocos2d::Scene* createScene();virtual bool init();CREATE_FUNC(FlyBirdGame);void initUI();void gameStart(Object* pSender); void update(float time);Obstacle* obstacle;};
#include "cocos2d.h"#include "FlyBirdGame.h"#include "resource.h"; USING_NS_CC;Scene* FlyBirdGame::createScene(){auto scene = Scene::create();auto layer = FlyBirdGame::create();scene->addChild(layer);return scene;}bool FlyBirdGame::init(){if (!Layer::init()){return false;}initUI();return true;}
initUI裡是一些UI初始化方法:
// win sizeauto winSize = Director::getInstance()->getVisibleSize();// game bgauto bg = Sprite::create(bird_bg);bg->setPosition(winSize.width / 2, winSize.height / 2);bg->setScale(winSize.width / bg->getContentSize().width, winSize.height / bg->getContentSize().height);this->addChild(bg);// start btnauto startBtn = MenuItemImage::create(bird_start_btn, bird_start_btn_pressed, CC_CALLBACK_1(FlyBirdGame::gameStart, this));auto menu = Menu::create(startBtn, NULL);menu->setTag(100);this->addChild(menu);// heroauto hero = Sprite::create(bird_hero);hero->setPosition(winSize.width / 5, winSize.height*0.8);hero->setVisible(false);hero->setTag(200);this->addChild(hero);
開始遊戲按鈕綁定的gameStart方法:
void FlyBirdGame::gameStart(Object* pSender){auto btn = this->getChildByTag(100);btn->setVisible(false);auto hero = this->getChildByTag(200); Size win = Director::getInstance()->getWinSize();obstacle->gameStart = true;}
隱藏開始按鈕,顯示小鳥,水管開始移動
還有更新方法:
scheduleUpdate();void FlyBirdGame::update(float time){obstacle->update();}
=======================================
水管類:Obstacle.cpp
update方法裡判斷遊戲是遊戲是否開始
void Obstacle::update(){if (gameStart == false)return;addCount++;if (addCount == 60){addOne(0);addCount = 0;}for (int i = obstacleList->count() - 1; i >= 0; i--){auto s = (Sprite*)obstacleList->getObjectAtIndex(i);s->setPositionX(s->getPositionX() - 3);if (s->getPositionX() < -s->getContentSize().width / 2){obstacleList->removeObjectAtIndex(i);this->removeChild(s);}}}水管類的更新方法裡,每60幀(1秒)添加一對水管
並且遍曆水管列表
出邊界的化銷毀
接下來是addOne方法:添加水管方法:
void Obstacle::addOne(int offsetX){Size size = Director::getInstance()->getWinSize();auto sprite = Sprite::create(bird_obstacle_up);Size spriteSize = sprite->getContentSize();obstacleList->addObject(sprite);this->addChild(sprite);auto sprite2 = Sprite::create(bird_obstacle_down);Size spriteSize2 = sprite->getContentSize();obstacleList->addObject(sprite2);this->addChild(sprite2);// set positonint maxUpY = size.height + spriteSize.height / 4;int minUpY = size.height - spriteSize.height / 4;int y1 = CCRANDOM_0_1()*(maxUpY - minUpY) + minUpY;int maxDownY = spriteSize.height / 4;int minDownY = -spriteSize.height / 4;int y2 = CCRANDOM_0_1()*(maxDownY - minDownY) + minDownY;if (y1 - y2 - spriteSize.height < 160){y2 = y1 - spriteSize.height - 160;}sprite->setPosition(ccp(size.width + spriteSize.width / 2 + offsetX, y1));sprite2->setPosition(ccp(size.width + spriteSize2.width / 2 + offsetX, y2));}這段代碼比較淩亂,就是找到水管上下位置的範圍
然後隨機一下,並且保證上下連個水管有個最小的距離
效果如下:
=============================
此時的遊戲還沒觸摸和碰撞邏輯
馬上添加:(剛才抽空玩了把魔方:五階的我只能搞定一個面,雖然有官方規律但是那樣好像比的是記憶力)
聽說cocos2dx3.0的事件監聽方式改變了
先在FlyBirdGame.h裡聲明倆方法:
void onTouchesEnded(const vector<Touch*>& touches, Event* event);void onTouchesBegan(const vector<Touch*>& touches, Event* event);
在cpp檔案的初始化裡綁定事件:
// touchauto dispatcher = Director::getInstance()->getEventDispatcher();auto listener = EventListenerTouchAllAtOnce::create();listener->onTouchesEnded = CC_CALLBACK_2(FlyBirdGame::onTouchesEnded, this);listener->onTouchesBegan = CC_CALLBACK_2(FlyBirdGame::onTouchesBegan, this);dispatcher->addEventListenerWithSceneGraphPriority(listener, this);
在兩個事件方法裡改變標記位,在小鳥的update方法雷根據這個標記位來改變高度
(哲哲喊我休息了,先到這吧,待續。。。)
=============================
碰撞檢測:
記得cocos2dx3.0以前都是自己寫一個根據CCSprite擷取CCRect的方法
現在直接用 Sprite的getBoundingBox()方法
不過如果有特殊需求還得自己寫,比如想擴大或縮小碰撞地區
在FlyBirdGame.cpp檔案裡
update算主邏輯方法:
void FlyBirdGame::update(float time){auto winSize = Director::getInstance()->getVisibleSize();auto hero = this->getChildByTag(TAG_HERO);Rect rHero = ((Sprite*)hero)->getBoundingBox();switch (GAME_STATUS){case GAME_STATUS_PLAYING:obstacle->update();// update bird positionYif (isFlying&&hero->getPositionY() < winSize.height){hero->setPositionY(hero->getPositionY() + v);}else if (hero->getPositionY()>0){hero->setPositionY(hero->getPositionY() - v);}//check collisionfor (int i = 0; i < obstacle->obstacleList->count(); i++){Sprite* obstacleRect = (Sprite*)obstacle->obstacleList->getObjectAtIndex(i);bool pia = rHero.intersectsRect(obstacleRect->getBoundingBox());if (pia == true){GAME_STATUS = GAME_STATUS_GAME_OVER;break;}}break;case GAME_STATUS_GAME_OVER:CCLog("over");this->getChildByTag(TAG_OVER)->setVisible(true);break;case GAME_STATUS_RESTART://reset gameobstacle->removeAllChildren();obstacle->obstacleList->removeAllObjects();// reset herohero->setPosition(winSize.width / 5, winSize.height*0.8);// show btnauto btn = this->getChildByTag(TAG_START_BTN);btn->setVisible(true);// show logoauto logo = this->getChildByTag(TAG_LOGO);logo->setVisible(true);break;}}
根據遊戲狀態處理。
碰撞檢測方法:intersectsRect
bool pia = rHero.intersectsRect(obstacleRect->getBoundingBox());
if (pia == true)
{
GAME_STATUS = GAME_STATUS_GAME_OVER;
break;
}
遊戲狀態定義在 resource.h 檔案裡
static const int GAME_STATUS_START = 10;static const int GAME_STATUS_PLAYING = 20;static const int GAME_STATUS_GAME_OVER = 30;static const int GAME_STATUS_RESTART = 40;
整個遊戲流程已經通了:開始,遊戲,結束,重新開始
接下來可以最佳化很多很多東西