cocos2dx实例开发之2048(添加动画版)

网上找了好多教程写2048,不过都没有实现卡片的移动动画,自己写了一个不太完美的带动画版。


开发步骤:

1,设计一个CardSprite类。

2,设计主游戏场景GameScene,实现游戏逻辑,添加动画逻辑。

3,添加游戏胜利或者游戏失败的层,添加历史分数存储。

4,添加声音等其他元素,专门弄了一个声音预加载的场景,主场景添加声音切换变量存储。


贴上主场景关键代码:

GameScene.h

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #pragma once  
  2. #include "cocos2d.h"  
  3. #include "cardSprite.h"  
  4. #include "MenuLayer.h"  
  5. class GameScene :public cocos2d::Layer  
  6. {  
  7. public:  
  8.     static cocos2d::Scene* createScene();  
  9.     virtual bool init();  
  10.     CREATE_FUNC(GameScene);  
  11. public:  
  12.     //触摸监听  
  13.     virtual bool onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event); //注意这里要加命名空间作用域cocos2d  
  14.     virtual void onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *event);  
  15.     //上下左右滑动动作  
  16.     bool moveLeft();  
  17.     bool moveRight();  
  18.     bool moveUp();  
  19.     bool moveDown();  
  20.     //创建4*4卡片矩阵  
  21.     void createCardArr(Size size);  
  22.     void randomCreateCard();  
  23.     //判断游戏赢输  
  24.     void checkGameWin();  
  25.     void checkGameOver();  
  26.     void restart(Ref *sender); //重新开始游戏菜单项  
  27. private:  
  28.     int score;  //当前分数  
  29.     int bestScore; //最好分数  
  30.     bool sound; //声音变量  
  31.     cocos2d::LabelTTF *scoreLabel;  
  32.     LabelTTF *restartBtn; //重新开始的按钮  
  33.     LabelTTF *isSoundBtn; //声音切换按钮  
  34.     CardSprite *cardArr[4][4];  //数字卡片矩阵  
  35.     CardSprite *cardArrAction[4][4]; //用于动画的临时数字卡片矩阵  
  36.     Point startPt; //触摸开始点  
  37.     int offsetX, offsetY;  //触摸水平和竖直方向偏移量  
  38.     MenuLayer *menuLayer; //菜单层  
  39.     timeval tv; //当前时间  
  40. };  


