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:(本来写了很多的,但又删了,还是代码说得清楚点)
struct CC_DLL skeleton_struct
{
char name[];
float version; //version
int childCount_arm;
int childCount_arm_b;
int childCount_arm_d;
int childCount_ani;
int childCount_ani_m;
int childCount_ani_b;
int childCount_ani_f;
int childCount_tex;
int childCount_tex_con;
int childCount_tex_vt; //float frameRate; //no work yet?
}; // CCArmatureData
struct CC_DLL Armature_struct
{
//有多个struct_Armature_b
char name[];
int child_count;
int child_index;
}; // CCBoneData
struct CC_DLL Armature_b_struct
{
//有多个struct_Armature_b_d // BaseData_struct baseData;//只用到了 只Order 属性
char name[];
char parentName[];
int child_count;
int child_index;
int zOrder;
}; // CCDisplayData
struct CC_DLL Armature_b_d_struct
{
char name[];
int displayType; //displayType base on this gay
// int child_count;
// int child_index; //float pX; //no useed in cocos2dx
//float pY; //no useed in cocos2dx
};
/**
* 深度遍历 CCArmatureData
*
* @return 返回 true 表示转换成功
*/
bool CCDataReaderHelper::ArmatureDataToStructData()
{
int child_index_arm = ;
int child_index_arm_b = ;
bool result = true; CCDictionary* arm_datas = CCArmatureDataManager::sharedArmatureDataManager()->getArmarureDatas();
CCDictElement* pArmElement;
CCDICT_FOREACH(arm_datas, pArmElement)
{
CCArmatureData* arm = (CCArmatureData*)pArmElement->getObject(); /* save data from CCArmatureData object to Armature_struct */
Armature_struct armStruct; /* set child info */
armStruct.child_count = arm->boneDataDic.count();
armStruct.child_index = child_index_arm;
child_index_arm += armStruct.child_count; /* length of name is beyond 63 */
if (isNameIllegal(arm->name))
{
result = false;
strncpy(armStruct.name, arm->name.c_str(), );
}
else
{
strncpy(armStruct.name, arm->name.c_str(), arm->name.length() + );
} wydArmLst.push_back(armStruct); /* ergodic CCBoneData in one CCArmatureData */
CCDictElement* pArmBElement;
CCDictionary* arm_b_dic = &(arm->boneDataDic);
CCDICT_FOREACH(arm_b_dic, pArmBElement)
{
CCBoneData* bone = (CCBoneData*)pArmBElement->getObject(); /* save data from CCBoneData object to Armature_b_struct */
Armature_b_struct boneStruct; boneStruct.zOrder = bone->zOrder;
// strcpy(boneStruct.name, bone->name.c_str());
// boneStruct.skewX = bone->skewX;
// boneStruct.skewY = bone->skewY;
// boneStruct.tweenRotate = bone->tweenRotate; boneStruct.child_count = bone->displayDataList.count();
boneStruct.child_index = child_index_arm_b;
child_index_arm_b += boneStruct.child_count; if (isNameIllegal(bone->name))
{
result = false;
strncpy(boneStruct.name, bone->name.c_str(), );
}
else
{
strncpy(boneStruct.name, bone->name.c_str(), bone->name.length() + );
} if (isNameIllegal(bone->parentName))
{
result = false;
strncpy(boneStruct.parentName, bone->parentName.c_str(), );
}
else
{
strncpy(boneStruct.parentName, bone->parentName.c_str(), bone->parentName.length() + );
} wydArm_bLst.push_back(boneStruct); /* ergodic CCDisplayData in one CCBoneData */
CCArray* displayArr = &(bone->displayDataList);
CCObject* objD;
CCARRAY_FOREACH(displayArr, objD)
{
CCDisplayData* display = (CCDisplayData*) objD; /* save data from CCDisplayData object to Armature_b_d_struct */
Armature_b_d_struct displayStruct;
displayStruct.displayType = display->displayType;//zou
std::string displayName; if (display->displayType == CS_DISPLAY_SPRITE)
{
displayName = ((CCSpriteDisplayData *)display)->displayName;
}
else
{
displayName = ((CCArmatureDisplayData *)display)->displayName;
} if (isNameIllegal(displayName))
{
result = false;
strncpy(displayStruct.name, displayName.c_str(), );
}
else
{
strncpy(displayStruct.name, displayName.c_str(), displayName.length() + );
} wydArm_dLst.push_back(displayStruct);// for write to file }
} } wydSkeleton.childCount_arm = arm_datas->count();
wydSkeleton.childCount_arm_b = child_index_arm;
wydSkeleton.childCount_arm_d = child_index_arm_b; return result;
}
里面的struct用到 child_index和child_count,这个东西用于 struct转armature时控制armature孩子的位置和数量的。上面代码的大概意思就是:遍历CCArmatureData、CCBoneData、CCDisplayData类,一一创建结构体 arm_struct、arm_b_struct、arm_b_d_struct,每次循环都对应创建一个struct然后加到对应的list列表里。
struct转骨骼数据:
void CCDataReaderHelper::decodeArmatureStructData()
{
for (int i = ; i < wydSkeleton.childCount_arm; i++)
{ CCArmatureData* arm = CCArmatureData::create();
Armature_struct armStruct = wydArms[i];
arm->name = armStruct.name; for (int j = ; j < armStruct.child_count; j++)
{
CCBoneData* bone = CCBoneData::create();
Armature_b_struct boneStruct = wydArms_b[j + armStruct.child_index];
bone->name = boneStruct.name;
bone->parentName = boneStruct.parentName;
bone->zOrder = boneStruct.zOrder; for (int k = ; k < boneStruct.child_count; k++)
{
CCDisplayData* display;// = CCDisplayData::create();
Armature_b_d_struct displayStruct = wydArms_d[k + boneStruct.child_index]; if ((DisplayType)displayStruct.displayType == CS_DISPLAY_SPRITE)
{
display = CCSpriteDisplayData::create();
display->displayType = CS_DISPLAY_SPRITE;
((CCSpriteDisplayData *)display)->displayName = displayStruct.name;
}
else
{
display = CCArmatureDisplayData::create();
display->displayType = CS_DISPLAY_ARMATURE;
((CCArmatureDisplayData *)display)->displayName = displayStruct.name;
} bone->addDisplayData(display);
} arm->addBoneData(bone);
} s_armatureDataInfo.data1.push_back(arm->name);
CCArmatureDataManager::sharedArmatureDataManager()->addArmatureData(arm->name.c_str(), arm);
}
}
每个类型的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 骨骼动画优化的更多相关文章
- cocos2dx加载骨骼动画,获取骨骼位置
2015/05/13 需求: (1)希望在骨骼上绑定一个粒子特效 (2)获取骨骼的位置 (3)获取骨骼动画的大小 (4)lua 1. cocostudio动画编辑器 (1)绑定粒子特效(跟随骨骼的移动 ...
- Away3d 骨骼动画优化
很多朋友说Away3D 的骨骼数限制在32根,确切的说应该是Stage3D 的限制.在 AGAL2.0之前 VC寄存器是128个,每个vc常量寄存器最大只能容纳4位,transform占用一个4*4的 ...
- cocos2dx骨骼动画Armature源码分析(三)
代码目录结构 cocos2dx里骨骼动画代码在cocos -> editor-support -> cocostudio文件夹中,win下通过筛选器,文件结构如下.(mac下没有分,是整个 ...
- cocos2dx骨骼动画Armature源码分析(一)
源码分析一body { font-family: Helvetica, arial, sans-serif; font-size: 14px; line-height: 1.6; padding-to ...
- cocos2dx骨骼动画Armature源码分析(二)
flash中数据与xml中数据关系 上篇博文从总体上介绍了cocos2dx自带的骨骼动画,这篇介绍一下导出的配置数据各个字段的含义(也解释了DragonBone导出的xml数据每个字段的含义). sk ...
- cocos2d-x 3.0 版本 骨骼动画设置shader
因为骨骼动画是由多个sprite组成, 所以需要遍历每个sprite 才能修改整体, 开头这样设置,在游戏中发现走路状态没问题,攻击状态就有部分sprite没效果 for (auto & ob ...
- Android设备 cocos2dx 骨骼动画注册事件播放音效,退到后台再返回黑屏问题
最近遇到一个cocos2dx 骨骼动画注册事件播放音效,在骨骼动画播放的时候,按HOME键退到桌面,再次打开游戏的时候,会黑屏. 解决办法如下,可能不是太完美,至少解决了大部分问题. 1.在org.c ...
- cocos2dx - v2.3.3编辑器骨骼动画
接上一节内容:cocos2dx - v2.3.3编辑器简单使用及不同分辨率适配 本节主要Cocos骨骼动画的创建及使用 一.新建 用Cocos Studio工具新建一个状态栏项目.如下图: 当然也可以 ...
- Unity骨骼动画资源解析与优化
一,背景 最近发现项目的动画文件有点大,不光内存大,而且文件也很大,所以从这2个方面下手处理 二,动画文件大小优化 为了优化动画文件大小,我们可以先分析下文件,Ctrl+D将动画文件从FBX拷贝出来, ...
随机推荐
- 使用jsPlumb制作流程图设计器
jsPlumb是一个比较强大的绘图组件,它提供了一种方法,主要用于连接网页上的元素.在现代浏览器中,它使用SVG或者Canvas技术,而对于IE8以下(含IE8)的古董浏览器,则使用VML技术. 项目 ...
- 使用NHibernate(8)-- 延迟加载
1,延迟加载. 延迟加载,即用到的时候再加载数据.这种机制是非常有情怀的,比如一篇中的用户实体有标签.问题等导航属性,如果只是用到用户名去查询整个实体,则把相关的标签和问题也都加载,性能会比较低.而有 ...
- Linux上成功编译CoreCLR源代码
>>Build日期:2015-2-5下午(编译失败). 开始Linux发行版用的是CentOS 6.5,操作步骤: 1)配置git: git config --global http.ss ...
- Python的with语句
写过多线程程序的人肯定对各种锁很熟悉,尤其是下面这种代码 def lock_usage: lock.Lock() if(...) : lock.Unlock() return lock.Unlock( ...
- grunt使用小记之开篇:grunt概述
Grunt是什么? Grunt是一个自动化的项目构建工具.如果你需要重复的执行像压缩,编译,单元测试,代码检查以及打包发布的任务.那么你可以使用Grunt来处理这些任务,你所需要做的只是配置好Grun ...
- java 32位MD5加密的大写字符串
package com.aok.test; import java.security.MessageDigest; public class MD5Test { public static void ...
- JavaScript 中的 this ,看着一篇就够了
tip 在 js 中,this 这个上下文总是变化莫测,很多时候出现 bug 总是一头雾水,其实,只要分清楚不同的情况下如何执行就 ok 了. 全局执行 首先,我们在全局环境中看看它的 this 是什 ...
- [jQuery学习系列一]1-选择器与DOM对象
前言: 好久没有更新博客了, 最近想复习下 之前学过的JS的相关内容, 也算是自己的一种总结. 知识长时间不用就会忘记, 多学多记多用!! 下面的程序都可以在下面的网站进行在线调试: http://w ...
- 如何处理Win7连接vpn时报错789的问题
[转]VPN错误提示: vpn连接出错789:L2TP连接尝试失败,因为安全层在初始化与远程计算机的协商时遇 (2014-08-11 15:09:10)转载▼标签: it xp连接VPN错误提示: v ...
- 【简单易懂的AMV图文教程-2】VEGAS基础进阶——认识关键帧
[简单易懂的AMV图文教程-2]VEGAS基础进阶--认识关键帧 经过了上一期VEGAS基础教程的学习,相信大家都能独立完成一些比较简单的纯剪辑作品了.今天在这里为大家继续介绍VEGAS的一大基础应用 ...