學習遊戲編程是一件很是有趣的事情,在cocos2dx官網找了幾個簡單的遊戲試試手,感受也不是那麼難,首先來看看2048這款遊戲吧,很火的緣由之一是由於它簡單而易操做。網上這位Legendof1991大神很早就寫過了,我大部分代碼都是根據他的文章來的,可是也有些細節的地方本身修改了,下面就正是進入遊戲吧。算法
先書寫一下整個遊戲的流程圖:編程
1、主場景的建立
|
首先仍是新建一個工程,名字隨便你怎麼取,而後按照老規矩該添加圖層就添加圖層。先來看下它的頭文件:安全
class HelloWorld : public cocos2d::Layer { public: // there's no 'id' in cpp, so we recommend returning the class instance pointer static cocos2d::Scene* createScene(); // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone virtual bool init(); // a selector callback void menuCloseCallback(cocos2d::Ref* pSender); // implement the "static create()" method manually CREATE_FUNC(HelloWorld); virtual bool onTouchBegan(Touch *touch, Event *unused_event); virtual void onTouchEnded(Touch *touch, Event *unused_event); bool doUp(); bool doDown(); bool doLeft(); bool doRight(); //建立卡片函數 void createCard(Size size); void autoCreateCardNumber(); //判斷遊戲是否可以繼續 void doCheckGameOver(); private: int firstX,firstY,endX,endY; CardSprite* cardArray[4][4]; //遊戲得分 int score; CCLabelTTF *labelTTFScoreName; CCLabelTTF* labelTTFScoreNumber; }; #endif // __HELLOWORLD_SCENE_H__
其中這兩個函數virtual bool onTouchBegan(Touch *touch, Event *unused_event);virtual void onTouchEnded(Touch *touch, Event *unused_event);主要是用來判斷觸屏滑動的方向。iphone
void HelloWorld::onTouchEnded(Touch *touch, Event *unused_event) { Point touchPoint=touch->getLocation(); //touch->getLocationInView(); endX=firstX-touchPoint.x; endY=firstY-touchPoint.y; if (abs(endX)>abs(endY)) { if(endX+5>0) { //向左 doLeft(); } else { //向右 doRight(); } } else { if(endY+5>0) { //向下 doDown(); } else { //向上 doUp(); } } }
這段代碼經過世界座標和窗口座標之間的差值來判斷的,通過測試可行。具體的原理他也沒有說明。函數
2、卡片的建立
|
卡片咱們須要新建一個卡片類來實現,類中咱們須要設置一些初始化動做,我把他放在下面這個函數中。學習
CardSprite* CardSprite::createCardSprite(int numbers,int width,int height,float CardSpriteX,float CardSpriteY) { //CardSprite *enemy=new CardSprite(); CardSprite* enemy=CardSprite::create(); //CardSprite* enemy=new CardSprite(); if (enemy&&enemy->init()) { //enemy->autorelease(); //自動釋放,這種寫法比較好,若是沒有初始化好的話也能夠安全刪除 enemy->enemyInit(numbers,width,height,CardSpriteX,CardSpriteY); enemy->retain(); //記得release return enemy; } CC_SAFE_DELETE(enemy); //安全釋放 return NULL; }
其中咱們須要注意的地方是若是你用create函數以後,須要retain一次,不須要用了則要release,原文博客中用的是這兩句:CardSprite *enemy=new CardSprite();enemy->autorelease();他這樣處理的好處就是內存由內存池自動管理了。測試
3、算法分析
|
每一個遊戲核心都是算法處理。2048也不例外,它的核心思想是每行每列遇到相同的數字則一個乘以2,另外一個卡片變成0,例如咱們向左滑動的時候代碼能夠這樣寫,時間複雜度o(N3),其它三個方向的算法思路也是同樣的。spa
bool HelloWorld::doLeft() { bool isdo = false; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { for (int x1 = x + 1; x1 < 4; x1++) { if (cardArray[x1][y]->getNumbers() > 0) { if (cardArray[x][y]->getNumbers() <= 0) { cardArray[x][y]->setNumbers(cardArray[x1][y]->getNumbers()); cardArray[x1][y]->setNumbers(0); x--; //這裏不會發生溢出,原來已經x1++了。 isdo = true; }else if(cardArray[x][y]->getNumbers() == cardArray[x1][y]->getNumbers()) { cardArray[x][y]->setNumbers(cardArray[x][y]->getNumbers()*2); cardArray[x1][y]->setNumbers(0); score+=cardArray[x][y]->getNumbers(); labelTTFScoreNumber->setString(String::createWithFormat("%i",score)->getCString()); isdo = true; } break; } } } } return isdo; }
至於當你的卡片消除以後,主層中多於兩個卡片空位時,你須要添加兩張卡片填充空位,至於位置也是隨機分佈的,它採用遞歸的方式尋找沒有數字的卡片。來看段代碼:code
void HelloWorld::autoCreateCardNumber() { int i=CCRANDOM_0_1()*4; //隨機生成數字0-4 int j=CCRANDOM_0_1()*4; //隨機生成數字 if (cardArray[i][j]->getNumbers()>0) { //有數字則遞歸調用直到有空白的地方爲止 autoCreateCardNumber(); } else { cardArray[i][j]->setNumbers(CCRANDOM_0_1()*10<1?2:4); //乘以10以後看是否小於1,出現2或者4,這裏就是卡片出現的機率問題了 } }
4、總結
|
整個遊戲的難點大概就是這些吧,至於其餘一些細節的地方你們能夠看他的原文,這個遊戲主要涉及到的難點就是卡片的消除及消除以後如何再把數字隨機的添加到卡片上。下期任務是寫一個簡單版的打飛機遊戲。望諸君共勉!orm
做者:曹麒文
出處:http://www.cnblogs.com/master-image/
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面