码迷,mamicode.com
首页 > 其他好文 > 详细

Cocos2d-x 3.x版2048游戏开发

时间:2015-06-02 12:38:04      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:

今天给大家介绍如何快速开发2048这样一款休闲游戏,理解整个2048游戏的开发流程,从中你将可以学习到以下内容:

  • 2048游戏的逻辑
  • Cocos2d-x中上下左右手势的识别
  • 游戏中卡片类的创建
  • 添加卡片到游戏中
  • 游戏中的逻辑实现
  • 游戏中随机卡片的生成
  • 游戏结束判断
  • 游戏分数的添加
  • 游戏美化

笔者的开发环境:
    Cocos2d-x 3.1.1(开发引擎)
    Visual Studio 2012(Win32)
    Xcode 5.1(Mac系统下)


这里注明一下,本教程来自极客学院,小巫对其中代码进行了解释。

 

理解2048游戏逻辑

        2048游戏逻辑并不复杂,4*4的卡片布局,玩家通过手势上下左右滑动来累加卡片数值,直到累加到2048。笔者用一张图说明:

技术分享


这是一张游戏中的图,在图中同一方向并且数值相同的卡片可以进行叠加,比如128和128在同一行,玩家可以通过向左或向右的手势,对其进行叠加。笔者向右滑动手势,则会变成以下效果:

 
技术分享


Cocos2d-x中上下左右手势的识别

玩家在玩2048游戏时,手势是最频繁的操作,所以我们需要对手势所产生的事件进行监听。
HelloWorldScene.h头文件中声明两个需要实现的监听事件:
    // 加入手势识别的事件  
    virtual bool onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *unused_event);  
    virtual void onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *unused_event);  

 

声明点击的位置属性
    // 点击的元素位置  
    int firstX, firstY, endX, endY;  
一个是触摸开始的事件,一个是触摸结束的事件。

然后再HelloWorldScene.cpp文件中实现这两个方法:
 // 加入手势识别的事件  
    bool HelloWorld::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *unused_event){  
    // 触摸点  
    Point touchP0 = touch->getLocation();  
  
    firstX = touchP0.x;  
    firstY = touchP0.y;  
  
  
    return true;  
}  
  
// 触摸结束触发  
void HelloWorld::onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *unused_event){  
    // 获取触摸点位置  
    Point touchP0 = touch->getLocation();  
    // 获取X轴和Y轴的移动距离  
    endX = firstX - touchP0.x;  
    endY = firstY - touchP0.y;  
  
    // 判断X轴和Y轴的移动距离,如果X轴的绝对值大于Y轴的绝对值就是左右否则是上下  
    if (abs(endX) > abs(endY)){  
        // 左右  
        if (endX + 5 > 0) {  
            // 左边  
            if(doLeft()) {  
                autoCreateCardNumber();  
                doCheckGameOver();  
            }  
  
        } else {  
            // 右边  
            if(doRight()){  
                autoCreateCardNumber();  
                doCheckGameOver();  
            }  
        }  
  
    } else {  
        // 上下  
        if (endY + 5 > 0) {  
            // 下边  
            if(doDown()) {  
                autoCreateCardNumber();  
                doCheckGameOver();  
            }  
        } else {  
            // 上边  
            if(doUp()) {  
                autoCreateCardNumber();  
                doCheckGameOver();  
            };  
        }  
  
    }  
}  

 

HelloWorldinit方法中设置监听器的这两个方法的监听回调:

// 创建手势识别的事件监听器  
auto touchListener = EventListenerTouchOneByOne::create();  
touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);  
touchListener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);  
   // 添加事件监听  
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);  
 
上面中根据计算开始位置到结束位置X轴和Y轴的移动距离来判断是向左、向右、向上还是向下的方向:
在头文件中声明四个方向的方法:

   
    // 上下左右的方法  
    bool doLeft();  
    bool doRight();  
    bool doUp();  
    bool doDown(); 

然后对其进行实现。这四个方法的逻辑实现放到后面进行讲解。


游戏中卡片类的创建

卡片类是组成2048游戏的基础,4*4的方格的16个位置放置不同的卡片,每个位置为独立的一张卡片。

创建CardSprite.h的头文件:

 1 //  
 2 //  CardSprite.h  
 3 //  2048Game  
 4 //  
 5 //  Created by mac on 15-06-02.  
 6 //  
 7 //  
 8   
 9 #ifndef ___048Game__CardSprite__  
10 #define ___048Game__CardSprite__  
11   
12 #include "cocos2d.h"  
13   
14 class CardSprite:public cocos2d::Sprite {  
15       
16 public:  
17     // 初始化游戏卡片的方法  
18     static CardSprite *createCardSprite(int numbers, int width, int height, float CardSpriteX, float CardSpriteY);  
19     virtual bool init();  
20     CREATE_FUNC(CardSprite);  
21       
22     // 设置数字  
23     void setNumber(int num);  
24       
25     // 获取数字  
26     int getNumber();  
27 private:  
28     // 显示在界面的数字  
29     int number;  
30     void enemyInit(int numbers, int width, int height, float CardSpriteX, float CardSpriteY);  
31       
32     // 定义显示数字的控件  
33     cocos2d::LabelTTF *labTTFCardNumber;  
34       
35     // 显示的背景  
36     cocos2d::LayerColor *layerColorBG;  
37       
38       
39 };  
40   
41 #endif /* defined(___048Game__CardSprite__) */  

 

我们可以从游戏中看到,每张卡片有背景颜色和一个数字,所以我们在头文件需要声明它这两个属性。

