Cocos2dx游戏开发——2048

  由于自己自学Cocos2d-x游戏引擎已经有一段时间,是时候该做一个小游戏来练手了。从游戏的逻辑分析到最后的实现大概花了一周左右吧,时间有点长哈。做游戏最不好找的就是图片资源,要是有个美术设计师帮忙,那该是一件多么美的事情,想想就好。游戏采用了Cocos2d-x V3.10版本,用VS2013进行开发的。

  2048游戏的玩法规则:在游戏开始时,随机在任意两个空白方块产生数字2或4,玩家可以通过上下左右来移动有数字的方块,在移动的同一方向,若两个数字之间没有其他数字方块阻隔且相等,则数字相加并合并为一个数字方块。每一次移动后,则随机在任意空白方块产生数字2或4,若是没有空白访块则代表游戏结束。

游戏难点分析:2048游戏的难点就在方块的移动上的数据保存和操作等。我的处理方法是,每一个方块数据里面保存当前数字,将要移动的步数,移动的方向,是否已经合并了。举个向上移动操作的例子,2048是一个由4*4的网格组成,向上移动的操作,首先我们先要移动的这个方块是空的方块还是带数字的方块,若是空的方块则无需移动;若是有数字的方块,我们需要判断它上面的方块是否为空或者是否含有同样的数字,若是为空,则可以继续往上判断;若是不为空则判断数字是否相等,数字相等且上面的数字没有合并过,则可以合并,若是不为空且数字不相等,则不能移动。在移动的判断的过程中,记录移动的方向、移动后更新的数字,移动的步数。

游戏实现:2048主要由三个类构成,GameScene负责游戏场景的实现、游戏事件的监听和处理,GameGraphic负责游戏图像的处理,GameHandle负责游戏逻辑的处理。每一次的移动操作,先执行GameHandler里面的逻辑处理,然后再根据GameHandler执行GameGraphic里面的图像处理。

  Common:主要用于定义一下枚举之类的常量和公用函数的实现。

#ifndef COMMON_H_
#define COMMON_H_

#include <string>

//Row number and column number
const int kRowAndColumn = 4;

//The Num of picture
const int kNum = 14;

//The distance from the boundary
const int kDistance = 84;

//The sum of picture and crack
const int kPictureWidth = 104;

//The move time of sprite
const double kMoveTime = 0.12;

//The key of the highest score
#define  kHighestScoreKey "Higest"

//The key of the highest score
#define  kHighestScore  "Highest Score:"

//Current Score
#define  kCurrentScore "Current Score:"

//Direction of movement
enum Direction
{
    kStop,
    kUp,
    kDown,
    kLeft,
    kRight
};

//Move Status
enum MoveStatus
{
    kMove,
    kDisableMove,
    kFillInNum
};

std::string IntToString(int temp_value);

#endif // !COMMON_H_

////////////////////////////////////////
#include "Common.h"

using std::string;

string IntToString(int temp_value)
{
    string str = "";

    do
    {
        str.insert(str.begin(), temp_value % 10 + ‘0‘);
        temp_value /= 10;
    } while (temp_value);

    return str;
}

Common

  GameScene:它继承于Cocos2d::Layer类,主要功能是负责游戏场景的实现,键盘和触摸事件的监听。关于触摸事件的,如何判断它是向上移动还是向下移动?我根据触摸起始点和触摸终点的坐标来判断,若x轴的坐标差的绝对值大于y的坐标差的绝对值10个像素点的话,则说明是在水平方向上的滑动,然后再根据x坐标差的正负来判断向左还是向右滑动。

#ifndef GAME_SCENE_H_
#define GAME_SCENE_H_

#include "cocos2d.h"
#include "SimpleAudioEngine.h"

#include "GameGraphic.h"
#include "GameHandler.h"

class GameScene : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();

    virtual bool init();
    virtual void onEnter();
    virtual void onEnterTransitionDidFinish();
    virtual void onExit();
    virtual void onExitTransitionDidStart();
    virtual void cleanup();

    virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
    virtual void onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *event);
    virtual void onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *event);

    virtual void onKeyPressed(cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event* event);
    virtual void onKeyReleased(cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event* event);

    void SlideToUp();
    void SlideToDown();
    void SlideToLeft();
    void SlideToRight();
    void DelayCallSlideToUp(float dt);
    void DelayCallSlideToDown(float dt);
    void DelayCallSlideToLeft(float dt);
    void DelayCallSlideToRight(float dt);

    void NewGameCallback(cocos2d::Ref* pSender);

    CREATE_FUNC(GameScene);

private:
    cocos2d::MenuItemFont* new_game_;
    cocos2d::Menu* menu_;

    cocos2d::Vec2 touch_began_point_;
    cocos2d::Vec2 touch_ended_point_;
};

#endif // GAME_SCENE_H_

////////////////////////////////////////////////////////////////
#include "GameScene.h"
#include "cocostudio/CocoStudio.h"
#include "ui/CocosGUI.h"

USING_NS_CC;

using namespace cocostudio::timeline;
using namespace CocosDenshion;

Scene* GameScene::createScene()
{
    auto scene = Scene::create();
    auto layer = GameScene::create();
    scene->addChild(layer);

    return scene;
}

