cocos2d-x通过zOrder来控制每个节点显示出来的顺序原理
我们为了控制一个节点的显示层级关系,通常会用到设置zOrder来控制,那么,其中的原理又是怎样的呢?下面来探究一下。
先上一段测试代码跟资源以及效果
#include "HelloWorldScene.h"
#include "cocostudio/CocoStudio.h"
#include "ui/CocosGUI.h"
USING_NS_CC;
using namespace cocostudio::timeline;
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
auto sp = Sprite::create("cocos-html5.png");
sp->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
this->addChild(sp, 0);
auto sprite1 = Sprite::create("cocos2dbanner.png");
sprite1->setPosition(Vec2(50,100));
sp->addChild(sprite1, 2);
auto sprite2 = Sprite::create("powered.png");
sprite2->setPosition(Vec2(50,50));
sp->addChild(sprite2, -2);
return true;
}
资源
效果
我们首先创建一个精灵,然后向这个精灵中添加两个精灵,一个zorder是正的,一个是负的,可以发现正的显示在它的上面,负的显示在它的下面。为什么呢?
来看看node的visit方法:
void Node::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags)
{
// quick return if not visible. children won't be drawn.
if (!_visible)
{
return;
}
uint32_t flags = processParentFlags(parentTransform, parentFlags);
// IMPORTANT:
// To ease the migration to v3.0, we still support the Mat4 stack,
// but it is deprecated and your code should not rely on it
_director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
_director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
bool visibleByCamera = isVisitableByVisitingCamera();
int i = 0;
if(!_children.empty())
{
sortAllChildren();
// draw children zOrder < 0
for( ; i < _children.size(); i++ )
{
auto node = _children.at(i);
if (node && node->_localZOrder < 0)
node->visit(renderer, _modelViewTransform, flags);
else
break;
}
// self draw
if (visibleByCamera)
this->draw(renderer, _modelViewTransform, flags);
for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
(*it)->visit(renderer, _modelViewTransform, flags);
}
else if (visibleByCamera)
{
this->draw(renderer, _modelViewTransform, flags);
}
_director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
// FIX ME: Why need to set _orderOfArrival to 0??
// Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920
// reset for next frame
// _orderOfArrival = 0;
}
这个方法中我们可以看到, 如果没有子节点的情况下只会把自己给渲染出来,如果有子节点,那么它会先根据其中的zOrder来从小到大排序,然后它先渲染小于0的子节点,再渲染它本身,最后渲染大于0的子节点,这个过程是递归的。由于后面渲染的是显示在前面渲染的上面,所以,我们就不难理解得出这个结论:
一个节点的子节点,如果zorder是小于0,那么显示在这个节点的下面,否则显示在上面;由于是递归的,子节点的子节点的显示是相当于子节点而言的,并不影响这个节点。