微信小游戏开发-label优化

label打断合批

渲染批次对游戏的性能有很大的影响,降低渲染批次是提升游戏体验的有效优化方式。通常我们会将游戏中的散图打包成图集,这样做的好处是如果同一个父节点下的子节点所使用的贴图都来自于同一张图集的话,这些子节点的渲染可以在一个drawcall中完成,有效地降低了渲染的批次。
但是我们在使用cocos creator开发的过程中发现,在合并散图之后,战场中的UI渲染批次依然居高不下。通过分析我们发现,战场中的UI使用了许多的label,而cocos在渲染label的时候,会为每个label创建一个离屏的canvas,将文字的渲染结果保存在一张单独的贴图上,这些label的渲染打断了原本合并的批次。如果使用位图字体(BMFont),将文字和数字也打包到图集里面,则可以避免这个问题。

固定的文字

对于游戏中固定的文字,可以直接输出文字对应的贴图来避免label的使用,从而避免合批的打断。

不确定的文字

在游戏中会有XX玩家–击杀–XX玩家的提示性信息,由于玩家的名字在游戏制作过程中是无法确定的,所以玩家的名字需要实时渲染。如果是在每次触发提示的时候去设置label的内容的话,都会触发引擎调用updateLabel重新烘焙label,会造成不必要的卡顿。其实玩家的名字在进入战场的时候就已经知道了,我们完全可以对这些名字进行预烘焙。

我们首先对所有的玩家名字都创建了不同颜色下的label,并手动调用了label的烘焙接口,最后将label缓存起来。由于这些缓存的label没有添加到场景中的节点下,所以label的update不会被触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PutInCache: function (playerName, ObjID) {
//每种颜色创建一个label
for (let i = 0; i < Colors.length; i++) {
if (this.PlayerNameLabelCache[i][ObjID]) { // 去除重复添加
continue;
}
//创建label用于烘焙
let node = cc.instantiate(this.LabelPrefab);
let label = node.getComponent(cc.Label);
label._initSgNode();
label.string = playerName;
//获取渲染节点sgNode
label._sgNode._renderCmd._displayedColor = new cc.Color().fromHEX(Colors[i]);
label._sgNode._renderCmd._bakeLabel();

this.PlayerNameLabelCache[i][ObjID] = label;
}
},

在需要设置玩家名字的时候,我们传入目标label和玩家id。根据颜色和玩家id取出缓存的label,使用缓存label的烘焙结果为目标label的_texture赋值,同时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

GetOutCache: function (targetLabel, ObjID, color, Type) {
let labelCache = this.PlayerNameLabelCache[color][ObjID];
if (labelCache)
{
let node = targetLabel.node;
let contentSize = labelCache._sgNode._contentSize;
//修改节点的大小
targetLabel.node._contentSize = cc.size(contentSize);
targetLabel._sgNode._contentSize = cc.size(contentSize);
//设置纹理
targetLabel._sgNode._renderCmd._texture = labelCache._sgNode._renderCmd._texture;
//将_backLabel置空避免调用updatelabel改变label的大小
targetLabel._sgNode._renderCmd._bakeLabel = function () {
};
}

},