CardSprite.cpp中对头文件方法的实现:
  1 //  
  2 //  CardSprite.cpp  
  3 //  2048Game  
  4 //  
  5 //  Created by wwj on 15-6-02.  
  6 //  
  7 //  
  8   
  9 #include "CardSprite.h"  
 10   
 11 USING_NS_CC;  
 12   
 13 // 初始化游戏卡片的方法  
 14 CardSprite* CardSprite::createCardSprite(int numbers, int width, int height, float CardSpriteX, float CardSpriteY) {  
 15     // new一个卡片精灵  
 16     CardSprite *enemy = new CardSprite();  
 17     if (enemy && enemy->init()) {  
 18         enemy->autorelease();  
 19         enemy->enemyInit(numbers, width, height, CardSpriteX, CardSpriteY);  
 20         return enemy;  
 21     }  
 22     CC_SAFE_DELETE(enemy);  
 23     return NULL;  
 24 }  
 25   
 26 // 卡片初始化方法  
 27 bool CardSprite::init() {  
 28     if (!Sprite::init()) {  
 29         return false;  
 30     }  
 31     return true;  
 32 }  
 33   
 34   
 35 // 设置数字  
 36 void CardSprite::setNumber(int num) {  
 37     number = num;  
 38       
 39     // 判断数字的大小来调整字体的大小  
 40     if (number >= 0) {  
 41         labTTFCardNumber->setFontSize(80);  
 42     }  
 43     if (number >= 16) {  
 44         labTTFCardNumber->setFontSize(60);  
 45     }  
 46     if (number >= 128) {  
 47         labTTFCardNumber->setFontSize(40);  
 48     }  
 49     if (number >= 1024) {  
 50         labTTFCardNumber->setFontSize(20);  
 51     }  
 52       
 53     // 判断数组的大小调整颜色  
 54     if (number == 0) {  
 55         layerColorBG->setColor(cocos2d::Color3B(200, 190, 180));  
 56     }  
 57     if (number == 2) {  
 58         layerColorBG->setColor(cocos2d::Color3B(240, 230, 220));  
 59     }  
 60     if (number == 4) {  
 61         layerColorBG->setColor(cocos2d::Color3B(240, 220, 200));  
 62     }  
 63     if (number == 8) {  
 64         layerColorBG->setColor(cocos2d::Color3B(240, 180, 120));  
 65     }  
 66     if (number == 16) {  
 67         layerColorBG->setColor(cocos2d::Color3B(240, 140, 90));  
 68     }  
 69     if (number == 32) {  
 70         layerColorBG->setColor(cocos2d::Color3B(240, 120, 90));  
 71     }  
 72     if (number == 64) {  
 73         layerColorBG->setColor(cocos2d::Color3B(240, 90, 60));  
 74     }  
 75     if (number == 128) {  
 76         layerColorBG->setColor(cocos2d::Color3B(240, 90, 60));  
 77     }  
 78     if (number == 256) {  
 79         layerColorBG->setColor(cocos2d::Color3B(240, 200, 70));  
 80     }  
 81     if (number == 512) {  
 82         layerColorBG->setColor(cocos2d::Color3B(240, 200, 70));  
 83     }  
 84     if (number == 1024) {  
 85         layerColorBG->setColor(cocos2d::Color3B(0, 130, 0));  
 86     }  
 87     if (number == 2048) {  
 88         layerColorBG->setColor(cocos2d::Color3B(0, 130, 0));  
 89     }  
 90       
 91       
 92     // 更新显示的数字  
 93     if (number > 0) {  
 94         labTTFCardNumber->setString(__String::createWithFormat("%i", num)->getCString() );  
 95     } else {  
 96         labTTFCardNumber->setString("");  
 97     }  
 98       
 99 }  
100   
101 // 获取数字  
102 int CardSprite::getNumber() {  
103     return number;  
104 }  
105   
106   
107 //第1个参数为数字,第2、3个参数为卡片的宽高,第4、5个参数为卡片的位置  
108 void CardSprite::enemyInit(int numbers, int width, int height, float CardSpriteX, float CardSpriteY) {  
109     // 初始化数字  
110     number = numbers;  
111       
112     // 加入游戏卡片的背景颜色  
113     layerColorBG = cocos2d::LayerColor::create(cocos2d::Color4B(200, 190, 180, 255), width - 15, height - 15);  
114     layerColorBG->setPosition(Point(CardSpriteX, CardSpriteY));  
115       
116     // 判断如果不等于0就显示,否则为空  
117     if (number > 0) {  
118         // 加入中间字体  
119         labTTFCardNumber = cocos2d::LabelTTF::create(__String::createWithFormat("%i", number)->getCString(), "HirakakuProN-W6", 100);  
120         // 显示卡片数字的位置,这里显示在背景的中间  
121         labTTFCardNumber->setPosition(Point(layerColorBG->getContentSize().width/2, layerColorBG->getContentSize().height/2));  
122         // 添加卡片数字到背景中  
123         layerColorBG->addChild(labTTFCardNumber);  
124     } else {  
125         // 加入中间字体  
126         labTTFCardNumber = cocos2d::LabelTTF::create("", "HirakakuProN-w6", 80);  
127         labTTFCardNumber->setPosition(Point(layerColorBG->getContentSize().width/2, layerColorBG->getContentSize().height/2));  
128         layerColorBG->addChild(labTTFCardNumber);  
129     }  
130     // 将卡片添加到层  
131     this->addChild(layerColorBG);  
132       
133 }
 
每张卡片都有相同的宽和高,但数字和位置不同,数字是显示在背景中间的,所以我们需要5个参数来初始化卡片的位置。

