Cocos2dx遊戲教程(八):“見縫插針”,UserDefault數據存儲與讀取

前面已經介紹了前兩個場景使用,中間涉及到了幾個核心類,菜單,label標籤等,同樣我們也實現了兩個場景的切換和關卡數字的顯示。那麼我們怎麼記錄遊戲相關的信息呢?

下面我們將走進cocos2dx的數據存儲,UserDefault。

一、UserDefault介紹

cocos2dx提供了一個數據存儲類UserDefault,可以作爲一個輕量級的數據庫來使用。它支持五種基本數據bool、int、float、double、string的存儲,3.x還增加了Date類型
新增類型如下,在此不做具體介紹。

void setDataForKey(const char* pKey, const Data& value);
Data getDataForKey(const char* pKey, const Data& defaultValue = Data::Null);

UserDefault和我們前面看到的導演類一樣,是一個單例模式,採用XML存儲技術,就是一般的鍵值對,這個類似C++中的map的映射(k,v)。一個關鍵字對應一個值。其實現的接口也比較簡單實用,通過傳統的set()、get()方法訪問和修改值。使用方法如下:

1、設置數據

UserDefault::getInstance()->setStringForKey("string","value");  //根據鍵值寫入std::string類型字符串
UserDefault::getInstance()->setIntegerForKey("int",1);
UserDefault::getInstance()->setFloatForKey("float",1.0f);
UserDefault::getInstance()->setDoubleForKey("double",1.0);
UserDefault::getInstance()->setBoolForKey("bool",false);

寫入後不要忘了存儲到硬盤上哦

UserDefault::getInstance()->flush();

2、讀取數據

auto s = UserDefault::getInstance()->getStringForKey("string");    //根據鍵值取出std::string類型字符串
auto i = UserDefault::getInstance()->getIntegerForKey("int");
auto f = UserDefault::getInstance()->getFloatForKey("float");
auto d = UserDefault::getInstance()->getDoubleForKey("double");
auto b = UserDefault::getInstance()->getBoolForKey("bool");

是不是感覺數據存儲很簡單?
那麼我們存儲的數據在哪呢?
在這裏插入圖片描述
我們打開看看裏面有什麼

<?xml version="1.0" encoding="UTF-8"?>
<userDefaultRoot>
    <_isInitGameData>true</_isInitGameData>
    <current_max_level>1</current_max_level>
</userDefaultRoot>

裏面記錄了是否初始化了遊戲數據,記錄的當前最大的關卡數。
當我們希望對某些數據只初始化一次的時候,我們可以用如下方式處理:

if(!UserDefault::getInstance()->getBoolForKey("_isInitGameData")){
	//判斷是否是第一次調用
	UserDefault::getInstance()->setBoolForKey("_isInitGameData",true);
}

UserDefault主要的用法到這就結束啦,當然cocos2dx支持的數據存儲有很多種,Json,xml,plist,csv,sqlite3等,大家可以慢慢的嘗試下,下面通過具體的事例應用來介紹一下。

二、新增類

前面主要是介紹了相關的基礎知識,現在更進一步,新增數據存儲類,我們看一下新增了哪些類呢
到這新增了類有
在這裏插入圖片描述

1、CSVParser
CSV數據格式解析可以參考
https://blog.csdn.net/slaron/article/details/55517440
本例遊戲配置採用的就是CSV數據格式
在這裏插入圖片描述
這裏面保存了關卡的id,默認小球的數量,玩家需要插得小球的數量,中心圓盤旋轉方向,遮罩層的開始結束角(後期介紹)
2、GameDataManage
我們來看一下GameDataManage做了哪些事情,爲了看的更清除,這裏簡單的使用單個方法來獲取各個屬性,小夥伴們可使用其他的方法獲取,比如結構體對象保存屬性。

頭文件GameDataManage.h

#pragma once
#include "cocos2d.h"
#include "CSVParser.h"

USING_NS_CC;
using namespace CSVParser;

