
如上图的prefab构造,一个sprite+label。label已打包位图字体。
实例化100个,drawcall能达到200。但如果去掉sprite,drawcall直接掉到个位数。
请问prefab既然会打断drawcall,那他的意义是什么?
我主职是做web开发,习惯了编写一个个组件,再用组件拼接整个程序。一直把prefab当作子组件来用。
既然prefab会打断drawcall。是否意味了我不能使用prefab做逻辑块的划分呢?
而是要手动分组,把sprite和label分别归纳到各自的组中呢?
你使用prefab的思路没有问题,可以在onLoad的时候做一层排序,把相同类型的节点放到一起,例如:
// 把列表中的节点重新排列
bindItems(){
this.itemList = [];
let cont = this.node.getChildByName("top_copy");
for (let i = 0; i < 10; i++) {
let item = this.itemContainer.children[i];
this.itemList.push(item.addComponent(RankListItem));
let node = this.itemList[i].iconSp.node;
node.translate(node.parent.position);
this.itemContainer.addChild(node);
node = this.itemList[i].nameLabel.node;
node.translate(node.parent.position);
cont.addChild(node);
node = this.itemList[i].scoreLabel.node;
node.translate(node.parent.position);
cont.addChild(node);
}
}
我之前在scrollview中是这样写的,写一个类,将prefab实例化的物体的子节点手动拆分放入一个层中,这样相同的子节点就在同一个层中。引擎是通用性的,当然不会针对特定的prefab优化
需要这样子吗,颠覆我的认知了。因为我觉得这种东西不是引擎在底层就该做的吗,居然需要开发者手动做,有点理解不能了 
引擎可以做,但是容易产生“自作聪明”的情况,例如你对item之间的层级有严格要求,那就不能自动分层自动合。我这个例子大多数用于排行榜、背包这种item之间明确不会相互遮挡的UI中
居然要这样,有点理解不了哈哈,感觉这应该是引擎要做的,居然抛给了开发者。
楼上的说的很明白了,在ui上一般使用深度优先遍历,保证父节点先于子节点渲染,同级节点按先后顺序。可以改渲染顺序,但是引擎只会出接口,不会直接给你改
Cocos 在易用性和通用性上,更偏向通用性,这是因为Cocos是开源的,你完全可以自己定制开发,往易用性上靠,Unity那种虽然一开始易用性特别好,但是一旦你想改点这种逻辑,就特别麻烦。。
看了这么多回答,有跑偏题的、有给了解决方案,却没给原因 
我来回答一下吧:
1,首先楼主得出的 prefab会打断drawCall 这个结论是错误的,prefab并不会打断合批。
2,合批的前提的条件是:1,着色器程序必须保持一致(有顶点着器、片元着色器、渲染状态等)2,资源保持一致(texture、顶点数据等)
3,cocos的合批顺序(渲染顺序)是采用的DFS(深度遍历),为什么采用深度遍历?因为用户习惯以及市场上的大部分软件也是这么做的。所以也决定了图像的遮挡关系 下面的渲染组件遮挡了上面的渲染组件。
了解了这么多,再根据上面的原理来分析楼主的问题:
预制体中包含了:一个bg, 两个文图字体。bg与位图是两个不同的texture,因此并不能合批,两个位图可以合批,所以一个预制体需要2个drawCall。实例化100个,所以你会看到200个drawCall。而删除bg ,实例化100个,所有的实例化中的位图字体都可以合批,应该只有1个drawCall。
等你做久了,颠覆你认知的多了去了 
所以要减少drawcall,还是只能改变层级吗?必须把sprite归sprite一组,label归label一组?
哈哈 
根据合批条件与自身的实际情况去修改。有能力就去修改渲染顺序,但是可能会出现其他问题(比如遮挡关系、事件不对等)。不想那么复杂那就把同材质,同纹理的放在一起,这也是最简单的办法。