如图,在右下角增加保存图标,点击后进行游戏的保存。
游戏保存采用json格式,具体如下: { "map_level":2, // 游戏关卡 "gameRoundCount":66, // 游戏回合数 "players":[ //角色信息 { "playerTag":1, //角色1 "playerPosition_x":320, //角色所处的x坐标 "playerPosition_y":192, //角色所处的y坐标 "restTimes":3, //角色休息回合数 "stop_x":0, //角色停留的x坐标 "stop_y":0, //角色停留的y坐标 "money":509000, //角色资金 "strength":100, //角色体力 "comeFromeRow":4, //角色从上一个位置的行 "comeFromCol":10, //角色从上一个位置的列 "isMyTurn":false, //角色是否该行走 "skill":"1-2-2", //角色技能等级 "lottery":"", //角色购买的彩票号码 "stocks":[ //角色持有的股票信息 {"stockCode":800100,"makedealprice":10,"storeNumber":100}, {"stockCode":800200,"makedealprice":0,"storeNumber":0}, {"stockCode":800300,"makedealprice":0,"storeNumber":0}, {"stockCode":800400,"makedealprice":10,"storeNumber":400}, {"stockCode":800500,"makedealprice":0,"storeNumber":0} ] }, { "playerTag":2, //角色2的保存信息,同上 "playerPosition_x":423.635, "playerPosition_y":96, "restTimes":0, "stop_x":10, "stop_y":13, "money":410300, "strength":80, "comeFromeRow":2, "comeFromCol":15, "isMyTurn":false, "skill":"3-2-1", "lottery":"", "stocks":[ {"stockCode":800100,"makedealprice":0,"storeNumber":0}, {"stockCode":800200,"makedealprice":20,"storeNumber":200}, {"stockCode":800300,"makedealprice":0,"storeNumber":0}, {"stockCode":800400,"makedealprice":0,"storeNumber":0}, {"stockCode":800500,"makedealprice":0,"storeNumber":0} ] } ], "landlayer":[ //地块的信息,在x行,y列 地块的gid值 {"x":5,"y":7,"gid":12}, {"x":5,"y":12,"gid":12}, {"x":6,"y":9,"gid":12}, {"x":6,"y":10,"gid":11}, {"x":7,"y":7,"gid":12}, {"x":7,"y":9,"gid":1}, {"x":7,"y":13,"gid":12}, {"x":8,"y":11,"gid":12}, {"x":9,"y":8,"gid":12}, {"x":9,"y":9,"gid":11}, {"x":9,"y":11,"gid":12}, {"x":10,"y":6,"gid":12}, {"x":10,"y":13,"gid":11}, {"x":11,"y":8,"gid":13}, {"x":11,"y":10,"gid":12}, {"x":11,"y":13,"gid":15}, {"x":12,"y":8,"gid":14}, {"x":12,"y":11,"gid":11}, {"x":13,"y":8,"gid":12}, {"x":13,"y":11,"gid":1}, {"x":14,"y":8,"gid":10}, {"x":14,"y":11,"gid":11}, {"x":15,"y":8,"gid":15}, {"x":15,"y":10,"gid":13}, {"x":15,"y":11,"gid":12}, {"x":16,"y":13,"gid":15}, {"x":17,"y":7,"gid":14}, {"x":17,"y":9,"gid":10} ] }
//在添加go按钮的方法中同时添加保存按钮 void GameBaseScene::addGoButton() { ...... saveMenuItemButton = MenuItemImage::create("map/save_normal.png", "map/save_pressed.png", this, menu_selector(GameBaseScene::goButtonCallback)); saveMenuItemButton->setPosition(ccp(winSize.width,0)); saveMenuItemButton->setAnchorPoint(ccp(1,0)); saveMenuItemButton->setTag(saveButtonTag); menu->addChild(saveMenuItemButton); } void GameBaseScene::goButtonCallback(cocos2d::CCObject *pSender) { ......... //当点击后调用saveGame()方法保存游戏 if(tag == saveButtonTag) { if(saveGame()) { CocosToast::createToast(this, LanguageString::getInstance()->getLanguageString(SAVE_SUCESS)->getCString(), TOAST_SHOW_TIME, winSize/2); }else { CocosToast::createToast(this, LanguageString::getInstance()->getLanguageString(SAVE_FAIL)->getCString(), TOAST_SHOW_TIME, winSize/2); } } }
saveGame()进行具体的游戏保存
cocos2dx使用了rapidjson库来替换原来的jsoncpp,我们就用这个cocos2dx自带的json库
//*** 生成 json 文件,存储在 getWritablePath 文件夹下 *** ,当前在proj.win32\Debug.win32目录下
bool GameBaseScene::saveGame() { rapidjson::Document writedoc; //创建Document writedoc.SetObject(); rapidjson::Document::AllocatorType& allocator = writedoc.GetAllocator(); rapidjson::Value players(rapidjson::kArrayType);//创建players数组 writedoc.AddMember("map_level", map_level, allocator); //添加map_level属性值 writedoc.AddMember("gameRoundCount", gameRoundCount, allocator); //添加gameRoundCount回合数 int playerNumber=1; rapidjson::Value player1_json(rapidjson::kObjectType); //创建player1的json对象 rapidjson::Value player2_json(rapidjson::kObjectType); //创建player2的json对象 rapidjson::Value player3_json(rapidjson::kObjectType); //创建player3的json对象 //保存各个角色的信息 for(auto it=players_vector.begin();it!=players_vector.end();it++) { RicherPlayer* richerPlayer = dynamic_cast<RicherPlayer*>(*it); switch(playerNumber) { case 1: { //在player1_json对象中添加角色各个属性值,json object 格式 “名称/值” player1_json.AddMember("playerTag", richerPlayer->getTag(), allocator); player1_json.AddMember("playerPosition_x", richerPlayer->getPosition().x, allocator); player1_json.AddMember("playerPosition_y", richerPlayer->getPosition().y, allocator); player1_json.AddMember("restTimes", richerPlayer->restTimes, allocator); player1_json.AddMember("stop_x", richerPlayer->stop_x, allocator); player1_json.AddMember("stop_y", richerPlayer->stop_y, allocator); player1_json.AddMember("money", richerPlayer->getMoney(), allocator); player1_json.AddMember("strength", richerPlayer->getStrength(), allocator); player1_json.AddMember("comeFromeRow", richerPlayer->getComeFromeRow(), allocator); player1_json.AddMember("comeFromCol", richerPlayer->getComeFromCol(), allocator); player1_json.AddMember("isMyTurn", richerPlayer->getIsMyTurn(), allocator); player1_json.AddMember("skill", String::createWithFormat("%d-%d-%d",richerPlayer->skill_vector.at(0),richerPlayer->skill_vector.at(1),richerPlayer->skill_vector.at(2))->getCString(), allocator); std::string tempstr; tempstr = ""; for(auto i=0;i<richerPlayer->lottery_vector.size();i++) { tempstr.append(String::createWithFormat("%02d",richerPlayer->lottery_vector.at(i))->getCString()).append("_"); } player1_json.AddMember("lottery", String::createWithFormat("%s",tempstr.c_str())->getCString(), allocator); rapidjson::Value stocks(rapidjson::kArrayType); for(auto i=0;i<richerPlayer->stockMap.size();i++) { rapidjson::Value stock(rapidjson::kObjectType); stock.AddMember("stockCode", richerPlayer->stockMap.at(i)->getCode(), allocator); stock.AddMember("makedealprice", richerPlayer->stockMap.at(i)->getMakedealprice(), allocator); stock.AddMember("storeNumber",richerPlayer->stockMap.at(i)->getStoreNumber(), allocator); stocks.PushBack(stock, allocator); } player1_json.AddMember("stocks",stocks,allocator); // 将player1_json加入到players数组 players.PushBack(player1_json, allocator); break; } case 2: { //添加角色2属性值 player2_json.AddMember("playerTag", richerPlayer->getTag(), allocator); player2_json.AddMember("playerPosition_x", richerPlayer->getPosition().x, allocator); player2_json.AddMember("playerPosition_y", richerPlayer->getPosition().y, allocator); player2_json.AddMember("restTimes", richerPlayer->restTimes, allocator); player2_json.AddMember("stop_x", richerPlayer->stop_x, allocator); player2_json.AddMember("stop_y", richerPlayer->stop_y, allocator); player2_json.AddMember("money", richerPlayer->getMoney(), allocator); player2_json.AddMember("strength", richerPlayer->getStrength(), allocator); player2_json.AddMember("comeFromeRow", richerPlayer->getComeFromeRow(), allocator); player2_json.AddMember("comeFromCol", richerPlayer->getComeFromCol(), allocator); player2_json.AddMember("isMyTurn", richerPlayer->getIsMyTurn(), allocator); player2_json.AddMember("skill", String::createWithFormat("%d-%d-%d",richerPlayer->skill_vector.at(0),richerPlayer->skill_vector.at(1),richerPlayer->skill_vector.at(2))->getCString(), allocator); std::string tempstr; tempstr = ""; for(auto i=0;i<richerPlayer->lottery_vector.size();i++) { tempstr.append(String::createWithFormat("%02d",richerPlayer->lottery_vector.at(i))->getCString()).append("_"); } player2_json.AddMember("lottery",String::createWithFormat("%s",tempstr.c_str())->getCString(), allocator); rapidjson::Value stocks(rapidjson::kArrayType); for(auto i=0;i<richerPlayer->stockMap.size();i++) { rapidjson::Value stock(rapidjson::kObjectType); stock.AddMember("stockCode", richerPlayer->stockMap.at(i)->getCode(), allocator); stock.AddMember("makedealprice", richerPlayer->stockMap.at(i)->getMakedealprice(), allocator); stock.AddMember("storeNumber",richerPlayer->stockMap.at(i)->getStoreNumber(), allocator); stocks.PushBack(stock, allocator); } player2_json.AddMember("stocks",stocks,allocator); players.PushBack(player2_json, allocator); break; } case 3: { //添加角色3属性值 player3_json.AddMember("playerTag", richerPlayer->getTag(), allocator); player3_json.AddMember("playerPosition_x", richerPlayer->getPosition().x, allocator); player3_json.AddMember("playerPosition_y", richerPlayer->getPosition().y, allocator); player3_json.AddMember("restTimes", richerPlayer->restTimes, allocator); player3_json.AddMember("stop_x", richerPlayer->stop_x, allocator); player3_json.AddMember("stop_y", richerPlayer->stop_y, allocator); player3_json.AddMember("money", richerPlayer->getMoney(), allocator); player3_json.AddMember("strength", richerPlayer->getStrength(), allocator); player3_json.AddMember("comeFromeRow", richerPlayer->getComeFromeRow(), allocator); player3_json.AddMember("comeFromCol", richerPlayer->getComeFromCol(), allocator); player3_json.AddMember("isMyTurn", richerPlayer->getIsMyTurn(), allocator); player3_json.AddMember("skill", String::createWithFormat("%d-%d-%d",richerPlayer->skill_vector.at(0),richerPlayer->skill_vector.at(1),richerPlayer->skill_vector.at(2))->getCString(), allocator); std::string tempstr; tempstr = ""; for(auto i=0;i<richerPlayer->lottery_vector.size();i++) { tempstr.append(String::createWithFormat("%02d",richerPlayer->lottery_vector.at(i))->getCString()).append("_"); } player3_json.AddMember("lottery",String::createWithFormat("%s",tempstr.c_str())->getCString(), allocator); rapidjson::Value stocks(rapidjson::kArrayType); for(auto i=0;i<richerPlayer->stockMap.size();i++) { rapidjson::Value stock(rapidjson::kObjectType); stock.AddMember("stockCode", richerPlayer->stockMap.at(i)->getCode(), allocator); stock.AddMember("makedealprice", richerPlayer->stockMap.at(i)->getMakedealprice(), allocator); stock.AddMember("storeNumber",richerPlayer->stockMap.at(i)->getStoreNumber(), allocator); stocks.PushBack(stock, allocator); } player3_json.AddMember("stocks",stocks,allocator); players.PushBack(player3_json, allocator); break; } } playerNumber++; } //将players数组写入到writedoc writedoc.AddMember("players", players, allocator); // 保存地块json rapidjson::Value landlayerJson(rapidjson::kArrayType); Size _landLayerSize = landLayer->getLayerSize(); for (int j = 0; j < _landLayerSize.width; j++) { for (int i = 0; i < _landLayerSize.height; i++) { Sprite* _sp = landLayer->tileAt(Point(j, i)); if (_sp) { rapidjson::Value landJson(rapidjson::kObjectType); int gid = landLayer->getTileGIDAt(Point(j, i)); landJson.AddMember("x", j, allocator); landJson.AddMember("y", i, allocator); landJson.AddMember("gid",gid, allocator); landlayerJson.PushBack(landJson, allocator); } } } writedoc.AddMember("landlayer", landlayerJson, allocator); //把json数据保存到path路径文件下,文件名称为saveJsonName ,saveJsonName在SeaScene.cpp中赋值 StringBuffer buffer; rapidjson::Writer<StringBuffer> writer(buffer); writedoc.Accept(writer); auto path = FileUtils::getInstance()->getWritablePath(); path.append(saveJsonName); FILE* file = fopen(path.c_str(), "wb"); if(file) { fputs(buffer.GetString(), file); fclose(file); } CCLOG("%s",buffer.GetString()); return true; }
效果如图
//在addMenuSprites()增加载入游戏按钮 void MenuScene:: addMenuSprites() { ............. LabelTTF* loadGameTTF = LabelTTF::create(LanguageString::getInstance()->getLanguageString(LOAD_GAME)->getCString(),FONT_MENU,Btn_FontSize); ControlButton* loadGameBtn = ControlButton::create(loadGameTTF,btnNormal4); loadGameBtn->setBackgroundSpriteForState(btnPress4, Control::State::SELECTED); loadGameBtn->setPosition(ccp(visibleSize.width/2,visibleSize.height-360)); loadGameBtn->setPreferredSize(Size(Btn_Width,Btn_Height)); loadGameBtn->addTargetWithActionForControlEvents(this,cccontrol_selector(MenuScene::menuTouchDown),Control::EventType::TOUCH_DOWN); loadGameBtn->setTag(Btn_Load_Game_TAG); addChild(loadGameBtn); ........ }
//点击后进入到popupLoadGameLayer(),弹出游戏存档的界面 void MenuScene::popupLoadGameLayer() { PopupLayer* popDialog = PopupLayer::create(DIALOG_BG); popDialog->setContentSize(CCSizeMake(Quit_Dialog_Size_Width, winSize.height)); popDialog->setTitle(LanguageString::getInstance()->getLanguageString(LOAD_GAME)->getCString()); popDialog->setContentText(LanguageString::getInstance()->getLanguageString(DIALOG_CONTENT)->getCString(), 20, 60, 250); popDialog->setPopType(LOADGAME); popDialog->setCallbackFunc(this, callfuncN_selector(MenuScene::quitButtonCallback)); popDialog->addButton(BUTTON_BG2, BUTTON_BG3, LanguageString::getInstance()->getLanguageString(CANCEL)->getCString(), Btn_Quit_Cancel_TAG); this->addChild(popDialog); }
PopupLayer会根据pop类型,调用setLoadGameContext(),创建载入游戏的对话框界面 void PopupLayer::onEnter() { ...... case LOADGAME: { setLoadGameContext(contentSize); break; } ...... }
//该方法主要是判断path路径下是否有存档文件。如果没有存档,显示无存档,有则显示关卡图片 void PopupLayer::setLoadGameContext(Size size) { Menu* menu = Menu::create(); menu->setPosition(CCPointZero); //判断是否有夏日海滩的存档文件 auto beach_path = FileUtils::getInstance()->getWritablePath(); beach_path.append("beach_save.json"); FILE* beach_file = fopen(beach_path.c_str(), "r"); //有则显示海滩图片,否则显示无存档 if(beach_file) { beachLoadGameMenuItem = MenuItemImage::create("map/beach_load_normal.png", "map/beach_load_pressed.png", this, menu_selector(PopupLayer::loadGameButtonCallback)); beachLoadGameMenuItem->setPosition(winSize/2+Size(0,120)); beachLoadGameMenuItem->setTag(save_beach_tag); menu->addChild(beachLoadGameMenuItem); fclose(beach_file); }else { beachLoadGameMenuItem = MenuItemImage::create("map/blank.png", "map/blank.png", this, menu_selector(PopupLayer::loadGameButtonCallback)); beachLoadGameMenuItem->setPosition(winSize/2+Size(0,120)); menu->addChild(beachLoadGameMenuItem); } //判断是否有海底世界的存档文件 auto sea_path = FileUtils::getInstance()->getWritablePath(); sea_path.append("sea_save.json"); FILE* sea_file = fopen(sea_path.c_str(), "r"); if(sea_file) { seaLoadGameMenuItem = MenuItemImage::create("map/sea_load_normal.png", "map/sea_load_pressed.png", this, menu_selector(PopupLayer::loadGameButtonCallback)); seaLoadGameMenuItem->setPosition(winSize/2+Size(0,20)); seaLoadGameMenuItem->setTag(save_sea_tag); menu->addChild(seaLoadGameMenuItem); fclose(sea_file); }else { seaLoadGameMenuItem = MenuItemImage::create("map/blank.png", "map/blank.png", this, menu_selector(PopupLayer::loadGameButtonCallback)); seaLoadGameMenuItem->setPosition(winSize/2+Size(0,20)); menu->addChild(seaLoadGameMenuItem); } //判断是否有空中花园的存档文件 auto garden_path = FileUtils::getInstance()->getWritablePath(); garden_path.append("garden_save.json"); FILE* garden_file = fopen(garden_path.c_str(), "r"); if(garden_file) { gardenLoadGameMenuItem = MenuItemImage::create("map/garden_load_normal.png", "map/garden_load_pressed.png", this, menu_selector(PopupLayer::loadGameButtonCallback)); gardenLoadGameMenuItem->setPosition(winSize/2+Size(0,-80)); gardenLoadGameMenuItem->setTag(save_garden_tag); menu->addChild(gardenLoadGameMenuItem); fclose(garden_file); }else { gardenLoadGameMenuItem = MenuItemImage::create("map/blank.png", "map/blank.png", this, menu_selector(PopupLayer::loadGameButtonCallback)); gardenLoadGameMenuItem->setPosition(winSize/2+Size(0,-80)); menu->addChild(gardenLoadGameMenuItem); } addChild(menu); }
//当点击各个存档文件图片后,载入相应的游戏存档,恢复游戏 void PopupLayer::loadGameButtonCallback(cocos2d::CCObject *pSender) { int tag = ((Node*)pSender)->getTag(); if(tag == save_beach_tag) { log("beach load"); } if(tag == save_sea_tag) { //点击海底世界图片,首先进入海底世界关卡 TransitionFadeBL* scene = TransitionFadeBL::create(1, SeaScene::createScene()); Director::getInstance()->pushScene(scene); //然后发送载入游戏的消息 String * str = String::createWithFormat("%d-%d",MSG_LOAD_GAME_TAG,tag); NotificationCenter::getInstance()->postNotification(MSG_LOAD_GAME,str); log("sea load"); } if(tag == save_garden_tag) { log("garden load"); } }
//GameBaseScene收到载入的消息后,调用reloadGame()方法,载入游戏存档 void GameBaseScene::receivedNotificationOMsg(Object* data) { ........ case MSG_LOAD_GAME_TAG: { int map_level = messageVector.at(1)->intValue(); reloadGame(map_level); break; } ....... }
//开始具体游戏的载入恢复 bool GameBaseScene::reloadGame(int map_level) { //根据关卡,载入相应的存档文件 auto path = FileUtils::getInstance()->getWritablePath(); switch(map_level) { case 1: { path.append("beach_save.json"); break; } case 2: { path.append("sea_save.json"); break; } case 3: { path.append("garden_save.json"); break; } } //*** 读取 json 文件 *** rapidjson::Document readdoc; bool bRet = false; ssize_t size = 0; std::string load_str; // getFileData 如果不指定,读取根目录是 Resource 文件夹 unsigned char* titlech = FileUtils::getInstance()->getFileData(path, "r", &size); load_str = std::string((const char*)titlech,size); readdoc.Parse<0>(load_str.c_str()); if(readdoc.HasParseError()) { CCLOG("GetParseError%s\n", readdoc.GetParseError()); } if(!readdoc.IsObject()) return 0; //回合数载入 rapidjson::Value& _gameRoundCount = readdoc["gameRoundCount"]; gameRoundCount = _gameRoundCount.GetInt(); refreshRoundDisplay(); //土地等级载人 rapidjson::Value& _landlayer = readdoc["landlayer"]; if(_landlayer.IsArray()) { for(int i=0; i<_landlayer.Capacity(); i++) { rapidjson::Value& arraydoc = _landlayer[i]; int x = arraydoc["x"].GetInt(); CCLOG("x:%d", x); int y = arraydoc["y"].GetInt(); CCLOG("y:%d", y); int gid = arraydoc["gid"].GetInt(); CCLOG("gid:%d", gid); landLayer->setTileGID(gid,ccp(x,y)); } } //人物信息载人 rapidjson::Value& _players = readdoc["players"]; if(_players.IsArray()) { for(int i=0; i<_players.Capacity(); i++) { rapidjson::Value& arraydoc = _players[i]; RicherPlayer* _richerPY = players_vector.at(i); int _restTimes = arraydoc["restTimes"].GetInt(); float _playerPositionX = arraydoc["playerPosition_x"].GetDouble(); float _playerPositionY = arraydoc["playerPosition_y"].GetDouble(); int _stop_x = arraydoc["stop_x"].GetInt(); int _stop_y = arraydoc["stop_y"].GetInt(); int _money = arraydoc["money"].GetInt(); int _strength = arraydoc["strength"].GetInt(); int _comeFromeRow = arraydoc["comeFromeRow"].GetInt(); int _comeFromCol = arraydoc["comeFromCol"].GetInt(); bool _isMyTurn = arraydoc["isMyTurn"].GetBool(); const char* _skill = arraydoc["skill"].GetString(); const char* _lottery = arraydoc["lottery"].GetString(); Vector<String*> lotteryVector = Util::splitString(_lottery,"_"); for(int i=0;i<lotteryVector.size();i++ ) { _richerPY->lottery_vector.push_back(lotteryVector.at(i)->intValue()); } _richerPY->restTimes = _restTimes; _richerPY->setPosition(ccp(_playerPositionX,_playerPositionY)); _richerPY->setComeFromeRow(_comeFromeRow); _richerPY->setComeFromCol(_comeFromCol); _richerPY->setIsMyTurn(_isMyTurn); _richerPY->stop_x = _stop_x; _richerPY->stop_y = _stop_y; _richerPY->setMoney(_money); _richerPY->setStrength(_strength); Vector<String*> skillVs = Util::splitString(_skill,"-"); _richerPY->skill_vector.at(0) = skillVs.at(0)->intValue(); _richerPY->skill_vector.at(1) = skillVs.at(1)->intValue(); _richerPY->skill_vector.at(2) = skillVs.at(2)->intValue(); refreshMoneyLabel(_richerPY,0); refreshStrengthLabel(_richerPY,0); } } //股票载入 for(int i=0; i<players_vector.size(); i++) { RicherPlayer* _richerPY = players_vector.at(i); rapidjson::Value& _stocks = _players[i]["stocks"]; if(_stocks.IsArray()) { for(int i=0; i<_stocks.Capacity(); i++) { rapidjson::Value& arraydoc = _stocks[i]; int _stockCode = arraydoc["stockCode"].GetInt(); int _makedealprice = arraydoc["makedealprice"].GetInt(); int _storeNumber = arraydoc["storeNumber"].GetInt(); _richerPY->stockMap.at(i)->setMakedealprice(_makedealprice); _richerPY->stockMap.at(i)->setStoreNumber(_storeNumber); } } } return 0; }