前几天在看一个cocos2d的战争类游戏的时候看到了CCDictionary这个类,之前貌似没见过,就顺带这学习了,其主要数据结构为一个HashMap,可以解析一写游戏工具生成的文件,如Box2D的数据,TexturePacker的数据等。这个类看字面意思就是一个字典类,但是其解析方式先简单说说吧,这样有助于理解。其在接写plist文件的时候类似于我们解析XML文件时的dom方式,其在内存中是以树状的结构呈现的,说到这里应该就简单多了,废话就不说了直接上代码吧,在这里我先把我写的这个例子的github地址跟上吧,这样大家就可以下到plist文件
git@github.com:jinjianxin/cocos2d-x.git
只要下载这个里面的TestDict就可以了。在这里我们就直接贴上解析plist文件的代码吧
1 const char * testPath = "/opt/cocos/cocos2d-x-2.2.1/projects/TestDict/Resources/BodyPlist.plist" ; 2 const char * fullPath = CCFileUtils::sharedFileUtils()->fullPathFromRelativeFile("BodyPlist.plist",testPath); 3 4 CCDictionary *plistDic = CCDictionary::createWithContentsOfFile(fullPath); 5 6 CCDictionary *metaDic = dynamic_cast<CCDictionary *>(plistDic->objectForKey("metadata")); 7 int format = dynamic_cast<CCString *>(metaDic->objectForKey("format"))->intValue(); 8 float ptmRatio = dynamic_cast<CCString *>(metaDic->objectForKey("ptm_ratio"))->floatValue(); 9 #ifdef DEBUG 10 CCLog("%d\t%2.2f\n",format,ptmRatio); 11 #endif 12 13 CCDictionary *bodyDic = dynamic_cast<CCDictionary *>(plistDic->objectForKey("bodies")); 14 15 CCDictElement *element; 16 CCDICT_FOREACH(bodyDic,element) 17 { 18 CCDictionary *test = dynamic_cast<CCDictionary *>(bodyDic->objectForKey("Head")); 19 CCPoint point = CCPointFromString(test->valueForKey("anchorpoint")->getCString()); 20 21 #ifdef DEBUG 22 CCLog("%2.2f\t%2.2f\n",point.x,point.y); 23 #endif 24 25 CCArray * fixturesList = static_cast<CCArray *>(test->objectForKey("fixtures")); 26 27 if(fixturesList !=NULL) 28 { 29 CCObject *obj; 30 CCARRAY_FOREACH(fixturesList,obj) 31 { 32 if(obj !=NULL) 33 { 34 CCLog("success\n"); 35 CCDictionary *itemDict = static_cast<CCDictionary *>(obj); 36 37 if(itemDict!=NULL) 38 { 39 int filter_categoryBits = dynamic_cast<CCString *>(itemDict->objectForKey("filter_categoryBits"))->intValue(); 40 int filter_maskBits = dynamic_cast<CCString *>(itemDict->objectForKey("filter_maskBits"))->intValue(); 41 int filter_groupIndex = dynamic_cast<CCString *>(itemDict->objectForKey("filter_groupIndex"))->intValue(); 42 float friction = dynamic_cast<CCString *>(itemDict->objectForKey("friction"))->floatValue(); 43 float density =dynamic_cast<CCString *>(itemDict->objectForKey("density"))->floatValue(); 44 float restitution =dynamic_cast<CCString *>(itemDict->objectForKey("restitution"))->floatValue(); 45 int isSensor = dynamic_cast<CCString *>(itemDict->objectForKey("isSensor"))->intValue(); 46 47 const char *fixture_type = dynamic_cast<CCString *>(itemDict->objectForKey("fixture_type"))->getCString(); 48 49 #ifdef DEBUG 50 CCLog("%d\t%d\t%d\t%2.2f\t%2.2f\t%2.2f\t%d\n",filter_categoryBits,filter_maskBits,filter_groupIndex, 51 friction,density,restitution,isSensor); 52 #endif 53 54 if(strcmp(fixture_type,"POLYGON") == 0) 55 { 56 #ifdef DEBUG 57 CCLog("fixture_type = %s\n",fixture_type); 58 #endif 59 60 #if 1 61 CCArray * arrayList = static_cast<CCArray *>(itemDict->objectForKey("polygons")); 62 63 if(arrayList!=NULL) 64 { 65 #ifdef DEBUG 66 CCLog("get arrayList success\n"); 67 #endif 68 #if 1 69 CCObject *obj = NULL; 70 CCARRAY_FOREACH(arrayList,obj) 71 { 72 CCArray *array = static_cast<CCArray *>(obj); 73 74 if(array !=NULL) 75 { 76 CCObject *tmp; 77 CCARRAY_FOREACH(array,tmp) 78 { 79 80 CCPoint point = CCPointFromString(static_cast<CCString *>(tmp)->getCString()); 81 CCLog("%2.2f\t%2.2f\n",point.x,point.y); 82 } 83 } 84 } 85 #endif 86 } 87 #endif 88 89 } 90 else if(strcmp(fixture_type,"CIRCLE") == 0) 91 { 92 #ifdef DEBUG 93 CCLog("fixture_type = %s\n",fixture_type); 94 #endif 95 } 96 else 97 { 98 CCLog("error\n"); 99 } 100 101 CCArray *polygonsList = static_cast<CCArray *>(itemDict->objectForKey("polygons")); 102 103 if(polygonsList!=NULL) 104 { 105 CCLog("success\n"); 106 } 107 108 } 109 else 110 { 111 CCLog("error\n"); 112 } 113 114 } 115 else 116 { 117 CCLog("error\n"); 118 } 119 } 120 } 121 else 122 { 123 CCLog("error\n"); 124 } 125 }
以上就是解析的全部代码了,接下来我们可以一下解析流程:
首先第四行的代码就是构造一个以plist文件作为参数的字典类,这个可以在其源代码里看到,其主要有三种创建方式,在这里我们用的是第三种,在这里我把它的声明贴一下:
1 static CCDictionary* create(); 2 static CCDictionary* createWithDictionary(CCDictionary* srcDict); 3 static CCDictionary* createWithContentsOfFile(const char *pFileName);
这个时候我们需要把plist文件的结构列一下,但是这个文件太多了,我就不列了,代码我已经上传了,想看的就自己打开吧,在这里我们需要取出其“metadata”字段的数据,把plist文件摘抄出一部分来如下
1 <key>metadata</key> 2 <dict> 3 <key>format</key> 4 <integer>1</integer> 5 <key>ptm_ratio</key> 6 <real>32</real> 7 </dict>
这个时候我们就可以把他递归的看作一个新的plist文件,这个时候我们就可以直接取出他的字段了,第六行至第八行的代码就是完成这样一个工作,在这里的代码就不多解释了。接着往下,我们继续解析这个文件,接着我们要取出“bodies”标签的内容,需要注意的是此处我们字典的父类还是plistDic对象。接着大家仔细看一下“bodies”标签下的内容就会发现其是一个循环结构,所以我们在这里就需要遍历我们获得的字典对象,在这里我们又看到一个新的数据结构CCDictElement,这个主要是用来遍历字典类的。接着我们使用和上述一样的方法取出“anchorpoint”字段的值,接下来我们要取得“fixtures”对象的字典,在这里我们分析了下plist文件,发现它的标签是array对象,直觉告诉我们,我们需要把这个东西转化为一个数组对象。接这个我们遍历刚刚转化的数组对象。接着我们往下看,发现其又退化为了一个CCDictionary类,所以我们在强制把数组对象转化为一个CCDictionary类,按照上面的方法依次取出其key值。接着我们看到“polygons”标签的值其又变化为了一个数组,那我们在按照之前的方法,将其转化为一个数组对象,接着我们发现其在array的标签里又嵌套了一层array的标签,所以我们在这里写两层循环就可以接着出这个值了。到这个这个文件就算解析完了。
由于本人也是在自学cocos2d-x,也不知道上面的理解是否有误,如果有高手发现错误还请指出,我会尽快作出修改。