从零开始のcocos2dx生活(二)Node

节点 Node

前言

建议看完后面章节的知识后,多多回顾节点的代码,有助于加深理解。

节点是场景图中的基本元素。
最常见的节点对象有:场景、图层、精灵、菜单、标签、按钮等。

节点的主要特征是:
-它们可以包含其他节点对象(’ addChild ‘、’ removeChild ‘等)
-他们可以安排定期回调(’ schedule ', ’ unschedule ‘等)
-他们可以执行动作(’ runAction ', ’ stopAction '等)

子类化一个节点通常意味着(一个/所有):
-覆盖init来初始化资源和调度回调
-创建回调函数来处理时间的推移
-覆盖“绘制”以呈现节点

节点的属性:
-位置(默认:x=0, y=0)
-缩放(默认值:x=1, y=1)
-旋转(角度,顺时针方向)(默认为0)
-锚点(默认:x=0, y=0)
-contentSize(默认:宽度=0,高度=0)
-可见性(默认为真)

变量初始化

static const int INVALID_TAG = -1;  //设置标签初始值

enum {
        FLAGS_TRANSFORM_DIRTY = (1 << 0),  // 1
        FLAGS_CONTENT_SIZE_DIRTY = (1 << 1),  // 2
        FLAGS_RENDER_AS_3D = (1 << 3),  // 8

        FLAGS_DIRTY_MASK = (FLAGS_TRANSFORM_DIRTY | FLAGS_CONTENT_SIZE_DIRTY), // 或运算
    };

static Node * create(); //初始化节点,并返回一个加入到自动内存释放池中的节点

static int getAttachedNodeCount(); //获取附加在节点上的节点个数,(统计父节点上的子节点个数)

创建一个节点对象

Node * Node::create()
{
    Node * ret = new (std::nothrow) Node(); //创建一个名为ret的Node类型的对象
    if (ret && ret->init())									//判断ret是否创建成功并初始化对象ret
    {
        ret->autorelease();									//将对象ret加入内存自动回收池
    }
    else
    {
        CC_SAFE_DELETE(ret);								//如果创建对象失败,删除这个对象
    }
    return ret;															//返回创建成功的节点对象ret
}

获取节点依赖的计数器

int Node::getAttachedNodeCount()
{
    return __attachedNodeCount;  //返回被依赖的计数
}

获取节点的描述(获取节点的Tag)

std::string Node::getDescription() const
{
    return StringUtils::format("<Node | Tag = %d", _tag); //返回节点的Tag 
  													// _tag(Node::INVALID_TAG) 实际返回的就是INVALID_TAG
}

初始化器结束


节点的局部层顺序值(LocalZOrder)

LocalZOrder是用于对节点相对于其兄弟节点进行排序的“键”。

节点的父节点将根据LocalZOrder值对所有子节点排序。
如果两个节点具有相同的LocalZOrder,那么首先添加到子数组中的节点将位于数组中另一个节点的前面。

此外,场景图使用中序遍历,先遍历左子树,然后根节点,最后是右子树。
LocalZOrder值< 0的节点是左子树
而LocalZOrder >=0的节点是右子树。

设置节点的LocalZOrder的值

void Node::setLocalZOrder(std::int32_t z)
{
    if (getLocalZOrder() == z) //如果设置前后值相等,不做操作直接返回
        return;
    
    _setLocalZOrder(z); //否则初始化_setLocalZOrder变量
    if (_parent) //如果存在父节点
    {
        _parent->reorderChild(this, z);  //对父节点的子节点顺序重新排序
    }
    _eventDispatcher->setDirtyForNode(this); //将这个节点加入到事件调度中(加入节点监听器中,并将子节点也做相同操作)
}
//兼容旧版本
CC_DEPRECATED_ATTRIBUTE virtual void setZOrder(std::int32_t localZOrder) { setLocalZOrder(localZOrder); }

获取节点的LocalZOrder的值

virtual std::int32_t getLocalZOrder() const { return _localZOrder; }
//兼容旧版本
CC_DEPRECATED_ATTRIBUTE virtual std::int32_t getZOrder() const { return getLocalZOrder(); }

相同等级子节点具有相同ZOrder时设置绘制顺序

void updateOrderOfArrival();

节点的全局层顺序值(GlobalZOrder)

设置节点的GlobalZOrder值

定义节点渲染的顺序。
globalZOrder较低的节点首先渲染。

如果两个或多个节点具有相同的globalZOrder,则不保证渲染顺序。
当节点的globalZOrder == 0时。在这种情况下,使用场景图顺序。

默认情况下,所有节点的globalZOrder为0。这意味着默认情况下,一定会使用场景图顺序用于呈现节点。

当需要以 与场景图顺序不同的顺序 呈现节点时,GlobalZOrder非常有用。

void Node::setGlobalZOrder(float globalZOrder)
{
    if (_globalZOrder != globalZOrder) //如果设置前后不相等
    {
        _globalZOrder = globalZOrder;  //给_globalZOrder赋值
        _eventDispatcher->setDirtyForNode(this);  //将这个节点加入到事件调度中(加入节点监听器中,并将子节点也做相同操作)
    }
}

获取节点的GlobalZOrder值

virtual float getGlobalZOrder() const { return _globalZOrder; }

节点的缩放(scale)

设置缩放大小

//设置一个比例因子,用于乘以节点及其 子节点 的宽度。
void Node::setScaleX(float scaleX)
{
    if (_scaleX == scaleX)
        return;
    
    _scaleX = scaleX;
    _transformUpdated = _transformDirty = _inverseDirty = true; 
}
//设置一个比例因子,用于乘以节点及其 子节点 的高度。
void Node::setScaleY(float scaleY)
{
    if (_scaleY == scaleY)
        return;
    
    _scaleY = scaleY;
    _transformUpdated = _transformDirty = _inverseDirty = true;
}
//设置一个比例因子,用于乘以节点及其 子节点 的高度。
void Node::setScaleZ(float scaleZ)
{
    if (_scaleZ == scaleZ)
        return;
    
    _scaleZ = scaleZ;
    _transformUpdated = _transformDirty = _inverseDirty = true;
}
//设置一个比例因子,用于乘以节点及其 子节点 的宽度、高度、深度。
void Node::setScale(float scale)
{
    if (_scaleX == scale && _scaleY == scale && _scaleZ == scale)
        return;
    
    _scaleX = _scaleY = _scaleZ = scale;
    _transformUpdated = _transformDirty = _inverseDirty = true;
}
//它是一个比例因子,乘以节点及其子节点的宽度和高度。
void Node::setScale(float scaleX,float scaleY)
{
    if (_scaleX == scaleX && _scaleY == scaleY)
        return;
    
    _scaleX = scaleX;
    _scaleY = scaleY;
    _transformUpdated = _transformDirty = _inverseDirty = true; //标记脏数据
}

获取缩放大小

float Node::getScaleX() const
{
    return _scaleX;
}
float Node::getScaleY() const
{
    return _scaleY;
}
float Node::getScaleZ() const
{
    return _scaleZ;
}

//获取节点的缩放因子,当X和Y具有相同的缩放因子时
float Node::getScale(void) const
{
    CCASSERT( _scaleX == _scaleY, "CCNode#scale. ScaleX != ScaleY. Don't know which one to return"); // ?
    return _scaleX;
}

节点位置(pisition)

设置节点在父坐标系中的位置

//设置x,y轴的位置
void Node::setPosition(const Vec2& position)
{
    setPosition(position.x, position.y);  //(x, y)
}
//使用0-1设置x,y轴的位置
void Node::setPositionNormalized(const Vec2& position)
{
    if (_normalizedPosition.equals(position)) //修改前后相等,不做修改直接返回
        return;

    _normalizedPosition = position;  //给_normalizedPosition赋值
    _usingNormalizedPosition = true;  //标记 使用规范化位置
    _normalizedPositionDirty = true;	//标记 使用规范化位置的Dirty  // ? 标记脏数据
    _transformUpdated = _transformDirty = _inverseDirty = true;  // ? 标记脏数据重新计算渲染坐标矩阵  //在上面的修改之后,渲染用的坐标系矩阵未经计算,造成值的不对应,在当调用getNodeToParentTransform() 重新计算渲染用的坐标系矩阵之后会使用修改之后的值渲染,渲染之后的值对应了,不存在脏数据了,会将_transformDirty再设为false
}
//直接使用x、y设置位置
virtual void setPosition(float x, float y);
virtual void getPosition(float* x, float* y) const;
virtual void  setPositionX(float x);
virtual float getPositionX(void) const;
virtual void  setPositionY(float y);
virtual float getPositionY(void) const;
//设置节点的三维属性
void Node::setPosition3D(const Vec3& position)
{
    setPositionZ(position.z);
    setPosition(position.x, position.y);
}
//设置三维的z坐标
virtual void setPositionZ(float positionZ)
{
    if (_positionZ == positionZ)
        return;
    
    _transformUpdated = _transformDirty = _inverseDirty = true;

    _positionZ = positionZ;
}

获取节点在父坐标系中的位置

//_position
const Vec2& Node::getPosition() const
{
    return _position;
}
//获取节点的规范化位置 0-1
const Vec2& Node::getPositionNormalized() const
{
    return _normalizedPosition;
}
//获取节点的三维属性
Vec3 Node::getPosition3D() const
{
    return Vec3(_position.x, _position.y, _positionZ);
}
//获取节点的z坐标
float Node::getPositionZ() const
{
    return _positionZ;
}

兼容旧版本

virtual void setNormalizedPosition(const Vec2 &position) { setPositionNormalized(position); }

virtual const Vec2& getNormalizedPosition() const { return getPositionNormalized(); }

CC_DEPRECATED_ATTRIBUTE virtual void setVertexZ(float vertexZ) { setPositionZ(vertexZ); }

CC_DEPRECATED_ATTRIBUTE virtual float getVertexZ() const { return getPositionZ(); }

节点倾斜(Skew)

设置倾斜角

void Node::setSkewX(float skewX)
{
    if (_skewX == skewX)
        return;
    
    _skewX = skewX;
    _transformUpdated = _transformDirty = _inverseDirty = true;
}
void Node::setSkewY(float skewY)
{
    if (_skewY == skewY)
        return;
    
    _skewY = skewY;
    _transformUpdated = _transformDirty = _inverseDirty = true;
}

获取倾斜角

float Node::getSkewX() const
{
    return _skewX;
}
float Node::getSkewY() const
{
    return _skewY;
}

节点锚点(AnchorPoint)

锚点是所有转换和定位操作发生的点。
它就像节点上的一个大头针,它被“连接”到它的父节点上。
锚点是标准化的,比如百分比。(0,0)表示左下角,(1,1)表示右上角。
但是也可以使用大于(1,1)和小于(0,0)的值。
默认锚点是(0,0),因此它从节点的左下角开始。

设置锚点

//以百分比设置锚点
void Node::setAnchorPoint(const Vec2& point)
{
    if (! point.equals(_anchorPoint))
    {
        _anchorPoint = point;
        _anchorPointInPoints.set(_contentSize.width * _anchorPoint.x, _contentSize.height * _anchorPoint.y);
        _transformUpdated = _transformDirty = _inverseDirty = true;
    }
}

获取锚点

//以百分比为单位返回锚点
const Vec2& Node::getAnchorPoint() const
{
    return _anchorPoint;
}
//以绝对像素点为单位返回锚点
const Vec2& Node::getAnchorPointInPoints() const
{
    return _anchorPointInPoints;
}

设置节点的锚点是否为(0,0)

//默认值为false,而在图层和场景中为true
void Node::setIgnoreAnchorPointForPosition(bool newValue)
{
    if (newValue != _ignoreAnchorPointForPosition) 
    {
        _ignoreAnchorPointForPosition = newValue;
        _transformUpdated = _transformDirty = _inverseDirty = true;
    }
}
//兼容旧版本
CC_DEPRECATED_ATTRIBUTE virtual void ignoreAnchorPointForPosition(bool ignore) { setIgnoreAnchorPointForPosition(ignore); }

获取节点的锚点是否是(0,0)

bool Node::isIgnoreAnchorPointForPosition() const
{
    return _ignoreAnchorPointForPosition;
}

节点的原始大小(ContentSize)

设置节点的原始大小

void Node::setContentSize(const Size & size)
{
    if (! size.equals(_contentSize))
    {
        _contentSize = size;

        _anchorPointInPoints.set(_contentSize.width * _anchorPoint.x, _contentSize.height * _anchorPoint.y);
        _transformUpdated = _transformDirty = _inverseDirty = _contentSizeDirty = true;
    }
}

获取节点的原始大小

const Size& Node::getContentSize() const
{
    return _contentSize;
}

节点可见性(Visible)

设置节点可见性

//默认为可见的
void Node::setVisible(bool visible)
{
    if(visible != _visible)
    {
        _visible = visible;
        if(_visible)
            _transformUpdated = _transformDirty = _inverseDirty = true;
    }
}

确定节点是否可见

//可见即返回true,不可见返回false
bool Node::isVisible() const
{
    return _visible;
}

##节点的旋转角度(Rotation)

设置节点的旋转角度

//设置节点的旋转角度,这里是直接旋转,和下面的RotationSkew不一样
void Node::setRotation(float rotation)
{
    if (_rotationZ_X == rotation)
        return;
    
    _rotationZ_X = _rotationZ_Y = rotation;
    _transformUpdated = _transformDirty = _inverseDirty = true;
    
    updateRotationQuat();    //?
}

获取节点的旋转角度

float Node::getRotation() const
{
    CCASSERT(_rotationZ_X == _rotationZ_Y, "CCNode#rotation. RotationX != RotationY. Don't know which one to return");
    return _rotationZ_X;
}

节点的3d旋转(Rotation3D)

设置节点的3d旋转

void Node::setRotation3D(const Vec3& rotation)
{
    if (_rotationX == rotation.x &&
        _rotationY == rotation.y &&
        _rotationZ_X == rotation.z)
        return;
    
    _transformUpdated = _transformDirty = _inverseDirty = true;

    _rotationX = rotation.x;
    _rotationY = rotation.y;

    // rotation Z is decomposed in 2 to simulate Skew for Flash animations
  	//模拟flash动画的倾斜
    _rotationZ_Y = _rotationZ_X = rotation.z;
    
    updateRotationQuat();
}

获取节点的3d旋转

Vec3 Node::getRotation3D() const
{
    // rotation Z is decomposed in 2 to simulate Skew for Flash animations
    CCASSERT(_rotationZ_X == _rotationZ_Y, "_rotationZ_X != _rotationZ_Y");

    return Vec3(_rotationX,_rotationY,_rotationZ_X);
}

节点的四元数(Quat)

对于四元数的学习可以看我的另外一篇博客
cocos2dx 四元数

设置节点的四元数

//按四元数设置旋转
void Node::setRotationQuat(const Quaternion& quat)
{
    _rotationQuat = quat;
    updateRotation3D();
    _transformUpdated = _transformDirty = _inverseDirty = true;
}

获取节点的四元数

Quaternion Node::getRotationQuat() const
{
    return _rotationQuat;
}

节点的旋转倾斜(RotationSkew)

设置旋转倾斜

//设置水平旋转倾斜,模拟Flash的歪斜功能
void Node::setRotationSkewX(float rotationX)
{
    if (_rotationZ_X == rotationX)
        return;
    
    _rotationZ_X = rotationX;
    _transformUpdated = _transformDirty = _inverseDirty = true;
    
    updateRotationQuat();
}
//设置垂直旋转倾斜的角度,模拟Flash的歪斜功能
void Node::setRotationSkewY(float rotationY)
{
    if (_rotationZ_Y == rotationY)
        return;
    
    _rotationZ_Y = rotationY;
    _transformUpdated = _transformDirty = _inverseDirty = true;
    
    updateRotationQuat();
}

获取旋转倾斜

float Node::getRotationSkewX() const
{
    return _rotationZ_X;
}
float getRotationSkewY() const
{
    return _rotationZ_Y;
}

兼容旧版本

CC_DEPRECATED_ATTRIBUTE virtual void setRotationX(float rotationX) { return setRotationSkewX(rotationX); }

CC_DEPRECATED_ATTRIBUTE virtual void setRotationY(float rotationY) { return setRotationSkewY(rotationY); }

C_DEPRECATED_ATTRIBUTE virtual float getRotationY() const { return getRotationSkewY(); }

子节点(Child)

添加子节点

void Node::addChild(Node *child)
{
    CCASSERT( child != nullptr, "Argument must be non-nil"); //判断节点是否是空节点
    this->addChild(child, child->getLocalZOrder(), child->_name);//
}
//添加子节点同时设置localZOrder属性
void Node::addChild(Node *child, int zOrder)
{
    CCASSERT( child != nullptr, "Argument must be non-nil");
    this->addChild(child, zOrder, child->_name);
}
//添加子节点同时设置localZOrder和tag属性
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);
}
//添加子节点同时设置localZOrder和name属性
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 Node::addChildHelper(Node* child, int localZOrder, int tag, const std::string &name, bool setTag)
{
    auto assertNotSelfChild
        ( [ this, child ]() -> bool
          {
              for ( Node* parent( getParent() ); parent != nullptr;
                    parent = parent->getParent() )
                  if ( parent == child )
                      return false;
              
              return true;
          } );
    (void)assertNotSelfChild;
    
    CCASSERT( assertNotSelfChild(),
              "A node cannot be the child of his own children" );
    
    if (_children.empty())
    {
        this->childrenAlloc();
    }
    
    this->insertChild(child, localZOrder);
    
    if (setTag)
        child->setTag(tag);
    else
        child->setName(name);
    
    child->setParent(this);

    child->updateOrderOfArrival();

    if( _running )
    {
        child->onEnter(); //调用onEnter 增加依附计数 完成过渡
        // prevent onEnterTransitionDidFinish to be called twice when a node is added in onEnter
        if (_isTransitionFinished)
        {
            child->onEnterTransitionDidFinish(); //结束过渡
        }
    }
    
    if (_cascadeColorEnabled)
    {
        updateCascadeColor();
    }
    
    if (_cascadeOpacityEnabled)
    {
        updateCascadeOpacity();
    }
}

