cocos2dx 2.x 骨骼動畫優化


 

本文原鏈接:http://www.cnblogs.com/zouzf/p/4450861.html

 

公司用的骨骼動畫的版本貌似還停留在2.1之前的年代而已沒有更新,該因各種歷史原因吧,而有個大項目“一直”處於馬上發布准備大推的階段,沒人敢動。恩,公司的骨骼動畫貌似是用Flash做然后通過插件導出成 plist、png、xml格式的,現在,大項目負責人說骨骼動畫卡,要優化,恩,交給我來做~~~

 

前期分析

通過耗時比較,90%的時間消耗在了 CCDataReaderHelper::addDataFromCache 這個方法里,其中90%的時間又花在 CCDataReaderHelper::decodeAnimation 這里。一看xml文件:3M多,25600多行,其中 animation部分有25000行。。。通過層層篩選分析,得出結論:xml文件過大導致xml樹節點過多,最終導致遍歷xml樹構建 CCArmatureData、CCAnimationData、CCMovmentBoneData、CCFrameData等數據時消耗過大,其中遍歷xml樹時的查詢也是比較耗時的一個環節。

 

方案選擇

在涉及到文件的優化方式里,序列化一直是考慮首選。查看了 CCBoneData、CCFrameData的類之后,發現它們的數據成員除了 name 是string之外 其他的都是 int、float、bool,挺好的,比xml優化那時的滿地字符串好多了,成員name可以用char[],大小固定64差不多了,就這樣愉快地決定了用序列化來優化。

 

大概思路

CCArmatureData、CCAnimationData等幾個類的關系是:CCArmatureData->CCBoneData->CCDisplayData; CCAnimationData->CCMovmentData->CCMovmentBoneData->CCFrameData; CCTextureData->CCContourData->CCContourVertex2,組合關系用了CCDictionary和CCArray。定義一系列struct和上面那十個類一一對應,如 arm_struct、ani_struct等,把類的數據都存到struct里,然后把struct直接寫到文本;加載的時候就讀文本,把數據寫到struct里,然后根據struct構建出CCArmatureData等數據。

 

細節實現

CCArmatureData等類和struct之間轉換時怎么實現呢?深度優先和廣度優先二選一,由於CCArmatureData等類之間的關系是包含關系,就是一棵樹,深度優先會更好一點。