class GameDataManage {
public:
	static GameDataManage* getInstance();
	static GameDataManage* singleInstance;
	GameDataManage();
	~GameDataManage();
	virtual bool init();
public:
	//載入遊戲數據
	void loadGameData(int level);
	//獲得出現的小球數
	int getObsBallNum(int level);
	//獲得用戶的小球數
	int getUserBallNum(int level);
	//獲得旋轉的速度
	int getRotateSpeed(int level);
	//獲得旋轉的方向
	int getTurnDir(int level);
	//獲得遮罩圓開始角度
	int getStartAngle(int level);
	//獲得遮罩圓結束角度
	int getEndAngle(int level);
public:
	//獲得是否初始化
	bool getIsFirstInit();
	//存儲是否初始化
	void setIsFirstInit(bool init);

	//獲得當前已經完成的關卡數
	int getCurrentMaxLevel();
	//保存當前已經完成的關卡數
	void setCurrentMaxLevel(int level);
public:
	//初始出現的小球數
	int obsBallNum;
	//用戶的小球數
	int userBallNum;
	//旋轉的速度
	int rotateSpeed;
	//旋轉的方向
	int turnDir;
	//總行數
	int totalRow;
	//遮罩圓開始角度
	int startAngle;
	//遮罩圓開始角度
	int endAngle;
private:
	Csv csv;
};

類文件GameDataManage.cpp

#include "GameDataManage.h"
#include "UserDefault.h"
#include "GBK2UTF.h"

GameDataManage* GameDataManage::singleInstance = NULL;

GameDataManage* GameDataManage::getInstance()
{
	if (NULL == singleInstance) {
		singleInstance = new GameDataManage();
	}
	return singleInstance;
}

GameDataManage::GameDataManage() 
	: csv("data/data.csv") 
{
	totalRow = csv.getRowCount() - 1;
}

GameDataManage::~GameDataManage() {
}

bool GameDataManage::init() {

	return true;
}

//載入遊戲數據
void GameDataManage::loadGameData(int level) {
	//獲得出現的小球數
	getObsBallNum(level);
	//獲得用戶的小球數
	getUserBallNum(level);
	//獲得旋轉的方向
	getTurnDir(level);
	//獲得旋轉的速度
	getRotateSpeed(level);
	//獲得遮罩圓開始角度
	getStartAngle(level);
	//獲得遮罩圓結束角度
	getEndAngle(level);
}

//獲得出現的小球數
int GameDataManage::getObsBallNum(int level) {
	obsBallNum = std::atoi(csv[level]["ObsNum"].c_str());
	log("%s %d", GBK2UTF("出現的小球數:"), obsBallNum);
	return obsBallNum;
}

//獲得用戶的小球數
int GameDataManage::getUserBallNum(int level) {
	userBallNum = std::atoi(csv[level]["UserNum"].c_str());
	log("%s %d", GBK2UTF("用戶的小球數:"), userBallNum);
	return userBallNum;
}

//獲得旋轉的方向
int GameDataManage::getTurnDir(int level) {
	turnDir = std::atoi(csv[level]["TurnDir"].c_str());
	if(turnDir == 1) {
		log("%s", GBK2UTF("旋轉的方向:逆時針"));
	} else {
		log("%s", GBK2UTF("旋轉的方向:順時針"));
	}
	return turnDir;
}


//獲得旋轉的速度
int GameDataManage::getRotateSpeed(int level) {
	rotateSpeed = std::atoi(csv[level]["RotateSpeed"].c_str());
	if(turnDir == 1) {
		rotateSpeed = 0 - rotateSpeed;
	}
	log("%s %d", GBK2UTF("旋轉的速度:"), rotateSpeed);
	return rotateSpeed;
}


//獲得遮罩圓開始角度
int GameDataManage::getStartAngle(int level) {
	startAngle = std::atoi(csv[level]["StartAngle"].c_str());
	log("%s %d", GBK2UTF("遮罩圓開始角度:"), startAngle);
	return startAngle;
}