获取子节点

//遍历子节点,通过tag找到所需的节点
Node* Node::getChildByTag(int tag) const
{
    CCASSERT(tag != Node::INVALID_TAG, "Invalid tag");

    for (const auto child : _children)
    {
        if(child && child->_tag == tag)
            return child;
    }
    return nullptr;
}
//返回具有给定名称的节点,该节点可以转换为类型T
template <typename T>
    T getChildByTag(int tag) const { return static_cast<T>(getChildByTag(tag)); }
//通过name找到所需的节点
Node* Node::getChildByName(const std::string& name) const
{
    CCASSERT(!name.empty(), "Invalid name"); //需要有名字
    
    std::hash<std::string> h;
    size_t hash = h(name);
    
    for (const auto& child : _children)
    {
        // Different strings may have the same hash code, but can use it to compare first for speed
        if(child->_hashOfName == hash && child->_name.compare(name) == 0)
            return child;
    }
    return nullptr;
}
//返回具有给定名称的节点,该节点可以转换为类型T
 template <typename T>
    T getChildByName(const std::string& name) const { return static_cast<T>(getChildByName(name)); }
//查找节点
//  '//':只能放在搜索字符串的开头。这表明它将递归搜索。
//  '..':搜索应该向上移动到节点的父节点。只能放在字符串的末尾。
//  '/' :当搜索字符串放置在除开始位置以外的任何位置时,这表示搜索应该移动到节点的子节点。
//例如:
//enumerateChildren("//MyName", ...)  // 递归查找子节点
//enumerateChildren("[[:alnum:]]+", ...) // 匹配子节点的每个节点
//enumerateChildren("A[[:digit:]]", ...) // 查找A0-A9
//enumerateChildren("Abby/Normal", ...)  // 搜索并返回名为Normal父节点为Abby的任何节点
//enumerateChildren("//Abby/Normal", ...) // 递归搜索并返回名为Normal父节点为Abby的任何节点
void Node::enumerateChildren(const std::string &name, std::function<bool (Node *)> callback) const
{
    CCASSERT(!name.empty(), "Invalid name");
    CCASSERT(callback != nullptr, "Invalid callback function");
    
    size_t length = name.length();
    
    size_t subStrStartPos = 0;  // sub string start index
    size_t subStrlength = length; // sub string length
    
    // Starts with '//'?
    bool searchRecursively = false;
    if (length > 2 && name[0] == '/' && name[1] == '/')
    {
        searchRecursively = true;
        subStrStartPos = 2;
        subStrlength -= 2;
    }
    
    // End with '/..'?
    bool searchFromParent = false;
    if (length > 3 &&
        name[length-3] == '/' &&
        name[length-2] == '.' &&
        name[length-1] == '.')
    {
        searchFromParent = true;
        subStrlength -= 3;
    }
    
    // Remove '//', '/..' if exist
    std::string newName = name.substr(subStrStartPos, subStrlength);

    if (searchFromParent)
    {
        newName.insert(0, "[[:alnum:]]+/");
    }
    
    
    if (searchRecursively)
    {
        // name is '//xxx'
        doEnumerateRecursive(this, newName, callback);
    }
    else
    {
        // name is xxx
        doEnumerate(newName, callback);
    }
}
//返回节点的子节点数组
virtual Vector<Node*>& getChildren() { return _children; }
virtual const Vector<Node*>& getChildren() const { return _children; }
//获取子节点的个数
ssize_t Node::getChildrenCount() const
{
    return _children.size();
}