bool GameScene::init()
{
    if ( !Layer::init() )
    {
        return false;
    }

    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 visibleOrigin = Director::getInstance()->getVisibleOrigin();

    if (g_gamehandler.Init() == false || g_gamegraphic.Init(this, visibleOrigin, visibleSize) == false)
    {
        return false;
    }

    //Get the highest score
    UserDefault* defaults = UserDefault::getInstance();
    int test = defaults->getIntegerForKey(kHighestScoreKey);
    g_gamehandler.SetHighestScore(defaults->getIntegerForKey(kHighestScoreKey));
    g_gamegraphic.ChangeDisplayScore();

    MenuItemFont::setFontName("Consolas");
    MenuItemFont::setFontSize(36);
    new_game_ = MenuItemFont::create("NewGame", CC_CALLBACK_1(GameScene::NewGameCallback, this));
    new_game_->setColor(Color3B(0, 0, 0));
    new_game_->setPosition(Vec2(visibleOrigin.x + visibleSize.width / 5 * 4, visibleOrigin.y + visibleSize.height / 6 * 5));
    menu_ = Menu::create(new_game_, NULL);
    menu_->setPosition(Vec2::ZERO);
    this->addChild(menu_);

    touch_began_point_ = Vec2(0, 0);
    touch_ended_point_ = Vec2(0, 0);
    this->setTouchEnabled(true);
    this->setTouchMode(Touch::DispatchMode::ONE_BY_ONE);

    this->setKeyboardEnabled(true);

    return true;
}

void GameScene::onEnter()
{
    Layer::onEnter();

}

void GameScene::onEnterTransitionDidFinish()
{
    Layer::onEnterTransitionDidFinish();

    SimpleAudioEngine::getInstance()->playBackgroundMusic("Sound/loop06a.mp3", true);
}

void GameScene::onExit()
{
    Layer::onExit();

    UserDefault* defaults = UserDefault::getInstance();
    if (defaults->getIntegerForKey(kHighestScoreKey) < g_gamehandler.GetHighestScore())
    {
        defaults->setIntegerForKey(kHighestScoreKey, g_gamehandler.GetHighestScore());
    }
}

void GameScene::onExitTransitionDidStart()
{
    Layer::onExitTransitionDidStart();

}

void GameScene::cleanup()
{
    Layer::cleanup();
}

bool GameScene::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event)
{
    touch_began_point_ = touch->getLocation();

    return true;
}

void GameScene::onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event)
{

}

void GameScene::onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event)
{
    touch_ended_point_ = touch->getLocation();

    double distanceX = touch_ended_point_.x - touch_began_point_.x;
    double distanceY = touch_ended_point_.y - touch_began_point_.y;

    if (fabs(distanceX) - fabs(distanceY) < 10 && fabs(distanceX) - fabs(distanceY) > -10)
    {
        return;
    }

    if (fabs(distanceX) > fabs(distanceY))
    {
        if (distanceX > 0)
        {
            SlideToRight();
        }
        else
        {
            SlideToLeft();
        }
    }
    else
    {
        if (distanceY > 0)
        {
            SlideToUp();
        }
        else
        {
            SlideToDown();
        }
    }
}

void GameScene::onKeyPressed(cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event* event)
{

}

void GameScene::onKeyReleased(cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event* event)
{
    switch (keyCode)
    {
    case EventKeyboard::KeyCode::KEY_UP_ARROW:
        SlideToUp();
        break;
    case EventKeyboard::KeyCode::KEY_DOWN_ARROW:
        SlideToDown();
        break;
    case EventKeyboard::KeyCode::KEY_LEFT_ARROW:
        SlideToLeft();
        break;
    case EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
        SlideToRight();
        break;
    default:
        break;
    }
}

void GameScene::SlideToUp()
{
    g_gamehandler.SlideToUp();

    MoveStatus move_status = g_gamehandler.CheckMapNumStatus();
    if (move_status == MoveStatus::kDisableMove)
    {

        return;
    }
    else if (move_status == MoveStatus::kFillInNum)
    {

        return;
    }
    else if (move_status == MoveStatus::kMove)
    {
        g_gamegraphic.SlideToUp();

        SimpleAudioEngine::getInstance()->playEffect("Sound/move.mp3");
        this->setTouchEnabled(false);
        this->setKeyboardEnabled(false);

        g_gamegraphic.ChangeDisplayScore();

        this->scheduleOnce(schedule_selector(GameScene::DelayCallSlideToUp), kMoveTime);
    }
}

void GameScene::SlideToDown()
{
    g_gamehandler.SlideToDown();

    MoveStatus move_status = g_gamehandler.CheckMapNumStatus();
    if (move_status == MoveStatus::kDisableMove)
    {

        return;
    }
    else if (move_status == MoveStatus::kFillInNum)
    {

        return;
    }
    else if (move_status == MoveStatus::kMove)
    {
        g_gamegraphic.SlideToDown();

        SimpleAudioEngine::getInstance()->playEffect("Sound/move.mp3");
        this->setTouchEnabled(false);
        this->setKeyboardEnabled(false);

        g_gamegraphic.ChangeDisplayScore();

        this->scheduleOnce(schedule_selector(GameScene::DelayCallSlideToDown), kMoveTime);
    }
}

void GameScene::SlideToLeft()
{
    g_gamehandler.SlideToLeft();

    MoveStatus move_status = g_gamehandler.CheckMapNumStatus();
    if (move_status == MoveStatus::kDisableMove)
    {

        return;
    }
    else if (move_status == MoveStatus::kFillInNum)
    {

        return;
    }
    else if (move_status == MoveStatus::kMove)
    {
        g_gamegraphic.SlideToLeft();

        SimpleAudioEngine::getInstance()->playEffect("Sound/move.mp3");
        this->setTouchEnabled(false);
        this->setKeyboardEnabled(false);

        g_gamegraphic.ChangeDisplayScore();

        this->scheduleOnce(schedule_selector(GameScene::DelayCallSlideToLeft), kMoveTime);
    }
}

void GameScene::SlideToRight()
{
    g_gamehandler.SlideToRight();

    MoveStatus move_status = g_gamehandler.CheckMapNumStatus();
    if (move_status == MoveStatus::kDisableMove)
    {

        return;
    }
    else if (move_status == MoveStatus::kFillInNum)
    {

        return;
    }
    else if (move_status == MoveStatus::kMove)
    {
        g_gamegraphic.SlideToRight();

        SimpleAudioEngine::getInstance()->playEffect("Sound/move.mp3");
        this->setTouchEnabled(false);
        this->setKeyboardEnabled(false);

        g_gamegraphic.ChangeDisplayScore();

        this->scheduleOnce(schedule_selector(GameScene::DelayCallSlideToRight), kMoveTime);
    }
}

