如图,在右下角增加保存图标,点击后进行游戏的保存。
游戏保存采用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,{"stockCode":800400,"storeNumber":400},{"stockCode":800500,"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":20,"storeNumber":200},"storeNumber":0} ] } ],"landlayer":[ //地块的信息,在x行,y列 地块的gID值 {"x":5,"y":7,"gID":12},{"x":5,"y":12,{"x":6,"y":9,"y":10,"gID":11},{"x":7,"gID":1},"y":13,{"x":8,"y":11,{"x":9,"y":8,{"x":10,"y":6,{"x":11,"gID":13},"gID":15},{"x":12,"gID":14},{"x":13,{"x":14,"gID":10},{"x":15,{"x":16,{"x":17,"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(),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",allocator); player2_Json.AddMember("playerposition_x",allocator); player2_Json.AddMember("playerposition_y",allocator); player2_Json.AddMember("restTimes",allocator); player2_Json.AddMember("stop_x",allocator); player2_Json.AddMember("stop_y",allocator); player2_Json.AddMember("money",allocator); player2_Json.AddMember("strength",allocator); player2_Json.AddMember("comeFromeRow",allocator); player2_Json.AddMember("comeFromCol",allocator); player2_Json.AddMember("isMyTurn",allocator); player2_Json.AddMember("skill",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",allocator); } player2_Json.AddMember("stocks",allocator); players.PushBack(player2_Json,allocator); break; } case 3: { //添加角色3属性值 player3_Json.AddMember("playerTag",allocator); player3_Json.AddMember("playerposition_x",allocator); player3_Json.AddMember("playerposition_y",allocator); player3_Json.AddMember("restTimes",allocator); player3_Json.AddMember("stop_x",allocator); player3_Json.AddMember("stop_y",allocator); player3_Json.AddMember("money",allocator); player3_Json.AddMember("strength",allocator); player3_Json.AddMember("comeFromeRow",allocator); player3_Json.AddMember("comeFromCol",allocator); player3_Json.AddMember("isMyTurn",allocator); player3_Json.AddMember("skill",richerPlayer->lottery_vector.at(i))->getCString()).append("_"); } player3_Json.AddMember("lottery",allocator); } player3_Json.AddMember("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;}
2、载入存档
效果如图
//在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(),d出游戏存档的界面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",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",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",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",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",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",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;}
至此,游戏从保存文档中恢复完毕。
点击下载代码 未完待续................ 总结
以上是内存溢出为你收集整理的Cocos2d-x 3.2 大富翁游戏项目开发-第二十八部分 游戏保存和载入存档游戏全部内容,希望文章能够帮你解决Cocos2d-x 3.2 大富翁游戏项目开发-第二十八部分 游戏保存和载入存档游戏所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)