笔者分析的是用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类节点树的实现。