void GameScene::DelayCallSlideToUp(float dt)
{
    g_gamegraphic.ChangePictureAndResetOnUp();

    this->setTouchEnabled(true);
    this->setKeyboardEnabled(true);
}

void GameScene::DelayCallSlideToDown(float dt)
{
    g_gamegraphic.ChangePictureAndResetOnDown();

    this->setTouchEnabled(true);
    this->setKeyboardEnabled(true);
}

void GameScene::DelayCallSlideToLeft(float dt)
{
    g_gamegraphic.ChangePictureAndResetLeft();

    this->setTouchEnabled(true);
    this->setKeyboardEnabled(true);
}

void GameScene::DelayCallSlideToRight(float dt)
{
    g_gamegraphic.ChangePictureAndResetRight();

    this->setTouchEnabled(true);
    this->setKeyboardEnabled(true);
}

void GameScene::NewGameCallback(cocos2d::Ref* pSender)
{
    g_gamegraphic.NewGamePictureReset();
}

GameScene

  GameHandler:主要用于游戏逻辑的处理,随机数的产生、移动时数据存储的变化、游戏分数的记录等。

#ifndef GAMEHANDLER_H_
#define GAMEHANDLER_H_

#include "cocos2d.h"

#include "Common.h"

struct NumData
{
    int num_;
    Direction direction_move_;
    int step_move_;
    bool is_merge_;
    bool is_visible_;

    NumData()
    {
        num_ = 0;
        direction_move_ = Direction::kStop;
        step_move_ = 0;
        is_merge_ = false;
        is_visible_ = true;
    }
};

class GameHandler
{
public:
    GameHandler();
    ~GameHandler();

    bool Init();

    void SlideToUp();
    void SlideToDown();
    void SlideToLeft();
    void SlideToRight();

    int GetNum(int row, int column);
    void SetNum(int row, int column, int num);
    Direction GetDirection(int row, int column);
    void SetDirection(int row, int column, Direction direction);
    int GetStepMove(int row, int column);
    void SetStepMove(int row, int column, int step_move);
    bool GetIsMerge(int row, int column);
    void SetIsMerge(int row, int column, bool is_merge);
    bool GetIsVisible(int row, int column);
    void SetIsVisible(int row, int column, bool is_visible);
    int GetTotalScore();
    int GetHighestScore();
    void SetHighestScore(int higheset_score);

    MoveStatus CheckMapNumStatus();
    void ResetNumDataAfterSlide(int &tepm_row, int &temp_column);
    void NewGameHandlerReset();

    int GetMoveGainScore();

private:
    void ProduceRandNum(int &tepm_row, int &temp_column);

    int history_highest_score_;
    int total_score_;
    int score_;
    NumData map_num_[kRowAndColumn][kRowAndColumn];
};

extern GameHandler g_gamehandler;
#endif // !GAMEHANDLER_H_

//////////////////////////////////////////////////////////////////
#include "GameHandler.h"

#include <string>
#include <ctime>

USING_NS_CC;

GameHandler g_gamehandler;

GameHandler::GameHandler()
{
    total_score_ = 0;
    score_ = 0;
}

GameHandler::~GameHandler()
{

}

bool GameHandler::Init()
{
    //在任意2个位置产生2或4
    int row = -1;
    int column = -1;
    srand((unsigned int)time(NULL));
    ProduceRandNum(row, column);
    ProduceRandNum(row, column);

    /*auto DefaultData = UserDefault::getInstance();
    history_highest_score_ = DefaultData->getIntegerForKey(kHighestScore, 0);*/

    return true;
}

void GameHandler::SlideToUp()
{
    int temp_row = 0;
    int temp_step = 0;

    for (int row = 1; row < kRowAndColumn; row++)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            if (map_num_[row][column].num_ == 0)
            {
                continue;
            }

            temp_row = row;
            temp_step = 0;

            while (temp_row > 0)
            {
                temp_row--;

                if (map_num_[temp_row][column].num_ != 0 && map_num_[temp_row][column].num_ != map_num_[row][column].num_)
                {
                    break;
                }

                if (map_num_[temp_row][column].num_ == 0)
                {
                    temp_step++;
                }

                if (map_num_[temp_row][column].num_ != 0 && map_num_[temp_row][column].num_ == map_num_[row][column].num_)
                {
                    if (map_num_[temp_row][column].is_merge_ == false)
                    {
                        temp_step++;
                        map_num_[temp_row][column].is_merge_ = true;
                    }

                    break;
                }
            }

            if (temp_step > 0)
            {
                if (map_num_[row - temp_step][column].num_ == 0)
                {
                    map_num_[row - temp_step][column].num_ = map_num_[row][column].num_;

                    map_num_[row][column].num_ = 0;
                    map_num_[row][column].direction_move_ = Direction::kUp;
                    map_num_[row][column].step_move_ = temp_step;
                }
                else if (map_num_[row - temp_step][column].num_ == map_num_[row][column].num_)
                {
                    map_num_[row - temp_step][column].num_ = map_num_[row][column].num_ * 2;

                    map_num_[row][column].num_ = 0;
                    map_num_[row][column].direction_move_ = Direction::kUp;
                    map_num_[row][column].step_move_ = temp_step;
                }
            }

        }
    }
}

