节点 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的问题 相当于级联的操作

最新文章

  1. 设计模式--建造者模式Builder(创建型)
  2. Huffman树实现_详细注释
  3. 初步理解JNDI
  4. Hibernate-list()与iterate()方法的区别
  5. 解决redmine写操作很慢的问题
  6. C++: std::string 与 Unicode 结合
  7. 将Windows 7导航窗格中的收藏夹、库、家庭组、网络全部去掉
  8. 【风马一族_Android】强制activity的横屏与纵屏
  9. mongodb的应用场景
  10. 树形dp-hdu-4714-Tree2cycle
  11. Hive和Jdbc示例
  12. 移动端 rem字体的使用demo
  13. 数据结构 链式哈希表(Hash Table)的接口定义与实现分析(完整代码)
  14. Django Haystack 全文检索与关键词高亮
  15. Python 元组内置函数
  16. SVN关于忽略xcuserdata目录
  17. [java]static关键字的四种用法
  18. Visual Studio中Image Watch的使用
  19. php用PDO查询mysql数据库结果中文乱码
  20. [已解决]An unhandled exception occurred while processing the request.

热门文章

  1. qt 利用Qtimer 定时器实现定时消息发送
  2. C++构造函数和文件组织
  3. @codeforces - 631E@ Product Sum
  4. @noi.ac - 442@ 牛羊被他抢了
  5. 为什么有时候Css样式表某个属性引用不成功?
  6. vue-awesome-swiper轮播插件的使用方法及问题。
  7. C++第三次作业:友元类
  8. xshell评估期已过怎么办
  9. HTML静态网页---标签
  10. 精选Pycharm里6大神器插件