添加父节点

void Node::setParent(Node * parent)
{
    _parent = parent;
    _transformUpdated = _transformDirty = _inverseDirty = true;
}

获取父节点

virtual Node* getParent() { return _parent; }
virtual const Node* getParent() const { return _parent; }

移除(remove)

//将这个节点从父节点中移除,如果没有父节点则不操作
void Node::removeFromParent()
{
    this->removeFromParentAndCleanup(true);
}
void Node::removeFromParentAndCleanup(bool cleanup)
{
    if (_parent != nullptr)
    {
        _parent->removeChild(this,cleanup);
    } 
}
void ParallaxNode::removeChild(Node* child, bool cleanup)
{
    for( int i=0;i < _parallaxArray->num;i++)
    {
        PointObject *point = (PointObject*)_parallaxArray->arr[i];
        if (point->getChild() == child)
        {
            ccArrayRemoveObjectAtIndex(_parallaxArray, i, true);
            break;
        }
    }
    Node::removeChild(child, cleanup);
}
//移除子节点
//如果所有正在运行的动作和回调函数都在子节点上,cleanup为true,否则为false
void Node::removeChild(Node* child, bool cleanup /* = true */)
{
    if (_children.empty())
    {
        return;
    }

    ssize_t index = _children.getIndex(child);
    if( index != CC_INVALID_INDEX )
        this->detachChild( child, index, cleanup );
}
//通过tag移除子节点
void Node::removeChildByTag(int tag, bool cleanup/* = true */)
{
    CCASSERT( tag != Node::INVALID_TAG, "Invalid tag");

    Node *child = this->getChildByTag(tag);

    if (child == nullptr)
    {
        CCLOG("cocos2d: removeChildByTag(tag = %d): child not found!", tag);
    }
    else
    {
        this->removeChild(child, cleanup);
    }
}
//通过Name移除子节点
void Node::removeChildByName(const std::string &name, bool cleanup)
{
    CCASSERT(!name.empty(), "Invalid name");
    
    Node *child = this->getChildByName(name);
    
    if (child == nullptr)
    {
        CCLOG("cocos2d: removeChildByName(name = %s): child not found!", name.c_str());
    }
    else
    {
        this->removeChild(child, cleanup);
    }
}
//移除所有子节点
void Node::removeAllChildren()
{
    this->removeAllChildrenWithCleanup(true);
}
//删除所有子节点,并根据cleanup参数对所有正在运行的操作执行清理(cleanup)
void Node::removeAllChildrenWithCleanup(bool cleanup)
{
    // not using detachChild improves speed here
    for (const auto& child : _children)
    {
        // IMPORTANT:
        //  -1st do onExit
        //  -2nd cleanup
        if(_running)
        {
            child->onExitTransitionDidStart();
            child->onExit();
        }

        if (cleanup)
        {
            child->cleanup();
        }
#if CC_ENABLE_GC_FOR_NATIVE_OBJECTS
        auto sEngine = ScriptEngineManager::getInstance()->getScriptEngine();
        if (sEngine)
        {
            sEngine->releaseScriptObject(this, child);
        }
#endif // CC_ENABLE_GC_FOR_NATIVE_OBJECTS
        // set parent nil at the end
        child->setParent(nullptr);
    }
    
    _children.clear();
}

排序(Sort) !

void Node::reorderChild(Node *child, int zOrder)
{
    CCASSERT( child != nullptr, "Child must be non-nil");
    _reorderChildDirty = true;
    child->updateOrderOfArrival();
    child->_setLocalZOrder(zOrder);
}
//对所有的子节点排序,不需要手动调用,只会在绘制之前执行一次,以提高性能
void Node::sortAllChildren()
{
    if (_reorderChildDirty)
    {
        sortNodes(_children);
        _reorderChildDirty = false;
        _eventDispatcher->setDirtyForNode(this);
    }
}
//    
template<typename _T> inline
    static void sortNodes(cocos2d::Vector<_T*>& nodes)
    {
        static_assert(std::is_base_of<Node, _T>::value, "Node::sortNodes: Only accept derived of Node!");
#if CC_64BITS
        std::sort(std::begin(nodes), std::end(nodes), [](_T* n1, _T* n2) {
            return (n1->_localZOrder$Arrival < n2->_localZOrder$Arrival);
        });
#else
        std::sort(std::begin(nodes), std::end(nodes), [](_T* n1, _T* n2) {
            return (n1->_localZOrder == n2->_localZOrder && n1->_orderOfArrival < n2->_orderOfArrival) || n1->_localZOrder < n2->_localZOrder;
        });
#endif
    }

数据和用户标签

设置

UserData基本不用,一般使用UserDefault来记录数据,生成类似xml的文件。

    virtual void setTag(int tag);
    virtual void setName(const std::string& name);
    virtual void setUserData(void *userData);//可以看到这里的UserData是void类型的,也就是说可以记录任意数据
    virtual void setUserObject(Ref *userObject);  

获取

    virtual int getTag() const;
    virtual const std::string& getName() const;
    virtual void* getUserData() { return _userData; }
    virtual const void* getUserData() const { return _userData; }
    virtual Ref* getUserObject() { return _userObject; }
    virtual const Ref* getUserObject() const { return _userObject; }
    virtual int getTag() const;
    virtual const std::string& getName() const;
    virtual void* getUserData() { return _userData; }
    virtual const void* getUserData() const { return _userData; }
    virtual Ref* getUserObject() { return _userObject; }
    virtual const Ref* getUserObject() const { return _userObject; }

OPenGL

获取OPenGL程序的状态

//每个node私有的状态
GLProgram * Node::getGLProgram() const
{
    return _glProgramState ? _glProgramState->getGLProgram() : nullptr;
}
//兼容旧版本
CC_DEPRECATED_ATTRIBUTE GLProgram* getShaderProgram() const { return getGLProgram(); }
//通用的状态
GLProgramState* Node::getGLProgramState() const
{
    return _glProgramState;
}