void GameHandler::SlideToDown()
{
    int temp_row = 0;
    int temp_step = 0;

    for (int row = 2; row >= 0; row--)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            if (map_num_[row][column].num_ == 0)
            {
                continue;
            }

            temp_row = row;
            temp_step = 0;

            while (temp_row < kRowAndColumn - 1)
            {
                temp_row++;

                if (map_num_[temp_row][column].num_ != 0 && map_num_[temp_row][column].num_ != map_num_[row][column].num_)
                {
                    break;
                }

                if (map_num_[temp_row][column].num_ == 0)
                {
                    temp_step++;
                }

                if (map_num_[temp_row][column].num_ != 0 && map_num_[temp_row][column].num_ == map_num_[row][column].num_)
                {
                    if (map_num_[temp_row][column].is_merge_ == false)
                    {
                        temp_step++;
                        map_num_[temp_row][column].is_merge_ = true;
                    }

                    break;
                }
            }

            if (temp_step > 0)
            {
                if (map_num_[row + temp_step][column].num_ == 0)
                {
                    map_num_[row + temp_step][column].num_ = map_num_[row][column].num_;

                    map_num_[row][column].num_ = 0;
                    map_num_[row][column].direction_move_ = Direction::kDown;
                    map_num_[row][column].step_move_ = temp_step;
                }
                else if (map_num_[row + temp_step][column].num_ == map_num_[row][column].num_)
                {
                    map_num_[row + temp_step][column].num_ = map_num_[row][column].num_ * 2;

                    map_num_[row][column].num_ = 0;
                    map_num_[row][column].direction_move_ = Direction::kDown;
                    map_num_[row][column].step_move_ = temp_step;
                }
            }

        }
    }
}

void GameHandler::SlideToLeft()
{
    int temp_column = 0;
    int temp_step = 0;

    for (int column = 1; column < kRowAndColumn; column++)
    {
        for (int row = 0; row < kRowAndColumn; row++)
        {
            if (map_num_[row][column].num_ == 0)
            {
                continue;
            }

            temp_column = column;
            temp_step = 0;

            while (temp_column > 0)
            {
                temp_column--;

                if (map_num_[row][temp_column].num_ != 0 && map_num_[row][temp_column].num_ != map_num_[row][column].num_)
                {
                    break;
                }

                if (map_num_[row][temp_column].num_ == 0)
                {
                    temp_step++;
                }

                if (map_num_[row][temp_column].num_ != 0 && map_num_[row][temp_column].num_ == map_num_[row][column].num_)
                {
                    if (map_num_[row][temp_column].is_merge_ == false)
                    {
                        temp_step++;
                        map_num_[row][temp_column].is_merge_ = true;
                    }

                    break;
                }
            }

            if (temp_step > 0)
            {
                if (map_num_[row][column - temp_step].num_ == 0)
                {
                    map_num_[row][column - temp_step].num_ = map_num_[row][column].num_;

                    map_num_[row][column].num_ = 0;
                    map_num_[row][column].direction_move_ = Direction::kLeft;
                    map_num_[row][column].step_move_ = temp_step;
                }
                else if (map_num_[row][column - temp_step].num_ == map_num_[row][column].num_)
                {
                    map_num_[row][column - temp_step].num_ = map_num_[row][column].num_ * 2;

                    map_num_[row][column].num_ = 0;
                    map_num_[row][column].direction_move_ = Direction::kLeft;
                    map_num_[row][column].step_move_ = temp_step;
                }
            }
        }
    }
}

void GameHandler::SlideToRight()
{
    int temp_column = 0;
    int temp_step = 0;

    for (int column = 2; column >= 0; column--)
    {
        for (int row = 0; row < kRowAndColumn; row++)
        {
            if (map_num_[row][column].num_ == 0)
            {
                continue;
            }

            temp_column = column;
            temp_step = 0;

            while (temp_column < kRowAndColumn - 1)
            {
                temp_column++;

                if (map_num_[row][temp_column].num_ != 0 && map_num_[row][temp_column].num_ != map_num_[row][column].num_)
                {
                    break;
                }

                if (map_num_[row][temp_column].num_ == 0)
                {
                    temp_step++;
                }

                if (map_num_[row][temp_column].num_ != 0 && map_num_[row][temp_column].num_ == map_num_[row][column].num_)
                {
                    if (map_num_[row][temp_column].is_merge_ == false)
                    {
                        temp_step++;
                        map_num_[row][column].is_merge_ = true;
                    }

                    break;
                }
            }

            if (temp_step > 0)
            {
                if (map_num_[row][column + temp_step].num_ == 0)
                {
                    map_num_[row][column + temp_step].num_ = map_num_[row][column].num_;

                    map_num_[row][column].num_ = 0;
                    map_num_[row][column].direction_move_ = Direction::kRight;
                    map_num_[row][column].step_move_ = temp_step;
                }
                else if (map_num_[row][column + temp_step].num_ == map_num_[row][column].num_)
                {
                    map_num_[row][column + temp_step].num_ = map_num_[row][column].num_ * 2;

                    map_num_[row][column].num_ = 0;
                    map_num_[row][column].direction_move_ = Direction::kRight;
                    map_num_[row][column].step_move_ = temp_step;
                }
            }

        }
    }
}

int GameHandler::GetNum(int row, int column)
{
    if (row >= 0 && row < kRowAndColumn && column >= 0 && column < kRowAndColumn)
    {
        return map_num_[row][column].num_;
    }

    return -1;
}

void GameHandler::SetNum(int row, int column, int num)
{
    if (row >= 0 && row < kRowAndColumn && column >= 0 && column < kRowAndColumn)
    {
        map_num_[row][column].num_ = num;
    }
}

Direction GameHandler::GetDirection(int row, int column)
{
    if (row >= 0 && row < kRowAndColumn && column >= 0 && column < kRowAndColumn)
    {
        return map_num_[row][column].direction_move_;
    }

    return Direction::kStop;
}

void GameHandler::SetDirection(int row, int column, Direction direction)
{
    if (row >= 0 && row < kRowAndColumn && column >= 0 && column < kRowAndColumn)
    {
        map_num_[row][column].direction_move_ = direction;
    }
}

