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