添加卡片到游戏中
卡片放置在4*4方框中的不同位置,首先我们需要计算出每张卡片的宽高,然后计算每张卡片所在的位置,最后进行显示。
HelloWorldScene.h头文件中声明创建卡片的方法:

// 创建卡片  
void createCardSprite(cocos2d::Size size);
 
HelloWorldScene.cpp中实现该方法:

    
    // 创建卡片,size为屏幕大小  
    void HelloWorld::createCardSprite(cocos2d::Size size) {  
    // 求出单元格的宽度和高度,28为左右距离  
    int lon = (size.width - 28) / 4;  
      
    // 4*4的单元格  
    for (int j = 0; j < 4; j++) {  
        for (int i = 0; i < 4; i++) {  
            // 数字0,宽高相同为lon,lon+j+20为卡片X轴位置,如lon+0+20为第一个卡片的位置,20是每张卡片的间隙,lon+i+20+size.height/6代表的意思是屏幕大小竖方向分了六份,我们这里只放4个位置  
           CardSprite *card = CardSprite::createCardSprite(0, lon, lon, lon * j + 10, lon * i + 10 + size.height / 6);  
            addChild(card);  
              
            // 添加卡片到二维数组中  
            cardArr[j][i] = card;  
        }  
    }  
}  

笔者对每张卡片显示的位置在代码中进行了说明,读者也可以思考一下为什么要这么做。

游戏中的逻辑实现
2048游戏最重要的部分就是四个方向的逻辑实现,也是开发这个游戏的难点所在。

    // 向左  
    bool HelloWorld::doLeft(){  
    log("doLeft");  
      
    bool isdo = false;  
    // 最外层循环为4*4迭代  
    for (int y = 0; y < 4; y++) {  
        for (int x = 0; x < 4; x++) {  
              
            // 这一层循环为判断卡片是合并还是清空  
            for (int x1 = x + 1; x1 < 4; x1++) {  
                if (cardArr[x1][y]->getNumber() > 0) {// 有数字  
                    if (cardArr[x][y]->getNumber() <= 0) { // 为空  
                        // 设置为右边卡片的数值  
                        cardArr[x][y]->setNumber(cardArr[x1][y]->getNumber());  
                        cardArr[x1][y]->setNumber(0);  
                          
                        x--;  
                        isdo = true;  
                          
                    } else if(cardArr[x][y]->getNumber() == cardArr[x1][y]->getNumber()) {  
                        // 当前卡片的值与其比较卡片的值相等,设置为其的2倍  
                        cardArr[x][y]->setNumber(cardArr[x][y]->getNumber()*2);  
                        cardArr[x1][y]->setNumber(0);  
                          
                          
                        // 设置分数  
                        score += cardArr[x][y]->getNumber();  
                        labelTTFCardNumber->setString(__String::createWithFormat("%i", score)->getCString());  
                        isdo = true;  
                    }  
                    break;// 跳出  
                }  
            }  
        }  
    }  
      
    return isdo;  
}  
  
// 向右  
bool HelloWorld::doRight(){  
    log("doRight");  
      
    bool isdo = false;  
    // 最外层循环为4*4迭代  
    for (int y = 0; y < 4; y++) {  
        for (int x = 3; x >= 0; x--) {  
              
            // 循环判断左边卡片往右是合并还是清空  
            for (int x1 = x - 1; x1 >= 0; x1-- ) {  
                if (cardArr[x1][y]->getNumber() > 0) {  
                    if (cardArr[x][y]->getNumber() <= 0) {  
                        cardArr[x][y]->setNumber(cardArr[x1][y]->getNumber());  
                          
                        x++;  
                        isdo = true;  
                    }  
                    else if (cardArr[x][y]->getNumber() == cardArr[x1][y]->getNumber()) {  
                        cardArr[x][y]->setNumber(cardArr[x][y]->getNumber() * 2);  
                        cardArr[x1][y]->setNumber(0);  
                          
                        // 设置分数  
                        score += cardArr[x][y]->getNumber();  
                        labelTTFCardNumber->setString(__String::createWithFormat("%i", score)->getCString());  
  
                        isdo = true;  
                    }  
                    break;  
                }  
  
            }  
        }  
          
    }  
      
    return isdo;  
  
}  
  
// 向上  
bool HelloWorld::doUp(){  
    log("doUp");  
    bool isdo = false;  
    // 最外层循环为4*4迭代  
    for (int x = 0; x < 4; x++) {  
        for (int y = 3; y >= 0; y--) {  
              
            // 这一层循环为判断卡片是合并还是清空  
            for (int y1 = y - 1; y1 >= 0; y1--) {  
                if (cardArr[x][y1]->getNumber() > 0) {// 有数字  
                    if (cardArr[x][y]->getNumber() <= 0) { // 为空  
                        // 设置为右边卡片的数值  
                        cardArr[x][y]->setNumber(cardArr[x][y1]->getNumber());  
                        cardArr[x][y1]->setNumber(0);  
                          
                        y++;  
                        isdo = true;  
                          
                    } else if(cardArr[x][y]->getNumber() == cardArr[x][y1]->getNumber()) {  
                        // 当前卡片的值与其比较卡片的值相等,设置为其的2倍  
                        cardArr[x][y]->setNumber(cardArr[x][y]->getNumber()*2);  
                        cardArr[x][y1]->setNumber(0);  
                          
                        // 设置分数  
                        score += cardArr[x][y]->getNumber();  
                        labelTTFCardNumber->setString(__String::createWithFormat("%i", score)->getCString());  
  
                        isdo = true;  
                    }  
                    break;// 跳出  
                }  
            }  
        }  
    }  
      
    return isdo;  
  
}  
  
