CocosCreator 3.7.3 - 平铺节点组件 NodeTileHelper
因为在ScrollerView或者Layout中总会排列一些相同的Item节点。

比如图中2个Item,按正常节点树的遍历顺序是 Item、sp1、lb1、lb2、sp2、lb3、 Item、sp1、lb1、lb2、sp2、lb3。
由于Label和Sprite的材质不同,所以合批会被打断,最终DC会变高。
按照这种遍历顺序 总DC = Item的DC * Item的个数。
于是有了另一个思路,希望遍历的顺序是 Item、Item、sp1、 sp1、lb1、lb1、lb2、lb2、sp2、sp2、lb3、lb3。
这样不同的Item之间不会打断合批, 总DC = Item的DC,在一些显示多个相同Item的场景下可以大大降低DC。
开始实现。
1、得到并存储我们想要的遍历顺序
对该组件下的子节点采取平铺遍历的方式。
即相当于对所有子节点同时按照节点树的顺序去遍历。
如上图,即为 Item、Item => sp1、sp1 => lb1、lb1 => lb2、lb2 => sp2、sp2 => lb3、lb3
最开始按照面对对象的思想,给每个Item配一个迭代器Iterator,每次所有迭代器调用next()按照节点树的顺序向下遍历一个节点,将得到的节点存入_tileChildren数组中。
直到next()均为空。
后来考虑到多层平铺,就不太方便了,然后采取了下面这种函数式迭代的方式来实现。
特点就是比如第一层平铺在Layout上挂载,当Item中有一个子节点需要平铺,遍历到该子节点的时候,会将所有Item的这个子节点联合起来平铺,平铺效果最大化。
记录思路(隔了一段时间再看,好久才看懂,哈哈,记录一下):
1、_titleChildren 平铺遍历顺序结果
tempStack 当前处理的这一层节点
stack 待处理的若干层节点
endStack 待处理的每一层的终止节点
childStack 当前处理层的若干层子节点
childEndStack 当前处理层的若干层的终止节点
2、挂载了该组件的是content节点,下面是若干结构类似的Item节点
3、将Item节点入stack和endStack作为初始化状态
4、每次根据stack和endStack拿到当前要处理的这一层节点,存入tempStack中
5、遍历当前tempStack中的当前层节点,idx = 0, idx 自增,根据idx遍历当前层节点的第idx个子节点,flag表示这次遍历第idx个子节点是否为空,若为false则表示当前层节点都没有idx个节点,则表示当前层节点的所有子节点都遍历完了,若为ture,则表示遍历完第idx个节点,需要存入childEndStack。title表示当前层节点是否有平铺组件,当有平铺组件的时候则该层下为若干Item,希望它们都能算同一层不打断。所以flag=true且title=false的时候,表示有idx子节点且无平铺,所以可以存入childEndStack,还有一种情况需要存入childEndStack就是tile=true时,中间不会存终止节点,所以当flag=false,表示当前层都处理完的时候,存入最后一个作为终止节点。
2、让引擎按照我们的顺序去渲染该节点
目前我只在Web进行了实现。
从director的tick()函数看起,一层一层往下,可以看到,最终遍历节点、填充渲染数据的操作是在batcher-2d的walk()函数中。

绿框中是原代码,红色框中是我添加的代码,我希望它在处理添加了NodeTileHelper组件的节点走我的逻辑。
先分析一下它原先的walk做了什么。
1、计算得到当前node的最终透明度,并设置到uiProps
2、填充数据
3、当有子节点的时候,递归处理,它的父节点的透明度的存储也是利用了递归,挺巧妙的,但是我用不上。
现在实现我们的逻辑。

我做的事情很简单,就是迭代我在NodeTileHelper中存储的顺序。
只是我对节点透明度的计算,直接读父节点的透明度,没利用递归来存储,不方便,我感觉也没必要。
其它部分就是复用原walk()的逻辑,因为我也不是很懂,所以只改自己懂的部分,哈哈。
3、编译引擎,看看效果
在Layout组件上挂载上我们的NodeTileHelper。
可以看见多个Item,但是DC只有1个Item的DC,完美。

这个方案有一个显而易见的问题就是,因为我们的顺序是特定的,不是原本的节点树顺序。
当Item有互相遮挡的时候,渲染就会出问题,Item下有2个sprite,sp1和 sp2,sp1是盖上一个Item的sp2上的。
本来按照原先的遍历顺序是sp1、sp2、(Item2的)sp1、sp2,这样是OK的,但是我们的顺序是sp1、sp1、sp2、sp2,那么Item2的sp1就反而是在Item1的后面渲染了。
不过一般来说,Item之前也不会互相遮挡,注意即可。
Over。

浙公网安备 33010602011771号