Cocos2d-x数据模块教程01:UserDefault数据存储
这是一个关于Cocos2d-x的数据模块的系列教程,内容涵盖UserDefault数据存储、Json数据操作、XML数据操作、plist文件操作、CSV文件解析以及SQLite3数据库基础用法。
在游戏开发中,游戏存档功能是不可或缺的。在Cocos2d-x中,提供了一个数据存储类CCUserDefault,可作为轻量级数据库使用。它支持五种数据类型的存储,分别是bool、int、float、double和string。
Cocos2d-x 3.x版本的变化
在Cocos2d-x 3.x版本中,CCUserDefault类有以下主要变化:
- 去掉 “CC”:类名不再以“CC”开头。
- 获取单例方式改变:
sharedUserDefault()方法改为getInstance()。 - 增加数据类型支持:新增了对
Data类型的支持,相关接口如下:void setDataForKey(const char* pKey, const Data& value); Data getDataForKey(const char* pKey, const Data& defaultValue = Data::Null); - 其他方面变化不大。
CCUserDefault类概述
CCUserDefault 类和之前讲的 CCDirector、SimpleAudioEngine 一样,采用单例模式。可以通过 sharedUserDefault() 函数来获取其唯一的实例对象。
CCUserDefault 采用XML存储技术,以键值对的形式存储数据,类似于C++中的 map 映射,一个关键字对应一个值。其实现的接口简单实用,通过传统的 set()、get() 方法来访问和修改值,支持存储 bool、int、float、double 和 string 五种数据类型。
原理
- 键值映射:类似于
map的映射关系,一个关键字对应一个值,通过set()和get()方法进行访问。 - 数据存储位置:数据直接存储在一个XML文件中,文件名与程序项目的名字相同,例如 “MyTest.xml”。
- 自动创建文件:首次使用时,如果XML文件不存在,
CCUserDefault会自动创建相应的XML文件。
设置数据值(set)
通过键值对的方式设置数据,相关接口如下:
void setBoolForKey(const char* pKey, bool value); // 设置一个bool值
void setIntegerForKey(const char* pKey, int value); // 设置一个int值
void setFloatForKey(const char* pKey, float value); // 设置一个float值
void setDoubleForKey(const char* pKey, double value); // 设置一个double值
void setStringForKey(const char* pKey, const std::string& value); // 设置一个string值
获取数据值(get)
通过关键字从XML文件中获取数据值。若关键字不存在,会自动设置键值映射,并设置对应的默认值 defaultValue。相关接口如下:
bool getBoolForKey(const char* pKey, bool defaultValue = false); // 读取一个bool值
int getIntegerForKey(const char* pKey, int defaultValue = 0); // 读取一个int值
float getFloatForKey(const char* pKey, float defaultValue = 0.0); // 读取一个float值
double getDoubleForKey(const char* pKey, double defaultValue = 0.0); // 读取一个double值
std::string getStringForKey(const char* pKey, const std::string& defaultValue = ""); // 读取一个string值
保存数据(flush)
当调用 set 方法设置数据后,数据不会马上保存到XML文件中。因此,一定要记得调用 flush() 方法来保存数据,否则数据会丢失,示例代码如下:
CCUserDefault::sharedUserDefault()->flush();
其他操作
还提供了一些其他操作,如获取单例对象、释放单例对象、获取XML文件路径、判断XML文件是否已经存在,相关接口如下:
static CCUserDefault* sharedUserDefault(); // 获取单例对象
static void purgeSharedUserDefault(); // 释放单例对象
const static std::string& getXMLFilePath(); // 获取XML路径
static bool isXMLFileExist(); // XML文件是否已创建
使用技巧
- 宏定义简化代码:每次操作都要写长长的
CCUserDefault::sharedUserDefault()来获取单例对象,比较麻烦。可以通过宏定义来缩短代码长度,示例如下:#define UserDefault CCUserDefault::sharedUserDefault() - 注意数据类型区别:在使用时,要特别注意
const char*和const std::string是不同的数据类型。 - 及时保存数据:当调用
set方法设置数据后,一定要记得调用flush()方法来保存数据,否则数据会丢失。
代码实战
代码来源于TestCpp项目,以下是具体的实现步骤和代码:
1. 引用头文件和命名空间
因为要使用C++的 string 类型,需要引用以下头文件和命名空间:
#include <string>
using namespace std;
2. 宏定义获取单例对象的函数
#define UserDefault CCUserDefault::sharedUserDefault()
3. 编写数据存储相关操作,并在控制台输出数据值
// 设置set
UserDefault->setBoolForKey("bool", true);
UserDefault->setIntegerForKey("integer", 100);
UserDefault->setFloatForKey("float", 33.33f);
UserDefault->setDoubleForKey("double", 44.44);
UserDefault->setStringForKey("string", "1111111");
// 获取get,并输出到控制台
// 通过关键字,获取数据
bool b = UserDefault->getBoolForKey("bool");
int i = UserDefault->getIntegerForKey("integer");
float f = UserDefault->getFloatForKey("float");
double d = UserDefault->getDoubleForKey("double");
string ret = UserDefault->getStringForKey("string");
// 输出到控制台
CCLOG((b == true)? "bool is true" : "bool is false");
CCLOG("integer is %d", i);
CCLOG("float is %f", f);
CCLOG("double is %f", d);
CCLOG("string is %s", ret.c_str());
// 输出XML文件路径
if (UserDefault->isXMLFileExist()) // 是否存在
{
string path = UserDefault->getXMLFilePath();
CCLOG("XML file is exist!");
CCLOG("XML file path : %s", path.c_str());
}
else
{
CCLOG("XML file is not exist!");
}
// 保存数据
UserDefault->flush();
4. 运行结果
此处未给出具体运行结果,可自行运行代码查看。
5. 分析与总结
- 浮点数精度问题:在输出结果中,可能会发现
float类型数据存在精度问题。例如,设置float值为 33.33,输出的却是 33.330002。这是因为float是单精度浮点数,有效精度在 6 - 7 位,超过 7 位就可能会失真。而double是双精度浮点数,有效精度在 15 - 16 位,超过 16 位才会失真。具体原理可自行百度查询。 - XML文件保存路径:
getXMLFilePath()方法获取的XML文件路径为绝对路径,XML文件保存的路径为项目的Debug.win32目录中,说明XML文件是保存在应用程序所在目录下的。