设置OPenGL程序的状态

//设置私有的程序状态
void Node::setGLProgram(GLProgram* glProgram)
{
    if (_glProgramState == nullptr || (_glProgramState && _glProgramState->getGLProgram() != glProgram))
    {
        CC_SAFE_RELEASE(_glProgramState);
        _glProgramState = GLProgramState::getOrCreateWithGLProgram(glProgram);
        _glProgramState->retain();

        _glProgramState->setNodeBinding(this);
    }
}
//兼容旧版本
CC_DEPRECATED_ATTRIBUTE void setShaderProgram(GLProgram *glprogram) { setGLProgram(glprogram); }
//设置通用的程序状态
void Node::setGLProgramState(cocos2d::GLProgramState* glProgramState)
{
    if (glProgramState != _glProgramState)
    {
        CC_SAFE_RELEASE(_glProgramState);
        _glProgramState = glProgramState;
        CC_SAFE_RETAIN(_glProgramState);

        if (_glProgramState)
            _glProgramState->setNodeBinding(this);
    }
}

isRunning()

//返回节点是否正在运行
//如果节点正在运行,它将接受onEnter()、onExit()、update()等事件回调
bool Node::isRunning() const
{
    return _running;
}

onEnter()

//过渡效果开始之前调用,预处理一些动作
void Node::onEnter()
{
    if (!_running) //没有运行说明还未依附,之后依附,给依附计数器+1
    {
        ++__attachedNodeCount;
    }
#if CC_ENABLE_SCRIPT_BINDING
    if (_scriptType == kScriptTypeJavascript)
    {
        if (ScriptEngineManager::sendNodeEventToJS(this, kNodeOnEnter))
            return;
    }
#endif
    
    if (_onEnterCallback)
        _onEnterCallback(); //调用自己的回调函数

    if (_componentContainer && !_componentContainer->isEmpty())
    {
        _componentContainer->onEnter();
    }
    
    _isTransitionFinished = false;
    
    for( const auto &child: _children) //子节点也会进入场景
        child->onEnter();
    
    this->resume();
    
    _running = true; //已经依附
    
#if CC_ENABLE_SCRIPT_BINDING
    if (_scriptType == kScriptTypeLua)
    {
        ScriptEngineManager::sendNodeEventToLua(this, kNodeOnEnter);
    }
#endif
}
//完全进入场景时调用,添加背景乐等动作
void Node::onEnterTransitionDidFinish()
{
#if CC_ENABLE_SCRIPT_BINDING
    if (_scriptType == kScriptTypeJavascript)
    {
        if (ScriptEngineManager::sendNodeEventToJS(this, kNodeOnEnterTransitionDidFinish))
            return;
    }
#endif
    
    if (_onEnterTransitionDidFinishCallback)
        _onEnterTransitionDidFinishCallback(); //调用结束过渡的回调函数

    _isTransitionFinished = true;
    for( const auto &child: _children) //子节点同步
        child->onEnterTransitionDidFinish();
    
#if CC_ENABLE_SCRIPT_BINDING
    if (_scriptType == kScriptTypeLua)
    {
        ScriptEngineManager::sendNodeEventToLua(this, kNodeOnEnterTransitionDidFinish);
    }
#endif
}