骨骼數據轉struct:(本來寫了很多的,但又刪了,還是代碼說得清楚點)

 1 struct CC_DLL skeleton_struct
 2 {
 3     char name[64];
 4     float   version;  //version
 5     int     childCount_arm;
 6     int     childCount_arm_b;
 7     int     childCount_arm_d;
 8     int     childCount_ani;
 9     int     childCount_ani_m;
10     int     childCount_ani_b;
11     int     childCount_ani_f;
12     int     childCount_tex;
13     int     childCount_tex_con;
14     int     childCount_tex_vt;
15     
16     //float frameRate;  //no work yet?
17 };
18 
19 
20 //  CCArmatureData
21 struct CC_DLL Armature_struct
22 {
23     //有多個struct_Armature_b
24     char    name[64];
25     int     child_count;
26     int     child_index;
27 };
28 
29 
30 //  CCBoneData
31 struct CC_DLL Armature_b_struct
32 {
33     //有多個struct_Armature_b_d
34     
35   //  BaseData_struct baseData;//只用到了 只Order 屬性
36     char    name[64];
37     char    parentName[64];
38     int     child_count;
39     int     child_index;
40     int     zOrder;
41 };
42 
43 
44 //  CCDisplayData
45 struct CC_DLL Armature_b_d_struct
46 {
47     char    name[64];
48     int     displayType; //displayType base on this gay
49 //    int     child_count;
50 //    int     child_index;
51     
52     //float pX;     //no useed in cocos2dx
53     //float pY;     //no useed in cocos2dx
54 };
View Code

 

  1 /**
  2 *  深度遍歷 CCArmatureData
  3 *
  4 *  @return 返回 true 表示轉換成功
  5 */
  6 bool CCDataReaderHelper::ArmatureDataToStructData()
  7 {
  8     int child_index_arm = 0;
  9     int child_index_arm_b = 0;
 10     bool result = true;
 11 
 12     CCDictionary* arm_datas = CCArmatureDataManager::sharedArmatureDataManager()->getArmarureDatas();
 13     CCDictElement* pArmElement;
 14     CCDICT_FOREACH(arm_datas, pArmElement)
 15     {
 16         CCArmatureData* arm = (CCArmatureData*)pArmElement->getObject();
 17 
 18         /* save data from CCArmatureData object to Armature_struct */
 19         Armature_struct armStruct;
 20 
 21         /* set child info */
 22         armStruct.child_count = arm->boneDataDic.count();
 23         armStruct.child_index = child_index_arm;
 24         child_index_arm += armStruct.child_count;
 25 
 26         /* length of name is beyond 63 */
 27         if (isNameIllegal(arm->name))
 28         {
 29             result = false;
 30             strncpy(armStruct.name, arm->name.c_str(), 63);
 31         }
 32         else
 33         {
 34             strncpy(armStruct.name, arm->name.c_str(), arm->name.length() + 1);
 35         }
 36 
 37         wydArmLst.push_back(armStruct);
 38 
 39 
 40         /*  ergodic CCBoneData in one CCArmatureData */
 41         CCDictElement* pArmBElement;
 42         CCDictionary* arm_b_dic = &(arm->boneDataDic);
 43         CCDICT_FOREACH(arm_b_dic, pArmBElement)
 44         {
 45             CCBoneData* bone = (CCBoneData*)pArmBElement->getObject();
 46 
 47             /* save data from CCBoneData object to Armature_b_struct */
 48             Armature_b_struct boneStruct;
 49 
 50             boneStruct.zOrder = bone->zOrder;
 51             //    strcpy(boneStruct.name, bone->name.c_str());
 52             //            boneStruct.skewX = bone->skewX;
 53             //            boneStruct.skewY = bone->skewY;
 54             //            boneStruct.tweenRotate = bone->tweenRotate;
 55 
 56             boneStruct.child_count = bone->displayDataList.count();
 57             boneStruct.child_index = child_index_arm_b;
 58             child_index_arm_b += boneStruct.child_count;
 59 
 60             if (isNameIllegal(bone->name))
 61             {
 62                 result = false;
 63                 strncpy(boneStruct.name, bone->name.c_str(), 63);
 64             }
 65             else
 66             {
 67                 strncpy(boneStruct.name, bone->name.c_str(), bone->name.length() + 1);
 68             }
 69 
 70             if (isNameIllegal(bone->parentName))
 71             {
 72                 result = false;
 73                 strncpy(boneStruct.parentName, bone->parentName.c_str(), 63);
 74             }
 75             else
 76             {
 77                 strncpy(boneStruct.parentName, bone->parentName.c_str(), bone->parentName.length() + 1);
 78             }
 79 
 80             wydArm_bLst.push_back(boneStruct);
 81 
 82 
 83             /*  ergodic CCDisplayData in one CCBoneData */
 84             CCArray* displayArr = &(bone->displayDataList);
 85             CCObject* objD;
 86             CCARRAY_FOREACH(displayArr, objD)
 87             {
 88                 CCDisplayData* display = (CCDisplayData*) objD;
 89 
 90                 /* save data from CCDisplayData object to Armature_b_d_struct */
 91                 Armature_b_d_struct displayStruct;
 92                 displayStruct.displayType = display->displayType;//zou
 93                 std::string displayName;
 94 
 95                 if (display->displayType == CS_DISPLAY_SPRITE)
 96                 {
 97                     displayName = ((CCSpriteDisplayData *)display)->displayName;
 98                 }
 99                 else
100                 {
101                     displayName = ((CCArmatureDisplayData *)display)->displayName;
102                 }
103 
104                 if (isNameIllegal(displayName))
105                 {
106                     result = false;
107                     strncpy(displayStruct.name, displayName.c_str(), 63);
108                 }
109                 else
110                 {
111                     strncpy(displayStruct.name, displayName.c_str(), displayName.length() + 1);
112                 }
113 
114 
115                 wydArm_dLst.push_back(displayStruct);// for write to file
116 
117             }
118         }
119 
120     }
121 
122     wydSkeleton.childCount_arm = arm_datas->count();
123     wydSkeleton.childCount_arm_b = child_index_arm;
124     wydSkeleton.childCount_arm_d = child_index_arm_b;
125 
126     return result;
127 }
View Code

