• 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

  • 相关阅读:
    时间转换成时间戳
    元字符为名称的时候,使用两个反斜杠转义:\
    批量修改文件夹及文件用户权限和用户组权限 centos
    HDU6797 多校第三场 Tokitsukaze and Rescue
    AtCoder Regular Contest 103 E
    2020牛客第六场 B题 Binary Vector
    Codeforces Round #659 (Div. 2) B1. Koa and the Beach (Easy Version)
    Codeforces Round #659 (Div. 2) C. String Transformation 1
    Codeforces Round #659 (Div. 2) D GameGame
    P3194 [HNOI2008]水平可见直线 计算几何栈维护下凸壳
  • 原文地址:https://www.cnblogs.com/zouzf/p/4450861.html
Copyright © 2020-2023  润新知