// 向下  
bool HelloWorld::doDown(){  
    log("doDown");  
    bool isdo = false;  
    // 最外层循环为4*4迭代  
    for (int x = 0; x < 4; x++) {  
        for (int y = 0; y < 4; y++) {  
              
            // 这一层循环为判断卡片是合并还是清空  
            for (int y1 = y + 1; y1 < 4; y1++) {  
                if (cardArr[x][y1]->getNumber() > 0) {// 有数字  
                    if (cardArr[x][y]->getNumber() <= 0) { // 为空  
                        // 设置为右边卡片的数值  
                        cardArr[x][y]->setNumber(cardArr[x][y1]->getNumber());  
                        cardArr[x][y1]->setNumber(0);  
                          
                        y--;  
                        isdo = true;  
                          
                    } else if(cardArr[x][y]->getNumber() == cardArr[x][y1]->getNumber()) {  
                        // 当前卡片的值与其比较卡片的值相等,设置为其的2倍  
                        cardArr[x][y]->setNumber(cardArr[x][y]->getNumber()*2);  
                        cardArr[x][y1]->setNumber(0);  
                          
                          
                        // 设置分数  
                        score += cardArr[x][y]->getNumber();  
                        labelTTFCardNumber->setString(__String::createWithFormat("%i", score)->getCString());  
  
                        isdo = true;  
                    }  
                    break;// 跳出  
                }  
            }  
        }  
    }  
      
    return isdo;  
}  

游戏中随机卡片的生成
HelloWorldScene.h头文件中声明随机生成卡片的方法:

// 自动卡片生成  
void autoCreateCardNumber(); 
 
HelloWorldScene.cpp实现该方法:

    // 自动生成卡片  
    void HelloWorld::autoCreateCardNumber() {  
    int i = CCRANDOM_0_1() * 4;  
    int j = CCRANDOM_0_1() * 4;  
      
    // 判断是否已经存在的位置  
    if (cardArr[i][j]->getNumber() > 0) {  
        // 已存在,递归创建  
        autoCreateCardNumber();  
    } else {  
        // 生成2和4的比例是1:9的概率  
        cardArr[i][j]->setNumber(CCRANDOM_0_1() * 10 < 1 ? 4:2);  
    }  
}  

 

游戏结束判断
HelloWorldScene.h中声明判断游戏结束的方法:

    // 判断游戏是否还能继续运行下去  
    void doCheckGameOver();
  
HelloWorldScene.cpp中实现该方法:

    // 游戏是否还能继续运行下去  
    void HelloWorld::doCheckGameOver() {  
    bool isGameOver = true;  
      
    for (int y = 0; y < 4; y++) {  
        for (int x = 0; x < 4; x++) {  
            if (cardArr[x][y]->getNumber() == 0  
                || (x>0 && (cardArr[x][y]->getNumber() == cardArr[x-1][y]->getNumber() ))  
                || (x<3 && (cardArr[x][y]->getNumber() == cardArr[x+1][y]->getNumber()))  
                || (y<0 && (cardArr[x][y]->getNumber() == cardArr[x][y-1]->getNumber()))  
                || (x<3 && (cardArr[x][y]->getNumber() == cardArr[x][y+1]->getNumber()))) {  
                isGameOver = false;  
            }  
        }  
    }  
    if (isGameOver) {  
        // 结束游戏  
        Director::getInstance()->replaceScene(TransitionFade::create(1, HelloWorld::createScene()));  
    }  
  
}  

 

游戏分数的添加
2048中需要对分数进行统计并显示给玩家,我们在HelloWolrdScene.h文件中声明分数和显示分数的控件:

   // 整体游戏的分数  
    int score;  
    // 定义显示数据的控件  
    cocos2d::LabelTTF *labelTTFCardNumber;  

HelloWorldScene.cpp中对分数初始化为0,并显示“分数”的文本:
score = 0; 
 // 获得屏幕可视大小  
 Size visibleSize = Director::getInstance()->getVisibleSize();  
 // 加入游戏的背景  
 auto layerColorBG = cocos2d::LayerColor::create(cocos2d::Color4B(180,170,160, 255));  
 this->addChild(layerColorBG);  
 // 在上方加入游戏的分数  
 auto labelTTFCardNumberName = LabelTTF::create("分数:","HirakakuProN-W6", 80);  
 labelTTFCardNumberName->setPosition(Point(visibleSize.width/5, visibleSize.height-100));  
 addChild(labelTTFCardNumberName);  
   
   
 labelTTFCardNumber = LabelTTF::create("0", "HirakakuProN-W6", 80);  
 labelTTFCardNumber->setPosition(visibleSize.width/2+100, visibleSize.height - 100);  
 addChild(labelTTFCardNumber  
          );  

 

关于分数的计算,在游戏中的逻辑已经实现,具体读者可以查看代码,后面笔者也会提供完整的代码。
 

游戏美化
2048中我们会发现不同的数字会有不同的背景,然后字体大小也会随数值的变化而变化,实现这个需要通过判断数值的大小来显示不同的颜色背景和设置不同字体大小。

