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:(本来写了很多的,但又删了,还是代码说得清楚点)

cocos2dx 2.x 骨骼动画优化
 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

 

cocos2dx 2.x 骨骼动画优化
  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转骨骼数据:

cocos2dx 2.x 骨骼动画优化
 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

 

你可能感兴趣的:(cocos2dx)