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


    代码目录结构

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

    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(类)

    数据相关源码

    从底层到高层分析一个类一个类分析

    再来看下数据相关的UML,总体来说,就是ArmatureDataManager依赖DataReaderHelper把flash导出的xml文件解析成程序直接用的XXData,XXData对应于xml的某个节点,比如FrameData就对应于<f>节点(<animaton><mov><b><f>)。

    BaseData

    BaseData:用来表示骨骼或帧的位置、旋转、颜色、缩放。

    BaseData.h

     1 class  BaseData : public cocos2d::Ref
     2 {
     3 public:
     4      //Calculate two BaseData's between value(to - from) and set to self
     5     virtual void subtract(BaseData *from, BaseData *to, bool limit);
     6 public:
     7      //位置,xml的x,y
     8     float x;                    
     9     float y;        
    10     //xml中z         
    11     int zOrder; 
    12     //旋转,xml的kX,kY
    13     float skewX;    
    14     float skewY;    
    15     //缩放,xml的cX,cY
    16     float scaleX;   
    17     float scaleY;   
    18      //啥??
    19     float tweenRotate;     
    20      //颜色的变化属性 
    21     bool isUseColorInfo;    
    22     int a, r, g, b;
    23 };

    作为FrameData和BoneData的基类,提供骨骼的状态信息。从下文可知BoneData对应xml中的<armature<b>>中的b节点,FrameData对应xml中的<f>节点,BoneData和FrameData都有

    <x,y,kX,kY,cX,cY,pX,pY,z>

    等属性,BaseDa代表了这些属性。

    BoneData

    BoneData对应xml中的<armature<b>>中的b节点

     1 class  BoneData : public BaseData
     2 {
     3 public:
     4     void addDisplayData(DisplayData *displayData);
     5     DisplayData *getDisplayData(int index);
     6 public:
     7     std::string name;           //! the bone's name
     8     std::string parentName;     //! the bone parent's name
     9     //! save DisplayData informations for the Bone
    10     cocos2d::Vector<DisplayData*> displayDataList; 
    11     //仿射变换,程序里好像没用这个属性   
    12     cocos2d::AffineTransform boneDataTransform;
    13 };

    BoneData里有displayDataList,用来放这个骨头上的皮肤(就是DisplayData), DisplayData对应xml节点中的<b<d>>节点,一个BoneData里可以有多个皮肤,换装等功能需要多个皮肤。

    FrameData

    FrameData对应xml中的<f>节点,就是flash里的关键帧信息。

     1 class  FrameData : public BaseData
     2 {
     3 public:
     4     int frameID;
     5     //xml中dr,这一帧长度
     6     int duration;               
     7     //不知要他干啥
     8     bool isTween;  
     9     //xml中dI,显示哪个图              
    10     int displayIndex;
    11 };

    DisplayData

    DisplayData是SpriteDisplayData、ArmatureDisplayData、ParticleDisplayData的父类,用来表示展示节点信息。

    ArmatureData

    ArmatureData是对应<armature>节点,里面有这个骨骼的所有骨头,可以看成骨骼动画的骨骼。

     1 class  ArmatureData : public cocos2d::Ref
     2 {
     3 public:
     4      //添加骨骼信息
     5     void addBoneData(BoneData *boneData);
     6     BoneData *getBoneData(const std::string& boneName);
     7 public:
     8     std::string name;
     9     //多个骨头信息
    10     cocos2d::Map<std::string, BoneData*> boneDataDic;
    11     float dataVersion;
    12 };

    AnimationData

    AnimationData对应<animation>节点,里面有多个MovementData,MovementData(下面介绍)对应xml中的mov,为flash中的一个带帧标签的动画。

     1 class  AnimationData : public cocos2d::Ref
     2 {
     3 public:
     4     void addMovement(MovementData *movData);
     5     MovementData *getMovement(const std::string& movementName);
     6     ssize_t getMovementCount();
     7 public:
     8      //<animation name="Dragon">中的name
     9     std::string name;
    10     //所有带帧标签的动画map
    11     cocos2d::Map<std::string, MovementData*> movementDataDic;
    12     //所有带帧标签的动画名
    13     std::vector<std::string> movementNames;
    14 };

    MovementData

    MovementData对应xml中<animation<mov>>, 其中有所有的带帧信息的骨骼MovementBoneData(mov中的b)。

     1 class  MovementData : public cocos2d::Ref
     2 {
     3 public:
     4     void addMovementBoneData(MovementBoneData *movBoneData);
     5     MovementBoneData *getMovementBoneData(const std::string& boneName);
     6 public:
     7     std::string name;
     8     //xml 中 dr
     9     int duration;
    10     //这怎么有个scale??    
    11     float scale;    
    12     //xml中to      
    13     int durationTo;
    14     //xml中drTW
    15     int durationTween;
    16      //xml中lp
    17     bool loop;
    18     //带帧信息的骨骼        
    19     cocos2d::Map<std::string, MovementBoneData*> movBoneDataDic;
    20 };

    MovementBoneData

    MovementBoneData对应xml中<mov<b>>的b,里面有frameList,即为关键帧信息。

     1 class  MovementBoneData : public cocos2d::Ref
     2 {
     3     void addFrameData(FrameData *frameData);
     4     FrameData *getFrameData(int index);
     5 public:
     6      //xml中的dl
     7     float delay;
     8     //xml中的sc              
     9     float scale;     
    10     //这个和MovementData中的duration是不是一个??      
    11     float duration;        
    12     std::string name;    
    13      //关键帧信息
    14     cocos2d::Vector<FrameData*> frameList;
    15 };

    小总结

    xml中的各个节点和XXData的对应关系如下表,xml各个字段的意义可以参考上篇文章

    再来看产生动画相关的代码

    ArmatureDataManager

    ArmatureDataManager利用DataReaderHelper解析出armarureDatas、animationDatas和_textureDatas。ArmatureDataManager是个单例,用到动画时会到ArmatureDataManager取得要生成动画的数据。

     1 class  ArmatureDataManager : public cocos2d::Ref
     2 {
     3 public:
     4      //单例    
     5     static ArmatureDataManager *getInstance();
     6     static void destroyInstance();
     7 public:
     8     void addArmatureData(const std::string& id, ArmatureData *armatureData, const std::string& configFilePath = "");
     9     ArmatureData *getArmatureData(const std::string& id);
    10     void removeArmatureData(const std::string& id);
    11     void addAnimationData(const std::string& id, AnimationData *animationData, const std::string& configFilePath = "");
    12     AnimationData *getAnimationData(const std::string& id);
    13     void removeAnimationData(const std::string& id);
    14     void addTextureData(const std::string& id, TextureData *textureData, const std::string& configFilePath = "");
    15     TextureData *getTextureData(const std::string& id);
    16     void removeTextureData(const std::string& id);
    17     void addArmatureFileInfo(const std::string& configFilePath);
    18     const cocos2d::Map<std::string, ArmatureData*>&     getArmatureDatas() const;
    19     const cocos2d::Map<std::string, AnimationData*>&    getAnimationDatas() const;
    20     const cocos2d::Map<std::string, TextureData*>&      getTextureDatas() const;
    21 protected:
    22     void addRelativeData(const std::string& configFilePath);
    23     RelativeData *getRelativeData(const std::string& configFilePath);
    24 private:
    25     cocos2d::Map<std::string, ArmatureData*> _armarureDatas;
    26     cocos2d::Map<std::string, AnimationData*> _animationDatas;
    27     cocos2d::Map<std::string, TextureData*> _textureDatas;
    28     std::unordered_map<std::string, RelativeData> _relativeDatas;
    29 };

    主要就是armarureDatas、animationDatas、_textureDatas三个map,那这三个map是怎么产生的呢?当执行

    1 ArmatureDataManager::getInstance()->addArmatureFileInfo(“dragon.xml”);

    后,那三个map变生成了。addArmatureFileInfo代码如下

    1 void ArmatureDataManager::addArmatureFileInfo(const std::string& configFilePath)
    2 {
    3     addRelativeData(configFilePath);
    4     _autoLoadSpriteFile = true;
    5     DataReaderHelper::getInstance()->addDataFromFile(configFilePath);
    6 }

    又调用了DataReaderHelper::getInstance()->addDataFromFile(),可知是DataReaderHelper真正完成了数据的解析。DataReaderHelper类里有一堆decodeXXX()(比如decodeArmature、decodeBone)解析xml的某个节点。看下addDataFromFile这个代码:

     1 void DataReaderHelper::addDataFromFile(const std::string& filePath)
     2 {
     3      //省略一些代码
     4     
     5     DataInfo dataInfo;
     6     dataInfo.filename = filePathStr;
     7     dataInfo.asyncStruct = nullptr;
     8     dataInfo.baseFilePath = basefilePath;
     9     if (str == ".xml")
    10     {
    11         DataReaderHelper::addDataFromCache(contentStr, &dataInfo);
    12     }
    13     else if(str == ".json" || str == ".ExportJson")
    14     {
    15         DataReaderHelper::addDataFromJsonCache(contentStr, &dataInfo);
    16     }
    17     else if(isbinaryfilesrc)
    18     {
    19         DataReaderHelper::addDataFromBinaryCache(contentStr.c_str(),&dataInfo);
    20     }
    21 
    22     CC_SAFE_DELETE_ARRAY(pBytes);
    23 }

    对应不同的文件(xml、json、二进制)解析方式,xml用到是addDataFromCache

     1 void DataReaderHelper::addDataFromCache(const std::string& pFileContent, DataInfo *dataInfo)
     2 {
     3     tinyxml2::XMLDocument document;
     4     document.Parse(pFileContent.c_str());
     5 
     6     tinyxml2::XMLElement *root = document.RootElement();
     7     CCASSERT(root, "XML error  or  XML is empty.");
     8 
     9     root->QueryFloatAttribute(VERSION, &dataInfo->flashToolVersion);
    10 
    11 
    12     /*
    13     * Begin decode armature data from xml
    14     */
    15     tinyxml2::XMLElement *armaturesXML = root->FirstChildElement(ARMATURES);
    16     tinyxml2::XMLElement *armatureXML = armaturesXML->FirstChildElement(ARMATURE);
    17     while(armatureXML)
    18     {
    19         ArmatureData *armatureData = DataReaderHelper::decodeArmature(armatureXML, dataInfo);
    20 
    21         if (dataInfo->asyncStruct)
    22         {
    23             _dataReaderHelper->_addDataMutex.lock();
    24         }
    25         ArmatureDataManager::getInstance()->addArmatureData(armatureData->name.c_str(), armatureData, dataInfo->filename.c_str());
    26         armatureData->release();
    27         if (dataInfo->asyncStruct)
    28         {
    29             _dataReaderHelper->_addDataMutex.unlock();
    30         }
    31 
    32         armatureXML = armatureXML->NextSiblingElement(ARMATURE);
    33     }
    34 
    35 
    36     /*
    37     * Begin decode animation data from xml
    38     */
    39     tinyxml2::XMLElement *animationsXML = root->FirstChildElement(ANIMATIONS);
    40     tinyxml2::XMLElement *animationXML = animationsXML->FirstChildElement(ANIMATION);
    41     while(animationXML)
    42     {
    43         AnimationData *animationData = DataReaderHelper::decodeAnimation(animationXML, dataInfo);
    44         if (dataInfo->asyncStruct)
    45         {
    46             _dataReaderHelper->_addDataMutex.lock();
    47         }
    48         ArmatureDataManager::getInstance()->addAnimationData(animationData->name.c_str(), animationData, dataInfo->filename.c_str());
    49         animationData->release();
    50         if (dataInfo->asyncStruct)
    51         {
    52             _dataReaderHelper->_addDataMutex.unlock();
    53         }
    54         animationXML = animationXML->NextSiblingElement(ANIMATION);
    55     }
    56 
    57 
    58     /*
    59     * Begin decode texture data from xml
    60     */
    61     tinyxml2::XMLElement *texturesXML = root->FirstChildElement(TEXTURE_ATLAS);
    62     tinyxml2::XMLElement *textureXML = texturesXML->FirstChildElement(SUB_TEXTURE);
    63     while(textureXML)
    64     {
    65         TextureData *textureData = DataReaderHelper::decodeTexture(textureXML, dataInfo);
    66 
    67         if (dataInfo->asyncStruct)
    68         {
    69             _dataReaderHelper->_addDataMutex.lock();
    70         }
    71         ArmatureDataManager::getInstance()->addTextureData(textureData->name.c_str(), textureData, dataInfo->filename.c_str());
    72         textureData->release();
    73         if (dataInfo->asyncStruct)
    74         {
    75             _dataReaderHelper->_addDataMutex.unlock();
    76         }
    77         textureXML = textureXML->NextSiblingElement(SUB_TEXTURE);
    78     }
    79 }

    里面有三个while,分别decodeArmature、decodeAnimation、decodeTexture,生成ArmatureData、AnimationData、TextureData之后又ArmatureDataManager::getInstance()->addArmatureData、addAnimationData、addTextureData,加到ArmatureDataManager对应map里。decodeXXX里又会调用各种decodeXX来生成相应的XXXData。

    Armature

    在载入了xml数据后,调用

    1     armature = Armature::create("Dragon");
    2     armature->getAnimation()->play("walk");
    3     armature->getAnimation()->setSpeedScale(1);
    4     armature->setPosition(VisibleRect::center().x, VisibleRect::center().y * 0.3f);
    5     armature->setScale(0.6f);
    6     addChild(armature);

    便展示了动画,那么这是如何做到的呢?

    Armature部分代码如下,ArmatureAnimation控制xml的mov节点,Bone中有Tween,这个Tween对应xml中b(MovementBoneData)

     1 class Armature: public cocos2d::Node, public cocos2d::BlendProtocol {
     2 protected:
     3      //要展示动画的ArmatureData
     4     ArmatureData *_armatureData;
     5     BatchNode *_batchNode;
     6     Bone *_parentBone;
     7     float _version;
     8     mutable bool _armatureTransformDirty;
     9     //所有Bone
    10     cocos2d::Map<std::string, Bone*> _boneDic;                           cocos2d::Vector<Bone*> _topBoneList;
    11 
    12     cocos2d::BlendFunc _blendFunc;                  
    13     cocos2d::Vec2 _offsetPoint;
    14     cocos2d::Vec2 _realAnchorPointInPoints;
    15      //动画控制器
    16     ArmatureAnimation *_animation;
    17 };

    Bone

    部分代码如下,tweenData为当前Bone的状态,每帧都会更新这个值,并用tweenData确定worldInfo,提供Skin显示信息。tween为骨头的整个动画过程。

     1 class Bone: public cocos2d::Node {
     2 protected:
     3     BoneData *_boneData;
     4 
     5     //! A weak reference to the Armature
     6     Armature *_armature;
     7 
     8     //! A weak reference to the child Armature
     9     Armature *_childArmature;
    10 
    11     DisplayManager *_displayManager;
    12 
    13     /*
    14      *  When Armature play an animation, if there is not a MovementBoneData of this bone in this MovementData, this bone will be hidden.
    15      *  Set IgnoreMovementBoneData to true, then this bone will also be shown.
    16      */
    17     bool _ignoreMovementBoneData;
    18 
    19     cocos2d::BlendFunc _blendFunc;
    20     bool _blendDirty;
    21 
    22     Tween *_tween;              //! Calculate tween effect
    23 
    24     //! Used for making tween effect in every frame
    25     FrameData *_tweenData;
    26 
    27     Bone *_parentBone;                 //! A weak reference to its parent
    28     bool _boneTransformDirty;          //! Whether or not transform dirty
    29 
    30     //! self Transform, use this to change display's state
    31     cocos2d::Mat4 _worldTransform;
    32 
    33     BaseData *_worldInfo;
    34     
    35     //! Armature's parent bone
    36     Bone *_armatureParentBone;
    37 
    38 };

    Tween

    这个是每个骨头的动画过程,见下面的movementBoneData。tweenData是Bone中tweenData的引用,在这每帧会计算这个tweenData值。

     1 class  Tween : public ProcessBase{
     2 protected:
     3     //! A weak reference to the current MovementBoneData. The data is in the data pool
     4     MovementBoneData *_movementBoneData;
     5 
     6     FrameData *_tweenData;          //! The computational tween frame data, //! A weak reference to the Bone's tweenData
     7     FrameData *_from;               //! From frame data, used for calculate between value
     8     FrameData *_to;                 //! To frame data, used for calculate between value
     9     
    10     // total diff guan
    11     FrameData *_between;            //! Between frame data, used for calculate current FrameData(m_pNode) value
    12 
    13     Bone *_bone;                    //! A weak reference to the Bone
    14 
    15     TweenType _frameTweenEasing;  //! Dedermine which tween effect current frame use
    16 
    17     int _betweenDuration;           //! Current key frame will last _betweenDuration frames
    18     
    19     // 总共运行了多少帧 guan
    20     int _totalDuration;
    21 
    22     int _fromIndex;                 //! The current frame index in FrameList of MovementBoneData, it's different from m_iFrameIndex
    23     int _toIndex;                   //! The next frame index in FrameList of MovementBoneData, it's different from m_iFrameIndex
    24 
    25     ArmatureAnimation *_animation;
    26 
    27     bool _passLastFrame;            //! If current frame index is more than the last frame's index
    28 };

    ArmatureAnimation

    控制动画的播放,看到_tweenList,所有骨头的集合就是动画了。

    class  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;
    }

    如何做到每帧更新骨头的信息?

    addChild(armature)后,Armaure中的onEnter(node进入舞台就会调用,比如addchild),onEnter调scheduleUpdate调scheduleUpdateWithPriority调_scheduler->scheduleUpdate。这样就每帧调用armature的update。

    1 void Armature::update(float dt)
    2 {
    3     _animation->update(dt);
    4     for(const auto &bone : _topBoneList) {
    5         bone->update(dt);
    6     }
    7     _armatureTransformDirty = false;
    8 }

    又调用了animation->update(dt);及遍历调用bone->update(dt);animation->update(dt)如下:

     1 void ArmatureAnimation::update(float dt)
     2 {
     3     ProcessBase::update(dt);
     4     
     5     for (const auto &tween : _tweenList)
     6     {
     7         tween->update(dt);
     8     }
     9     //省略一堆代码
    10 }

    又调用了tween->update(dt); 每一个update都会调用updateHandler(ProcessBase中update调用了update里调用updateHandler)

     1 void Tween::updateHandler()
     2 {
     3      //省略一堆代码
     4     if (_loopType > ANIMATION_TO_LOOP_BACK)
     5     {
     6         percent = updateFrameData(percent);
     7     }
     8 
     9     if(_frameTweenEasing != ::cocos2d::tweenfunc::TWEEN_EASING_MAX)
    10     {
    11         tweenNodeTo(percent);
    12     }
    13 }

    tweenNodeTo调用了tweenNodeTo,其中的tweenData其实就是Bone的tweenData。根据percent计算了_tweenData的变化量。

     1 FrameData *Tween::tweenNodeTo(float percent, FrameData *node)
     2 {
     3     node = node == nullptr ? _tweenData : node;
     4 
     5     if (!_from->isTween)
     6     {
     7         percent = 0;
     8     }
     9 
    10     node->x = _from->x + percent * _between->x;
    11     node->y = _from->y + percent * _between->y;
    12     node->scaleX = _from->scaleX + percent * _between->scaleX;
    13     node->scaleY = _from->scaleY + percent * _between->scaleY;
    14     node->skewX = _from->skewX + percent * _between->skewX;
    15     node->skewY = _from->skewY + percent * _between->skewY;
    16 
    17     _bone->setTransformDirty(true);
    18 
    19     if (node && _between->isUseColorInfo)
    20     {
    21         tweenColorTo(percent, node);
    22     }
    23 
    24     return node;
    25 }

    转了一大圈终于在每帧更新了Bone中的tweenData,最后看Bone的update,其根据tweenData计算了worldInfo、worldTransform。而且updateDisplay更新skin的信息,staticcast<skin*>(display)->updateArmatureTransform();再transform = TransformConcat(_bone->getNodeToArmatureTransform(), _skinTransform);

     1 void Bone::update(float delta)
     2 {
     3     if (_parentBone)
     4         _boneTransformDirty = _boneTransformDirty || _parentBone->isTransformDirty();
     5 
     6     if (_armatureParentBone && !_boneTransformDirty)
     7     {
     8         _boneTransformDirty = _armatureParentBone->isTransformDirty();
     9     }
    10 
    11     if (_boneTransformDirty)
    12     {
    13         if (_dataVersion >= VERSION_COMBINED)
    14         {
    15             TransformHelp::nodeConcat(*_tweenData, *_boneData);
    16             _tweenData->scaleX -= 1;
    17             _tweenData->scaleY -= 1;
    18         }
    19 
    20         _worldInfo->copy(_tweenData);
    21 
    22         _worldInfo->x = _tweenData->x + _position.x;
    23         _worldInfo->y = _tweenData->y + _position.y;
    24         _worldInfo->scaleX = _tweenData->scaleX * _scaleX;
    25         _worldInfo->scaleY = _tweenData->scaleY * _scaleY;
    26         _worldInfo->skewX = _tweenData->skewX + _skewX + _rotationZ_X;
    27         _worldInfo->skewY = _tweenData->skewY + _skewY - _rotationZ_Y;
    28 
    29         if(_parentBone)
    30         {
    31             applyParentTransform(_parentBone);
    32         }
    33         else
    34         {
    35             if (_armatureParentBone)
    36             {
    37                 applyParentTransform(_armatureParentBone);
    38             }
    39         }
    40 
    41         TransformHelp::nodeToMatrix(*_worldInfo, _worldTransform);
    42 
    43         if (_armatureParentBone)
    44         {
    45             _worldTransform = TransformConcat(_worldTransform, _armature->getNodeToParentTransform());
    46         }
    47     }
    48 
    49     DisplayFactory::updateDisplay(this, delta, _boneTransformDirty || _armature->getArmatureTransformDirty());
    50 
    51     for(const auto &obj: _children) {
    52         Bone *childBone = static_cast<Bone*>(obj);
    53         childBone->update(delta);
    54     }
    55 
    56     _boneTransformDirty = false;

    如何展示(draw)出图片(skin)

    Armature诗歌node,加入父节点后会调用其draw函数,遍历draw了bone的显示元素。

     1 void Armature::draw(cocos2d::Renderer *renderer, const Mat4 &transform, uint32_t flags)
     2 {
     3     if (_parentBone == nullptr && _batchNode == nullptr)
     4     {
     5 //        CC_NODE_DRAW_SETUP();
     6     }
     7 
     8 
     9     for (auto& object : _children)
    10     {
    11         if (Bone *bone = dynamic_cast<Bone *>(object))
    12         {
    13             Node *node = bone->getDisplayRenderNode();
    14 
    15             if (nullptr == node)
    16                 continue;
    17 
    18             switch (bone->getDisplayRenderNodeType())
    19             {
    20             case CS_DISPLAY_SPRITE:
    21             {
    22                 Skin *skin = static_cast<Skin *>(node);
    23                 skin->updateTransform();
    24                 
    25                 BlendFunc func = bone->getBlendFunc();
    26                 
    27                 if (func.src != _blendFunc.src || func.dst != _blendFunc.dst)
    28                 {
    29                     skin->setBlendFunc(bone->getBlendFunc());
    30                 }
    31                 else
    32                 {
    33                     skin->setBlendFunc(_blendFunc);
    34                 }
    35                 skin->draw(renderer, transform, flags);
    36             }
    37             break;
    38             case CS_DISPLAY_ARMATURE:
    39             {
    40                 node->draw(renderer, transform, flags);
    41             }
    42             break;
    43             default:
    44             {
    45                 node->visit(renderer, transform, flags);
    46 //                CC_NODE_DRAW_SETUP();
    47             }
    48             break;
    49             }
    50         }
    51         else if(Node *node = dynamic_cast<Node *>(object))
    52         {
    53             node->visit(renderer, transform, flags);
    54 //            CC_NODE_DRAW_SETUP();
    55         }
    56     }
    57 }

    再skin->draw(renderer, transform, flags);会用到刚刚更新的_quad,显示出最新的图片信息。

    1 {
    2     Mat4 mv = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    3 
    4     //TODO implement z order
    5     _quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, mv);
    6     renderer->addCommand(&_quadCommand);
    7 }

    至此,大家对cocos2dx里的骨骼动画应该有了全面的认识,三篇文章介绍的比较粗糙,其实有些细节内容我也没看懂,不过不要在意这些细节,没有实际的改动需求的话,懂80%就可以了,细节可以需要的时候在仔细理解。

  • 相关阅读:
    工作
    失败
    理想和一些未来的计划
    安静
    重新开始
    如何度过周末
    放假
    WPF学习笔记-数据采集与监控项目01-登录界面
    VS2017-断点感叹号问题,调试代码显示“当前无法命中断点,还没有为该文档加载任何符号”
    WPF-MVVM模式-表现层的UI框架【学习笔记】
  • 原文地址:https://www.cnblogs.com/BigFeng/p/4787822.html
Copyright © 2020-2023  润新知