里面的struct用到 child_index和child_count,這個東西用於 struct轉armature時控制armature孩子的位置和數量的。上面代碼的大概意思就是:遍歷CCArmatureData、CCBoneData、CCDisplayData類,一一創建結構體 arm_struct、arm_b_struct、arm_b_d_struct,每次循環都對應創建一個struct然后加到對應的list列表里。

struct轉骨骼數據:

 1 void CCDataReaderHelper::decodeArmatureStructData()
 2 {
 3     for (int i = 0; i < wydSkeleton.childCount_arm; i++)
 4     {
 5 
 6         CCArmatureData* arm = CCArmatureData::create();
 7         Armature_struct armStruct = wydArms[i];
 8         arm->name = armStruct.name;
 9 
10         for (int j = 0; j < armStruct.child_count; j++)
11         {
12             CCBoneData* bone = CCBoneData::create();
13             Armature_b_struct boneStruct = wydArms_b[j + armStruct.child_index];
14             bone->name = boneStruct.name;
15             bone->parentName = boneStruct.parentName;
16             bone->zOrder = boneStruct.zOrder;
17 
18             for (int k = 0; k < boneStruct.child_count; k++)
19             {
20                 CCDisplayData* display;// = CCDisplayData::create();
21                 Armature_b_d_struct displayStruct = wydArms_d[k + boneStruct.child_index];
22 
23                 if ((DisplayType)displayStruct.displayType == CS_DISPLAY_SPRITE)
24                 {
25                     display = CCSpriteDisplayData::create();
26                     display->displayType  = CS_DISPLAY_SPRITE;
27                     ((CCSpriteDisplayData *)display)->displayName = displayStruct.name;
28                 }
29                 else
30                 {
31                     display = CCArmatureDisplayData::create();
32                     display->displayType  = CS_DISPLAY_ARMATURE;
33                     ((CCArmatureDisplayData *)display)->displayName = displayStruct.name;
34                 }
35 
36                 bone->addDisplayData(display);
37             }
38 
39             arm->addBoneData(bone);
40         }
41 
42         s_armatureDataInfo.data1.push_back(arm->name);
43         CCArmatureDataManager::sharedArmatureDataManager()->addArmatureData(arm->name.c_str(), arm);
44     }
45 }
View Code

 

每個類型的struct都對應創建一個數組和一個list列表。

骨骼數組轉struct時:遍歷CCArmatureData、CCBoneData、CCDisplayData時,每次遍歷都對應創建一個對應的struct加到list列表里,重點在於獲取到struct對象的child_index和child_count。

struct轉骨骼動畫時:遍歷arm_struct、arm_b_struct、arm_b_d_struct對應的數組,每次遍歷都對應創建一個CCArmatureData、CCBoneData、CCDisplayData,重點在於根據struct對象的child_index和child_count來控制循環的次數、子節點在struct數組里的起始位置


 

優化效果

那個3M多、25600多行的xml文件,轉成struct保存好,如果struct里沒有 strMovement、strEvent 、strSound、strSoundEffect 這四個字段的話,大小是原來的一半,如果有這四個字節,大小是原來的兩倍,其實,cocos2dx里對這四個字段的備注是: m_strMovement, m_strEvent, m_strSound, m_strSoundEffect do not support yet(2.1)。解析耗時這塊,耗時大概減少80%~90%,甚是可觀。

 

本文原鏈接:http://www.cnblogs.com/zouzf/p/4450861.html

 


免責聲明!

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



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