onExit()

/* if(_running)
        {
            child->onExitTransitionDidStart();
            child->onExit();
        }
*/ //belong to void Node::removeAllChildren()

//在退出场景之前调用
void Node::onExitTransitionDidStart()
{
#if CC_ENABLE_SCRIPT_BINDING
    if (_scriptType == kScriptTypeJavascript)
    {
        if (ScriptEngineManager::sendNodeEventToJS(this, kNodeOnExitTransitionDidStart))
            return;
    }
#endif
    
    if (_onExitTransitionDidStartCallback)
        _onExitTransitionDidStartCallback(); //调用回调函数
    
    for( const auto &child: _children) //子节点同步
        child->onExitTransitionDidStart();
    
#if CC_ENABLE_SCRIPT_BINDING
    if (_scriptType == kScriptTypeLua)
    {
        ScriptEngineManager::sendNodeEventToLua(this, kNodeOnExitTransitionDidStart);
    }
#endif
}


//退出场景时调用
void Node::onExit()
{
    if (_running)
    {
        --__attachedNodeCount; //依附计数器-1
    }
#if CC_ENABLE_SCRIPT_BINDING
    if (_scriptType == kScriptTypeJavascript)
    {
        if (ScriptEngineManager::sendNodeEventToJS(this, kNodeOnExit))
            return;
    }
#endif
    
    if (_onExitCallback)
        _onExitCallback(); //调用自己的回调函数
    
    if (_componentContainer && !_componentContainer->isEmpty())
    {
        _componentContainer->onExit();
    }
    
    this->pause(); //暂停事务
    
    _running = false; //不在运行中
    
    for( const auto &child: _children) //子节点也会被退出
        child->onExit(); 
    
#if CC_ENABLE_SCRIPT_BINDING
    if (_scriptType == kScriptTypeLua)
    {
        ScriptEngineManager::sendNodeEventToLua(this, kNodeOnExit);
    }
#endif
}