这个功能的实现是在卡片类设置数值的时候实现的,代码逻辑如下:
    // 设置数字  
    void CardSprite::setNumber(int num) {  
    number = num;  
      
    // 判断数字的大小来调整字体的大小  
    if (number >= 0) {  
        labTTFCardNumber->setFontSize(80);  
    }  
    if (number >= 16) {  
        labTTFCardNumber->setFontSize(60);  
    }  
    if (number >= 128) {  
        labTTFCardNumber->setFontSize(40);  
    }  
    if (number >= 1024) {  
        labTTFCardNumber->setFontSize(20);  
    }  
      
    // 判断数组的大小调整颜色  
    if (number == 0) {  
        layerColorBG->setColor(cocos2d::Color3B(200, 190, 180));  
    }  
    if (number == 2) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 230, 220));  
    }  
    if (number == 4) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 220, 200));  
    }  
    if (number == 8) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 180, 120));  
    }  
    if (number == 16) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 140, 90));  
    }  
    if (number == 32) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 120, 90));  
    }  
    if (number == 64) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 90, 60));  
    }  
    if (number == 128) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 90, 60));  
    }  
    if (number == 256) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 200, 70));  
    }  
    if (number == 512) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 200, 70));  
    }  
    if (number == 1024) {  
        layerColorBG->setColor(cocos2d::Color3B(0, 130, 0));  
    }  
    if (number == 2048) {  
        layerColorBG->setColor(cocos2d::Color3B(0, 130, 0));  
    }  
      
      
    // 更新显示的数字  
    if (number > 0) {  
        labTTFCardNumber->setString(__String::createWithFormat("%i", num)->getCString() );  
    } else {  
        labTTFCardNumber->setString("");  
    }  
      
}  
 

最后笔者给出所有代码清单:
  • AppDelegate.h
  • AppDelegate.cpp
  • HelloWorldScene.h
  • HelloWorldScene.cpp
  • CardSprite.h
  • CardSprite.cpp
>>>AppDelegate.h
#ifndef  _APP_DELEGATE_H_  
#define  _APP_DELEGATE_H_  
  
#include "cocos2d.h"  
  
/** 
@brief    The cocos2d Application. 
 
The reason for implement as private inheritance is to hide some interface call by Director. 
*/  
class  AppDelegate : private cocos2d::Application  
{  
public:  
    AppDelegate();  
    virtual ~AppDelegate();  
  
    /** 
    @brief    Implement Director and Scene init code here. 
    @return true    Initialize success, app continue. 
    @return false   Initialize failed, app terminate. 
    */  
    virtual bool applicationDidFinishLaunching();  
  
    /** 
    @brief  The function be called when the application enter background 
    @param  the pointer of the application 
    */  
    virtual void applicationDidEnterBackground();  
  
    /** 
    @brief  The function be called when the application enter foreground 
    @param  the pointer of the application 
    */  
    virtual void applicationWillEnterForeground();  
};  
  
#endif // _APP_DELEGATE_H_ 
 
>>>AppDelegate.cpp
#include "AppDelegate.h"  
#include "HelloWorldScene.h"  
  
USING_NS_CC;  
  
AppDelegate::AppDelegate() {  
  
}  
  
AppDelegate::~AppDelegate()   
{  
}  
  
bool AppDelegate::applicationDidFinishLaunching() {  
    // initialize director  
    auto director = Director::getInstance();  
    auto glview = director->getOpenGLView();  
    if(!glview) {  
        glview = GLView::create("My Game");  
        director->setOpenGLView(glview);  
    }  
  
    glview->setDesignResolutionSize(480, 800, ResolutionPolicy::SHOW_ALL);  
    // turn on display FPS  
    director->setDisplayStats(false);  
  
    // set FPS. the default value is 1.0/60 if you don‘t call this  
    director->setAnimationInterval(1.0 / 60);  
  
    // create a scene. it‘s an autorelease object  
    auto scene = HelloWorld::createScene();  
  
    // run  
    director->runWithScene(scene);  
  
    return true;  
}  
  
// This function will be called when the app is inactive. When comes a phone call,it‘s be invoked too  
void AppDelegate::applicationDidEnterBackground() {  
    Director::getInstance()->stopAnimation();  
  
    // if you use SimpleAudioEngine, it must be pause  
    // SimpleAudioEngine::getInstance()->pauseBackgroundMusic();  
}  
  
// this function will be called when the app is active again  
void AppDelegate::applicationWillEnterForeground() {  
    Director::getInstance()->startAnimation();  
  
    // if you use SimpleAudioEngine, it must resume here  
    // SimpleAudioEngine::getInstance()->resumeBackgroundMusic();  
}  

>>>HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__  
#define __HELLOWORLD_SCENE_H__  
  
#include "cocos2d.h"  
#include "CardSprite.h"  
  
class HelloWorld : public cocos2d::Layer  
{  
public:  
    static cocos2d::Scene* createScene();  
    virtual bool init();    
    void menuCloseCallback(cocos2d::Ref* pSender);  
    CREATE_FUNC(HelloWorld);  
  
    // 加入手势识别的事件  
    virtual bool onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *unused_event);  
    virtual void onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *unused_event);  
  
    // 上下左右的方法  
    bool doLeft();  
    bool doRight();  
    bool doUp();  
    bool doDown();  
    // 自动卡片生成  
    void autoCreateCardNumber();  
    // 判断游戏是否还能继续运行下去  
    void doCheckGameOver();  
      
  
private:  
    // 点击的元素位置  
    int firstX, firstY, endX, endY;  
      
    // 定义一个二维数组  
    CardSprite *cardArr[4][4];  
      
    // 创建卡片  
    void createCardSprite(cocos2d::Size size);  
      
    // 整体游戏的分数  
    int score;  
    // 定义显示数据的控件  
    cocos2d::LabelTTF *labelTTFCardNumber;  
};  
  
#endif // __HELLOWORLD_SCENE_H__ 

>>>HelloWorldScene.cpp
#include "HelloWorldScene.h"  
#include "CardSprite.h"  
  
USING_NS_CC;  
  
