年前用cocos2d实现了2048的鼠标手势识别,数字变换,得分记录以及卡片对象的大小位置颜色设置

 游戏基本思想:

在原有游戏界面的基础上创建4*4的卡片排列矩阵并且存入一个二维数组,每个卡片对象内置数字初始化方法,包括设置数字,更改数字。

卡片类头文件如下:

#ifndef _2048_CardSprite_
#define _2048_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 // !

各个方法的实现:

#include"CardSprite.h"


USING_NS_CC;



//初始化游戏卡片的方法
CardSprite* CardSprite::createCardSprite(int numbers, int width, int height, float CardSpriteX, float CardSpriteY){
    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(40);
    }

    if (number >= 16){
        labTTFCardNumber->setFontSize(35);
    }
    if (number >= 128){
        labTTFCardNumber->setFontSize(30);
    }
    if (number >= 1024){
        labTTFCardNumber->setFontSize(20);
    }

    //设置字体的颜色
    if (number == 0){
        labTTFCardNumber->setColor(cocos2d::Color3B(255, 222, 173));
    }
    if (number == 2){
        labTTFCardNumber->setColor(cocos2d::Color3B(176, 196, 222));
    }
    if (number == 4){
        labTTFCardNumber->setColor(cocos2d::Color3B(100, 149, 237));
    }
    if (number == 8){
        labTTFCardNumber->setColor(cocos2d::Color3B(0, 0, 255));
    }
    if (number == 16){
        labTTFCardNumber->setColor(cocos2d::Color3B(102, 205, 170));
    }
    if (number == 32){
        labTTFCardNumber->setColor(cocos2d::Color3B(124, 252, 0));
    }
    if (number == 64){
        labTTFCardNumber->setColor(cocos2d::Color3B(0, 255, 0));
    }
    if (number == 128){
        labTTFCardNumber->setColor(cocos2d::Color3B(0, 250, 154));
    }
    if (number == 256){
        labTTFCardNumber->setColor(cocos2d::Color3B(138, 43, 226));
    }
    if (number == 512){
        labTTFCardNumber->setColor(cocos2d::Color3B(255, 165, 0));
    }
    if (number == 1024){
        labTTFCardNumber->setColor(cocos2d::Color3B(255, 114, 86));
    }
    if (number == 2048){
        labTTFCardNumber->setColor(cocos2d::Color3B(139, 0, 0));
    }
    if (number == 4096){
        labTTFCardNumber->setColor(cocos2d::Color3B(130, 130, 130));
    }
    if (number == 8192){
        labTTFCardNumber->setColor(cocos2d::Color3B(255, 250, 250));
    }

    //更新显示的数字

    if (number > 0){
        labTTFCardNumber->setString(__String::createWithFormat("%i", number)->getCString());
    }
    else{
        labTTFCardNumber->setString("");

    }

}

//获取数字
int CardSprite::getNumber(){
    return number;
}

void CardSprite::enemyInit(int numbers, int width, int height, float CardSpriteX, float CardSpriteY){
    //初始化数字
    number = numbers;

    //加入游戏卡片的背景颜色

    layerColorBG = cocos2d::LayerColor::create(cocos2d::Color4B(202, 255, 112, 255), width - 3, height - 3);
    layerColorBG->setPosition(Point(CardSpriteX, CardSpriteY));


    //判断如果不等于0就显示,否则为空

    if (number > 0)
    {
        //加入中间字体
        labTTFCardNumber = cocos2d::LabelTTF::create(__String::createWithFormat("%i", number)->getCString(), "Arial", 15);
        labTTFCardNumber->setPosition(Point(layerColorBG->getContentSize().width / 2, layerColorBG->getContentSize().height/2));
        layerColorBG->addChild(labTTFCardNumber);
    }
    else{
        labTTFCardNumber = cocos2d::LabelTTF::create("", "Arial", 15);
        labTTFCardNumber->setPosition(Point(layerColorBG->getContentSize().width / 2, layerColorBG->getContentSize().height / 2));
        layerColorBG->addChild(labTTFCardNumber);
    }

    this->addChild(layerColorBG);

}

由此可见,每个卡片对象的表现形式就是背景颜色。。。。

 

在游戏主界面创建卡片的方法:

void HelloWorld::createCardSprite(cocos2d::Size size){
    //求出单元格的宽度跟高度

    int lon = (size.width - 60) / 4;

    //4*4的单元格

    for (int j = 0; j < 4; j++)
        for (int i = 0; i < 4; i++)
        {
            CardSprite * card = CardSprite::createCardSprite(0, lon, lon, lon*j + 110, lon*i+ size.height / 12-10);
            addChild(card);
            //加到数组里
            cardArr[j][i] = card;
        }
}

鼠标手势的识别:

bool HelloWorld::onTouchBegan(cocos2d::CCTouch *touch, cocos2d::Event *unused_event){
    Point touchPO = touch->getLocation();


    firstX = touchPO.x;
    firstY = touchPO.y;



    return true;
}



void HelloWorld::onTouchEnded(cocos2d::CCTouch *touch, cocos2d::Event *unused_event){
    Point touchPO = touch->getLocation();


    endX = firstX - touchPO.x;
    endY = firstY - touchPO.y;

    if (abs(endX) > abs(endY))
    {
        //左右
        if (endX + 5 < 0){        //5的偏移分量一般很小,防止误识别的话尽量往大的方向设置!!!
            if (doRight()){
                autoCreateCardNumber();
                //doCheckGameOver();
            }
        }
        else{
            if (doLeft()){
                autoCreateCardNumber();
                //doCheckGameOver();
            }
        }

    }
    else{
        //上下
        if (endY + 5 < 0){
            if (doUp()){
                autoCreateCardNumber();
                //doCheckGameOver();
            }
        }
        else{
            if (doDown()){
                autoCreateCardNumber();
                //doCheckGameOver();
            }
        }
    }
}


//监听事件的绑定:

//监听事件绑定
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
touchListener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);

 

2048主算法(左移):

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 (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())
                    {
                        cardArr[x][y]->setNumber(cardArr[x1][y]->getNumber() * 2);
                        cardArr[x1][y]->setNumber(0);
                        //设置分数

                        score += cardArr[x][y]->getNumber();
                        labTTFCardNumber->setString(__String::createWithFormat("%i", score)->getCString());

                        isDo = true;

                    }
                    break;
                }
            }
        }
    }
    return isDo;
}

算法分析:当识别手势执行相应方法后:从第一排第一列c1开始遍历,观察c1右边的卡片c2是否有数字,有的话进入下一层判断,如果两个数字相同,c2归零,c1乘2,如果c1没有数字,c1设置为c2,c2归零,c1的位置还要左移一位,当然还有不相同但都有数字的情况,暂且搁一边。除了相同的数字合并外,c1都要左移,且跳出这个循环,从下一个卡片再开始判断,由于c1左移,所以又从原来的卡片位置开始判断,原来c2的位置已归零,所以内层循环起作用c2右移,所以就遍历了c1右边的所有卡片,只要合并过一次或移动到头一次,就会跳入第一排第二列c2的判断循环,方法如上,这就解释了当数字不同的时候,要么有一个数字是合并过的,另一个就该在此处,或是两个都没合并过,一起移动到最左。其它三个方法也是一样的思想,只不过方向不同。。。。

 

 

 

最后游戏bug和疑问:1.每个行为方法里面的x--和break语句仔细考虑后净是为了减少运算量,,。。。。。

                             2.由于没有设置随机种子,每次自动生成的数字在游戏前期貌似都是相同的位置,特别是开始的时候只有两个固定的位置。。。。- -