cleanup()

//停止所有的操作和调度器
void Node::cleanup()
{
#if CC_ENABLE_SCRIPT_BINDING
    if (_scriptType == kScriptTypeJavascript)
    {
        if (ScriptEngineManager::sendNodeEventToJS(this, kNodeOnCleanup))
            return;
    }
    else if (_scriptType == kScriptTypeLua)
    {
        ScriptEngineManager::sendNodeEventToLua(this, kNodeOnCleanup);
    }
#endif // #if CC_ENABLE_SCRIPT_BINDING
    
    // actions 
    this->stopAllActions();  
    // timers
    this->unscheduleAllCallbacks();  

    
    for( const auto &child: _children) //子节点同步
        child->cleanup();
}

补充:
1、GlobalZorder、LocalZorder和orderOfArrival的区别
//渲染的优先级是Globalzorder > LocalZorder > orderOfArrival,类似于权重
值越大的越迟渲染,因为节点是使用二叉树的中序遍历来渲染的。
会将所有Globalzorder < 0,Globalzorder > 0,Globalzorder > 0,的节点都放在数组中。
localZorder区别节点本身与兄弟节点的渲染顺序,当两个或多个节点的localZorder值相等时会比较orderOfArrival的值。
orderOfArrival的值不需要人为的特别设置,在给节点添加子节点时会自动的自增, orderOfArrival的值默认为0。

2、setIgnoreAnchorPointForPosition();//一般Node的锚点默认为(0.5, 0.5),而Layer的锚点则在左下角(0,0),这个函数用来给Layer使用,layer的_ignoreAnchorPointForPosition值默认为true,忽略了锚点设置,如果自己设置了锚点也不会生效getChildren()

3、getChildren()有const修饰的问题 如果节点被const修饰,则只能调用被const修饰的getChildren函数。

4、_componentContainer的问题 相当于级联的操作

posted @ 2019-07-25 10:16  软不隆咚的二更  阅读(310)  评论(0编辑  收藏  举报