本人所用cocos2dx的版本为2.X
众所周知:CCNode的渲染顺序是有两个参数决定的:m_nZOrder,m_uOrderOfArrival;如果m_nZOrder相等,才会比较后一个参数。
渲染子节点之前会先排序子节点:
void CCNode::visit()
{
// quick return if not visible. children won't be drawn.
if (!m_bVisible)
{
return;
}
kmGLPushMatrix();
if (m_pGrid && m_pGrid->isActive())
{
m_pGrid->beforeDraw();
}
this->transform();
CCNode* pNode = NULL;
unsigned int i = 0;
if(m_pChildren && m_pChildren->count() > 0)
{
<span style="color:#ff0000;">sortAllChildren();</span>
// draw children zOrder < 0
ccArray *arrayData = m_pChildren->data;
for( ; i < arrayData->num; i++ )
{
pNode = (CCNode*) arrayData->arr[i];
if ( pNode && pNode->m_nZOrder < 0 )
{
pNode->visit();
}
else
{
break;
}
}
// self draw
this->draw();
for( ; i < arrayData->num; i++ )
{
pNode = (CCNode*) arrayData->arr[i];
if (pNode)
{
pNode->visit();
}
}
}
else
{
this->draw();
}
// reset for next frame
m_uOrderOfArrival = 0;
if (m_pGrid && m_pGrid->isActive())
{
m_pGrid->afterDraw(this);
}
kmGLPopMatrix();
}
void CCNode::sortAllChildren()
{
if (m_bReorderChildDirty)
{
int i,j,length = m_pChildren->data->num;
CCNode ** x = (CCNode**)m_pChildren->data->arr;
CCNode *tempItem;
// insertion sort
for(i=1; i<length; i++)
{
tempItem = x[i];
j = i-1;
//continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller
while(j>=0 && ( tempItem->m_nZOrder < x[j]->m_nZOrder || ( tempItem->m_nZOrder== x[j]->m_nZOrder && tempItem->m_uOrderOfArrival < x[j]->m_uOrderOfArrival ) ) )
{
x[j+1] = x[j];
j = j-1;
}
x[j+1] = tempItem;
}
//don't need to check children recursively, that's done in visit of each child
m_bReorderChildDirty = false;
}
}
一般情况下我们利用第三方UI编辑器编辑界面的过程中很少手动设置m_nZOder ,会默认使用系统自然赋值的增长,所以大多数情况下所有的相同父节点的子节点的m_nZOder都是相同的,那么我们就会大量使用到这个m_uOrderOfArrival参数了,虽然系统提供了修改接口,可是我们也很少关注这个。如果有时候我们不注意这个参数可能会有意想到不到的Bug出现。
假如我们在第三方UI编辑器里摆好了UI界面,回到程序中我们想在其中一个节点中动态添加一些子节点,然后显示的修改子节点的m_nZOder ,调用了下面的函数:
void CCNode::setZOrder(int z)
{
_setZOrder(z);
if (m_pParent)
{
m_pParent-><span style="color:#ff0000;">reorderChild</span>(this, z);
}
}
void CCNode::reorderChild(CCNode *child, int zOrder)
{
CCAssert( child != NULL, "Child must be non-nil");
m_bReorderChildDirty = true;
child-><span style="color:#ff0000;">setOrderOfArrival</span>(s_globalOrderOfArrival++);
child->_setZOrder(zOrder);
}
父节点的渲染次序就被偷偷的改变了,解决的方法也很多,写出来只是为了明白产生Bug的原因。