1.3 读写Plist文件
Plist是Apple公司提供的一种格式,只在iOS系统下使用,但Cocos2d-x将其发扬光大了,Plist是一种XML格式,所以XML存在的问题,它也存在。对于Plist而言,Cocos2d-x已经将接口封装好了,唯一存在的平台差异性问题,就是在iOS下的Dictionary和Windows/Android下的有些不同,在你遍历一个iOS下的字典时,是无序的,字典结构本身也是无序的,而在Windows/Android下,CCDictionary是Cocos2d-x自己实现的,在遍历的时候,字典里面的每一项,跟你的Plist文件里每一项的顺序是一致的。所以,你的代码不要依赖于字典的顺序。因为最恐怖的事情不是代码通不过,而是代码有时候可以通过,有时候又通不过。
Cocos2d-x里的粒子系统、动画、图集等大多都用到了Plist,粒子编辑器、拼图工具、动画编辑器等都可以直接导出Plist格式的文件,其中粒子格式比较特殊的一点是将粒子图片也直接放到Plist文件里了,因为粒子图片一般都比较小,放到一起管理起来非常方便。
1.3.1 Plist格式简介
Plist里面有一些特有的结构,主要包含以下标签。
❑ <string>:UTF-8字符串。
❑ <real>、<integer>:十进制的数字字符串。
❑ <true/>、<false />:真和假。
❑ <date>:日期字符串(ISO8601格式,例如2013-11-3)。
❑ <data>:Base64编码的数据。
❑ <array>:任意长度的数组。
❑ <dict>:key-value格式的字典,key是<key>标签,value可以是任意格式。
可以用Notepad++或者plist Editor之类的软件来编辑Plist文件,下面是一个粒子系统的Plist文件的一部分内容,我们可以看到和普通的XML文件不同的是,Plist文件多了一个DTD字段用于描述这个文件,而且标签的名字并不是随意的,基本由上面列出的标签组成,根节点是一个名为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"/> <plist version="1.0"> <dict> <key>a</key> <string>string</string> <key>b</key> <false/> <key>c</key> <integer>123</integer> <key>d</key> <real>0.2500000</real> <key>e</key> <dict> <key>a</key> <string>string</string> <key>b</key> <false/> <key>c</key> <integer>123</integer> <key>d</key> <real>0.2500000</real> </dict> </dict> </plist>
1.3.2 读写Plist文件
在Cocos2d-x中读取一个Plist文件是一件非常简单的事情,通过FileUtils单例的一些方法直接从Plist文件中加载并创建ValueVector和ValueMap等容器,但是要加载的Plist文件的plist节点下必须是dict或者array节点。
//传入Plist文件名,解析后返回一个ValueMap对象 virtual ValueMap getValueMapFromFile(const std::string& filename); //传入Plist文件名,解析后返回一个ValueVector对象 virtual ValueVector getValueVectorFromFile(const std::string& filename);
下面介绍一下Plist文件的读取,通过FileUtils的getValueMapFromFile()方法将Plist文件解析成ValueMap并返回,然后调用自定义的dumpValueMap()方法,将容器的内容打印出来。
string plistFile = FileUtils::getInstance()->getWritablePath() + "myplist. plist"; ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(plistFile); dumpValueMap(dict);
dumpValueMap()方法会遍历传入的ValueMap对象,根据对象的类型进行打印,dumpValueMap的实现如下。
void dumpValueMap(ValueMap& vm) { //根据对象类型打印对象值 for (auto& item : vm) { switch (item.second.getType()) { case Value::Type::BOOLEAN: CCLOG("%s is %d", item.first.c_str(), item.second.asBool()); break; case Value::Type::INTEGER: CCLOG("%s is %d", item.first.c_str(), item.second.asInt()); break; case Value::Type::STRING: CCLOG("%s is %s", item.first.c_str(), item.second.asString(). c_str()); break; case Value::Type::FLOAT: case Value::Type::DOUBLE: CCLOG("%s is %f", item.first.c_str(), item.second.asFloat()); break; case Value::Type::MAP: CCLOG("========== %s is ValueMap ==========", item.first.c_str()); dumpValueMap(item.second.asValueMap()); CCLOG("===================================="); } } }
除了读取Plist文件之外,FileUtils还提供了写入Plist文件的接口,通过FileUtils的writeValueMapToFile()方法可以将一个ValueMap序列化到指定的文件中。
ValueMap dict; dict.insert(pair<string, Value>(string("a"), Value("string"))); dict.insert(pair<string, Value>(string("b"), Value(false))); dict.insert(pair<string, Value>(string("c"), Value(123))); dict.insert(pair<string, Value>(string("d"), Value(0.25f))); dict.insert(pair<string, Value>(string("e"), Value(dict))); string plistFile = FileUtils::getInstance()->getWritablePath() + "myplist. plist"; if (FileUtils::getInstance()->writeValueMapToFile(dict, plistFile)) { CCLOG("write plist %s success", plistFile.c_str()); }