由于自己自学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上做后续的更新。