筆者分析的是用C++語言實現、版本號爲cocos2d-x-3.3rc0的cocos2d框架的源代碼。本文爲筆者原創,容許讀者分享和轉載,只要讀者註明文章來源便可。node
Node對象時場景圖的基本元素,而且場景圖的基本元素必須是Node對象和Node的子類對象。常見的Node類的子類有:Scene、Layer、Sprite、Menu和Label類。數組
這些屬性會在後續的源碼分析中作具體介紹。框架
Node比較龐大,筆者打算在多篇博客中分別詳細介紹Node節點的不一樣模塊。前面說到Node對象可以持有其餘Node對象做爲其子節點,也就是說一個Node對象其實可以擴展出一個節點樹。因此筆者先介紹節點樹模塊。ide
添加子節點的過程須要到下面的屬性。函數
int _localZOrder; ///< Local order (relative to its siblings) used to sort the node float _globalZOrder; ///< Global order used to sort the node Vector<Node*> _children; ///< array of children nodes Node *_parent; ///< weak reference to parent node int _tag; ///< a tag. Can be any number you assigned just to identify this node std::string _name; ///<a string label, an user defined string to identify this node int _orderOfArrival; ///< used to preserve sequence while sorting children with the same localZOrder bool _running; ///< is running
下面看此addChild函數的聲明。源碼分析
/** * Adds a child to the container with z order and tag * * If the child is added to a 'running' node, then 'onEnter' and 'onEnterTransitionDidFinish' will be called immediately. * * @param child A child node * @param zOrder Z order for drawing priority. Please refer to `setLocalZOrder(int)` * @param tag An integer to identify the node easily. Please refer to `setTag(int)` * * Please use `addChild(Node* child, int localZOrder, const std::string &name)` instead. */ virtual void addChild(Node* child, int localZOrder, int tag); /** * Adds a child to the container with z order and tag * * If the child is added to a 'running' node, then 'onEnter' and 'onEnterTransitionDidFinish' will be called immediately. * * @param child A child node * @param zOrder Z order for drawing priority. Please refer to `setLocalZOrder(int)` * @param name A string to identify the node easily. Please refer to `setName(int)` * */ virtual void addChild(Node* child, int localZOrder, const std::string &name);
LocalZOrder參數決定了子節點被添加到節點樹的位置,子節點在節點樹中的位置決定了節點顯示的順序。關於節點樹的遍歷會在後續的博客中介紹,讀者如今只須要知道LocalZOrder取值從負軸到正軸,顯示順序遞減。this
函數聲明還提到,若是當前父節點處於running狀態,那麼被添加的子節點會被馬上調用onEnter和onEnterTransitionDidFinish函數。下面看此函數的具體實現。spa
void Node::addChild(Node *child, int localZOrder, int tag) { CCASSERT( child != nullptr, "Argument must be non-nil"); CCASSERT( child->_parent == nullptr, "child already added. It can't be added again"); addChildHelper(child, localZOrder, tag, "", true); } void Node::addChild(Node* child, int localZOrder, const std::string &name) { CCASSERT(child != nullptr, "Argument must be non-nil"); CCASSERT(child->_parent == nullptr, "child already added. It can't be added again"); addChildHelper(child, localZOrder, INVALID_TAG, name, false); }
這兩個函數都調用了一個私有函數 void addChildHelper(Node* child, int localZOrder, int tag, const std::string &name, bool setTag)。下面看該函數的實現。code
void Node::addChildHelper(Node* child, int localZOrder, int tag, const std::string &name, bool setTag) { if (_children.empty()) { this->childrenAlloc(); } this->insertChild(child, localZOrder); if (setTag) child->setTag(tag); else child->setName(name); child->setParent(this); /* 筆者注 * 設置節點到達順序,若是節點樹中不一樣節點有相同的LocalZOrder時, * 到達順序小的節點先畫 */ child->setOrderOfArrival(s_globalOrderOfArrival++); /* 筆者注 * 若是使用了物理引擎,須要爲節點添加物理世界的性質 */ #if CC_USE_PHYSICS // Recursive add children with which have physics body. Scene* scene = this->getScene(); if (scene != nullptr && scene->getPhysicsWorld() != nullptr) { child->updatePhysicsBodyTransform(scene); scene->addChildToPhysicsWorld(child); } #endif if( _running ) { child->onEnter(); // prevent onEnterTransitionDidFinish to be called twice when a node is added in onEnter if (_isTransitionFinished) { child->onEnterTransitionDidFinish(); } } if (_cascadeColorEnabled) { updateCascadeColor(); } if (_cascadeOpacityEnabled) { updateCascadeOpacity(); } }
從實現源碼不難看出,全部的子節點都被保存到 _children 數組中。若是父節點不處於 _running 狀態,那麼子節點在添加時就不會被調用 onEnter和onEnterTransitionDidFinished函數,這會產生什麼影響筆者從此再作補充。orm
本文就先介紹Node類實現往父節點的節點樹添加子節點的過程。下一篇博客會繼續介紹Node類節點樹的實現。