这次我们来完成整个2048的数字相加逻辑其实2048玩起来简单,做起来也简单,复杂就复杂在这整个游戏的逻辑。
1.分析向左滑动
第一轮相加
步骤:
1. 单1+单2 单1=2 单2赋值为0 (单1为空,可以加任何数字)
2. 单1+单3 单1=4 单3赋值为0 (单1不为空,只能加和他相同的数字)
3. 单1+单4 单1=4 单4不变 (单1不为空,只能加和他相同的数字)
1. 单1+单2 单1=2 单2赋值为0 (单1为空,可以加任何数字)
2. 单1+单3 单1=4 单3赋值为0 (单1不为空,只能加和他相同的数字)
3. 单1+单4 单1=4 单4不变 (单1不为空,只能加和他相同的数字)
第二轮相加步骤:
1. 单2+单3 单2=0 单3不变 (单2为0可以加任何数字,但是单3也是0,,其实加不加都是一个效果)
2. 单2+单4 单2=2 单4赋值0 (单2为0可以加任何数字)
接着就是单3加单4了,这两个都为空,什么都不做,最终的效果也就是,第二轮相加后的效果了
这个其实就是用的冒泡算法,好了,理解了之后,那么我们来写代码。
首先,我们在初始化矩阵中给所有的数字方块初始化为2,暂时先注释掉随机创建的方法
void HelloWorld::initMatrix(CCSize size)
{
//两个方块之间的空隙
int space=10;
int SquareSize=(size.width-space*5)/4;
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 4; y++)
{
float pointx=space+x*SquareSize+x*space;
float pointy=40+y*SquareSize+y*space;
SquareSprite* pSquareSprite=SquareSprite::createSquareSprite(2,pointx,pointy,SquareSize,SquareSize);
this->addChild(pSquareSprite,1);
m_squarearray[x][y]=pSquareSprite;
}
}
/*
//刚开始游戏,创建两个方块
autoSquare();
autoSquare();
*/
}
OK,向左滑动,那么此时我们需要在doLeft方法中写代码咯
bool HelloWorld::doLeft()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
for (int afterx = x+1; afterx < 4; afterx++)
{
}
}
}
return true;
}
大概的框架就是这样子吧??最外层的y我们可以忽视,这是左加不是上下加
里面两个循环表示什么呢??x=0时 afterx=1
即单1和单2 依次类推
OK,我们在循环中写代码,
bool HelloWorld::doLeft()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
for (int afterx = x+1; afterx < 4; afterx++)
{
if (m_squarearray[x][y]->getNumber()==0)
{
m_squarearray[x][y]->setNumber(m_squarearray[afterx][y]->getNumber());
m_squarearray[afterx][y]->setNumber(0);
}
else if (m_squarearray[afterx][y]->getNumber()==m_squarearray[x][y]->getNumber())
{
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[afterx][y]->setNumber(0);
}
}
}
}
return true;
}
这里有两种情况,
1.单1等于0时,不管单2是什么,都要和单2调换位置
2.单1不等于0时,那么只有单1和单2相等,才能相加
大家可以运行看看效果。
2.分析向右滑动
这里和向左滑动差不多,其实就是一个是顺着来一个是倒着来,我就不画图了,直接上代码
bool HelloWorld::doReight()
{
for (int y = 0; y < 4; y++)
{
for (int x = 3; x >=0; x--)
{
for (int afterx = x-1; afterx >=0; afterx--)
{
if (m_squarearray[x][y]->getNumber()==0)
{
m_squarearray[x][y]->setNumber(m_squarearray[afterx][y]->getNumber());
m_squarearray[afterx][y]->setNumber(0);
}
else if (m_squarearray[afterx][y]->getNumber()==m_squarearray[x][y]->getNumber())
{
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[afterx][y]->setNumber(0);
}
}
}
}
return true;
}
其他地方都没改,就把两个循环改了一下
3.分析向上滑动
bool HelloWorld::doTop()
{
for (int x = 0; x < 4; x++)
{
for (int y = 3; y >=0; y--)
{
for (int aftery = y-1; aftery >=0; aftery--)
{
if (m_squarearray[x][y]->getNumber()==0)
{
m_squarearray[x][y]->setNumber(m_squarearray[x][aftery]->getNumber());
m_squarearray[x][aftery]->setNumber(0);
}
else if (m_squarearray[x][aftery]->getNumber()==m_squarearray[x][y]->getNumber())
{
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[x][aftery]->setNumber(0);
}
}
}
}
return true;
}
4.分析向下滑动
bool HelloWorld::doDown()
{
for (int x = 0; x < 4; x++)
{
for (int y = 0; y <4; y++)
{
for (int aftery = y+1; aftery <4; aftery++)
{
if (m_squarearray[x][y]->getNumber()==0)
{
m_squarearray[x][y]->setNumber(m_squarearray[x][aftery]->getNumber());
m_squarearray[x][aftery]->setNumber(0);
}
else if (m_squarearray[x][aftery]->getNumber()==m_squarearray[x][y]->getNumber())
{
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[x][aftery]->setNumber(0);
}
}
}
}
return true;
}
现在基本上成了,那么我再修改其他几个函数,
首先把初始化矩阵的方法还原
void HelloWorld::initMatrix(CCSize size)
{
//两个方块之间的空隙
int space=10;
int SquareSize=(size.width-space*5)/4;
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 4; y++)
{
float pointx=space+x*SquareSize+x*space;
float pointy=40+y*SquareSize+y*space;
SquareSprite* pSquareSprite=SquareSprite::createSquareSprite(0,pointx,pointy,SquareSize,SquareSize);
this->addChild(pSquareSprite,1);
m_squarearray[x][y]=pSquareSprite;
}
}
//刚开始游戏,创建两个方块
autoSquare();
autoSquare();
}
然后,不管用户向那个方向滑动,只要是滑动了,就都得产生一个数字方块
void HelloWorld::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
bool isTouch=false;
CCPoint point= pTouch->getLocation();
m_RangeX=m_StartX-point.x;
m_RangeY=m_StartY-point.y;
if (abs(m_RangeX)>abs(m_RangeY))
{
//X大于Y 左右移动
if (m_RangeX>5)
{
//正数 向左
isTouch=doLeft();
}
else if(m_RangeX<-5)
{
//负数 向右
isTouch=doReight();
}
}
else
{
//否则 上下移动
if (m_RangeY>5)
{
//正数 向下
isTouch=doDown();
}
else if(m_RangeY<-5)
{
//负数 向上
isTouch=doTop();
}
}
if (isTouch)
{
autoSquare();
}
}
测试一下,貌似我有发现了一个BUG
结合我们的代码分析一下也确实是这种情况,那么怎么破呢??
应该在两个同等数字相加后,就Brack,不能再继续加下去了
else if (m_squarearray[x][aftery]->getNumber()==m_squarearray[x][y]->getNumber())
{
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[x][aftery]->setNumber(0);
break;
}
刚测试,又发现一个BUG
本来是
4 2 4 0
向右滑动应该是
0 4 2 4
结果是:
0 0 2 8
大家结合doReight,在看看,好像也是这么回事
那么又应该怎么修复呢??
这里还不能再第一个IF加break
不然 2 2 2 0 就会变为 0 2 2 2了 而不是
0 0 2 4
这是一个很纠结的问题
我们应该要循环遍历一下 两个数字的中间是不是还有数字隔着,有就不加,没有就加
这里贴上所有逻辑代码
bool HelloWorld::doTop()
{
for (int x = 0; x < 4; x++)
{
for (int y = 3; y >=0; y--)
{
for (int aftery = y-1; aftery >=0; aftery--)
{
if (m_squarearray[x][y]->getNumber()==0)
{
m_squarearray[x][y]->setNumber(m_squarearray[x][aftery]->getNumber());
m_squarearray[x][aftery]->setNumber(0);
}
else if (m_squarearray[x][aftery]->getNumber()==m_squarearray[x][y]->getNumber())
{
bool isAdd=false;
for (int temp = aftery+1; temp < y; temp++)
{
if (m_squarearray[x][temp]->getNumber()!=0)
{
isAdd=true;
break;
}
}
if (isAdd)
{
continue;
}
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[x][aftery]->setNumber(0);
break;
}
}
}
}
return true;
}
bool HelloWorld::doDown()
{
for (int x = 0; x < 4; x++)
{
for (int y = 0; y <4; y++)
{
for (int aftery = y+1; aftery <4; aftery++)
{
if (m_squarearray[x][y]->getNumber()==0)
{
m_squarearray[x][y]->setNumber(m_squarearray[x][aftery]->getNumber());
m_squarearray[x][aftery]->setNumber(0);
}
else if (m_squarearray[x][aftery]->getNumber()==m_squarearray[x][y]->getNumber())
{
bool isAdd=false;
for (int temp = y+1; temp < aftery; temp++)
{
if (m_squarearray[x][temp]->getNumber()!=0)
{
isAdd=true;
break;
}
}
if (isAdd)
{
continue;
}
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[x][aftery]->setNumber(0);
break;
}
}
}
}
return true;
}
bool HelloWorld::doReight()
{
for (int y = 0; y < 4; y++)
{
for (int x = 3; x >=0; x--)
{
for (int afterx = x-1; afterx >=0; afterx--)
{
if (m_squarearray[x][y]->getNumber()==0)
{
m_squarearray[x][y]->setNumber(m_squarearray[afterx][y]->getNumber());
m_squarearray[afterx][y]->setNumber(0);
}
else if (m_squarearray[afterx][y]->getNumber()==m_squarearray[x][y]->getNumber())
{
bool isAdd=false;
for (int temp = afterx+1; temp < x; temp++)
{
if (m_squarearray[temp][y]->getNumber()!=0)
{
isAdd=true;
break;
}
}
if (isAdd)
{
continue;
}
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[afterx][y]->setNumber(0);
break;
}
}
}
}
return true;
}
bool HelloWorld::doLeft()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
for (int afterx = x+1; afterx < 4; afterx++)
{
if (m_squarearray[x][y]->getNumber()==0)
{
m_squarearray[x][y]->setNumber(m_squarearray[afterx][y]->getNumber());
m_squarearray[afterx][y]->setNumber(0);
}
else if (m_squarearray[afterx][y]->getNumber()==m_squarearray[x][y]->getNumber())
{
bool isAdd=false;
for (int temp = x+1; temp < afterx; temp++)
{
if (m_squarearray[temp][y]->getNumber()!=0)
{
isAdd=true;
break;
}
}
if (isAdd)
{
continue;
}
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[afterx][y]->setNumber(0);
break;
}
}
}
}
return true;
}
5.为游戏增加动画效果
最后在来点,动画效果
这里,动画就是,在创建一个数字方块的时候他是慢慢放大的,
我们的数字方块是什么??CCLayerColor
我也不知道为什么,我们之间这样
m_squarearray[x][y]->runAction(CCSequence::create(CCScaleTo::create(0,0,0),CCScaleTo::create(0.3f,1,1),NULL));
出现的效果并不理想。
那么我们就在SquareSprite中提供一个接口用来获得 m_layercolor
然后在用m_layercolor来执行动画
CCLayerColor* SquareSprite::getCClayerColor()
{
return this->m_layercolor;
}
void HelloWorld::autoSquare()
{
int x=CCRANDOM_0_1()*4;
int y=CCRANDOM_0_1()*4;
if (m_squarearray[x][y]->getNumber()>0)
{
autoSquare();
}
else
{
m_squarearray[x][y]->setNumber(2);
m_squarearray[x][y]->getCClayerColor()->runAction(CCSequence::create(CCScaleTo::create(0,0,0),CCScaleTo::create(0.3f,1,1),NULL));
}
}
6.附源码
SquareSprite.h
#ifndef _SQUARE_SPRITE_H_
#define _SQUARE_SPRITE_H_
#include "cocos2d.h"
using namespace cocos2d;
class SquareSprite:public CCSprite
{
public:
SquareSprite();
static SquareSprite* createSquareSprite(int number,float pointx,float pointy,int width,int height);
int getNumber();
void setNumber(int number);
CCLayerColor* getCClayerColor();
CREATE_FUNC(SquareSprite);
private:
int m_number;
CCLabelTTF* m_lablenumber;
CCLayerColor* m_layercolor;
void initSquareSprite(int number,float pointx,float pointy,int width,int height);
};
#endif // !_SQUARE_SPRITE_H_
SquareSprite.cpp
#include "SquareSprite.h"
SquareSprite::SquareSprite()
:m_number(0)
,m_lablenumber(NULL)
,m_layercolor(NULL)
{
}
SquareSprite* SquareSprite::createSquareSprite(int number,float pointx,float pointy,int width,int height)
{
SquareSprite *pSprite = new SquareSprite();
if (pSprite && pSprite->init())
{
pSprite->autorelease();
pSprite->initSquareSprite( number, pointx, pointy, width, height);
return pSprite;
}
CC_SAFE_DELETE(pSprite);
return NULL;
}
int SquareSprite::getNumber()
{
return m_number;
}
void SquareSprite::setNumber(int number)
{
m_number=number;
m_lablenumber->setString("");
m_layercolor->setColor(ccc3(200,190,180));
if (m_number>0)
{
m_lablenumber->setString(CCString::createWithFormat("%i",m_number)->getCString());
//设置卡片颜色
switch (m_number)
{
case 2:
m_layercolor->setColor(ccc3(255,245,238));
break;
case 32:
case 4:
m_layercolor->setColor(ccc3(255,0,0));
break;
case 8:
m_layercolor->setColor(ccc3(244,164,96));
break;
case 16:
m_layercolor->setColor(ccc3(255,69,0));
break;
case 64:
m_layercolor->setColor(ccc3(250,128,114));
break;
case 128:
m_layercolor->setColor(ccc3(255,228,181));
break;
case 256:
m_layercolor->setColor(ccc3(240,230,140));
break;
case 512:
m_layercolor->setColor(ccc3(255,250,205));
break;
case 1024:
m_layercolor->setColor(ccc3(255,160,122));
break;
case 2048:
m_layercolor->setColor(ccc3(250,240,230));
break;
case 4096:
m_layercolor->setColor(ccc3(255,228,225));
break;
case 8192:
m_layercolor->setColor(ccc3(188,143,143));
break;
case 16384:
m_layercolor->setColor(ccc3(205,92,92));
break;
default:
break;
}
}
}
void SquareSprite::initSquareSprite(int number,float pointx,float pointy,int width,int height)
{
m_number=number;
m_layercolor=CCLayerColor::create(ccc4(200,190,180,255),width,height);
m_layercolor->setPosition(ccp(pointx,pointy));
this->addChild(m_layercolor);
//创建字体
m_lablenumber=CCLabelTTF::create("","arial.ttf",30);
m_lablenumber->setColor(ccc3(0,0,0));
m_lablenumber->setPosition(ccp(m_layercolor->getContentSize().width/2,m_layercolor->getContentSize().height/2));
m_layercolor->addChild(m_lablenumber);
setNumber(number);
}
CCLayerColor* SquareSprite::getCClayerColor()
{
return this->m_layercolor;
}
HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
#include "SimpleAudioEngine.h"
#include "SquareSprite.h"
using namespace CocosDenshion;
using namespace cocos2d;
class HelloWorld : public cocos2d::CCLayer
{
public:
HelloWorld();
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::CCScene* scene();
// implement the "static node()" method manually
CREATE_FUNC(HelloWorld);
public:
virtual void onEnter();
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
//上下左右滑动时调用
bool doTop();
bool doDown();
bool doReight();
bool doLeft();
//初始化矩阵
void initMatrix(CCSize size);
//随机产生方块
void autoSquare();
private:
//启点的X坐标,Y坐标
//起点到终点X的距离,Y的距离
int m_StartX,m_StartY,m_RangeX,m_RangeY;
//二维数组存储方块
SquareSprite* m_squarearray[4][4];
};
#endif // __HELLOWORLD_SCENE_H__
HelloWorldScene.cpp
#include "HelloWorldScene.h"
USING_NS_CC;
HelloWorld::HelloWorld()
:m_StartX(0)
,m_StartY(0)
,m_RangeX(0)
,m_RangeY(0)
{
}
CCScene* HelloWorld::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
HelloWorld *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 ( !CCLayer::init() )
{
return false;
}
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
initMatrix(visibleSize);
//搞点背景
CCLayerColor* layerColorBG= CCLayerColor::create(ccc4(180,170,160,255));
this->addChild(layerColorBG,0);
return true;
}
void HelloWorld::initMatrix(CCSize size)
{
//两个方块之间的空隙
int space=10;
int SquareSize=(size.width-space*5)/4;
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 4; y++)
{
float pointx=space+x*SquareSize+x*space;
float pointy=40+y*SquareSize+y*space;
SquareSprite* pSquareSprite=SquareSprite::createSquareSprite(0,pointx,pointy,SquareSize,SquareSize);
this->addChild(pSquareSprite,1);
m_squarearray[x][y]=pSquareSprite;
}
}
//刚开始游戏,创建两个方块
autoSquare();
autoSquare();
}
void HelloWorld::autoSquare()
{
int x=CCRANDOM_0_1()*4;
int y=CCRANDOM_0_1()*4;
if (m_squarearray[x][y]->getNumber()>0)
{
autoSquare();
}
else
{
m_squarearray[x][y]->setNumber(2);
m_squarearray[x][y]->getCClayerColor()->runAction(CCSequence::create(CCScaleTo::create(0,0,0),CCScaleTo::create(0.3f,1,1),NULL));
}
}
void HelloWorld::onEnter()
{
CCLayer::onEnter();
this->setTouchMode(kCCTouchesOneByOne);
this->setTouchEnabled(true);
}
bool HelloWorld::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
m_StartX=pTouch->getLocation().x;
m_StartY=pTouch->getLocation().y;
return true;
}
void HelloWorld::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
bool isTouch=false;
CCPoint point= pTouch->getLocation();
m_RangeX=m_StartX-point.x;
m_RangeY=m_StartY-point.y;
if (abs(m_RangeX)>abs(m_RangeY))
{
//X大于Y 左右移动
if (m_RangeX>5)
{
//正数 向左
isTouch=doLeft();
}
else if(m_RangeX<-5)
{
//负数 向右
isTouch=doReight();
}
}
else
{
//否则 上下移动
if (m_RangeY>5)
{
//正数 向下
isTouch=doDown();
}
else if(m_RangeY<-5)
{
//负数 向上
isTouch=doTop();
}
}
if (isTouch)
{
autoSquare();
}
}
bool HelloWorld::doTop()
{
for (int x = 0; x < 4; x++)
{
for (int y = 3; y >=0; y--)
{
for (int aftery = y-1; aftery >=0; aftery--)
{
if (m_squarearray[x][y]->getNumber()==0)
{
m_squarearray[x][y]->setNumber(m_squarearray[x][aftery]->getNumber());
m_squarearray[x][aftery]->setNumber(0);
}
else if (m_squarearray[x][aftery]->getNumber()==m_squarearray[x][y]->getNumber())
{
bool isAdd=false;
for (int temp = aftery+1; temp < y; temp++)
{
if (m_squarearray[x][temp]->getNumber()!=0)
{
isAdd=true;
break;
}
}
if (isAdd)
{
continue;
}
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[x][aftery]->setNumber(0);
break;
}
}
}
}
return true;
}
bool HelloWorld::doDown()
{
for (int x = 0; x < 4; x++)
{
for (int y = 0; y <4; y++)
{
for (int aftery = y+1; aftery <4; aftery++)
{
if (m_squarearray[x][y]->getNumber()==0)
{
m_squarearray[x][y]->setNumber(m_squarearray[x][aftery]->getNumber());
m_squarearray[x][aftery]->setNumber(0);
}
else if (m_squarearray[x][aftery]->getNumber()==m_squarearray[x][y]->getNumber())
{
bool isAdd=false;
for (int temp = y+1; temp < aftery; temp++)
{
if (m_squarearray[x][temp]->getNumber()!=0)
{
isAdd=true;
break;
}
}
if (isAdd)
{
continue;
}
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[x][aftery]->setNumber(0);
break;
}
}
}
}
return true;
}
bool HelloWorld::doReight()
{
for (int y = 0; y < 4; y++)
{
for (int x = 3; x >=0; x--)
{
for (int afterx = x-1; afterx >=0; afterx--)
{
if (m_squarearray[x][y]->getNumber()==0)
{
m_squarearray[x][y]->setNumber(m_squarearray[afterx][y]->getNumber());
m_squarearray[afterx][y]->setNumber(0);
}
else if (m_squarearray[afterx][y]->getNumber()==m_squarearray[x][y]->getNumber())
{
bool isAdd=false;
for (int temp = afterx+1; temp < x; temp++)
{
if (m_squarearray[temp][y]->getNumber()!=0)
{
isAdd=true;
break;
}
}
if (isAdd)
{
continue;
}
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[afterx][y]->setNumber(0);
break;
}
}
}
}
return true;
}
bool HelloWorld::doLeft()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
for (int afterx = x+1; afterx < 4; afterx++)
{
if (m_squarearray[x][y]->getNumber()==0)
{
m_squarearray[x][y]->setNumber(m_squarearray[afterx][y]->getNumber());
m_squarearray[afterx][y]->setNumber(0);
}
else if (m_squarearray[afterx][y]->getNumber()==m_squarearray[x][y]->getNumber())
{
bool isAdd=false;
for (int temp = x+1; temp < afterx; temp++)
{
if (m_squarearray[temp][y]->getNumber()!=0)
{
isAdd=true;
break;
}
}
if (isAdd)
{
continue;
}
m_squarearray[x][y]->setNumber(m_squarearray[x][y]->getNumber()*2);
m_squarearray[afterx][y]->setNumber(0);
break;
}
}
}
}
return true;
}
最终效果图: