Cocos2d-x 3.2 大富翁游戏项目开发-第二十八部分 游戏保存和载入存档游戏

前端之家收集整理的这篇文章主要介绍了Cocos2d-x 3.2 大富翁游戏项目开发-第二十八部分 游戏保存和载入存档游戏前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
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,{"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(),弹出游戏存档的界面
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;
}


至此,游戏从保存文档中恢复完毕。

点击下载代码 未完待续................ 原文链接:https://www.f2er.com/cocos2dx/344256.html

猜你在找的Cocos2d-x相关文章