Cocos2d-x ValueMap
声明:本文分析的是cocos2d-x-3.13的代码
Value类
Cocos中的Value类可以存放各种基本类型如int、bool、string、float等等。Value类采用联合体实现,支持的数据类型有byte、int、unsigned、float、double、bool、string、vector、ValueMap、ValueMapIntKey。对于对象类型string、vector、ValueMap、ValueMapIntKey,Value类只存放指针,减少联合体的大小。以下时Value类的联合体定义:
union
{
unsigned char byteVal;
int intVal;
unsigned int unsignedVal;
float floatVal;
double doubleVal;
bool boolVal;
std::string *strVal;
ValueVector *vectorVal;
ValueMap *mapVal;
ValueMapIntKey *intKeyMapVal;
}_field;
Value类重载了所以类型的构造函数和operator=,这样Value可以直接通过等于号,或者构造函数赋值任何支持的类型。
Value类也重载了关系运算符==和!=。
Value类提供了每中类型的XXX asXXX()成员函数,该函数可以实现数据类型的内部转换,如Value当前类型为int,通过asString可以返回一个int数值转换后的字符穿,但Value的类型依然为int。
预定义Value容器
typedef std::vector<Value> ValueVector;
typedef std::unordered_map<std::string, Value> ValueMap;
typedef std::unordered_map<int, Value> ValueMapIntKey;
ValueMap类型
ValueMap实际的类型如下:
typedef std::unordered_map<std::string, Value> ValueMap;
是一个哈希表的Map,Key为string类型,值为Value类型。
这种类型非常适合存放键值对,可以存放一个key为字符串,值可以为任意类型(Value类所支持的类型),包括ValueMap类型。例如:
ValueMap vm;
vm.insert(make_pair(std::string("first"),Value(10)));
vm.insert(make_pair(std::string("second"),Value("abc")));
vm.insert(make_pair(std::string("third"),Value(vm)));
ValueVector vv;
vv.push_back(Value(1));vv.push_back(Value(2));vv.push_back(Value(3));
vm.insert(make_pair(std::string("fourth"),Value(vv)));
ValueMap序列化存储
保存
Cocos中的FileUtils支持将ValueMap转换为相应的XML文件保存,通过以下函数保存。
bool FileUtils::writeValueMapToFile(const ValueMap&dict,const std::string&fullPath)
例如:
ValueMap vm;
vm.insert(make_pair(std::string("first"),Value(10)));
vm.insert(make_pair(std::string("second"),Value("abc")));
vm.insert(make_pair(std::string("third"),Value(vm)));
ValueVector vv;
vv.push_back(Value(1));vv.push_back(Value(2));vv.push_back(Value(3));
vm.insert(make_pair(std::string("fourth"),Value(vv)));
FileUtils::getInstance()->writeValueMapToFile(vm,path+"ValueMap.plist");
结果ValueMap.plist文件内容:
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC"-//Apple//DTD PLIST 1.0//EN""http://www.apple.com/DTDs/PropertyList-1.0.dtd"/>
<plistversion="1.0">
<dict>
<key>fourth</key>
<array>
<integer>1</integer>
<integer>2</integer>
<integer>3</integer>
</array>
<key>first</key>
<integer>10</integer>
<key>second</key>
<string>abc</string>
<key>third</key>
<dict>
<key>first</key>
<integer>10</integer>
<key>second</key>
<string>abc</string>
</dict>
</dict>
</plist>
根节点为plist,ValueMap对象对应dict节点,数组对应array节点,其他类型对应相应节点。
读取
Cocos中的FileUtils也支持从特定格式的XML文件读取并返回ValueMap对象,通过以下函数读取。
ValueMap FileUtils::getValueMapFromFile(const std::string& filename)
例如读取上个例子保存的ValueMap.plist文件:
ValueMap vm2 =FileUtils::getInstance()->getValueMapFromFile(path+"ValueMap.plist");
CCLOG("%s,%s",vm2["first"].asString().c_str(),vm2["second"].asString().c_str());
结果:
10, abc
FileUtils对ValueMap的支持
写入ValueMap文件
CCFileUtils.cpp文件中有三个生成XML文档节点的函数
static tinyxml2::XMLElement*generateElementForDict(const ValueMap&dict, tinyxml2::XMLDocument *doc)
static tinyxml2::XMLElement*generateElementForArray(const ValueVector&array, tinyxml2::XMLDocument *pDoc)
static tinyxml2::XMLElement*generateElementForObject(const Value&value, tinyxml2::XMLDocument *doc)
Cocos使用tinyxml2来解析XML文档。
这个三个函数分别是生成ValueMap节点,数组节点和一般数据类型节点。
保存ValueMap函数
bool FileUtils::writeValueMapToFile(const ValueMap&dict,const std::string&fullPath)
会调用这三个函数生成相应的XML文档对象,然后保存XML文件。
读取ValueMap文件
CCFileUtils.cpp文件实现了以下类读取并转换XML文件。
class DictMaker: public SAXDelegator
SAXDelegator接口是用来遍历XML文档,有以下三个函数:
class CC_DLL SAXDelegator
{
public:
virtual ~SAXDelegator(){}
//开始访问节点时调用
virtual void startElement(void *ctx,const char*name,const char **atts) = 0;
//结束访问节点时调用
virtual void endElement(void *ctx,const char *name)= 0;
//访问节点文本内容时调用
virtual void textHandler(void *ctx,const char*s,int len)= 0;
};
以下函数实现了对XML文件的读取并转换成ValueMap对象
Value Map DictMaker::dictionaryWithContentsOfFile(const std::string& fileName)
函数FileUtils::getValueMapFromFile只是简单调用DictMaker::dictionaryWithContentsOfFile
ValueMap FileUtils::getValueMapFromFile(const std::string &filename)
{
const std::string fullPath=fullPathForFilename(filename);
DictMaker tMaker;
return tMaker.dictionaryWithContentsOfFile(fullPath);
}
扩展
1. 通过TexPacker将小图打包成为大图生成的配置文件就是一个plist的XML文件,文件格式就是按照ValueMap格式进行存储的。读取plist后便会生成一个ValueMap对象。
2. AnimationCache加载动画使用的Animation配置文件也时一个ValueMap文件,且有两中格式,一种是简单配置,一种是复杂配置。