int GameHandler::GetStepMove(int row, int column)
{
    if (row >= 0 && row < kRowAndColumn && column >= 0 && column < kRowAndColumn)
    {
        return map_num_[row][column].step_move_;
    }

    return 0;
}

void GameHandler::SetStepMove(int row, int column, int step_move)
{
    if (row >= 0 && row < kRowAndColumn && column >= 0 && column < kRowAndColumn)
    {
        map_num_[row][column].step_move_ = step_move;
    }
}

bool GameHandler::GetIsMerge(int row, int column)
{
    if (row >= 0 && row < kRowAndColumn && column >= 0 && column < kRowAndColumn)
    {
        return map_num_[row][column].is_merge_;
    }

    return false;
}

void GameHandler::SetIsMerge(int row, int column, bool is_merge)
{
    if (row >= 0 && row < kRowAndColumn && column >= 0 && column < kRowAndColumn)
    {
        map_num_[row][column].is_merge_ = is_merge;
    }
}

bool GameHandler::GetIsVisible(int row, int column)
{
    if (row >= 0 && row < kRowAndColumn && column >= 0 && column < kRowAndColumn)
    {
        return map_num_[row][column].is_visible_;
    }

    return true;
}

void GameHandler::SetIsVisible(int row, int column, bool is_visible)
{
    if (row >= 0 && row < kRowAndColumn && column >= 0 && column < kRowAndColumn)
    {
        map_num_[row][column].is_visible_ = is_visible;
    }
}

int GameHandler::GetTotalScore()
{
    return total_score_;
}

int GameHandler::GetHighestScore()
{
    return history_highest_score_;
}

void GameHandler::SetHighestScore(int higheset_score)
{
    history_highest_score_ = higheset_score;
}

MoveStatus GameHandler::CheckMapNumStatus()
{
    int step_move_zero = 0;
    int fill_num = 0;
    for (int row = 0; row < kRowAndColumn; row++)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            if (map_num_[row][column].step_move_ == 0)
            {
                ++step_move_zero;
            }

            if (map_num_[row][column].num_ != 0)
            {
                ++fill_num;
            }

        }
    }

    if (step_move_zero == kRowAndColumn*kRowAndColumn && fill_num == kRowAndColumn*kRowAndColumn)
    {
        return MoveStatus::kFillInNum;
    }
    else if (step_move_zero == kRowAndColumn*kRowAndColumn)
    {
        return MoveStatus::kDisableMove;
    }

    return kMove;
}

void GameHandler::ResetNumDataAfterSlide(int &tepm_row, int &temp_column)
{
    for (int row = 0; row < kRowAndColumn; row++)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            map_num_[row][column].direction_move_ = Direction::kStop;
            map_num_[row][column].step_move_ = 0;
            map_num_[row][column].is_merge_ = false;
            map_num_[row][column].is_visible_ = true;
        }
    }

    ProduceRandNum(tepm_row, temp_column);
}

void GameHandler::NewGameHandlerReset()
{
    total_score_ = 0;
    score_ = 0;

    for (int row = 0; row < kRowAndColumn; row++)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            map_num_[row][column].num_ = 0;
            map_num_[row][column].direction_move_ = kStop;
            map_num_[row][column].step_move_ = 0;
            map_num_[row][column].is_merge_ = false;
            map_num_[row][column].is_visible_ = true;
        }
    }

    //在任意2个位置产生2或4
    int row = -1;
    int column = -1;
    ProduceRandNum(row, column);
    ProduceRandNum(row, column);
}

int GameHandler::GetMoveGainScore()
{
    score_ = 0;
    for (int row = 0; row < kRowAndColumn; row++)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            if (map_num_[row][column].is_merge_)
            {
                score_ += map_num_[row][column].num_;
            }
        }
    }

    total_score_ += score_;

    return score_;
}

void GameHandler::ProduceRandNum(int &tepm_row, int &temp_column)
{
    //Ten times the risk of 2 is 4
    int randnum = 0;
    if (rand() % 100 >= 10)
    {
        randnum = 2;
    }
    else
    {
        randnum = 4;
    }

    //The position of the random number
    int count_of_null = 0;
    for (int row = 0; row < kRowAndColumn; row++)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            if (map_num_[row][column].num_ == 0)
            {
                count_of_null++;
            }
        }
    }

    int index = rand() % count_of_null + 1;
    for (int row = 0; row < kRowAndColumn; row++)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            if (map_num_[row][column].num_ == 0)
            {
                index--;
                if (0 == index)
                {
                    tepm_row = row;
                    temp_column = column;
                    map_num_[row][column].num_ = randnum;
                    map_num_[row][column].is_visible_ = true;
                    return;
                }
            }
        }
    }
}

GameHandler

  GameGraphic:主要用于游戏图像和动画的处理,他一般在游戏逻辑调用之后才使用。

#ifndef GAMEGRAPHIC_H_
#define GAMEGRAPHIC_H_

#include <map>

#include "cocos2d.h"

#include "Common.h"
#include "GameHandler.h"

class GameGraphic
{
public:
    GameGraphic();
    ~GameGraphic();

    bool Init(cocos2d::Layer *layer, cocos2d::Vec2 visible_origin, cocos2d::Size visible_size);

    void SlideToUp();
    void SlideToDown();
    void SlideToLeft();
    void SlideToRight();

    void ChangePictureAndResetOnUp();
    void ChangePictureAndResetOnDown();
    void ChangePictureAndResetLeft();
    void ChangePictureAndResetRight();
    void ChangeDisplayScore();

    void NewGamePictureReset();

private:
    cocos2d::Vec2 visible_origin_;
    cocos2d::Size visible_size_;

    cocos2d::Layer* layer_;
    cocos2d::Sprite* background_;
    cocos2d::Sprite* icon_;
    cocos2d::LabelTTF* highest_socre_;
    cocos2d::LabelTTF* current_score_;
    cocos2d::Sprite* map_background_[kRowAndColumn][kRowAndColumn];

