程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> cocos2dx骨骼動畫Armature源碼分析(三),cocos2dxarmature

cocos2dx骨骼動畫Armature源碼分析(三),cocos2dxarmature

編輯:C++入門知識

cocos2dx骨骼動畫Armature源碼分析(三),cocos2dxarmature


代碼目錄結構

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%就可以了,細節可以需要的時候在仔細理解。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved