2048主要是对方块的操作,所以我们最好封装一个方块类
新建头文件CardSprite.h,代码如下:
#ifndef __CARDSPRITE_SCENE_H__
#define __CARDSPRITE_SCENE_H__
#include "cocos2d.h"
class CardSprite : public cocos2d::Sprite
{
public:
//初始化的数值,宽度,高度,卡片X轴,卡片Y轴
static CardSprite* createCardSprite(int numbers,int width,int height,float CardSpriteX,float CardSpriteY);
virtual bool init();
CREATE_FUNC(CardSprite);
//获取数字
int getNumber();
//设置数字
void setNumber(int num);
private:
//显示在界面中的数字
int number;
void enemyInit(int numbers,int width,int height,float CardSpriteX,float CardSpriteY);
//定义显示数字的控件
cocos2d::LabelTTF* labelTTFCardNumber;
//显示背景
cocos2d::LayerColor* layerColorBG;
};
#endif // __CARDSPRITE_SCENE_H__
CardSprite.cpp
bool CardSprite::init()
{
if(!Sprite::init())
{
return false;
}
return true;
}
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;
}
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)
{
//加入中间字体
labelTTFCardNumber = LabelTTF::create(String::createWithFormat("%i",number)->getCString(),"HiraKakuProN-W6",100);
labelTTFCardNumber->setPosition(Point(layerColorBG->getContentSize().width/2,layerColorBG->getContentSize().height/2));
labelTTFCardNumber->setTag(8);
layerColorBG->addChild(labelTTFCardNumber);
}
else
{
//加入中间字体
labelTTFCardNumber = LabelTTF::create("","HiraKakuProN-W6",100);
labelTTFCardNumber->setPosition(Point(layerColorBG->getContentSize().width/2,layerColorBG->getContentSize().height/2));
labelTTFCardNumber->setTag(8);
layerColorBG->addChild(labelTTFCardNumber);
}
this->addChild(layerColorBG);
}
//获取数字
int CardSprite::getNumber()
{
return number;
}
//设置数字
void CardSprite::setNumber(int num)
{
number = num;
if(number > 0)
{
//获取数字重新更新数字
labelTTFCardNumber->setString(String::createWithFormat("%i",number)->getCString());
}
else
{
labelTTFCardNumber->setString("");
}
//判断数字的大小来调整字体
if (number >= 0) {
labelTTFCardNumber->setFontSize(100);
}
if (number >= 16) {
labelTTFCardNumber->setFontSize(90);
}
if(number >= 128){
labelTTFCardNumber->setFontSize(60);
}
if(number >= 1024){
labelTTFCardNumber->setFontSize(40);
}
//判断数字的大小来调整颜色
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));
}
}
这个类的主要功能是创建卡片以及给卡片设置属性,也就是卡片的数字以及数字大小、颜色。
有了卡片类,下面就把卡片加入到界面GameScene上:
GameScene.h
//创建一个卡片二位数组
CardSprite* cardArr[4][4];
//创建卡片
void createCardSprite(cocos2d::Size size);
//自动生成卡片
void autoCreateCardNumber();
GameScene.cpp
在init()函数中:
Size visibleSize = Director::getInstance()->getVisibleSize();
//创建卡片
createCardSprite(visibleSize);
//加入游戏的背景颜色
auto layerColorBG = cocos2d::LayerColor::create(cocos2d::Color4B(180,170,160,255));
this->addChild(layerColorBG);
//在游戏刚开始的时候,创建两个卡片,所以调用两次这个函数创建2张自动生成卡片
autoCreateCardNumber();
autoCreateCardNumber();
//判断游戏是否还能继续
void doCheckGameOver();
//滑向上下左右的方法
bool doUp();
bool doDown();
bool doLeft();
bool doRight();
//点击元素
int firstX,firstY,endX,endY;
//触摸监听
auto touchListener=EventListenerTouchOneByOne::create();
touchListener->onTouchBegan=CC_CALLBACK_2(HelloWorld::onTouchBegan,this);
touchListener->onTouchEnded=CC_CALLBACK_2(HelloWorld::onTouchEnded,this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener,this);
//创建卡片
void GameScene::createCardSprite(cocos2d::Size size)
{
//求出单元格的宽度和高度
int unitSize = (size.height-28)/4;
//4*4的单元格
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
{
//最后两个参数,需要根据手机屏幕进行适配。
CardSprite* card = CardSprite::createCardSprite(2, unitSize, unitSize, unitSize*i+140, unitSize*j+20);
addChild(card);
//把卡片加入到数组中
cardArr[i][j] = card;
}
}
}
//自动生成卡片
void GameScene::autoCreateCardNumber()
{
int i = CCRANDOM_0_1()*4;
int j = CCRANDOM_0_1()*4;
//判断是否这个位置已存在卡片
if(cardArr[i][j]->getNumber() > 0)
{
autoCreateCardNumber();
}
else
{
cardArr[i][j]->setNumber(CCRANDOM_0_1()*10 < 1 ? 2: 4);
}
}
卡片已经加入到界面中,然后就是游戏的算法逻辑,因为该游戏根据手势滑动来处理,所以逻辑的处理都应在触摸事件中:
向左滑动函数的逻辑代码:
bool GameScene::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[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;
}
大概意思就是遍历所有方块,如果这个方块右边的方块不为空,则该方块会向左侧移动,如果右边的数等于左边的数,那么左边的数乘以2,然后把右边的数设置为0,也就变为了空。
向右滑动函数的逻辑代码:
bool GameScene::doRight(){
bool isdo = false;
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());
cardArr[x1][y]->setNumber(0);
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);
isdo = true;
}
break;
}
}
}
}
return isdo;
}
向下滑动函数的逻辑代码:
bool GameScene::doDown(){
bool isdo = false;
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()){
cardArr[x][y]->setNumber(cardArr[x][y]->getNumber()*2);
cardArr[x][y1]->setNumber(0);
isdo = true;
}
break;
}
}
}
}
return isdo;
}
向上滑动函数的逻辑代码:
bool GameScene::doUp(){
bool isdo = false;
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()){
cardArr[x][y]->setNumber(cardArr[x][y]->getNumber()*2);
cardArr[x][y1]->setNumber(0);
isdo = true;
}
break;
}
}
}
}
return isdo;
}
//判断游戏是否还能继续
//利用五个条件判断游戏是否还能够继续:(1)还有空卡片 (2)还可以向右滑 (3)还可以向左滑 (4)还可以向上滑 (5)还可以向下滑。
只要以上条件满足一个,游戏就可以再继续。否则,游戏就不能够再继续了,会重新回到开始的界面。
void GameScene::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()))||
(y<3&&(cardArr[x][y]->getNumber() == cardArr[x][y+1]->getNumber()))) {
isGameOver = false;
}
}
}
if (isGameOver) {
//游戏结束,重新开始游戏
log("游戏结束");
Director::getInstance()->replaceScene(TransitionFade::create(1, HelloWorld::createScene()));
}
}
//事件监听回调:触摸开始
bool GameScene::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *unused_event)
{
//获取触摸的X轴和Y轴
Point touchPoint = touch->getLocation(); //获取OpenGL坐标(即cocos2d-x坐标,原点在左下角)
touch->getLocationInView();
firstX=touchPoint.x;
firstY=touchPoint.y;
return true;
}
//事件监听回调:触摸结束
void GameScene::onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *unused_event)
{
//获取X轴和Y轴的移动范围
Point touchPoint=touch->getLocation(); //获取OpenGL坐标(即cocos2d-x坐标,原点在左下角)
endX=firstX - touchPoint.x;
endY=firstY - touchPoint.y;
//判断X轴和Y轴的移动距离,如果X轴的绝对值大,则向左右滑动,如果Y轴的绝对值大,则向上下滑动
if(abs(endX) > abs(endY))
{
//手势向左右
//判断向左还是向右
if(endX+5>0)
{
//向左
doleft();
}
else
{
//向右
doRight();
}
}
else
{
//手势向上下
//判断手势向上还是向下
if(endY+5>0)
{
//向下
doDown();
}
else
{
//向上
doUp();
}
}
//判断游戏是否还能继续
doCheckGameOver();
}