1. 程式人生 > >cocos2d-x通過zOrder來控制每個節點顯示出來的順序原理

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,那麼顯示在這個節點的下面,否則顯示在上面;由於是遞迴的,子節點的子節點的顯示是相當於子節點而言的,並不影響這個節點。