Cocos2d-x 3.x版2048游戏开发

Cocos2d-x 3.x版2048游戏开发


本篇博客给大家介绍如何快速开发2048这样一款休闲游戏,理解整个2048游戏的开发流程,从本篇博客你将可以学习到以下内容:

这里注明一下,本教程来自极客学院,小巫对其中代码进行了解释。

  • 2048游戏的逻辑
  • Cocos2d-x中上下左右手势的识别
  • 游戏中卡片类的创建
  • 添加卡片到游戏中
  • 游戏中的逻辑实现
  • 游戏中随机卡片的生成
  • 游戏结束判断
  • 游戏分数的添加
  • 游戏美化

笔者的开发环境:
Cocos2d-x 3.1.1(开发引擎)
Visual Studio 2012(Win32)
Xcode 5.1(Mac系统下)

理解2048游戏逻辑

2048游戏逻辑并不复杂,4*4的卡片布局,玩家通过手势上下左右滑动来累加卡片数值,直到累加到2048。笔者用一张图说明:
这是一张游戏中的图,在图中同一方向并且数值相同的卡片可以进行叠加,比如128和128在同一行,玩家可以通过向左或向右的手势,对其进行叠加。笔者向右滑动手势,则会变成以下效果:


Cocos2d-x中上下左右手势的识别

玩家在玩2048游戏时,手势是最频繁的操作,所以我们需要对手势所产生的事件进行监听。
在HelloWorldScene.h头文件中声明两个需要实现的监听事件:
[objc] view plain copy
  1. //加入手势识别的事件
  2. virtualboolonTouchBegan(cocos2d::Touch*touch,cocos2d::Event*unused_event);
  3. voidonTouchEnded(cocos2d::Event*unused_event);

声明点击的位置属性
[cpp] copy
    //点击的元素位置
  1. intfirstX,firstY,endX,endY;


一个是触摸开始的事件,一个是触摸结束的事件。
然后再HelloWorldScene.cpp文件中实现这两个方法:

在HelloWorld的init方法中设置监听器的这两个方法的监听回调:

上面中根据计算开始位置到结束位置X轴和Y轴的移动距离来判断是向左、向右、向上还是向下的方向:
在头文件中声明四个方向的方法:

然后对其进行实现。这四个方法的逻辑实现放到后面进行讲解。



游戏中卡片类的创建

卡片类是组成2048游戏的基础,4*4的方格的16个位置放置不同的卡片,每个位置为独立的一张卡片。

创建CardSprite.h的头文件:

我们可以从游戏中看到,每张卡片有背景颜色和一个数字,所以我们在头文件需要声明它这两个属性。


