首页 > 代码库 > 关于NODE类
关于NODE类
class CC_DLL Node : public Ref
因此NODE可以直接使用aurelease方法实现自动内存管理
什么是锚点呢?有过动画制作经验的同学可能了解,在这里小鱼简单提一下,锚点通俗一点理解就是图形在做变形,旋转时候的一个基准点,比如上面的一些gif图形进行x,y轴方向变换时的原点就是它的锚点,上面所有图的锚点都是左下角,这也是cocos2d-x默认的锚点位置。
node的有些成员如下,非常重要
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; ///可以给当前的Node对象定义一个 int类型的标识 std::string _name; ///可以给当前Node对象起一个字符串类型的名称。
这几个变量说明Node是一个树的数据结构,除非是根否则每个node对象都有父结点, _parent,每个Node还有一系列子结点 _children 这些子结点用了一个 Vector来存放,并且每个Node对象都有同级子结点(同一个父亲的子结点)的一个Z轴方向的顺序_localZOrder,在在游戏开发中有一个名词叫做深度排序,类似这个意思。
还有一个变量_globalZOrder这是全局的一个深度排序,当localorder相同的时候,根据globalorder进行排列
void Node::addChild(Node *child, int zOrder, int tag){ CCASSERT( child != nullptr, "Argument must be non-nil"); CCASSERT( child->_parent == nullptr, "child already added. It can‘t be added again"); if (_children.empty()) { this->childrenAlloc(); } this->insertChild(child, zOrder); #if CC_USE_PHYSICS if (child->getPhysicsBody() != nullptr) { child->getPhysicsBody()->setPosition(this->convertToWorldSpace(child->getPosition())); } for (Node* node = this->getParent(); node != nullptr; node = node->getParent()) { if (dynamic_cast<Scene*>(node) != nullptr) { (dynamic_cast<Scene*>(node))->addChildToPhysicsWorld(child); break; } }#endif child->_tag = tag; child->setParent(this); child->setOrderOfArrival(s_globalOrderOfArrival++); 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(); }}
先判断了当前结点是的子结点列表是否为空,如果 是空调用了Node类的成员函数 childrenAlloc(); 分配了内存。
然后调用了
this->insertChild(child, zOrder);
这个函数是根据zOrder的顺序将child加入到当前结点的子结点列表里面,我们跟进这个函数看看是怎么实现的。
void Node::insertChild(Node* child, int z){ _reorderChildDirty = true; _children.pushBack(child); child->_setLocalZOrder(z);}
这个insertChild并没有将 _children这个vecort的顺序重新排列,只是将child这个对象加到了_children 列表的最后面。还做了改child的zOrder的设置操作。
注意到这里使用了_reorderChildDirty 这个变量,命名上理解,这个变量是标记着,当前Node对象的子对象列表是否需要重新排列操作,这里的设计很巧妙,在insertChild的时候不必排列一遍结点顺序,小鱼猜,肯定在使用这个结点的时候会根据_reorderChildDirty 这个变量的值来决定这个结点是否需要排列一遍子结点的顺序。于是我在Node类定义中找到了这样的一个方法。
void Node::sortAllChildren(){ if( _reorderChildDirty ) { std::sort( std::begin(_children), std::end(_children), nodeComparisonLess ); _reorderChildDirty = false; }}
在running状态下,新加入的子结点会调用一个 onEnter函数,前面提到过,Node类定义了一些事件,这个onEnter就是其中的一个事件,从代码上直接可以理解这个onEnter事件的含义是,当结点被加入到正在运行的结点后就会触发的一个回调函数。
if (_isTransitionFinished) { child->onEnterTransitionDidFinish(); }
if (_cascadeColorEnabled) { updateCascadeColor(); } if (_cascadeOpacityEnabled) { updateCascadeOpacity(); }
这两个变量是标记是否继承父结点的颜色与透明度如果父结点定义了要子结点继承它的颜色与透明设置那么会递归的更新每个子结点的颜色与透明度与父结点一样。
到此,这个addChild方法我们已经看明白了,关于物理方面的东西先放到一边,从后章节我们来分析。
下面我们看一下Node类最重要的一个创建对象方法create方法
Node * Node::create(void){ Node * ret = new Node(); if (ret && ret->init()) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } return ret;}
这个create方法很简单,
1. new一个Node对象
2. 调用Node的init方法进行初始化。
3. 设置Node 为自动内存释放。
Cocos2d-x推荐我们作用create方法来创建结点,而不要用new的方式创建。我们在应用的时候应该尊重这条建议。
create方法里面提供到了一个init方法,下面我们跟进源码,看一下init都干了些什么。
virtual bool init();bool Node::init(){ return true;}
看到了这么干净的init方法,里面就一行代码。怎么回事呢?
我们看一下init方法的声明为 virtual 所以这个方法是给它的子类使用的,不同的子类有不同的init过程 所以这里只是预留了一个初始化的接口,在你的类中如果有自己的特殊的初始化过程那么重载这个init就可以了。
从命名上理解,_isTransitionfinished 是一个标记着Node对象是否做完了变换的一个状态,这里触发了事件的回调函数
node结点具体怎么来渲染使用的是 draw方法,
如果要显示一个node结点及其子结点那么我们就要使用visit方法,这样可以递归的按照zOrder顺序地draw每一个子结点。
- Node 类在Cocos2d-x里地位显赫,它是显示对象(在手机等设备里显示的东西)的基类。
- Node类是一个树状结构的一个结点,它最多只有一个父结点,可以有多个子结点,这些子结点存放在一个vector的数据结构中
- 创建Node对象不要使用new方法,而使用create方法。
- Node类的内存管理是走的autorelease机制的,所以不要delete对象而是采用Cocos2d-x的引用计数机制来释放对象。
- 向node结点中加子结点时用addchild方法(这里如果忘记了addchild都干了些什么可以翻到上面回顾一下)
- 将node结点显示到屏幕上使用visit方法,在visit方法里面会调用draw来绘制node.我们在使用的时候可以重载draw方法这样就可以让node按自己的方式来显示出来。
- node还支持名称,tag(id)等标识,可以通过这些标识来查找node的指针。
- Node还支持一些旋转,变形,绽放等操作,并且这些设置子结点也会继承的。
- Node里面还引用了 定时器,事件分发,动作管理器等。
- Node有一些自己的事件,当被加入到入结点中会调用 enter当被移出父结点时会触发 exit
关于NODE类