zIndex? 我有解决方案。

本人未使用CocosCreator发布线上项目,未经线上验证,仅供大家学习,目前暂不从事CocosCreator工作。


import * as cc from 'cc';

/**给Node添加__batch_enabled属性 */

cc.Node.prototype.__batch_enabled = false;

/**给Node添加__batch_index属性 */

cc.Node.prototype.__batch_index = 0;

/**主要依据当前版本引擎的batcher-2d.ts调整(native需调整Batcher2d.cpp) */

if (!cc.UI.prototype.__walk_old) {

    cc.UI.prototype.__walk_old = cc.UI.prototype.walk;

    cc.UI.prototype.walk = function (node: cc.Node, level?: number) {

        if (node.__batch_enabled) {

            if (!node.activeInHierarchy) {

                return;

            }

            const childs = m.func.getAllChildren(node);

            childs.sort((a, b) => {

                return a.__batch_index - b.__batch_index;

            });

            childs.forEach(child => {

                const _static = child._static;

                child._static = true;

                this.__walk_old(child, level);

                child._static = _static;

            });

        } else {

            this.__walk_old(node, level);

        }

    }

}

declare module 'cc' {

    /**Node扩展 */

    interface Node {

        /**是否合批子节点 */

        __batch_enabled: boolean

        /**是否合批索引 */

        __batch_index: number

    }

    /**UI扩展 */

    interface UI {

        /**旧walk */

        __walk_old: (node: cc.Node, level?: number) => void

    }

}

/**下面是native实现的demo

 * 参数可以在Node.h中定义__batch_enabled和__batch_index的get和set

 * 重要:经测试引擎版本383,在Node.h直接定义__batch_enabled和__batch_index属性也是可以的

void Batcher2d::walk(Node* node, float parentOpacity, bool bWalkChild) { // NOLINT(misc-no-recursion)

    if (!node->isActiveInHierarchy()) {

        return;

    }

    se::Value value;

    node->getScriptObject()->getProperty("__batch_enabled", &value, true);

    if (bWalkChild && value.toBoolean()) {

        std::vector<Node*> childs;

        getAllChildren(node, childs);

        //使用lambda表达式作为比较函数进行排序

        std::sort(childs.begin(), childs.end(), [](Node* a, Node* b) {

            se::Value valuea;

            a->getScriptObject()->getProperty("__batch_index", &valuea, true);

            se::Value valueb;

            b->getScriptObject()->getProperty("__batch_index", &valueb, true);

            return valuea.toInt32() < valueb.toInt32();

        });

        for(const auto& child : childs) {

            auto* e = static_cast<RenderEntity*>(node->getParent()->getUserData());

            walk(child, node == child ? parentOpacity : (e ? e->getOpacity() : parentOpacity), false);

        }

    } else {

        bool breakWalk = false;

        auto* entity = static_cast<RenderEntity*>(node->getUserData());

        if (entity) {

            if (entity->getColorDirty()) {

                float localOpacity = entity->getLocalOpacity();

                float localColorAlpha = entity->getColorAlpha();

                entity->setOpacity(parentOpacity * localOpacity * localColorAlpha);

                entity->setColorDirty(false);

                entity->setVBColorDirty(true);

            }

            if (math::isEqualF(entity->getOpacity(), 0)) {

                breakWalk = true;

            } else if (entity->isEnabled()) {

                uint32_t size = entity->getRenderDrawInfosSize();

                for (uint32_t i = 0; i < size; i++) {

                    auto* drawInfo = entity->getRenderDrawInfoAt(i);

                    handleDrawInfo(entity, drawInfo, node);

                }

                entity->setVBColorDirty(false);

            }

            if (entity->getRenderEntityType() == RenderEntityType::CROSSED) {

                breakWalk = true;

            }

        }

        if (bWalkChild && !breakWalk) {

            const auto& children = node->getChildren();

            float thisOpacity = entity ? entity->getOpacity() : parentOpacity;

            for (const auto& child : children) {

                // we should find parent opacity recursively upwards if it doesn't have an entity.

                walk(child, thisOpacity);

            }

        }

        // post assembler

        if (_stencilManager->getMaskStackSize() > 0 && entity && entity->isEnabled()) {

            handlePostRender(entity);

        }

    }

}

*/

使用方式

const Node_unit = this.node.getChildByName(`Node_unit`);
const nodes = Node_unit.children;
node.__batch_enabled = true;
nodes.sort((a, b) => {
    return b.position.y - a.position.y;
});
nodes.forEach((node, index) => {
    node.__batch_index = index;
});