本文原链接: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[];
  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. // CCArmatureData
  20. struct CC_DLL Armature_struct
  21. {
  22. //有多个struct_Armature_b
  23. char name[];
  24. int child_count;
  25. int child_index;
  26. };
  27.  
  28. // CCBoneData
  29. struct CC_DLL Armature_b_struct
  30. {
  31. //有多个struct_Armature_b_d
  32.  
  33. // BaseData_struct baseData;//只用到了 只Order 属性
  34. char name[];
  35. char parentName[];
  36. int child_count;
  37. int child_index;
  38. int zOrder;
  39. };
  40.  
  41. // CCDisplayData
  42. struct CC_DLL Armature_b_d_struct
  43. {
  44. char name[];
  45. int displayType; //displayType base on this gay
  46. // int child_count;
  47. // int child_index;
  48.  
  49. //float pX; //no useed in cocos2dx
  50. //float pY; //no useed in cocos2dx
  51. };
  1. /**
  2. * 深度遍历 CCArmatureData
  3. *
  4. * @return 返回 true 表示转换成功
  5. */
  6. bool CCDataReaderHelper::ArmatureDataToStructData()
  7. {
  8. int child_index_arm = ;
  9. int child_index_arm_b = ;
  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(), );
  31. }
  32. else
  33. {
  34. strncpy(armStruct.name, arm->name.c_str(), arm->name.length() + );
  35. }
  36.  
  37. wydArmLst.push_back(armStruct);
  38.  
  39. /* ergodic CCBoneData in one CCArmatureData */
  40. CCDictElement* pArmBElement;
  41. CCDictionary* arm_b_dic = &(arm->boneDataDic);
  42. CCDICT_FOREACH(arm_b_dic, pArmBElement)
  43. {
  44. CCBoneData* bone = (CCBoneData*)pArmBElement->getObject();
  45.  
  46. /* save data from CCBoneData object to Armature_b_struct */
  47. Armature_b_struct boneStruct;
  48.  
  49. boneStruct.zOrder = bone->zOrder;
  50. // strcpy(boneStruct.name, bone->name.c_str());
  51. // boneStruct.skewX = bone->skewX;
  52. // boneStruct.skewY = bone->skewY;
  53. // boneStruct.tweenRotate = bone->tweenRotate;
  54.  
  55. boneStruct.child_count = bone->displayDataList.count();
  56. boneStruct.child_index = child_index_arm_b;
  57. child_index_arm_b += boneStruct.child_count;
  58.  
  59. if (isNameIllegal(bone->name))
  60. {
  61. result = false;
  62. strncpy(boneStruct.name, bone->name.c_str(), );
  63. }
  64. else
  65. {
  66. strncpy(boneStruct.name, bone->name.c_str(), bone->name.length() + );
  67. }
  68.  
  69. if (isNameIllegal(bone->parentName))
  70. {
  71. result = false;
  72. strncpy(boneStruct.parentName, bone->parentName.c_str(), );
  73. }
  74. else
  75. {
  76. strncpy(boneStruct.parentName, bone->parentName.c_str(), bone->parentName.length() + );
  77. }
  78.  
  79. wydArm_bLst.push_back(boneStruct);
  80.  
  81. /* ergodic CCDisplayData in one CCBoneData */
  82. CCArray* displayArr = &(bone->displayDataList);
  83. CCObject* objD;
  84. CCARRAY_FOREACH(displayArr, objD)
  85. {
  86. CCDisplayData* display = (CCDisplayData*) objD;
  87.  
  88. /* save data from CCDisplayData object to Armature_b_d_struct */
  89. Armature_b_d_struct displayStruct;
  90. displayStruct.displayType = display->displayType;//zou
  91. std::string displayName;
  92.  
  93. if (display->displayType == CS_DISPLAY_SPRITE)
  94. {
  95. displayName = ((CCSpriteDisplayData *)display)->displayName;
  96. }
  97. else
  98. {
  99. displayName = ((CCArmatureDisplayData *)display)->displayName;
  100. }
  101.  
  102. if (isNameIllegal(displayName))
  103. {
  104. result = false;
  105. strncpy(displayStruct.name, displayName.c_str(), );
  106. }
  107. else
  108. {
  109. strncpy(displayStruct.name, displayName.c_str(), displayName.length() + );
  110. }
  111.  
  112. wydArm_dLst.push_back(displayStruct);// for write to file
  113.  
  114. }
  115. }
  116.  
  117. }
  118.  
  119. wydSkeleton.childCount_arm = arm_datas->count();
  120. wydSkeleton.childCount_arm_b = child_index_arm;
  121. wydSkeleton.childCount_arm_d = child_index_arm_b;
  122.  
  123. return result;
  124. }

里面的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 = ; 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 = ; 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 = ; 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. }