//獲得遮罩圓結束角度
int GameDataManage::getEndAngle(int level) {
	endAngle = std::atoi(csv[level]["EndAngle"].c_str());
	log("%s %d", GBK2UTF("遮罩圓結束角度:"), endAngle);
	return endAngle;
}


/************************************************************************************************
*	用戶數據
************************************************************************************************/
//獲得是否初始化
bool GameDataManage::getIsFirstInit() {
	auto isInit = getBoolFromXML("_isInitGameData");
	return isInit;
}
//存儲是否初始化
void GameDataManage::setIsFirstInit(bool init) {
	setBoolToXML("_isInitGameData", init);
}

//獲得當前已經完成的關卡數
int GameDataManage::getCurrentMaxLevel() {
	auto level = getIntegerFromXML("current_max_level");
	return level;
}
//保存當前已經完成的關卡數
void GameDataManage::setCurrentMaxLevel(int level) {
	if(level >= getIntegerFromXML("current_max_level")) {
		setIntegerToXML("current_max_level", level);
	}	
}

這裏面出現CSV和GBK2UTF的類,GBK2UTF只做編碼轉換,大家可以把創建的文件已UTF創建,就不需要轉換啦,所以在此不做多樣贅述

3、UserDefault
UserDefault類只是簡單的對原UserDefault進行了封裝,大家可以不用關注,可以吧後面代碼中是數據獲取都改爲原生方式或者採用自己定義的數據結構,單純的修改,很單純~~

#include "UserDefault.h"
#include "cocos2d.h"
#include "cocos-ext.h"

USING_NS_CC;
USING_NS_CC_EXT;

using namespace std;
//保存數據到XML
void setStringToXML(const char* key, std::string value){
	userDefault->setStringForKey(key,value);
	userDefault->flush();
}

void setIntegerToXML(const char* key,int value){
	userDefault->setIntegerForKey(key,value);
	userDefault->flush();
}

void setBoolToXML(const char* key,bool value){
	userDefault->setBoolForKey(key,value);
	userDefault->flush();
}

void setDoubleToXML(const char* key,double value){
	userDefault->setDoubleForKey(key,value);
	userDefault->flush();
}

void setFloatToXML(const char* key,float value){
	userDefault->setFloatForKey(key,value);
	userDefault->flush();
}

//從XML讀取數據
std::string getStringFromXML(const char* key){
	return userDefault->getStringForKey(key);   
}

int getIntegerFromXML(const char* key){
	return userDefault->getIntegerForKey(key);   
}

bool getBoolFromXML(const char* key){
	return userDefault->getBoolForKey(key);   
}

double getDoubleToXML(const char* key){
	return userDefault->getDoubleForKey(key);   
}

float getFloatToXML(const char* key){
	return userDefault->getFloatForKey(key);   
}

那麼整個數據存儲都已經完成了,我們在WelcomeScene進行初次的數據獲取吧
在WelcomeScene.h中加上初始化方法

//初始化第一次登錄數據
void initFirstLoginData();

具體實現

//初始化第一次登錄數據
void WelcomeScene::initFirstLoginData() {
	if (!GameDataManage::getInstance()->getIsFirstInit()) {
		//設置已經初始化
		GameDataManage::getInstance()->setIsFirstInit(true);
		//初始化當前最大關卡
		GameDataManage::getInstance()->setCurrentMaxLevel(1);
	}
}

別忘了在init中調用啊
到這裏我們起兩個場景包括數據加載已經實現了哦,我們看看關卡加載的效果吧
我們在GameMenuScene init方法中添加如下代碼

//獲得最大關卡數據
auto maxLevel = GameDataManage::getInstance()->getCurrentMaxLevel();
GameDataManage::getInstance()->loadGameData(maxLevel);

我們在運行一下看看,運行後在控制檯我們可以看到,CSV格式的數據是不是被打印出來啦
在這裏插入圖片描述
我們會建立場景,會加載數據,離我們遊戲的完成是不是又進了一步呢。
彆着急,我們前面介紹了replaceScene,是不是感覺場景切換太過單調呢?下一節將會給大家介紹場景的過渡和相關效果哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章