前言:
之前写了一篇优化背包的分层渲染,是通过把一个item拆分出来,让item所有节点同一层级,然后通过改zIndex让节点聚在同一层级,达到分层的效果。
但要处理的手尾太多了,特别涉及父节点变换后,子节点也要跟着变换,自己写太麻烦了。
所以这次直接进行引擎修改,把原本的深度渲染,改为层级渲染。
自从用了层级渲染,打开几个界面,dc基本都在100以下。
使用方法:
1:项目初始化时调用CCCExtend.init().通过这个脚本的初始化,进行引擎渲染流的扩展
2:背包等一些滑动面板的content或需要进行分层渲染的节点,挂上LevelRender组件,挂上组件后,该节点下的所有子节点将进行层级渲染
这样,就能愉快的使用层级渲染了,不单只滑动面板,像主界面有很多规律性很强的按钮,如 背包,坐骑,排行榜这类并排,并且都是一个icon和一个label的拼成的(一般这类按钮都没法合批,除非把字体和icon打图集和一些骚操作)。给这些按钮一个父节点,并且挂上LevelRender组件,这样,这些并排按钮就会合批渲染。
像背包滑动面版这种,无论一个item还是多个item,dc都是一个item的dc数量!
原理:
先看引擎render-flow.js一段代码
// 这是孩子节点进入渲染流的部分
_proto._children = function (node) {
let cullingMask = _cullingMask;
let batcher = _batcher;
let parentOpacity = batcher.parentOpacity;
let opacity = (batcher.parentOpacity *= (node._opacity / 255));
let worldTransformFlag = batcher.worldMatDirty ? WORLD_TRANSFORM : 0;
let worldOpacityFlag = batcher.parentOpacityDirty ? OPACITY_COLOR : 0;
let worldDirtyFlag = worldTransformFlag | worldOpacityFlag;
let children = node._children;
for (let i = 0, l = children.length; i < l; i++) { // 遍历孩子数组
let c = children[i];
c._renderFlag |= worldDirtyFlag; //在节点树中如果有进行过 平移、旋转、缩放、透明度 更改,则该孩子需要重新进行渲染
if (!c._activeInHierarchy || c._opacity === 0) continue;
_cullingMask = c._cullingMask = c.groupIndex === 0 ? cullingMask : 1 << c.groupIndex;
let colorVal = c._color._val;
c._color._fastSetA(c._opacity * opacity);
flows[c._renderFlag]._func(c); // 孩子进入渲染流
c._color._val = colorVal;
}
batcher.parentOpacity = parentOpacity;
this._next._func(node); //进入下一个流程
};
上段代码需要关注的地方是,遍历孩子节点数组,如果孩子节点可见,则孩子节点进入渲染流,孩子进入渲染流后,又会继续遍历孩子数组。。。一直递归到没有孩子为止,当孩子的渲染流完成了,之前的父节点才进行下一个流程。现在需要把这个流程改变,碰到孩子节点时,先不进入孩子渲染流,而是把孩子分层存进一个队列中。
举个例子:现在有一百个item,item是由一个背景和一个Label组成,之前引擎的代码是,进入背景的渲染流时,到达孩子流程时,会遍历孩子数组,发现有一个Label,就会进入Label的渲染流程,等Label的流程结束并且没有孩子时,背景才进入下一个流程。现在稍微改一下,遇到孩子节点时,先不进入孩子的流程,而是进入一个队列renderQueue,这个队列把节点分层,如:[[背景1, 背景2…(共100个背景)], [Label1, Label2…(共100个Label)]],这样就把节点分层了。然后通过以下步骤
1.renderQueue出队,获得第一个数组 [背景1, 背景2…(共100个背景)] ,然后逐个出队,调用flows[c._renderFlag]._func©;进入渲染流,这样就会先将100个背景进入渲染流.
2.renderQueue出队,获得第二个数组 [Label1, Label2…(共100个Label)],然后逐个出队,调用flows[c._renderFlag]._func©;这样就会将100个Label进入渲染流.
3.循环往复。直到renderQueue长度为0.
这样,就完成了层级渲染的部分改造,还有一些改造,如父节点变换后,孩子节点也要跟着变换那些就不说了,感兴趣的可以自行看代码,或者与我交流。遇到问题欢迎指正与提出。
项目中深度渲染和层级渲染搭配使用,能让项目dc大量下降!
注意:
-
label要合批,要符合Label的合批要求,如使用Bitmap或Char模式,或者Bmfont之类的,具体自行了解~
-
引擎渲染流要求是v2.x
-
多个LevelRender,只会最外层的生效
-
使用LevelRender组件的子节点不能有Mask组件
-
demo示例用上循环列表+分帧加载。假设滑动面板显示5x5=25个item,循环列表则创建6x5=30个item,无论一千个还是一万个item,内存中只占30个item的大小。结合层级渲染,能让多item滑动面板性能巨幅提升
最后附运行截图:
图中7个dc,左下角1个,空scroll2个,scrollItem 2个,角色按钮那些2个。
demo.zip (206.3 KB)
附:最近也搞了3.x版本的,有需求可以看看~