本人未使用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;
});