Scene* HelloWorld::createScene()  
{  
    // ‘scene‘ is an autorelease object  
    auto scene = Scene::create();  
  
    // ‘layer‘ is an autorelease object  
    auto 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 ( !Layer::init() )  
    {  
        return false;  
    }  
      
    score = 0;  
      
      
    // 获得屏幕可视大小  
    Size visibleSize = Director::getInstance()->getVisibleSize();  
    // 加入游戏的背景  
    auto layerColorBG = cocos2d::LayerColor::create(cocos2d::Color4B(180,170,160, 255));  
    this->addChild(layerColorBG);  
    // 在上方加入游戏的分数  
    auto labelTTFCardNumberName = LabelTTF::create("分数:","HirakakuProN-W6", 80);  
    labelTTFCardNumberName->setPosition(Point(visibleSize.width/5, visibleSize.height-100));  
    addChild(labelTTFCardNumberName);  
      
      
    labelTTFCardNumber = LabelTTF::create("0", "HirakakuProN-W6", 80);  
    labelTTFCardNumber->setPosition(visibleSize.width/2+100, visibleSize.height - 100);  
    addChild(labelTTFCardNumber  
             );  
      
     
    // 创建手势识别的事件监听器  
    auto touchListener = EventListenerTouchOneByOne::create();  
    touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);  
    touchListener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);  
    // 添加事件监听  
    _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);  
  
      
    // 调用生成卡片的方法  
    createCardSprite(visibleSize);  
      
    // 调用生成随机数  
    autoCreateCardNumber();  
    autoCreateCardNumber();  
    return true;  
}  
  
// 游戏是否还能继续运行下去  
void HelloWorld::doCheckGameOver() {  
    bool isGameOver = true;  
      
    for (int y = 0; y < 4; y++) {  
        for (int x = 0; x < 4; x++) {  
            if (cardArr[x][y]->getNumber() == 0  
                || (x>0 && (cardArr[x][y]->getNumber() == cardArr[x-1][y]->getNumber() ))  
                || (x<3 && (cardArr[x][y]->getNumber() == cardArr[x+1][y]->getNumber()))  
                || (y<0 && (cardArr[x][y]->getNumber() == cardArr[x][y-1]->getNumber()))  
                || (x<3 && (cardArr[x][y]->getNumber() == cardArr[x][y+1]->getNumber()))) {  
                isGameOver = false;  
            }  
        }  
    }  
    if (isGameOver) {  
        // 结束游戏  
        Director::getInstance()->replaceScene(TransitionFade::create(1, HelloWorld::createScene()));  
    }  
  
}  
  
// 自动生成卡片  
void HelloWorld::autoCreateCardNumber() {  
    int i = CCRANDOM_0_1() * 4;  
    int j = CCRANDOM_0_1() * 4;  
      
    // 判断是否已经存在的位置  
    if (cardArr[i][j]->getNumber() > 0) {  
        // 已存在,递归创建  
        autoCreateCardNumber();  
    } else {  
        // 生成2和4的比例是1:9的概率  
        cardArr[i][j]->setNumber(CCRANDOM_0_1() * 10 < 1 ? 4:2);  
    }  
}  
  
// 创建卡片,size为屏幕大小  
void HelloWorld::createCardSprite(cocos2d::Size size) {  
    // 求出单元格的宽度和高度,28为左右距离  
    int lon = (size.width - 28) / 4;  
      
    // 4*4的单元格  
    for (int j = 0; j < 4; j++) {  
        for (int i = 0; i < 4; i++) {  
            // 数字0,宽高相同为lon,lon+j+20为卡片X轴位置,如lon+0+20为第一个卡片的位置,20是每张卡片的间隙,lon+i+20+size.height/6代表的意思是屏幕大小竖方向分了六份,我们这里只放4个位置  
           CardSprite *card = CardSprite::createCardSprite(0, lon, lon, lon * j + 10, lon * i + 10 + size.height / 6);  
            addChild(card);  
              
            // 添加卡片到二维数组中  
            cardArr[j][i] = card;  
        }  
    }  
}  
  
// 加入手势识别的事件  
bool HelloWorld::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *unused_event){  
    // 触摸点  
    Point touchP0 = touch->getLocation();  
  
    firstX = touchP0.x;  
    firstY = touchP0.y;  
  
  
    return true;  
}  
  