GameScene.cpp

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /* 
  2. *game:2048 
  3. *author:tashaxing 
  4. *time:2014/10/12 
  5. */  
  6. #include "GameScene.h"  
  7. #include "SimpleAudioEngine.h"  
  8. using namespace cocos2d;  
  9. using namespace CocosDenshion;  
  10. Scene* GameScene::createScene()  
  11. {  
  12.     auto scene = Scene::create();  
  13.     auto layer = GameScene::create();  
  14.     scene->addChild(layer);  
  15.     return scene;  
  16. }  
  17.   
  18. bool GameScene::init()  
  19. {  
  20.     if (!Layer::init())  
  21.         return false;  
  22.     //获得屏幕尺寸和原点  
  23.     Size visibleSize = Director::getInstance()->getVisibleSize();  
  24.     Vec2 origin = Director::getInstance()->getVisibleOrigin();  
  25.     //添加背景  
  26.     auto gameBkGround = LayerColor::create(Color4B(180, 170, 160, 255));  
  27.     this->addChild(gameBkGround);  
  28.     //添加标题  
  29.     auto title = LabelTTF::create("My2048""Arial", 60);  
  30.     title->setColor(Color3B(255, 255, 153));  
  31.     title->setPosition(Point(visibleSize.width / 2, visibleSize.height - 50));  
  32.     this->addChild(title);  
  33.     //加入restart按钮    
  34.     restartBtn = LabelTTF::create("Restart""Arial", 40);  
  35.     restartBtn->setColor(Color3B(204, 255, 253));  
  36.     restartBtn->setPosition(Point(visibleSize.width / 2, visibleSize.height - 110));  
  37.     this->addChild(restartBtn);  
  38.     //添加声音切换按钮  
  39.     //初始化获取最好分数和声音变量,第一次启动应用的话xml里没有任何值,所以下面的会返回0和false  
  40.     sound = UserDefault::getInstance()->getBoolForKey("SOUND");  
  41.     if (sound)  
  42.         isSoundBtn = LabelTTF::create("Sound On""Arial", 40);  
  43.     else  
  44.         isSoundBtn = LabelTTF::create("Sound Off""Arial", 40);  
  45.     isSoundBtn->setColor(Color3B(204, 255, 253));  
  46.     isSoundBtn->setPosition(Point(visibleSize.width / 2, 50));  
  47.     this->addChild(isSoundBtn);  
  48.   
  49.     //加入游戏分数    
  50.     auto slabel = LabelTTF::create("Score""Arial", 30);  
  51.     slabel->setPosition(Point(visibleSize.width / 5, visibleSize.height - 150));  
  52.     this->addChild(slabel);  
  53.     score = 0;  
  54.     scoreLabel = LabelTTF::create("0""Arial", 30);  
  55.     scoreLabel->setColor(Color3B(0, 255, 37));  
  56.     scoreLabel->setPosition(Point(visibleSize.width / 2+30, visibleSize.height - 150));  
  57.     this->addChild(scoreLabel);  
  58.     bestScore = UserDefault::getInstance()->getIntegerForKey("BEST");  
  59.       
  60.   
  61.     //初始化卡片  
  62.     createCardArr(visibleSize);  
  63.     randomCreateCard();  
  64.     randomCreateCard();  
  65.   
  66.       
  67.   
  68.     //添加触摸监听  
  69.     auto listener = EventListenerTouchOneByOne::create();  
  70.     listener->onTouchBegan = CC_CALLBACK_2(GameScene::onTouchBegan, this);  
  71.     listener->onTouchEnded = CC_CALLBACK_2(GameScene::onTouchEnded, this);  
  72.     _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);  
  73.     return true;  
  74. }  
  75.   
  76. void GameScene::restart(Ref* sender)  
  77. {  
  78.     //转场,重新开始游戏  
  79.     Director::getInstance()->replaceScene(TransitionFade::create(0.7f, GameScene::createScene()));  
  80. }  
  81.   
  82. bool GameScene::onTouchBegan(Touch *touch, Event *event)  
  83. {  
  84.     gettimeofday(&tv, NULL); //记录当前时间  
  85.     startPt = touch->getLocation(); //保存开始触摸点  
  86.     //判断如果触摸点在restart按钮区域内则重新开始  
  87.     if (restartBtn->getBoundingBox().containsPoint(restartBtn->convertToNodeSpace(touch->getLocation())))  
  88.         Director::getInstance()->replaceScene(TransitionFade::create(0.7f, GameScene::createScene()));  
  89.     //声音开关  
  90.     if (isSoundBtn->getBoundingBox().containsPoint(isSoundBtn->convertToNodeSpace(touch->getLocation())))  
  91.     {  
  92.         sound = !sound;  
  93.         UserDefault::getInstance()->setBoolForKey("SOUND", sound);  
  94.         if (sound)  
  95.             isSoundBtn->setString("Sound On");  
  96.         else  
  97.             isSoundBtn->setString("Sound Off");  
  98.     }  
  99.     return true;  
  100. }  
  101.   
  102. void GameScene::onTouchEnded(Touch *touch, Event *event)  
  103. {  
  104.     timeval tv_end;  
  105.     gettimeofday(&tv_end, NULL);  
  106.     if (tv_end.tv_sec - tv.tv_sec > 3)  
  107.     {  
  108.         //开个后门,用来测试游戏赢了  
  109.         cardArr[0][3]->setNumber(2048);  
  110.         checkGameWin();  
  111.     }  
  112.   
  113.     auto endPt = touch->getLocation();  //获得触摸结束点  
  114.     offsetX = endPt.x - startPt.x;  //计算偏移  
  115.     offsetY = endPt.y - startPt.y;  
  116.     bool isTouch = false;   
  117.     if (abs(offsetX) > abs(offsetY))  //判断为方向  
  118.     {  
  119.         if (offsetX < -5)  
  120.             isTouch = moveLeft();  
  121.         else if (offsetX > 5)  
  122.             isTouch = moveRight();  
  123.     }  
  124.     else  
  125.     {  
  126.         if (offsetY > 5)   //注意这里的纵向坐标别弄反  
  127.             isTouch = moveDown();  
  128.         else if (offsetY<-5)  
  129.             isTouch = moveUp();  
  130.     }  
  131.     if (isTouch)  //如果滑动成功则判断  
  132.     {  
  133.         scoreLabel->setString(String::createWithFormat("%d", score)->getCString());  
  134.         //这三个的顺序不能乱  
  135.         checkGameWin();  
  136.         randomCreateCard();  
  137.         checkGameOver();  
  138.     }  
  139. }  
  140.   
  141. void GameScene::createCardArr(Size size)  
  142. {  
  143.     int space = 5; //卡片间的间隔  
  144.     int cardSize = (size.width - 4 * space) / 4;  
  145.       
  146.     //创建卡片矩阵  
  147.     for (int i = 0; i < 4; i++)  
  148.     {  
  149.         for (int j = 0; j < 4; j++)  
  150.         {  
  151.             //最左边留白12,最下面留白size.height/6  
  152.             //坐标从左下角算起,右为正,上为正  
  153.             CardSprite *card = CardSprite::createCard(0, cardSize, cardSize, cardSize*i + 12, cardSize*j + 12 + size.height / 6);  
  154.             this->addChild(card);  //一定要把card添加到子节点才能渲染出来  
  155.             cardArr[i][j] = card;  //存到卡片矩阵  
  156.         }  
  157.     }  
  158.   
  159.     //创建临时卡片矩阵,用于动画,每个动画卡片对应一个实际卡片的动画,这是个技巧,并且动画层在卡片层之上,所以后加入,也可以设置addchild层次  
  160.     for (int i = 0; i < 4; i++)  
  161.     {  
  162.         for (int j = 0; j < 4; j++)  
  163.         {  
  164.             //最左边留白12,最下面留白size.height/6  
  165.             CardSprite *card = CardSprite::createCard(0, cardSize, cardSize, cardSize*i + 12, cardSize*j + 12 + size.height / 6);  
  166.             this->addChild(card);  
  167.             cardArrAction[i][j] = card;  
  168.             //一开始把这层全部因此  
  169.             auto hide = Hide::create();  
  170.             cardArrAction[i][j]->getCardLayer()->runAction(hide);  
  171.         }  
  172.     }  
  173. }  
  174.   
  175. void GameScene::randomCreateCard()  
  176. {  
  177.     //在随机位置生成卡片  
  178.     int row = CCRANDOM_0_1() * 4;  
  179.     int col = CCRANDOM_0_1() * 4;  
  180.     if (cardArr[row][col]->getNumber() > 0)  //如果有数字,则递归调用  
  181.         randomCreateCard();  
  182.     else  
  183.     {  
  184.         cardArr[row][col]->setNumber(CCRANDOM_0_1() * 10 < 1 ? 4 : 2); //有10%的几率生成4  
  185.         //用动画效果生成  
  186.         auto action = Sequence::createWithTwoActions(ScaleTo::create(0, 0), ScaleTo::create(0.3f, 1));  //在0.3秒内从小缩放到大  
  187.         cardArr[row][col]->getCardLayer()->runAction(action);  //用卡片的层而不是卡片精灵本身做动作是为了使用局部坐标缩放  
  188.     }  
  189. }  
  190.   
  191. //向左滑动游戏逻辑,其他方向类似  
  192. bool GameScene::moveLeft()  
  193. {  
  194.     //是否有移动的逻辑变量,如果没有任何移动,则不需要随机生成卡片,也不检验赢输,这一点很关键,否则很容易出bug  
  195.     bool moved = false;  
  196.     //计算移动的步进间距  
  197.     auto cardSize = (Director::getInstance()->getVisibleSize().width - 5 * 4) / 4;  
  198.     //y表示行标号,x表示列标号  
  199.     for (int y = 0; y < 4; y++)  //最外层的行遍历可以先不管  
  200.     {  
  201.         for (int x = 0; x < 4; x++)   //内部的N^2复杂度的类似冒泡排序  
  202.         {  
  203.             for (int x1 = x + 1; x1 < 4; x1++)  
  204.             {  
  205.                 if (cardArr[x1][y]->getNumber()>0)  //x右边的卡片有数字才动作  
  206.                 {  
  207.                     if (cardArr[x][y]->getNumber() == 0)  
  208.                     {  
  209.                         //专门弄一个动画层卡片实现定位、显现、移动、隐藏系列动画  
  210.                         auto place = Place::create(Point(cardSize*x1 + 12, cardSize*y + 12 + Director::getInstance()->getVisibleSize().height / 6));  
  211.                         cardArrAction[x1][y]->setNumber(cardArr[x1][y]->getNumber());  //每次都重新把动画卡片重新定位到实际对应的卡片位置,并设置相同的数字  
  212.                         auto show = Show::create();  
  213.                         auto move = MoveBy::create(0.1f, Point(-cardSize*(x1 - x), 0));  //注意移动的距离  
  214.                         auto hide = Hide::create();  
  215.                         cardArrAction[x1][y]->getCardLayer()->runAction(Sequence::create(place, show, move, hide, NULL));       
  216.                         //如果x位置是空卡片,就把x1卡片移到x处,x1处变成空卡片  
  217.                         cardArr[x][y]->setNumber(cardArr[x1][y]->getNumber());  
  218.                         cardArr[x1][y]->setNumber(0);  
  219.                         x--;  //再扫描一遍,确保所有结果正确  
  220.                         moved = true;  
  221.                     }  
  222.                     else if (cardArr[x][y]->getNumber() == cardArr[x1][y]->getNumber())  
  223.                     {  
  224.                         auto place = Place::create(Point(cardSize*x1 + 12, cardSize*y + 12 + Director::getInstance()->getVisibleSize().height / 6));  
  225.                         cardArrAction[x1][y]->setNumber(cardArr[x1][y]->getNumber());  
  226.                         auto show = Show::create();  
  227.                         auto move = MoveBy::create(0.1f, Point(-cardSize*(x1 - x), 0));  //注意移动的距离  
  228.                         auto hide = Hide::create();  
  229.                         cardArrAction[x1][y]->getCardLayer()->runAction(Sequence::create(place, show, move, hide, NULL));  
  230.   
  231.                         //如果x位置非空,且与x1处数字相同,则乘2  
  232.                         cardArr[x][y]->setNumber(cardArr[x][y]->getNumber() * 2);  
  233.                         cardArr[x1][y]->setNumber(0);  
  234.                           
  235.                         //数字合并动画  
  236.                         auto merge = Sequence::create(ScaleTo::create(0.1f, 1.2f), ScaleTo::create(0.1f, 1.0f), NULL);  
  237.                         cardArr[x][y]->getCardLayer()->runAction(merge);  
  238.                           
  239.                         score += cardArr[x][y]->getNumber();  
  240.                           
  241.                         //播放得分声音  
  242.                         if (sound)  
  243.                             SimpleAudioEngine::getInstance()->playEffect("get.mp3");  
  244.   
  245.                         moved = true;  
  246.                     }  
  247.                     break;   //此处break防止出现连续乘2的bug  
  248.                 }  
  249.             }  
  250.         }  
  251.     }  
  252.     return moved;  
  253. }  
  254.   
  255. bool GameScene::moveRight()  
  256. {  
  257.     bool moved = false;  
  258.     //计算移动的步进间距  
  259.     auto cardSize = (Director::getInstance()->getVisibleSize().width - 5 * 4) / 4;  
  260.     //y表示行标号,x表示列标号  
  261.     for (int y = 0; y < 4; y++)  //最外层的行遍历可以先不管  
  262.     {  
  263.         for (int x = 3; x >=0; x--)   //内部的N^2复杂度的类似冒泡排序  
  264.         {  
  265.             for (int x1 = x -1; x1 >= 0; x1--)  
  266.             {  
  267.                 if (cardArr[x1][y]->getNumber()>0)  //x左边的卡片有数字才动作  
  268.                 {  
  269.                     if (cardArr[x][y]->getNumber() == 0)  
  270.                     {  
  271.                         auto place = Place::create(Point(cardSize*x1 + 12, cardSize*y + 12 + Director::getInstance()->getVisibleSize().height / 6));  
  272.                         cardArrAction[x1][y]->setNumber(cardArr[x1][y]->getNumber());  
  273.                         auto show = Show::create();  
  274.                         auto move = MoveBy::create(0.1f, Point(-cardSize*(x1 - x), 0));  //注意移动的距离  
  275.                         auto hide = Hide::create();  
  276.                         cardArrAction[x1][y]->getCardLayer()->runAction(Sequence::create(place, show, move, hide, NULL));  
  277.   
  278.                         //如果x位置是空卡片,就把x1卡片移到x处,x1处变成空卡片  
  279.                         cardArr[x][y]->setNumber(cardArr[x1][y]->getNumber());  
  280.                         cardArr[x1][y]->setNumber(0);  
  281.                         x++;  
  282.                         moved = true;  
  283.                     }  
  284.                     else if (cardArr[x][y]->getNumber() == cardArr[x1][y]->getNumber())  
  285.                     {  
  286.                         auto place = Place::create(Point(cardSize*x1 + 12, cardSize*y + 12 + Director::getInstance()->getVisibleSize().height / 6));  
  287.                         cardArrAction[x1][y]->setNumber(cardArr[x1][y]->getNumber());  
  288.                         auto show = Show::create();  
  289.                         auto move = MoveBy::create(0.1f, Point(-cardSize*(x1 - x), 0));  //注意移动的距离,此处算出来为正  
  290.                         auto hide = Hide::create();  
  291.                         cardArrAction[x1][y]->getCardLayer()->runAction(Sequence::create(place, show, move, hide, NULL));  
  292.   
  293.                         //如果x位置非空,且与x1处数字相同,则乘2  
  294.                         cardArr[x][y]->setNumber(cardArr[x][y]->getNumber() * 2);  
  295.                         cardArr[x1][y]->setNumber(0);  
  296.   
  297.                         auto merge = Sequence::create(ScaleTo::create(0.1f, 1.2f), ScaleTo::create(0.1f, 1.0f), NULL);  
  298.                         cardArr[x][y]->getCardLayer()->runAction(merge);  
  299.   
  300.                         score += cardArr[x][y]->getNumber();  
  301.                         if (sound)  
  302.                             SimpleAudioEngine::getInstance()->playEffect("get.mp3");  
  303.                         moved = true;  
  304.                     }  
  305.                     break;   //此处break防止出现连续乘2的bug  
  306.                 }  
  307.             }  
  308.         }  
  309.     }  
  310.     return moved;  
  311. }  
  312.   
  313. bool GameScene::moveUp()   //这里的“上”是逻辑上往坐标值小的方向,在屏幕上实际是往下动  
  314. {  
  315.     bool moved=false;  
  316.     //计算移动的步进间距  
  317.     auto cardSize = (Director::getInstance()->getVisibleSize().width - 5 * 4) / 4;  
  318.     //y表示行标号,x表示列标号  
  319.     for (int x = 0; x < 4; x++)  //最外层的列遍历可以先不管  
  320.     {  
  321.         for (int y = 0; y < 4; y++)   //内部的N^2复杂度的类似冒泡排序  
  322.         {  
  323.             for (int y1 = y + 1; y1 < 4; y1++)  
  324.             {  
  325.                 if (cardArr[x][y1]->getNumber()>0)  //x下边的卡片有数字才动作  
  326.                 {  
  327.                     if (cardArr[x][y]->getNumber() == 0)  
  328.                     {  
  329.                         auto place = Place::create(Point(cardSize*x + 12, cardSize*y1 + 12 + Director::getInstance()->getVisibleSize().height / 6));  
  330.                         cardArrAction[x][y1]->setNumber(cardArr[x][y1]->getNumber());  
  331.                         auto show = Show::create();  
  332.                         auto move = MoveBy::create(0.1f, Point(0 ,- cardSize*(y1 - y)));  //注意移动的距离  
  333.                         auto hide = Hide::create();  
  334.                         cardArrAction[x][y1]->getCardLayer()->runAction(Sequence::create(place, show, move, hide, NULL));  
  335.                           
  336.                         //如果x位置是空卡片,就把x1卡片移到x处,x1处变成空卡片  
  337.                         cardArr[x][y]->setNumber(cardArr[x][y1]->getNumber());  
  338.                         cardArr[x][y1]->setNumber(0);  
  339.                         y--;  
  340.                         moved = true;  
  341.                     }  
  342.                     else if (cardArr[x][y]->getNumber() == cardArr[x][y1]->getNumber())  
  343.                     {  
  344.                         auto place = Place::create(Point(cardSize*x + 12, cardSize*y1 + 12 + Director::getInstance()->getVisibleSize().height / 6));  
  345.                         cardArrAction[x][y1]->setNumber(cardArr[x][y1]->getNumber());  
  346.                         auto show = Show::create();  
  347.                         auto move = MoveBy::create(0.1f, Point(0, -cardSize*(y1 - y)));  //注意移动的距离  
  348.                         auto hide = Hide::create();  
  349.                         cardArrAction[x][y1]->getCardLayer()->runAction(Sequence::create(place, show, move, hide, NULL));  
  350.   
  351.                         //如果x位置非空,且与x1处数字相同,则乘2  
  352.                         cardArr[x][y]->setNumber(cardArr[x][y]->getNumber() * 2);  
  353.                         cardArr[x][y1]->setNumber(0);  
  354.   
  355.                         auto merge = Sequence::create(ScaleTo::create(0.1f, 1.2f), ScaleTo::create(0.1f, 1.0f), NULL);  
  356.                         cardArr[x][y]->getCardLayer()->runAction(merge);  
  357.   
  358.                         score += cardArr[x][y]->getNumber();  
  359.                         if (sound)  
  360.                             SimpleAudioEngine::getInstance()->playEffect("get.mp3");  
  361.                         moved = true;  
  362.                     }  
  363.                     break;   //此处break防止出现连续乘2的bug  
  364.                 }  
  365.             }  
  366.         }  
  367.     }  
  368.     return moved;  
  369. }  
  370.   
  371. bool GameScene::moveDown()   //这里的“下”是逻辑上往坐标值小的方向,在屏幕上实际是往上动  
  372. {  
  373.     bool moved=false;  
  374.     //计算移动的步进间距  
  375.     auto cardSize = (Director::getInstance()->getVisibleSize().width - 5 * 4) / 4;  
  376.     //y表示行标号,x表示列标号  
  377.     for (int x = 0; x < 4; x++)  //最外层的列遍历可以先不管  
  378.     {  
  379.         for (int y = 3; y >= 0; y--)   //内部的N^2复杂度的类似冒泡排序  
  380.         {  
  381.             for (int y1 = y - 1; y1 >= 0; y1--)  
  382.             {  
  383.                 if (cardArr[x][y1]->getNumber()>0)  //x上边的卡片有数字才动作  
  384.                 {  
  385.                     if (cardArr[x][y]->getNumber() == 0)  
  386.                     {  
  387.                         auto place = Place::create(Point(cardSize*x + 12, cardSize*y1 + 12 + Director::getInstance()->getVisibleSize().height / 6));  
  388.                         cardArrAction[x][y1]->setNumber(cardArr[x][y1]->getNumber());  
  389.                         auto show = Show::create();  
  390.                         auto move = MoveBy::create(0.1f, Point(0, -cardSize*(y1 - y)));  //注意移动的距离  
  391.                         auto hide = Hide::create();  
  392.                         cardArrAction[x][y1]->getCardLayer()->runAction(Sequence::create(place, show, move, hide, NULL));  
  393.   
  394.                         //如果x位置是空卡片,就把x1卡片移到x处,x1处变成空卡片  
  395.                         cardArr[x][y]->setNumber(cardArr[x][y1]->getNumber());  
  396.                         cardArr[x][y1]->setNumber(0);  
  397.                         y++;  
  398.                         moved = true;  
  399.                     }  
  400.                     else if (cardArr[x][y]->getNumber() == cardArr[x][y1]->getNumber())  
  401.                     {  
  402.                         auto place = Place::create(Point(cardSize*x + 12, cardSize*y1 + 12 + Director::getInstance()->getVisibleSize().height / 6));  
  403.                         cardArrAction[x][y1]->setNumber(cardArr[x][y1]->getNumber());  
  404.                         auto show = Show::create();  
  405.                         auto move = MoveBy::create(0.1f, Point(0, -cardSize*(y1 - y)));  //注意移动的距离  
  406.                         auto hide = Hide::create();  
  407.                         cardArrAction[x][y1]->getCardLayer()->runAction(Sequence::create(place, show, move, hide, NULL));  
  408.   
  409.                         //如果x位置非空,且与x1处数字相同,则乘2  
  410.                         cardArr[x][y]->setNumber(cardArr[x][y]->getNumber() * 2);  
  411.                         cardArr[x][y1]->setNumber(0);  
  412.   
  413.                         auto merge = Sequence::create(ScaleTo::create(0.1f, 1.2f), ScaleTo::create(0.1f, 1.0f), NULL);  
  414.                         cardArr[x][y]->getCardLayer()->runAction(merge);  
  415.   
  416.                         score += cardArr[x][y]->getNumber();  
  417.                         if (sound)  
  418.                             SimpleAudioEngine::getInstance()->playEffect("get.mp3");  
  419.                         moved = true;  
  420.                     }  
  421.                     break;   //此处break防止出现连续乘2的bug  
  422.                 }  
  423.             }  
  424.         }  
  425.     }  
  426.     return moved;  
  427. }  
  428.   
  429.   
  430.   
  431. void GameScene::checkGameWin()  
  432. {  
  433.     bool isWin = false;  
  434.     for (int i = 0; i < 4; i++)  
  435.         for (int j = 0; j < 4; j++)  
  436.             if (2048 == cardArr[i][j]->getNumber())  
  437.                 isWin = true;  
  438.     if (isWin)  
  439.     {  
  440.         //播放音效  
  441.         if (sound)  
  442.             SimpleAudioEngine::getInstance()->playEffect("gamewin.mp3");  
  443.         //有一个2048游戏就是赢了  
  444.         /*初始化菜单层*/  
  445.         menuLayer = MenuLayer::create(Color4B(0, 0, 0, 100));  
  446.         this->addChild(menuLayer);  
  447.         auto menuSize = menuLayer->getContentSize();  
  448.         //添加标题  
  449.         auto menuTitle = LabelTTF::create("YOU WIN""Arial", 30);  
  450.         menuTitle->setPosition(menuSize.width / 2, menuSize.height / 2 + 50);  
  451.         menuLayer->addChild(menuTitle);  
  452.         //添加当前分数  
  453.         auto menuscoreLabel = LabelTTF::create(String::createWithFormat("current: %d", score)->getCString(), "Arial", 20);  
  454.         menuscoreLabel->setPosition(menuSize.width / 2, menuSize.height / 2);  
  455.         menuLayer->addChild(menuscoreLabel);  
  456.         //添加最好分数  
  457.         bestScore = UserDefault::getInstance()->getIntegerForKey("BEST");  
  458.         if (score > bestScore)  
  459.         {  
  460.             bestScore = score;  
  461.             UserDefault::getInstance()->setIntegerForKey("BEST", bestScore);  
  462.         }  
  463.         auto menuBestscoreLabel = LabelTTF::create(String::createWithFormat("best: %d", bestScore)->getCString(), "Arial", 20);  
  464.         menuBestscoreLabel->setPosition(menuSize.width / 2, menuSize.height / 2 - 30);  
  465.         menuLayer->addChild(menuBestscoreLabel);  
  466.         MenuItemFont::setFontName("Arial");  
  467.         MenuItemFont::setFontSize(25);  
  468.         auto menuItemRestart = MenuItemFont::create("Restart"this, menu_selector(GameScene::restart));  
  469.         menuItemRestart->setColor(Color3B(255, 255, 0));  
  470.         auto menu = Menu::create(menuItemRestart, NULL);  
  471.         menuLayer->addChild(menu);  
  472.         menu->setPosition(Point(menuSize.width / 2, menuSize.height / 2 - 80));  
  473.     }  
  474. }  
  475.   
  476. void GameScene::checkGameOver()  
  477. {  
  478.     bool isGameOver = true;  
  479.     //以下情况则游戏继续  
  480.     for (int j = 0; j < 4; j++)  
  481.     {  
  482.         for (int i = 0; i < 4; i++)  
  483.         {  
  484.             if ((cardArr[i][j]->getNumber()==0)||  
  485.                 (i>0 && cardArr[i][j]->getNumber() == cardArr[i - 1][j]->getNumber()) ||  
  486.                 (i<3 && cardArr[i][j]->getNumber() == cardArr[i + 1][j]->getNumber()) ||  
  487.                 (j>0 && cardArr[i][j]->getNumber() == cardArr[i][j - 1]->getNumber()) ||  
  488.                 (j<3 && cardArr[i][j]->getNumber() == cardArr[i][j + 1]->getNumber()))  
  489.             {  
  490.                 isGameOver = false;  
  491.             }  
  492.         }  
  493.     }  
  494.     //否则游戏结束  
  495.     if (isGameOver)  
  496.     {  
  497.         if (sound)  
  498.             SimpleAudioEngine::getInstance()->playEffect("gameover.mp3");  
  499.         /*初始化菜单层*/  
  500.         menuLayer = MenuLayer::create(Color4B(0, 0, 0, 100));  
  501.         this->addChild(menuLayer);  
  502.         auto menuSize = menuLayer->getContentSize();  
  503.         //添加标题  
  504.         auto menuTitle = LabelTTF::create("GAME OVER""Arial", 30);  
  505.         menuTitle->setPosition(menuSize.width / 2, menuSize.height / 2 + 50);  
  506.         menuLayer->addChild(menuTitle);  
  507.         //添加当前分数  
  508.         auto menuscoreLabel = LabelTTF::create(String::createWithFormat("current: %d", score)->getCString(), "Arial", 20);  
  509.         menuscoreLabel->setPosition(menuSize.width / 2, menuSize.height / 2);  
  510.         menuLayer->addChild(menuscoreLabel);  
  511.         //添加最好分数  
  512.         bestScore = UserDefault::getInstance()->getIntegerForKey("BEST");  
  513.         if (score > bestScore)  
  514.         {  
  515.             bestScore = score;  
  516.             UserDefault::getInstance()->setIntegerForKey("BEST", bestScore);  
  517.         }  
  518.         auto menuBestscoreLabel = LabelTTF::create(String::createWithFormat("best: %d", bestScore)->getCString(), "Arial", 20);  
  519.         menuBestscoreLabel->setPosition(menuSize.width / 2, menuSize.height / 2 - 30);  
  520.         menuLayer->addChild(menuBestscoreLabel);  
  521.         MenuItemFont::setFontName("Arial");  
  522.         MenuItemFont::setFontSize(25);  
  523.         auto menuItemRestart = MenuItemFont::create("Restart"this, menu_selector(GameScene::restart));  
  524.         menuItemRestart->setColor(Color3B(255, 255, 0));  
  525.         auto menu = Menu::create(menuItemRestart, NULL);  
  526.         menuLayer->addChild(menu);  
  527.         menu->setPosition(Point(menuSize.width / 2, menuSize.height / 2 - 80));  
  528.     }  
  529.           
  530. }  

关键点:

1,专门弄了一个4*4的卡片临时矩阵做为动画层,也就是有16个卡片专门负责对应卡片的动画(卡片生成的动画是实际卡片,这个是例外)。

2,关于游戏逻辑中每次移动后面都有一个break

如果不加这个break就会出现:

  • 本来是 2 2 4 2 
    向左滑动应该是 4 4 2 0 
    结果是: 8 2 0 0    
加上break就正常了。


游戏截图:

  


源代码

csdn下载:2048源码

github下载:2048源码





FROM: http://blog.csdn.net/u012234115/article/details/40061303?utm_source=tuicool&utm_medium=referral

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值