特效編輯器開發手記2——cocos2d-x粒子系統的plist文件


粒子編輯器必須要有一個保存粒子文件的功能,cocos2d-x使用plist來保存粒子文件(這是蘋果的一種基於xml的文件格式,也適用於動畫等)
於是我查看了cocos2d-x里面加載plist文件的代碼,它是先把plist加載到一個CCDictionary類中,然后在這個類里面方便地通過key-value來獲取相應的信息
 
 1 CCParticleSystem.cpp
 2     m_sPlistFile = CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(plistFile);
 3     CCDictionary *dict = CCDictionary::createWithContentsOfFileThreadSafe(m_sPlistFile.c_str());
 4  
 5 CCDictionary.cpp
 6 CCDictionary* CCDictionary::createWithContentsOfFileThreadSafe(const char *pFileName)
 7 {
 8     return ccFileUtils_dictionaryWithContentsOfFileThreadSafe(pFileName);
 9 }
10  
11 CCFileUtilsCommon_cpp.h
12 CCDictionary* ccFileUtils_dictionaryWithContentsOfFileThreadSafe(const char *pFileName)
13 {
14     CCDictMaker tMaker;
15     return tMaker.dictionaryWithContentsOfFile(pFileName);
16 }
17  
18 CCFileUtilsCommon_cpp.h
19     CCDictionary* dictionaryWithContentsOfFile(const char *pFileName)
20     {
21         m_eResultType = SAX_RESULT_DICT;
22         CCSAXParser parser;
23  
24         if (false == parser.init("UTF-8"))
25         {
26             return NULL;
27         }
28         parser.setDelegator(this);
29  
30         parser.parse(pFileName);
31         return m_pRootDict;
32     }
33  
34  
35 bool CCSAXParser::parse(const char *pszFile)
36 {
37     bool bRet = false;
38     unsigned long size = 0;
39     char* pBuffer = (char*)CCFileUtils::sharedFileUtils()->getFileData(pszFile, "rt", &size);
40     if (pBuffer != NULL && size > 0)
41     {
42         bRet = parse(pBuffer, size);
43     }
44     CC_SAFE_DELETE_ARRAY(pBuffer);
45     return bRet;
46 }
47  
48  
49 bool CCSAXParser::parse(const char* pXMLData, unsigned int uDataLength)
50 {
51     /*
52      * this initialize the library and check potential ABI mismatches
53      * between the version it was compiled for and the actual shared
54      * library used.
55      */
56     LIBXML_TEST_VERSION
57     xmlSAXHandler saxHandler;
58     memset( &saxHandler, 0, sizeof(saxHandler) );
59     // Using xmlSAXVersion( &saxHandler, 2 ) generate crash as it sets plenty of other pointers...
60     saxHandler.initialized = XML_SAX2_MAGIC;  // so we do this to force parsing as SAX2.
61     saxHandler.startElement = &CCSAXParser::startElement;
62     saxHandler.endElement = &CCSAXParser::endElement;
63     saxHandler.characters = &CCSAXParser::textHandler;
64     
65     int result = xmlSAXUserParseMemory( &saxHandler, this, pXMLData, uDataLength );
66     if ( result != 0 )
67     {
68         return false;
69     }
70     /*
71      * Cleanup function for the XML library.
72      */
73     xmlCleanupParser();
74     /*
75      * this is to debug memory for regression tests
76      */
77 #if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA)
78     xmlMemoryDump();
79 #endif
80     
81     return true;
82 }

 

 
通過上面的代碼可以看到,CCDictMaker通過調用CCSAXParser 這個類來進行plist文件的讀取和解析,也就是 parse函數,然后生成一個CCDictionary
通過CCSAXParser 自己的startElement和endElement來對plist進行解析,然后插入到CCDictionary的哈希中,上層調用valueforkey即可獲取對應的值
但說了這么多,我們如何保存呢?cocos2d-x提供了怎樣的接口給我們進行保存呢?
 