// 触摸结束触发  
void HelloWorld::onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *unused_event){  
    // 获取触摸点位置  
    Point touchP0 = touch->getLocation();  
    // 获取X轴和Y轴的移动距离  
    endX = firstX - touchP0.x;  
    endY = firstY - touchP0.y;  
  
    // 判断X轴和Y轴的移动距离,如果X轴的绝对值大于Y轴的绝对值就是左右否则是上下  
    if (abs(endX) > abs(endY)){  
        // 左右  
        if (endX + 5 > 0) {  
            // 左边  
            if(doLeft()) {  
                autoCreateCardNumber();  
                doCheckGameOver();  
            }  
  
        } else {  
            // 右边  
            if(doRight()){  
                autoCreateCardNumber();  
                doCheckGameOver();  
            }  
        }  
  
    } else {  
        // 上下  
        if (endY + 5 > 0) {  
            // 下边  
            if(doDown()) {  
                autoCreateCardNumber();  
                doCheckGameOver();  
            }  
        } else {  
            // 上边  
            if(doUp()) {  
                autoCreateCardNumber();  
                doCheckGameOver();  
            };  
        }  
  
    }  
}  
  
  
// 向左  
bool HelloWorld::doLeft(){  
    log("doLeft");  
      
    bool isdo = false;  
    // 最外层循环为4*4迭代  
    for (int y = 0; y < 4; y++) {  
        for (int x = 0; x < 4; x++) {  
              
            // 这一层循环为判断卡片是合并还是清空  
            for (int x1 = x + 1; x1 < 4; x1++) {  
                if (cardArr[x1][y]->getNumber() > 0) {// 有数字  
                    if (cardArr[x][y]->getNumber() <= 0) { // 为空  
                        // 设置为右边卡片的数值  
                        cardArr[x][y]->setNumber(cardArr[x1][y]->getNumber());  
                        cardArr[x1][y]->setNumber(0);  
                          
                        x--;  
                        isdo = true;  
                          
                    } else if(cardArr[x][y]->getNumber() == cardArr[x1][y]->getNumber()) {  
                        // 当前卡片的值与其比较卡片的值相等,设置为其的2倍  
                        cardArr[x][y]->setNumber(cardArr[x][y]->getNumber()*2);  
                        cardArr[x1][y]->setNumber(0);  
                          
                          
                        // 设置分数  
                        score += cardArr[x][y]->getNumber();  
                        labelTTFCardNumber->setString(__String::createWithFormat("%i", score)->getCString());  
                        isdo = true;  
                    }  
                    break;// 跳出  
                }  
            }  
        }  
    }  
      
    return isdo;  
}  
  
// 向右  
bool HelloWorld::doRight(){  
    log("doRight");  
      
    bool isdo = false;  
    // 最外层循环为4*4迭代  
    for (int y = 0; y < 4; y++) {  
        for (int x = 3; x >= 0; x--) {  
              
            // 循环判断左边卡片往右是合并还是清空  
            for (int x1 = x - 1; x1 >= 0; x1-- ) {  
                if (cardArr[x1][y]->getNumber() > 0) {  
                    if (cardArr[x][y]->getNumber() <= 0) {  
                        cardArr[x][y]->setNumber(cardArr[x1][y]->getNumber());  
                          
                        x++;  
                        isdo = true;  
                    }  
                    else if (cardArr[x][y]->getNumber() == cardArr[x1][y]->getNumber()) {  
                        cardArr[x][y]->setNumber(cardArr[x][y]->getNumber() * 2);  
                        cardArr[x1][y]->setNumber(0);  
                          
                        // 设置分数  
                        score += cardArr[x][y]->getNumber();  
                        labelTTFCardNumber->setString(__String::createWithFormat("%i", score)->getCString());  
  
                        isdo = true;  
                    }  
                    break;  
                }  
  
            }  
        }  
          
    }  
      
    return isdo;  
  
}  
  
// 向上  
bool HelloWorld::doUp(){  
    log("doUp");  
    bool isdo = false;  
    // 最外层循环为4*4迭代  
    for (int x = 0; x < 4; x++) {  
        for (int y = 3; y >= 0; y--) {  
              
            // 这一层循环为判断卡片是合并还是清空  
            for (int y1 = y - 1; y1 >= 0; y1--) {  
                if (cardArr[x][y1]->getNumber() > 0) {// 有数字  
                    if (cardArr[x][y]->getNumber() <= 0) { // 为空  
                        // 设置为右边卡片的数值  
                        cardArr[x][y]->setNumber(cardArr[x][y1]->getNumber());  
                        cardArr[x][y1]->setNumber(0);  
                          
                        y++;  
                        isdo = true;  
                          
                    } else if(cardArr[x][y]->getNumber() == cardArr[x][y1]->getNumber()) {  
                        // 当前卡片的值与其比较卡片的值相等,设置为其的2倍  
                        cardArr[x][y]->setNumber(cardArr[x][y]->getNumber()*2);  
                        cardArr[x][y1]->setNumber(0);  
                          
                        // 设置分数  
                        score += cardArr[x][y]->getNumber();  
                        labelTTFCardNumber->setString(__String::createWithFormat("%i", score)->getCString());  
  
                        isdo = true;  
                    }  
                    break;// 跳出  
                }  
            }  
        }  
    }  
      
    return isdo;  
  
}  
  
// 向下  
bool HelloWorld::doDown(){  
    log("doDown");  
    bool isdo = false;  
    // 最外层循环为4*4迭代  
    for (int x = 0; x < 4; x++) {  
        for (int y = 0; y < 4; y++) {  
              
            // 这一层循环为判断卡片是合并还是清空  
            for (int y1 = y + 1; y1 < 4; y1++) {  
                if (cardArr[x][y1]->getNumber() > 0) {// 有数字  
                    if (cardArr[x][y]->getNumber() <= 0) { // 为空  
                        // 设置为右边卡片的数值  
                        cardArr[x][y]->setNumber(cardArr[x][y1]->getNumber());  
                        cardArr[x][y1]->setNumber(0);  
                          
                        y--;  
                        isdo = true;  
                          
                    } else if(cardArr[x][y]->getNumber() == cardArr[x][y1]->getNumber()) {  
                        // 当前卡片的值与其比较卡片的值相等,设置为其的2倍  
                        cardArr[x][y]->setNumber(cardArr[x][y]->getNumber()*2);  
                        cardArr[x][y1]->setNumber(0);  
                          
                          
                        // 设置分数  
                        score += cardArr[x][y]->getNumber();  
                        labelTTFCardNumber->setString(__String::createWithFormat("%i", score)->getCString());  
  
                        isdo = true;  
                    }  
                    break;// 跳出  
                }  
            }  
        }  
    }  
      
    return isdo;  
}  

void HelloWorld::menuCloseCallback(Ref* pSender)  
{  
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)  
    MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");  
    return;  
#endif  
  
    Director::getInstance()->end();  
  
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)  
    exit(0);  
#endif  
}

 

 
>>>CardSprite.h
//  
//  CardSprite.h  
//  2048Game  
//  
//  Created by mac on 15-6-02.  
//  
//  
  
#ifndef ___048Game__CardSprite__  
#define ___048Game__CardSprite__  
  
#include "cocos2d.h"  
  
class CardSprite:public cocos2d::Sprite {  
      
public:  
    // 初始化游戏卡片的方法  
    static CardSprite *createCardSprite(int numbers, int width, int height, float CardSpriteX, float CardSpriteY);  
    virtual bool init();  
    CREATE_FUNC(CardSprite);  
      
    // 设置数字  
    void setNumber(int num);  
      
    // 获取数字  
    int getNumber();  
private:  
    // 显示在界面的数字  
    int number;  
    void enemyInit(int numbers, int width, int height, float CardSpriteX, float CardSpriteY);  
      
    // 定义显示数字的控件  
    cocos2d::LabelTTF *labTTFCardNumber;  
      
    // 显示的背景  
    cocos2d::LayerColor *layerColorBG;  
      
      
};  
  
#endif /* defined(___048Game__CardSprite__) */ 

>>>CardSprite.cpp
//  
//  CardSprite.cpp  
//  2048Game  
//  
//  Created by wwj on 15-6-02.  
//  
//  
  
#include "CardSprite.h"  
  
USING_NS_CC;  
  
// 初始化游戏卡片的方法  
CardSprite* CardSprite::createCardSprite(int numbers, int width, int height, float CardSpriteX, float CardSpriteY) {  
    // new一个卡片精灵  
    CardSprite *enemy = new CardSprite();  
    if (enemy && enemy->init()) {  
        enemy->autorelease();  
        enemy->enemyInit(numbers, width, height, CardSpriteX, CardSpriteY);  
        return enemy;  
    }  
    CC_SAFE_DELETE(enemy);  
    return NULL;  
}  
  
// 卡片初始化方法  
bool CardSprite::init() {  
    if (!Sprite::init()) {  
        return false;  
    }  
    return true;  
}  
  
  
// 设置数字  
void CardSprite::setNumber(int num) {  
    number = num;  
      
    // 判断数字的大小来调整字体的大小  
    if (number >= 0) {  
        labTTFCardNumber->setFontSize(80);  
    }  
    if (number >= 16) {  
        labTTFCardNumber->setFontSize(60);  
    }  
    if (number >= 128) {  
        labTTFCardNumber->setFontSize(40);  
    }  
    if (number >= 1024) {  
        labTTFCardNumber->setFontSize(20);  
    }  
      
    // 判断数组的大小调整颜色  
    if (number == 0) {  
        layerColorBG->setColor(cocos2d::Color3B(200, 190, 180));  
    }  
    if (number == 2) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 230, 220));  
    }  
    if (number == 4) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 220, 200));  
    }  
    if (number == 8) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 180, 120));  
    }  
    if (number == 16) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 140, 90));  
    }  
    if (number == 32) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 120, 90));  
    }  
    if (number == 64) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 90, 60));  
    }  
    if (number == 128) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 90, 60));  
    }  
    if (number == 256) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 200, 70));  
    }  
    if (number == 512) {  
        layerColorBG->setColor(cocos2d::Color3B(240, 200, 70));  
    }  
    if (number == 1024) {  
        layerColorBG->setColor(cocos2d::Color3B(0, 130, 0));  
    }  
    if (number == 2048) {  
        layerColorBG->setColor(cocos2d::Color3B(0, 130, 0));  
    }  
// 更新显示的数字 if (number > 0) { labTTFCardNumber->setString(__String::createWithFormat("%i", num)->getCString() ); } else { labTTFCardNumber->setString(""); } } // 获取数字 int CardSprite::getNumber() { return number; } //第1个参数为数字,第2、3个参数为卡片的宽高,第4、5个参数为卡片的位置 void CardSprite::enemyInit(int numbers, int width, int height, float CardSpriteX, float CardSpriteY) { // 初始化数字 number = numbers; // 加入游戏卡片的背景颜色 layerColorBG = cocos2d::LayerColor::create(cocos2d::Color4B(200, 190, 180, 255), width - 15, height - 15); layerColorBG->setPosition(Point(CardSpriteX, CardSpriteY)); // 判断如果不等于0就显示,否则为空 if (number > 0) { // 加入中间字体 labTTFCardNumber = cocos2d::LabelTTF::create(__String::createWithFormat("%i", number)->getCString(), "HirakakuProN-W6", 100); // 显示卡片数字的位置,这里显示在背景的中间 labTTFCardNumber->setPosition(Point(layerColorBG->getContentSize().width/2, layerColorBG->getContentSize().height/2)); // 添加卡片数字到背景中 layerColorBG->addChild(labTTFCardNumber); } else { // 加入中间字体 labTTFCardNumber = cocos2d::LabelTTF::create("", "HirakakuProN-w6", 80); labTTFCardNumber->setPosition(Point(layerColorBG->getContentSize().width/2, layerColorBG->getContentSize().height/2)); layerColorBG->addChild(labTTFCardNumber); } // 将卡片添加到层 this->addChild(layerColorBG); }

最后,骚年们就不要向我要源码了,所有的代码在这里均有实现,只要把这些代码集成到你的项目中去就可以实现跟笔者一样的效果,希望各位能好好体会2048开发的流程。
 技术分享

Cocos2d-x 3.x版2048游戏开发

标签:

原文地址:http://www.cnblogs.com/dan-alone/p/4545715.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!