    cocos2d::Sprite* map_graphic_[kRowAndColumn][kRowAndColumn];
    std::map<int, cocos2d::Texture2D*> numlibrary_;
};

extern GameGraphic g_gamegraphic;
#endif // !GAMEGRAPHIC_H_

////////////////////////////////////////////////////////////
#include "GameGraphic.h"

#include <sstream>

#include "cocos2d.h"

USING_NS_CC;
using namespace std;

GameGraphic g_gamegraphic;

GameGraphic::GameGraphic()
{
    layer_ = nullptr;
    memset(map_graphic_, 0, sizeof(Sprite*)*kRowAndColumn*kRowAndColumn);
}

GameGraphic::~GameGraphic()
{
    layer_ = nullptr;
    memset(map_graphic_, 0, sizeof(Sprite*)*kRowAndColumn*kRowAndColumn);
}

bool GameGraphic::Init(cocos2d::Layer *layer, cocos2d::Vec2 visible_origin, cocos2d::Size visible_size)
{
    layer_ = layer;
    visible_origin_ = visible_origin;
    visible_size_ = visible_size;

    background_ = Sprite::create("background.png");
    background_->setPosition(Vec2(visible_origin_.x + visible_size_.width / 2, visible_origin_.y + visible_size_.height / 2));
    layer_->addChild(background_);

    icon_ = Sprite::create("Num/2048.png");
    icon_->setPosition(Vec2(visible_origin_.x + visible_size_.width / 6, visible_origin_.y + visible_size_.height / 6 * 5));
    layer_->addChild(icon_);

    highest_socre_ = LabelTTF::create(kHighestScore + IntToString(g_gamehandler.GetHighestScore()), "Fonts/tahoma.ttf", 18);
    highest_socre_->setColor(Color3B(0, 0, 0));
    highest_socre_->setPosition(Vec2(visible_origin_.x + visible_size_.width / 2 - 30, visible_origin_.y + visible_size_.height / 8 * 7));
    layer_->addChild(highest_socre_, 10);

    current_score_ = LabelTTF::create(kCurrentScore + IntToString(g_gamehandler.GetTotalScore()), "Fonts/tahoma.ttf", 18);
    current_score_->setColor(Color3B(0, 0, 0));
    current_score_->setPosition(Vec2(visible_origin_.x + visible_size_.width / 2 - 30, visible_origin_.y + visible_size_.height / 8 * 6 + 30));
    layer_->addChild(current_score_);

    stringstream str;
    string picture_name = "";
    numlibrary_[0] = TextureCache::sharedTextureCache()->addImage("Num/0.png");
    for (int index = 1; index < kNum; index++)
    {
        picture_name = "Num/";
        str << pow(2, index);
        picture_name =  picture_name + str.str() + ".png\0";
        str.str("");

        numlibrary_[pow(2, index)] = TextureCache::sharedTextureCache()->addImage(picture_name);
    }
    for (int row = 0; row < kRowAndColumn; row++)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            //设置背景方块
            map_background_[row][column] = Sprite::create("Num/0.png");
            map_background_[row][column]->setPosition(Vec2(visible_origin_.x + kPictureWidth * column + kDistance, visible_origin_.y + kPictureWidth * (kRowAndColumn - row - 1) + kDistance));
            layer_->addChild(map_background_[row][column]);

            //初始化图片数组坐标
            map_graphic_[row][column] = Sprite::create("Num/0.png");
            map_graphic_[row][column]->setPosition(Vec2(visible_origin_.x + kPictureWidth * column + kDistance, visible_origin_.y + kPictureWidth * (kRowAndColumn - row - 1) + kDistance));
        }
    }

    for (int row = 0; row < kRowAndColumn; row++)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            map_graphic_[row][column]->setTexture(numlibrary_[g_gamehandler.GetNum(row, column)]);
            layer_->addChild(map_graphic_[row][column]);
        }
    }

    return true;
}

void GameGraphic::SlideToUp()
{
    int step_move = 0;
    for (int row = 1; row < kRowAndColumn; row++)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            step_move = g_gamehandler.GetStepMove(row, column);
            if (step_move != 0)
            {
                map_graphic_[row][column]->runAction(MoveTo::create(kMoveTime, Vec2(visible_origin_.x + kPictureWidth * column + kDistance, visible_origin_.y + kPictureWidth * (kRowAndColumn - row - 1 + step_move) + kDistance)));
            }

        }
    }

}

void GameGraphic::SlideToDown()
{
    int step_move = 0;
    for (int row = 2; row >= 0; row--)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            step_move = g_gamehandler.GetStepMove(row, column);
            if (step_move != 0)
            {
                map_graphic_[row][column]->runAction(MoveTo::create(kMoveTime, Vec2(visible_origin_.x + kPictureWidth * column + kDistance, visible_origin_.y + kPictureWidth * (kRowAndColumn - row - 1 - step_move) + kDistance)));
            }
        }
    }
}

void GameGraphic::SlideToLeft()
{
    int step_move = 0;
    for (int column = 1; column < kRowAndColumn; column++)
    {
        for (int row = 0; row < kRowAndColumn; row++)
        {
            step_move = g_gamehandler.GetStepMove(row, column);
            if (step_move != 0)
            {
                map_graphic_[row][column]->runAction(MoveTo::create(kMoveTime, Vec2(visible_origin_.x + kPictureWidth * (column - step_move) + kDistance, visible_origin_.y + kPictureWidth * (kRowAndColumn - row - 1) + kDistance)));
            }
        }
    }
}