每个类型的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 2.x 骨骼动画优化的更多相关文章

  1. cocos2dx加载骨骼动画,获取骨骼位置

    2015/05/13 需求: (1)希望在骨骼上绑定一个粒子特效 (2)获取骨骼的位置 (3)获取骨骼动画的大小 (4)lua 1. cocostudio动画编辑器 (1)绑定粒子特效(跟随骨骼的移动 ...

  2. Away3d 骨骼动画优化

    很多朋友说Away3D 的骨骼数限制在32根,确切的说应该是Stage3D 的限制.在 AGAL2.0之前 VC寄存器是128个,每个vc常量寄存器最大只能容纳4位,transform占用一个4*4的 ...

  3. cocos2dx骨骼动画Armature源码分析(三)

    代码目录结构 cocos2dx里骨骼动画代码在cocos -> editor-support -> cocostudio文件夹中,win下通过筛选器,文件结构如下.(mac下没有分,是整个 ...

  4. cocos2dx骨骼动画Armature源码分析(一)

    源码分析一body { font-family: Helvetica, arial, sans-serif; font-size: 14px; line-height: 1.6; padding-to ...

  5. cocos2dx骨骼动画Armature源码分析(二)

    flash中数据与xml中数据关系 上篇博文从总体上介绍了cocos2dx自带的骨骼动画,这篇介绍一下导出的配置数据各个字段的含义(也解释了DragonBone导出的xml数据每个字段的含义). sk ...

  6. cocos2d-x 3.0 版本 骨骼动画设置shader

    因为骨骼动画是由多个sprite组成, 所以需要遍历每个sprite 才能修改整体, 开头这样设置,在游戏中发现走路状态没问题,攻击状态就有部分sprite没效果 for (auto & ob ...

  7. Android设备 cocos2dx 骨骼动画注册事件播放音效,退到后台再返回黑屏问题

    最近遇到一个cocos2dx 骨骼动画注册事件播放音效,在骨骼动画播放的时候,按HOME键退到桌面,再次打开游戏的时候,会黑屏. 解决办法如下,可能不是太完美,至少解决了大部分问题. 1.在org.c ...

  8. cocos2dx - v2.3.3编辑器骨骼动画

    接上一节内容:cocos2dx - v2.3.3编辑器简单使用及不同分辨率适配 本节主要Cocos骨骼动画的创建及使用 一.新建 用Cocos Studio工具新建一个状态栏项目.如下图: 当然也可以 ...

  9. Unity骨骼动画资源解析与优化

    一,背景 最近发现项目的动画文件有点大,不光内存大,而且文件也很大,所以从这2个方面下手处理 二,动画文件大小优化 为了优化动画文件大小,我们可以先分析下文件,Ctrl+D将动画文件从FBX拷贝出来, ...

随机推荐

  1. SQLite数据库在本地可以写,发布到服务器就不能写

    用SQLite开发的一个Web Api,提供Json和Jsonp格式的数据,在本地使用vs2012开发并运行时,数据库的读写均正常. 但发布到Windows Server 2008 + IIS 7.5 ...

  2. IQueryable和IQueryProvider初尝

    前言 相信大家对Entity Framework一定不陌生,我相信其中Linq To Sql是其最大的亮点之一,但是我们一直使用到现在却不曾明白内部是如何实现的,今天我们就简单的介绍IQueryabl ...

  3. Color颜色对照表

    Color.AliceBlue 240,248,255 Color.LightSalmon 255,160,122 Color.AntiqueWhite 250,235,215 Color.Light ...

  4. Nutz Dao实体中索引注解的使用(@TableIndexes@Index)

    Nutz是一组轻便小型的框架的集合, 各个部分可以被独立使用,把SSH的精华封装在一个1M左右的jar包中,Nutz不对其他任何第三方库产生依赖,如果不考虑数据库链接和日志的话,创建完美的Web应用只 ...

  5. 升级webapi依赖的Newtonsoft.json的版本

    随着微软日渐重视开源社区的贡献,微软在自己的产品中往往也会集成开源的第三方库. 比如System.Net.Http.Foramatting.dll 就依赖于Newtonsoft.json v4.5. ...

  6. Qt之Dialog\widget\ mainwindow的区别和布局管理器 & 分裂器的区别

    1.Dialog\widget\ mainwindow的区别 注意mainwindow和widget的区别,mainwindow都工具栏和菜单栏 Dialog and mainwinodws 都是继承 ...

  7. C#与数据库访问技术总结(十三)之DataReader对象

    DataReader对象与数据获取 DataReader对象以“基于连接”的方式来访问数据库. 也就是说,在访问数据库.执行SQL操作时,DataReader要求一直连在数据库上. 这将会给数据库的连 ...

  8. Java程序员的日常 —— 工作一天的收获

    看题目可能是扯皮,其实还是有很多专业知识的.从最开始没有注意到设计原则,到后面的jquery实战技巧,都是今天一天碰到的问题. 每天整理一点点,每天收获一点点. 关于软件设计 在设计系统结构的时候,一 ...

  9. Leetcode 165 Compare Version Numbers

    题意:比较版本号的大小 有点变态,容易犯错 本质是字符串的比较,请注意他的版本号的小数点不知1个,有的会出现01.0.01这样的变态版本号 class Solution { public: int c ...

  10. Python面试题(一)

    **晚上在公司的论坛上看到一道面试题,题目如下:随机给定一字符串和字符,要求重排,比如:'abde','c'.重排之后变成'abcde' **看到他们给的答案很多都是二分法重排,既然是字符类的处理,当 ...