1、游戏保存
如图,在右下角增加保存图标,点击后进行游戏的保存。
游戏保存采用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;
}
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(),弹出游戏存档的界面
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;
}
至此,游戏从保存文档中恢复完毕。