void GameGraphic::SlideToRight()
{
    int step_move = 0;
    for (int column = 2; column >= 0; column--)
    {
        for (int row = 0; row < kRowAndColumn; row++)
        {
            step_move = g_gamehandler.GetStepMove(row, column);
            if (step_move != 0)
            {
                map_graphic_[row][column]->runAction(MoveTo::create(kMoveTime, Vec2(visible_origin_.x + kPictureWidth * (column + step_move) + kDistance, visible_origin_.y + kPictureWidth * (kRowAndColumn - row - 1) + kDistance)));
            }
        }
    }
}

void GameGraphic::ChangePictureAndResetOnUp()
{
    //Change Picture
    int step_move = 0;
    for (int row = 0; row < kRowAndColumn; row++)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            step_move = g_gamehandler.GetStepMove(row, column);
            if (step_move != 0)
            {
                map_graphic_[row][column]->setVisible(false);
                map_graphic_[row][column]->setPosition(Vec2(visible_origin_.x + kPictureWidth * column + kDistance, visible_origin_.y + kPictureWidth * (kRowAndColumn - row - 1) + kDistance));
                map_graphic_[row][column]->setTexture(numlibrary_[g_gamehandler.GetNum(row, column)]);
                map_graphic_[row][column]->setVisible(true);
            }
            else
            {
                map_graphic_[row][column]->setTexture(numlibrary_[g_gamehandler.GetNum(row, column)]);
            }

        }
    }

    //Reset Data
    int temp_row = 0;
    int temp_column = 0;
    g_gamehandler.ResetNumDataAfterSlide(temp_row, temp_column);
    map_graphic_[temp_row][temp_column]->setTexture(numlibrary_[g_gamehandler.GetNum(temp_row, temp_column)]);
}

void GameGraphic::ChangePictureAndResetOnDown()
{
    //Change Picture
    int step_move = 0;
    for (int row = kRowAndColumn - 1; row >= 0; row--)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            step_move = g_gamehandler.GetStepMove(row, column);
            if (step_move != 0)
            {
                map_graphic_[row][column]->setVisible(false);
                map_graphic_[row][column]->setPosition(Vec2(visible_origin_.x + kPictureWidth * column + kDistance, visible_origin_.y + kPictureWidth * (kRowAndColumn - row - 1) + kDistance));
                map_graphic_[row][column]->setTexture(numlibrary_[g_gamehandler.GetNum(row, column)]);
                map_graphic_[row][column]->setVisible(true);
            }
            else
            {
                map_graphic_[row][column]->setTexture(numlibrary_[g_gamehandler.GetNum(row, column)]);
            }

        }
    }

    //Reset Data
    int temp_row = 0;
    int temp_column = 0;
    g_gamehandler.ResetNumDataAfterSlide(temp_row, temp_column);
    map_graphic_[temp_row][temp_column]->setTexture(numlibrary_[g_gamehandler.GetNum(temp_row, temp_column)]);
}

void GameGraphic::ChangePictureAndResetLeft()
{
    //Change Picture
    int step_move = 0;
    for (int column = 0; column < kRowAndColumn; column++)
    {
        for (int row = 0; row < kRowAndColumn; row++)
        {
            step_move = g_gamehandler.GetStepMove(row, column);
            if (step_move != 0)
            {
                map_graphic_[row][column]->setVisible(false);
                map_graphic_[row][column]->setPosition(Vec2(visible_origin_.x + kPictureWidth * column + kDistance, visible_origin_.y + kPictureWidth * (kRowAndColumn - row - 1) + kDistance));
                map_graphic_[row][column]->setTexture(numlibrary_[g_gamehandler.GetNum(row, column)]);
                map_graphic_[row][column]->setVisible(true);
            }
            else
            {
                map_graphic_[row][column]->setTexture(numlibrary_[g_gamehandler.GetNum(row, column)]);
            }
        }
    }

    //Reset Data
    int temp_row = 0;
    int temp_column = 0;
    g_gamehandler.ResetNumDataAfterSlide(temp_row, temp_column);
    map_graphic_[temp_row][temp_column]->setTexture(numlibrary_[g_gamehandler.GetNum(temp_row, temp_column)]);
}

void GameGraphic::ChangePictureAndResetRight()
{
    int step_move = 0;
    for (int column = kRowAndColumn - 1; column >= 0; column--)
    {
        for (int row = 0; row < kRowAndColumn; row++)
        {
            step_move = g_gamehandler.GetStepMove(row, column);
            if (step_move != 0)
            {
                map_graphic_[row][column]->setVisible(false);
                map_graphic_[row][column]->setPosition(Vec2(visible_origin_.x + kPictureWidth * column + kDistance, visible_origin_.y + kPictureWidth * (kRowAndColumn - row - 1) + kDistance));
                map_graphic_[row][column]->setTexture(numlibrary_[g_gamehandler.GetNum(row, column)]);
                map_graphic_[row][column]->setVisible(true);
            }
            else
            {
                map_graphic_[row][column]->setTexture(numlibrary_[g_gamehandler.GetNum(row, column)]);
            }
        }
    }

    //Reset Data
    int temp_row = 0;
    int temp_column = 0;
    g_gamehandler.ResetNumDataAfterSlide(temp_row, temp_column);
    map_graphic_[temp_row][temp_column]->setTexture(numlibrary_[g_gamehandler.GetNum(temp_row, temp_column)]);
}

void GameGraphic::ChangeDisplayScore()
{
    if (g_gamehandler.GetMoveGainScore() > 0)
    {
        current_score_->setString(kCurrentScore + IntToString(g_gamehandler.GetTotalScore()));
    }

    if (g_gamehandler.GetTotalScore() > g_gamehandler.GetHighestScore())
    {
        g_gamehandler.SetHighestScore(g_gamehandler.GetTotalScore());
        highest_socre_->setString(kHighestScore + IntToString(g_gamehandler.GetTotalScore()));
    }
    else
    {
        highest_socre_->setString(kHighestScore + IntToString(g_gamehandler.GetHighestScore()));
    }
}