查閱CCDictionary這個類,發現與valueforkey有那么點對應關系的,也就setObject這個函數,但這個函數只是把Object插入到CCDictionary本身的哈希中而已,並沒有保存到plist,所以這里CCDictionary這個類跟plist唯一的聯系僅僅只是從plist中解析,獲取數據而已。
 
那么我們只能把目光轉移到生成CCDictionary的CCDictMaker 這個類來了,CCDictionary 是由CCDictMaker調用CCSAXParser 生成的,那么CCDictMaker 可有提供保存到plist的方法?答案還是沒有!
 
最后到了CCSAXParser這個類,只能看到,他調用xmlSAXUserParseMemory函數來將plist文件加載進來,至於xmlSAXUserParseMemory函數,那是在libxml/parser.h這個頭文件中。
 
隨后又查看了大量代碼,從頭到尾都沒有保存plist文件的代碼,至於CCUserDefault這個類,僅僅只是將數據保存在一個默認的xml文件中。
 
到了這里,也就不指望cocos提供什么接口了,直接查看粒子系統的plist文件,然后,根據其格式,自己實現一個plist類,用來保存粒子系統到plist文件。
 
plist文件格式大致如下,第一行是xml頭,包含xml版本和字符編碼
第二行是文檔類型,"-//Apple//DTD PLIST 1.0//EN"是它的pubid "http://www.apple.com/DTDs/PropertyList-1.0.dtd"是它的sysid
第三行是plist的根節點,有version屬性,下面有一個子節點dict,該子節點下面存放粒子系統的所有屬性值
每個值由兩個節點來表示,一個key節點,緊跟着還有一個value節點來表這個key的值,value節點有以下幾種類型:<real>表示浮點數,<integer>表示整型,<string>表示字符串,<array>表示數組
 
<?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>angle</key>
<real>270</real>
<key>angleVariance</key>
<real>0.0</real>
......
</dict>
</plist>

 

 
關於xml的操作,之前用過CMarkUpSTL,tinyxml,這兩個用得比較熟,但cocos用的是libxml,也只能去學習一下libxml
這是官網地址http://www.xmlsoft.org/
還有相關example的地址http://www.xmlsoft.org/examples/testWriter.c
在項目中實現一段如下的測試代碼來保存plist
 
 1 //創建test.plist文件
 2 m_Writer = xmlNewTextWriterFilename(plist, 0);
 3  
 4 //設置編碼為utf-8並開始文檔
 5 xmlTextWriterStartDocument(m_Writer, NULL, "UTF-8", NULL);
 6 //設置文檔類型
 7 xmlTextWriterWriteDTD(m_Writer, BAD_CAST "plist", BAD_CAST "-//Apple//DTD PLIST 1.0//EN", BAD_CAST "http://www.apple.com/DTDs/PropertyList-1.0.dtd", NULL);
 8 //根節點為plist,version屬性為1.0
 9 xmlTextWriterStartElement(m_Writer, BAD_CAST "plist");
10 xmlTextWriterWriteAttribute(m_Writer, BAD_CAST "version", BAD_CAST "1.0");
11 
12 //dict節點
13 xmlTextWriterStartElement(m_Writer, BAD_CAST "dict");
14  
15 //寫入測試數據
16 xmlTextWriterWriteElement(m_Writer, BAD_CAST "key", BAD_CAST "key1");
17 xmlTextWriterWriteElement(m_Writer, BAD_CAST "real", BAD_CAST "key1");
18  
19 //寫入Base64數據
20 xmlTextWriterStartElement(m_Writer, BAD_CAST "Texture");
21 xmlTextWriterWriteBase64(m_Writer, "abcdefghij", 0, 12);
22 xmlTextWriterEndElement(m_Writer);
23  
24 //結束並保存
25 xmlTextWriterEndDocument(m_Writer);

 

 
查看保存后的plist文件,發現內容是正確的,但既無縮進,又無回車,所有的代碼都被寫在一行,難看之極,谷歌之,需要在打開文檔之前加入xmlKeepBlanksDefault(0);加了進去也毫無效果,那便算了,反正plist文件一般也是只用不看,有時間看一下libxml的源碼再研究下吧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM