armature(目录): animation(目录):动画控制相关。CCProcessBase(文件): ProcessBase(类):CCTween和ArmatureAnimation的基类。CCTWeen(文件): Tween(类):控制flash里一个layer的动画。CCArmatureAnimation(文件): ArmatureAnimation(类):控制整个动画,内有多个Tween。 datas(目录):xml或json转成c++中直接用的数据结构。CCDatas(文件): BaseData(类):BoneData、FrameData的基类,包含大小位置颜色等信息。 DisplayData(类): SpriteDisplayData、ArmatureDisplayData、ParticleDisplayData的基类。 SpriteDisplayData(类):骨骼中的显示数据。 ArmatureDisplayData(类): ParticleDisplayData(类): BoneData(类):单个骨骼数据,flash中一个layer是一个骨骼。 ArmatureData(类):骨骼数据,整个骨骼结构数据。 FrameData(类):关键帧数据。 MovementBoneData(类):带有关键帧的骨骼数据。 MovementData(类):一个完整动画数据。 AnimationData(类):组动画数据,包含多个MovementData。 ContourData(类): TextureData(类):显示图片数据。 utils(目录):CCArmatureDataManager(文件): RelativeData(类): ArmatureDataManager(类):管理ArmatureData、AnimationData、TextureData。CCArmatureDefine(文件):CCDataReaderHelper(文件): _AsyncStruct(类): _DataInfo(类): DataReaderHelper(类):这正解析xml或json的类。CCSpriteFrameCacheHelper(文件): SpriteFrameCacheHelper(类):CCTransformHelp(文件): TransformHelp(类):矩阵运算。CCUtilMath(文件): CCArmature(文件):Armature(类):控制整个骨骼动画,内有ArmatureAnimation和ArmatureData。 CCBone(文件):Bone(类):骨骼控制类 display(目录):显示的图片管理。CCBatchNode(文件): BatchNode(类):CCDecorativeDisplay(文件): DecorativeDisplay(类):CCDisplayFactory(文件): DisplayFactory(类):CCDisplayManager(文件): DisplayManager(类):CCSkin(文件): Skin(类): physics(目录):物理引擎相关,不分析。ColliderFilter(文件): ColliderFilter(类): ColliderBody(类): ColliderDetecotor(类)数据相关源码

BaseData
BaseData:用来表示骨骼或帧的位置、旋转、颜色、缩放。
BaseData.h class BaseData : public cocosd::Ref { public://Calculate two BaseData"s between value(to - from) and set to selfvirtual void subtract(BaseData *from, BaseData *to, bool limit); public://位置,xml的x,yfloat x; float y;//xml中z int zOrder; //旋转,xml的kX,kYfloat skewX; float skewY; //缩放,xml的cX,cYfloat scaleX; float scaleY; //啥??float tweenRotate;//颜色的变化属性 bool isUseColorInfo; int a, r, g, b; };作为FrameData和BoneData的基类,提供骨骼的状态信息。从下文可知BoneData对应xml中的<armature<b>>中的b节点,FrameData对应xml中的<f>节点,BoneData和FrameData都有class BoneData : public BaseData { public:void addDisplayData(DisplayData *displayData);DisplayData *getDisplayData(int index); public:std::string name; //! the bone"s namestd::string parentName;//! the bone parent"s name//! save DisplayData informations for the Bonecocosd::Vector<DisplayData*> displayDataList; //仿射变换,程序里好像没用这个属性 cocosd::AffineTransform boneDataTransform; };BoneData里有displayDataList,用来放这个骨头上的皮肤(就是DisplayData), DisplayData对应xml节点中的<b<d>>节点,一个BoneData里可以有多个皮肤,换装等功能需要多个皮肤。 class FrameData : public BaseData { public:int frameID;//xml中dr,这一帧长度int duration;//不知要他干啥bool isTween; //xml中dI,显示哪个图int displayIndex; };DisplayDataclass ArmatureData : public cocosd::Ref { public://添加骨骼信息void addBoneData(BoneData *boneData);BoneData *getBoneData(const std::string& boneName); public:std::string name;//多个骨头信息cocosd::Map<std::string, BoneData*> boneDataDic;float dataVersion; };AnimationDataclass AnimationData : public cocosd::Ref { public:void addMovement(MovementData *movData);MovementData *getMovement(const std::string& movementName);ssize_t getMovementCount(); public://<animation name="Dragon">中的namestd::string name;//所有带帧标签的动画mapcocosd::Map<std::string, MovementData*> movementDataDic;//所有带帧标签的动画名std::vector<std::string> movementNames; };MovementData class MovementData : public cocosd::Ref { public:void addMovementBoneData(MovementBoneData *movBoneData);MovementBoneData *getMovementBoneData(const std::string& boneName); public:std::string name;//xml 中 drint duration;//这怎么有个scale?? float scale; //xml中toint durationTo;//xml中drTWint durationTween;//xml中lpbool loop;//带帧信息的骨骼cocosd::Map<std::string, MovementBoneData*> movBoneDataDic; };MovementBoneDataclass MovementBoneData : public cocosd::Ref {void addFrameData(FrameData *frameData);FrameData *getFrameData(int index); public://xml中的dlfloat delay;//xml中的scfloat scale;//这个和MovementData中的duration是不是一个??float duration;std::string name; //关键帧信息cocosd::Vector<FrameData*> frameList; };小总结 
再来看产生动画相关的代码

ArmatureDataManager
ArmatureDataManager利用DataReaderHelper解析出armarureDatas、animationDatas和_textureDatas。
ArmatureDataManager是个单例,用到动画时会到ArmatureDataManager取得要生成动画的数据。
class ArmatureDataManager : public cocosd::Ref { public://单例 static ArmatureDataManager *getInstance();static void destroyInstance(); public:void addArmatureData(const std::string& id, ArmatureData *armatureData, const std::string& configFilePath = "");ArmatureData *getArmatureData(const std::string& id);void removeArmatureData(const std::string& id);void addAnimationData(const std::string& id, AnimationData *animationData, const std::string& configFilePath = "");AnimationData *getAnimationData(const std::string& id);void removeAnimationData(const std::string& id);void addTextureData(const std::string& id, TextureData *textureData, const std::string& configFilePath = "");TextureData *getTextureData(const std::string& id);void removeTextureData(const std::string& id);void addArmatureFileInfo(const std::string& configFilePath);const cocosd::Map<std::string, ArmatureData*>&getArmatureDatas() const;const cocosd::Map<std::string, AnimationData*>& getAnimationDatas() const;const cocosd::Map<std::string, TextureData*>&getTextureDatas() const; protected:void addRelativeData(const std::string& configFilePath);RelativeData *getRelativeData(const std::string& configFilePath); private:cocosd::Map<std::string, ArmatureData*> _armarureDatas;cocosd::Map<std::string, AnimationData*> _animationDatas;cocosd::Map<std::string, TextureData*> _textureDatas;std::unordered_map<std::string, RelativeData> _relativeDatas; };主要就是armarureDatas、animationDatas、_textureDatas三个map,那这三个map是怎么产生的呢?当执行ArmatureDataManager::getInstance()->addArmatureFileInfo(“dragon.xml”);
void ArmatureDataManager::addArmatureFileInfo(const std::string& configFilePath) {addRelativeData(configFilePath);_autoLoadSpriteFile = true;DataReaderHelper::getInstance()->addDataFromFile(configFilePath); }又调用了DataReaderHelper::getInstance()->addDataFromFile(),可知是DataReaderHelper真正完成了数据的解析。void DataReaderHelper::addDataFromFile(const std::string& filePath) {//省略一些代码DataInfo dataInfo;dataInfo.filename = filePathStr;dataInfo.asyncStruct = nullptr;dataInfo.baseFilePath = basefilePath;if (str == ".xml"){ DataReaderHelper::addDataFromCache(contentStr, &dataInfo);}else if(str == ".json" || str == ".ExportJson"){ DataReaderHelper::addDataFromJsonCache(contentStr, &dataInfo);}else if(isbinaryfilesrc){ DataReaderHelper::addDataFromBinaryCache(contentStr.c_str(),&dataInfo);} CC_SAFE_DELETE_ARRAY(pBytes); }对应不同的文件(xml、json、二进制)解析方式,xml用到是addDataFromCache void DataReaderHelper::addDataFromCache(const std::string& pFileContent, DataInfo *dataInfo) {tinyxml::XMLDocument document;document.Parse(pFileContent.c_str()); tinyxml::XMLElement *root = document.RootElement();CCASSERT(root, "XML error or XML is empty."); root->QueryFloatAttribute(VERSION, &dataInfo->flashToolVersion);/** Begin decode armature data from xml*/tinyxml::XMLElement *armaturesXML = root->FirstChildElement(ARMATURES);tinyxml::XMLElement *armatureXML = armaturesXML->FirstChildElement(ARMATURE);while(armatureXML){ ArmatureData *armatureData = DataReaderHelper::decodeArmature(armatureXML, dataInfo);if (dataInfo->asyncStruct) {_dataReaderHelper->_addDataMutex.lock(); } ArmatureDataManager::getInstance()->addArmatureData(armatureData->name.c_str(), armatureData, dataInfo->filename.c_str()); armatureData->release(); if (dataInfo->asyncStruct) {_dataReaderHelper->_addDataMutex.unlock(); }armatureXML = armatureXML->NextSiblingElement(ARMATURE);}/** Begin decode animation data from xml*/tinyxml::XMLElement *animationsXML = root->FirstChildElement(ANIMATIONS);tinyxml::XMLElement *animationXML = animationsXML->FirstChildElement(ANIMATION);while(animationXML){ AnimationData *animationData = DataReaderHelper::decodeAnimation(animationXML, dataInfo); if (dataInfo->asyncStruct) {_dataReaderHelper->_addDataMutex.lock(); } ArmatureDataManager::getInstance()->addAnimationData(animationData->name.c_str(), animationData, dataInfo->filename.c_str()); animationData->release(); if (dataInfo->asyncStruct) {_dataReaderHelper->_addDataMutex.unlock(); } animationXML = animationXML->NextSiblingElement(ANIMATION);}/** Begin decode texture data from xml*/tinyxml::XMLElement *texturesXML = root->FirstChildElement(TEXTURE_ATLAS);tinyxml::XMLElement *textureXML = texturesXML->FirstChildElement(SUB_TEXTURE);while(textureXML){ TextureData *textureData = DataReaderHelper::decodeTexture(textureXML, dataInfo);if (dataInfo->asyncStruct) {_dataReaderHelper->_addDataMutex.lock(); } ArmatureDataManager::getInstance()->addTextureData(textureData->name.c_str(), textureData, dataInfo->filename.c_str()); textureData->release(); if (dataInfo->asyncStruct) {_dataReaderHelper->_addDataMutex.unlock(); } textureXML = textureXML->NextSiblingElement(SUB_TEXTURE);} }里面有三个while,分别decodeArmature、decodeAnimation、decodeTexture,生成ArmatureData、AnimationData、TextureData之后又ArmatureDataManager::getInstance()->addArmatureData、addAnimationData、addTextureData,加到ArmatureDataManager对应map里。decodeXXX里又会调用各种decodeXX来生成相应的XXXData。armature = Armature::create("Dragon");armature->getAnimation()->play("walk");armature->getAnimation()->setSpeedScale();armature->setPosition(VisibleRect::center().x, VisibleRect::center().y * .f);armature->setScale(.f);addChild(armature);便展示了动画,那么这是如何做到的呢?
class Armature: public cocosd::Node, public cocosd::BlendProtocol { protected://要展示动画的ArmatureDataArmatureData *_armatureData;BatchNode *_batchNode;Bone *_parentBone;float _version;mutable bool _armatureTransformDirty;//所有Bonecocosd::Map<std::string, Bone*> _boneDic; cocosd::Vector<Bone*> _topBoneList; cocosd::BlendFunc _blendFunc; cocosd::Vec _offsetPoint;cocosd::Vec _realAnchorPointInPoints;//动画控制器ArmatureAnimation *_animation; };Boneclass Bone: public cocosd::Node { protected:BoneData *_boneData; //! A weak reference to the ArmatureArmature *_armature; //! A weak reference to the child ArmatureArmature *_childArmature; DisplayManager *_displayManager; /** When Armature play an animation, if there is not a MovementBoneData of this bone in this MovementData, this bone will be hidden.* Set IgnoreMovementBoneData to true, then this bone will also be shown.*/bool _ignoreMovementBoneData; cocosd::BlendFunc _blendFunc;bool _blendDirty; Tween *_tween;//! Calculate tween effect //! Used for making tween effect in every frameFrameData *_tweenData; Bone *_parentBone; //! A weak reference to its parentbool _boneTransformDirty; //! Whether or not transform dirty //! self Transform, use this to change display"s statecocosd::Mat _worldTransform; BaseData *_worldInfo;//! Armature"s parent boneBone *_armatureParentBone;};Tweenclass Tween : public ProcessBase{ protected://! A weak reference to the current MovementBoneData. The data is in the data poolMovementBoneData *_movementBoneData; FrameData *_tweenData; //! The computational tween frame data, //! A weak reference to the Bone"s tweenDataFrameData *_from;//! From frame data, used for calculate between valueFrameData *_to; //! To frame data, used for calculate between value// total diff guanFrameData *_between; //! Between frame data, used for calculate current FrameData(m_pNode) value Bone *_bone; //! A weak reference to the Bone TweenType _frameTweenEasing; //! Dedermine which tween effect current frame use int _betweenDuration; //! Current key frame will last _betweenDuration frames// 总共运行了多少帧 guanint _totalDuration; int _fromIndex; //! The current frame index in FrameList of MovementBoneData, it"s different from m_iFrameIndexint _toIndex; //! The next frame index in FrameList of MovementBoneData, it"s different from m_iFrameIndex ArmatureAnimation *_animation; bool _passLastFrame; //! If current frame index is more than the last frame"s index };ArmatureAnimationclass ArmatureAnimation : public ProcessBase {protected: //! AnimationData save all MovementDatas this animation used. AnimationData *_animationData; MovementData *_movementData;//! MovementData save all MovementFrameDatas this animation used. Armature *_armature;//! A weak reference of armature std::string _movementID;//! Current movment"s name int _toIndex;//! The frame index in MovementData->m_pMovFrameDataArr, it"s different from m_iFrameIndex. cocos2d::Vector<Tween*> _tweenList;}如何做到每帧更新骨头的信息?void Armature::update(float dt) {_animation->update(dt);for(const auto &bone : _topBoneList) { bone->update(dt);}_armatureTransformDirty = false; }又调用了animation->update(dt);及遍历调用bone->update(dt);animation->update(dt)如下:void ArmatureAnimation::update(float dt) {ProcessBase::update(dt);for (const auto &tween : _tweenList){ tween->update(dt);}//省略一堆代码 }又调用了tween->update(dt); 每一个update都会调用updateHandler(ProcessBase中update调用了update里调用updateHandler) void Tween::updateHandler() {//省略一堆代码if (_loopType > ANIMATION_TO_LOOP_BACK){ percent = updateFrameData(percent);} if(_frameTweenEasing != ::cocosd::tweenfunc::TWEEN_EASING_MAX){ tweenNodeTo(percent);} }tweenNodeTo调用了tweenNodeTo,其中的tweenData其实就是Bone的tweenData。根据percent计算了_tweenData的变化量。 FrameData *Tween::tweenNodeTo(float percent, FrameData *node) {node = node == nullptr ? _tweenData : node; if (!_from->isTween){ percent = ;} node->x = _from->x + percent * _between->x;node->y = _from->y + percent * _between->y;node->scaleX = _from->scaleX + percent * _between->scaleX;node->scaleY = _from->scaleY + percent * _between->scaleY;node->skewX = _from->skewX + percent * _between->skewX;node->skewY = _from->skewY + percent * _between->skewY; _bone->setTransformDirty(true); if (node && _between->isUseColorInfo){ tweenColorTo(percent, node);} return node; }转了一大圈终于在每帧更新了Bone中的tweenData,最后看Bone的update,其根据tweenData计算了worldInfo、worldTransform。而且updateDisplay更新skin的信息,staticcast<skin*>(display)->updateArmatureTransform();再transform = TransformConcat(_bone->getNodeToArmatureTransform(), _skinTransform); void Bone::update(float delta) {if (_parentBone) _boneTransformDirty = _boneTransformDirty || _parentBone->isTransformDirty(); if (_armatureParentBone && !_boneTransformDirty){ _boneTransformDirty = _armatureParentBone->isTransformDirty();} if (_boneTransformDirty){ if (_dataVersion >= VERSION_COMBINED) {TransformHelp::nodeConcat(*_tweenData, *_boneData);_tweenData->scaleX -= ;_tweenData->scaleY -= ; }_worldInfo->copy(_tweenData);_worldInfo->x = _tweenData->x + _position.x; _worldInfo->y = _tweenData->y + _position.y; _worldInfo->scaleX = _tweenData->scaleX * _scaleX; _worldInfo->scaleY = _tweenData->scaleY * _scaleY; _worldInfo->skewX = _tweenData->skewX + _skewX + _rotationZ_X; _worldInfo->skewY = _tweenData->skewY + _skewY - _rotationZ_Y;if(_parentBone) {applyParentTransform(_parentBone); } else {if (_armatureParentBone){ applyParentTransform(_armatureParentBone);} }TransformHelp::nodeToMatrix(*_worldInfo, _worldTransform);if (_armatureParentBone) {_worldTransform = TransformConcat(_worldTransform, _armature->getNodeToParentTransform()); }} DisplayFactory::updateDisplay(this, delta, _boneTransformDirty || _armature->getArmatureTransformDirty()); for(const auto &obj: _children) { Bone *childBone = static_cast<Bone*>(obj); childBone->update(delta);} _boneTransformDirty = false;如何展示(draw)出图片(skin) void Armature::draw(cocosd::Renderer *renderer, const Mat &transform, uint_t flags) {if (_parentBone == nullptr && _batchNode == nullptr){ //CC_NODE_DRAW_SETUP();}for (auto& object : _children){ if (Bone *bone = dynamic_cast<Bone *>(object)) {Node *node = bone->getDisplayRenderNode(); if (nullptr == node) continue; switch (bone->getDisplayRenderNodeType()){case CS_DISPLAY_SPRITE:{ Skin *skin = static_cast<Skin *>(node); skin->updateTransform();BlendFunc func = bone->getBlendFunc();if (func.src != _blendFunc.src || func.dst != _blendFunc.dst) {skin->setBlendFunc(bone->getBlendFunc()); } else {skin->setBlendFunc(_blendFunc); } skin->draw(renderer, transform, flags);}break;case CS_DISPLAY_ARMATURE:{ node->draw(renderer, transform, flags);}break;default:{ node->visit(renderer, transform, flags); //CC_NODE_DRAW_SETUP();}break;} } else if(Node *node = dynamic_cast<Node *>(object)) {node->visit(renderer, transform, flags); // CC_NODE_DRAW_SETUP(); }} }再skin->draw(renderer, transform, flags);会用到刚刚更新的_quad,显示出最新的图片信息。{Mat mv = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); //TODO implement z order_quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, , mv);renderer->addCommand(&_quadCommand); }至此,大家对cocos2dx里的骨骼动画应该有了全面的认识,三篇文章介绍的比较粗糙,其实有些细节内容我也没看懂,不过不要在意这些细节,没有实际的改动需求的话,懂80%就可以了,细节可以需要的时候在仔细理解。