void GameGraphic::NewGamePictureReset()
{
    g_gamehandler.NewGameHandlerReset();

    for (int row = 0; row < kRowAndColumn; row++)
    {
        for (int column = 0; column < kRowAndColumn; column++)
        {
            map_graphic_[row][column]->setTexture(numlibrary_[g_gamehandler.GetNum(row, column)]);
        }
    }

    current_score_->setString(kCurrentScore + IntToString(g_gamehandler.GetTotalScore()));
    highest_socre_->setString(kHighestScore + IntToString(g_gamehandler.GetHighestScore()));
}

GameGraphic

  游戏到此已经完成了绝大部分功能,Game Over部分还没有做很好的处理,本人也没有找到合适的Game Over的图片素材,所以也就放在以后去处理吧。此版本的游戏只适合在Windows平台用Cocos2d-x V3.10版本的游戏引擎,跨平台的还没有去弄。过段时间会挂到Github上做后续的更新。

时间: 2024-11-10 17:28:50

Cocos2dx游戏开发——2048的相关文章

cocos2d-x游戏开发实战原创视频讲座系列1之2048游戏开发

 第一讲 游戏的演示和工具介绍...1 第二讲 创建项目...2 第三讲 界面显示...3 第四讲 数字2的产生...7 第五讲 输入操作的推断...9 第六讲 输入操作的反应...13 第七讲 分数的累加.游戏结束检測...18 第八讲 界面美化...22 视持续更新中.... 视频存放地址例如以下:http://ipd.pps.tv/user/1058663622 或者:http://www.iqiyi.com/u/1058663622 持续更新中~~~~~~~~~~~~~~. 第一讲 

《实例妙解 Cocos2d-x 游戏开发》反馈勘误

我的新书 <实例妙解 Cocos2d-x 游戏开发>已经上市了. 大家可以在书店或者网上购买: 部分购买地址: china-pub当当网京东 这个页面主要用于发布勘误.书中遇到了问题可以在 我的博客网站 或者 csdn博客页面 留言.当然更好的方式是加QQ群:305889963 与大家交流讨论. 书中Github代码网址:https://github.com/fansongy/Example-of-Cocos2DX

cocos2dx游戏开发学习笔记3-lua面向对象分析

在lua中,可以通过元表来实现类.对象.继承等.与元表相关的方法有setmetatable().__index.getmetatable().__newindex. 具体什么是元表在这里就不细说了,网上很多介绍,这里主要讲与cocos2dx相关联的部分. 在lua-binding库中extern.lua里,有如下方法: --Create an class. function class(classname, super) local superType = type(super) local c

cocos2dx游戏开发学习笔记1-基本概念

这里主要讲构建整个游戏需要的基本元素,很大部分都摘自cocos2dx官网. 1.Director 导演 导演,顾名思义,就是对整个游戏进行整体控制的. "Director"是一个共享的(单元素集)对象,负责不同场景之间的控制.导演知道当前哪个场景处于活动状态,允许你改变场景,或替换当前的场景,或推出一个新场景.当你往场景堆中推出一个新场景时,"Director"会暂停当前场景,但会记住这个场景.之后场景堆中最顶层的场景跳离时,该场景又会继续活跃.此外"Di

cocos2dx游戏开发学习笔记2-从helloworld开始

一.新建工程 具体安装和新建工程的方法在cocos2dx目录下的README.md文件中已经有详细说明,这里只做简单介绍. 1.上官网下载cocos2dx-3.0的源码,http://www.cocos2d-x.org/ 2.安装python2.7 3.运行setup.py安装 4.执行cocos new helloworld -p helloworld -l cpp,生成新工程 二.新建工程中包含的东西 -Classes AppDelegate.cpp      -----游戏真正开始执行的地

《Cocos2d-x游戏开发实战精解》学习笔记3--在Cocos2d-x中播放声音

<Cocos2d-x游戏开发实战精解>学习笔记1--在Cocos2d中显示图像 <Cocos2d-x游戏开发实战精解>学习笔记2--在Cocos2d-x中显示一行文字 之前的内容主要都是介绍如何在屏幕上显示图像,事实上除了图像之外,音乐的播放也可以被理解为一种显示的方式,本节将学习在Cocos2d-x中播放声音的方法. (1)在HelloWorld.h中对HelloWorld类进行如下定义: class HelloWorld : public Cocos2d::Layer { pu

cocos2dx游戏开发&mdash;&mdash;微信打飞机学习笔记(三)&mdash;&mdash;WelcomeScene的搭建

一.场景与层的关系: cocos2dx的框架可以说主要由导演,场景,层,精灵来构成: 1.其中导演,意如其名,就是操控整个游戏的一个单例,管理着整个游戏. 2.场景就像电影的一幕剧情,所以说,懂得如何划分好游戏的场景,是开始动手做游戏的第一步. 3.一个场景会有很多层,用来处理场景不同的功能. 4.而精灵则是最小的单位,比如子弹,飞机,敌机都是一个个的精灵所组成的.   二.WelcomeScene的搭建: 1.场景和层的二种搭建方法: (1)一种就是跟HelloWorld示例一样的方法,以一个

cocos2dx游戏开发——微信打飞机学习笔记(二)——游戏框架

一.游戏的基本框架: WelcomeScene    ——>    GameScene   ——>   GameOverScene ||                                       ||                                    || ∨                                      ∨                                   ∨ WelcomeLayer            

cocos2dx游戏开发——微信打飞机学习笔记(一)——开发准备

一.环境的搭建 1.Windows开发准备: (1)软件下载及安装 •下载Cocos2d-x 最新版本:http://www.cocos2d-x.org/download 或者从Cocos2d-x GitHub主页中克隆Develop分支:https://github.com/cocos2d/cocos2d-x •配置Python 2.7 环境:http://www.python.org/download/releases/ •建议IDE:Visual Studio 2013 •运行cocos2