CardSprite.cpp中对头文件方法的实现:
copy
//CardSprite.cpp
  • //Createdbywwjon14-7-16.
  • #include"CardSprite.h"
  • USING_NS_CC;
  • CardSprite*CardSprite::createCardSprite(intnumbers,intwidth,87); font-weight:bold; background-color:inherit">intheight,87); font-weight:bold; background-color:inherit">floatCardSpriteX,87); font-weight:bold; background-color:inherit">floatCardSpriteY){
  • //new一个卡片精灵
  • CardSprite*enemy=newCardSprite();
  • if(enemy&&enemy->init()){
  • enemy->autorelease();
  • enemy->enemyInit(numbers,width,height,CardSpriteX,CardSpriteY);
  • returnenemy;
  • CC_SAFE_DELETE(enemy);
  • returnNULL;
  • //卡片初始化方法
  • boolCardSprite::init(){
  • if(!Sprite::init()){
  • false;
  • true;
  • //设置数字
  • voidCardSprite::setNumber(intnum){
  • number=num;
  • //判断数字的大小来调整字体的大小
  • if(number>=0){
  • labTTFCardNumber->setFontSize(80);
  • if(number>=16){
  • labTTFCardNumber->setFontSize(60);
  • if(number>=128){
  • labTTFCardNumber->setFontSize(40);
  • if(number>=1024){
  • labTTFCardNumber->setFontSize(20);
  • //判断数组的大小调整颜色
  • 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){
  • if(number==16){
  • if(number==32){
  • if(number==64){
  • if(number==128){
  • if(number==256){
  • if(number==512){
  • if(number==1024){
  • layerColorBG->setColor(cocos2d::Color3B(0,0));
  • if(number==2048){
  • layerColorBG->setColor(cocos2d::Color3B(0,0));
  • //更新显示的数字
  • if(number>0){
  • labTTFCardNumber->setString(__String::createWithFormat("%i",num)->getCString());
  • labTTFCardNumber->setString("");
  • intCardSprite::getNumber(){
  • returnnumber;
  • //第1个参数为数字,第2、3个参数为卡片的宽高,第4、5个参数为卡片的位置
  • voidCardSprite::enemyInit(//初始化数字
  • number=numbers;
  • //加入游戏卡片的背景颜色
  • layerColorBG=cocos2d::LayerColor::create(cocos2d::Color4B(200,255),width-15,height-15);
  • layerColorBG->setPosition(Point(CardSpriteX,CardSpriteY));
  • //判断如果不等于0就显示,否则为空
  • //加入中间字体
  • labTTFCardNumber=cocos2d::LabelTTF::create(__String::createWithFormat("%i",number)->getCString(),"HirakakuProN-W6",100);
  • //显示卡片数字的位置,这里显示在背景的中间
  • labTTFCardNumber->setPosition(Point(layerColorBG->getContentSize().width/2,layerColorBG->getContentSize().height/2));
  • //添加卡片数字到背景中
  • layerColorBG->addChild(labTTFCardNumber);
  • }else{
  • //加入中间字体
  • labTTFCardNumber=cocos2d::LabelTTF::create("","HirakakuProN-w6",80);
  • layerColorBG->addChild(labTTFCardNumber);
  • //将卡片添加到层
  • this->addChild(layerColorBG);
  • }

  • 每张卡片都有相同的宽和高,但数字和位置不同,数字是显示在背景中间的,所以我们需要5个参数来初始化卡片的位置。


    添加卡片到游戏中

    卡片放置在4*4方框中的不同位置,首先我们需要计算出每张卡片的宽高,然后计算每张卡片所在的位置,最后进行显示。
    在HelloWorldScene.h头文件中声明创建卡片的方法:

    在HelloWorldScene.cpp中实现该方法:

    笔者对每张卡片显示的位置在代码中进行了说明,读者也可以思考一下为什么要这么做。

    游戏中的逻辑实现

    2048游戏最重要的部分就是四个方向的逻辑实现,也是开发这个游戏的难点所在。
    copy
    //向左
  • boolHelloWorld::doLeft(){
  • log("doLeft");
  • boolisdo=//最外层循环为4*4迭代
  • inty=0;y<4;y++){
  • intx=0;x<4;x++){
  • //这一层循环为判断卡片是合并还是清空
  • intx1=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=elseif(cardArr[x][y]->getNumber()==cardArr[x1][y]->getNumber()){
  • //当前卡片的值与其比较卡片的值相等,设置为其的2倍
  • cardArr[x][y]->setNumber(cardArr[x][y]->getNumber()*2);
  • //设置分数
  • score+=cardArr[x][y]->getNumber();
  • labelTTFCardNumber->setString(__String::createWithFormat("%i",score)->getCString());
  • isdo=break;//跳出
  • returnisdo;
  • //向右
  • boolHelloWorld::doRight(){
  • log("doRight");
  • intx=3;x>=0;x--){
  • //循环判断左边卡片往右是合并还是清空
  • intx1=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());
  • x++;
  • cardArr[x][y]->setNumber(cardArr[x][y]->getNumber()*2);
  • cardArr[x1][y]->setNumber(0);
  • break;
  • returnisdo;
  • //向上
  • boolHelloWorld::doUp(){
  • log("doUp");
  • false;
  • //最外层循环为4*4迭代
  • inty=3;y>=0;y--){
  • //这一层循环为判断卡片是合并还是清空
  • inty1=y-1;y1>=0;y1--){
  • if(cardArr[x][y1]->getNumber()>0){//有数字
  • //为空
  • //设置为右边卡片的数值
  • cardArr[x][y]->setNumber(cardArr[x][y1]->getNumber());
  • cardArr[x][y1]->setNumber(0);
  • y++;
  • if(cardArr[x][y]->getNumber()==cardArr[x][y1]->getNumber()){
  • //当前卡片的值与其比较卡片的值相等,设置为其的2倍
  • //跳出
  • //向下
  • boolHelloWorld::doDown(){
  • log("doDown");
  • inty1=y+1;y1<4;y1++){
  • y--;
  • //设置分数
  • score+=cardArr[x][y]->getNumber();
  • labelTTFCardNumber->setString(__String::createWithFormat("%i",score)->getCString());
  • }




  • 游戏中随机卡片的生成

    在HelloWorldScene.h头文件中声明随机生成卡片的方法:

    在HelloWorldScene.cpp实现该方法:

    游戏结束判断

    在HelloWorldScene.h中声明判断游戏结束的方法:
    在HelloWorldScene.cpp中实现该方法:

    游戏分数的添加

    2048中需要对分数进行统计并显示给玩家,我们在HelloWolrdScene.h文件中声明分数和显示分数的控件:

    在HelloWorldScene.cpp中对分数初始化为0,并显示“分数”的文本:

    关于分数的计算,在游戏中的逻辑已经实现,具体读者可以查看代码,后面笔者也会提供完整的代码。

    游戏美化

    2048中我们会发现不同的数字会有不同的背景,然后字体大小也会随数值的变化而变化,实现这个需要通过判断数值的大小来显示不同的颜色背景和设置不同字体大小。

    这个功能的实现是在卡片类设置数值的时候实现的,代码逻辑如下:
    copy
    }


    最后笔者给出所有代码清单:
    AppDelegate.h
    AppDelegate.cpp
    HelloWorldScene.h
    HelloWorldScene.cpp
    CardSprite.h
    CardSprite.cpp

    >>>AppDelegate.h

    >>>AppDelegate.cpp

    >>>HelloWorldScene.h

    >>>HelloWorldScene.cpp
    copy
    #include"HelloWorldScene.h"
  • #include"CardSprite.h"
  • Scene*HelloWorld::createScene()
  • //'scene'isanautoreleaseobject
  • autoscene=Scene::create();
  • //'layer'isanautoreleaseobject
  • autolayer=HelloWorld::create();
  • //addlayerasachildtoscene
  • scene->addChild(layer);
  • //returnthescene
  • returnscene;
  • //on"init"youneedtoinitializeyourinstance
  • boolHelloWorld::init()
  • //////////////////////////////
  • //1.superinitfirst
  • if(!Layer::init())
  • score=0;
  • autotouchListener=EventListenerTouchOneByOne::create();
  • touchListener->onTouchBegan=CC_CALLBACK_2(HelloWorld::onTouchBegan,this);
  • touchListener->onTouchEnded=CC_CALLBACK_2(HelloWorld::onTouchEnded,153); font-weight:bold; background-color:inherit">this);
  • //调用生成卡片的方法
  • createCardSprite(visibleSize);
  • //调用生成随机数
  • //游戏是否还能继续运行下去
  • voidHelloWorld::doCheckGameOver(){
  • inty=0;y<4;y++){
  • intx=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()))
  • ||(x<3&&(cardArr[x][y]->getNumber()==cardArr[x][y+1]->getNumber()))){
  • isGameOver=if(isGameOver){
  • //结束游戏
  • Director::getInstance()->replaceScene(TransitionFade::create(1,HelloWorld::createScene()));
  • //自动生成卡片
  • voidHelloWorld::autoCreateCardNumber(){
  • inti=CCRANDOM_0_1()*4;
  • intj=CCRANDOM_0_1()*4;
  • //判断是否已经存在的位置
  • if(cardArr[i][j]->getNumber()>0){
  • //已存在,递归创建
  • //生成2和4的比例是1:9的概率
  • cardArr[i][j]->setNumber(CCRANDOM_0_1()*10<1?4:2);
  • boolHelloWorld::onTouchBegan(cocos2d::Touch*touch,cocos2d::Event*unused_event){
  • PointtouchP0=touch->getLocation();
  • firstX=touchP0.x;
  • firstY=touchP0.y;
  • voidHelloWorld::onTouchEnded(cocos2d::Touch*touch,248)"> endX=firstX-touchP0.x;
  • endY=firstY-touchP0.y;
  • if(endX+5>0){
  • if(endY+5>0){
  • voidHelloWorld::menuCloseCallback(Ref*pSender)
  • #if(CC_TARGET_PLATFORM==CC_PLATFORM_WP8)||(CC_TARGET_PLATFORM==CC_PLATFORM_WINRT)
  • MessageBox("Youpressedtheclosebutton.WindowsStoreAppsdonotimplementaclosebutton.","Alert");
  • return;
  • #endif
  • Director::getInstance()->end();
  • #if(CC_TARGET_PLATFORM==CC_PLATFORM_IOS)
  • exit(0);
  • }

  • >>>CardSprite.h

    >>>CardSprite.cpp

    最后,骚年们就不要向我要源码了,所有的代码在这里均有实现,只要把这些代码集成到你的项目中去就可以实现跟笔者一样的效果,希望各位能好好体会2048开发的流程。




    FROM:http://blog.csdn.net/wwj_748/article/details/38168649

    相关文章

        本文实践自 RayWenderlich、Ali Hafizji 的文章《...
    Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
    第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
        Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
    1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
       Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...