cocos creator 优化微信小游戏速度

近期在cocos creator 3.7.2开发微信小游戏过程中,发现微信小游戏的表现比其他平台速度明显慢,尤其在做一些有大量文本的页面时,每次加载都有明显的迟滞感,比在其他平台,如android下,甚至浏览器下都慢很多。花了几天时间优化,最终达到理想效果,比优化前速度提升10倍以上,甚至比原来android app还要快,具体来说:

1. 预编译参数优化

根据cocos creator官网的建议,在内存允许条件下,增加编译条件,就是动态合图:

macro.CLEANUP_IMAGE_CACHE = false;
dynamicAtlasManager.enabled = true;
dynamicAtlasManager.maxFrameSize = 2048;

实际效果不太明显,性能提升有限。

2. label组件优化

由于游戏中某个场景label比较多,经过测试就是label组件拖慢了整体速度,由于是功能所需,不愿意删除label,那么只有全力优化。

2.1 合并相邻label

为减少数量,同时又不减少显示内容,可以将显示风格一致的label用一个label代替。例如:可以一行本身多个label,组合成一个字符串用一个label代替。

还有纵向多行label用一个代替,设置多行字体行间距,是否截断、是否自动换行等等。纵向和横向对齐方式设置。通过合理设置可以到达原来多个label效果。

2.2 合理设置字体缓存模式

缺省情况下label的cache mode为none,这种情况下效率最低,但问题最少,在没有效率问题下,可以采用。采用char模式适合动态变化比较大的情况;bitmap的开销稍大,但兼容性不错,比如一些特殊符号,🥜🚀,类似于这些符号char模式支持比较差,而bitmap模式则没有问题。

2.3 字体本身优化

如果追求最好性能,可以选择位图字体,这样渲染效率最高。但是效果不怎么样,背景抠图和放大效果都不理想。

2.4 合理放置label顺序

这个环节最为关键。根据渲染的规则,同样条件可以合批渲染,但是有个限制就是这些节点必须在一个节点下,而且连续。那么为了管理需要很多时候label和sprite混排,以及分成多个node节点管理的方式有可能导致大量的Draw Call,也就是多次渲染,最终影响效率。优化后,Draw Call数量将减少一大半。

因此,优化label,将一个场景下尽可能多的label设置为相同属性,放置在同一个node下,并且连续放置,中间不要有其他控件。

2.5 减少label属性访问次数

为提高效率,减少了label数量也就减少属性访问次数,为防止对label.string的反复多次修改,可以将字符串单独处理,然后统一赋值给label.string。针对label合并后,多行内容设置问题,可以采用字符串数组进行管理,预先定义字符串数组,甚至可以是多维度:

private labelStrings: string[] = ['','','','','','']

然后对每行单独访问,最后统一赋值:

this.round.string = this.labelString.join('\n');

 3. 启用节点常驻

通过以上方法优化后,对于复杂场景一些页面仍然感觉加载有时延,不够顺畅。这种情况下,可以继续优化,就是将一些页面通过常驻内存方式保留,这样每次调用时不用再次初始化,通过这种方式可以将场景中多次打开窗体的情况变得速度非常快。

3.1 设置常驻节点

核心思想就是将节点拖到常驻的root节点,通常为了播放音乐方便,游戏中会安排一个常驻节点,不妨叫gameRoot,将你的希望常驻节点从canvas直接拖到gameRoot下。另一种方式是代码实现:

director.addPersistRootNode(this.gameNode);

或者:

this.gameNode.parent = this.gameRoot;

gameRoot需要提前在页面编辑部分链接设置,在头部进行定义:

    @property(Node)
    public gameRoot: Node = null;

3.2 显示节点

思想就是将节点移动回到当前场景中

this.gameNode.parent = this.canvas;

这里面需要注意的是,this.gameNode可能因为本身场景的变化,导致this.gameNode的值变成null,这种情况下建议将gameNode保存到一个静态变量中,如定义一个同名的同类下变量,首次运行时保存到静态变量中,以后可以直接读取静态变量。

//定义常驻节点
private static gameNode: Node;
//定义判断是否第一次运行
private static ifFirstRun:Boolean = true;
..
..
//第一次运行赋值
if(GameClass.ifFirstRun){
   GameClass.gameNode = this.gameNode;
   GameClass.ifFirstRun = false;
}
..
..
//用静态变量实现移动节点
GameClass.gameNode.parent = this.canvas;

3.3 关闭常驻节点

显示完成后,实现关闭逻辑有两种方法:1是将节点移动到gameRoot

GameClass.gameNode.parent = this.gameRoot;
GameClass.gameNode.active = false;

那么每次重复打开窗体时,会反复设置parent和active属性,听起来很好,实际操作中发现仍然可能导致性能不够快。

第2种方式,不切换parent,直接把窗体移动到手机视角以外,需要显示时,直接移动回来即可,这种方式速度最快!但缺点是场景结束前必须把他移动到gameRoot中去,否则会被释放掉,下次场景加载时报错!

//移除窗体
gameClass.position = new math.Vec3(2000, 0, 0);
..
..
//显示窗体
gameClass.position = new math.Vec3(0, 0, 0);

4. 场景常驻模式

以上的方法采用后,整体速度就非常快了,重复打开的窗体显示速度都是毫秒级显示,用户感觉不到任何迟滞。但是,但是在特殊情况下,在场景的加载可能耗费较多时间,而游戏可能面临场景切换时候比较多,那能不能干脆把场景直接缓存呢?

在cocos 2d之前版本中有专门的场景切换方法,可以比较容易的保留和缓存场景,在cocos creator 3.0以后,这些方法都没有了,但是仍然可以代码实现缓存的效果,主要有几个要点:

4.1 添加到常驻节点

//定义场景静态变量
public static currentScenceCanvas:Node;
..
..
//首次运行需要设置为常驻节点
GameClass.currentScenceCanvas = director.getScene().getChildByName('Canvas');
director.addPersistRootNode(GameClass.currentScenceCanvas);

要点是只能添加Canvas节点,把它作为场景的root节点,如果场景文件中有和root平行的其他节点,建议移动到CanVas下面,否则不能也缓存。

4.2 使用静态变量

注意要使用静态变量,确保第一次运行时保存到静态变量中去。

4.3 场景显示和关闭

因为被缓存了,所以显示和关闭方法不能使用loadScene方法,只能用active控制。

//打开场景
GameClass.currentScenceCanvas.active = true;    
..
..
//关闭场景
GameClass.currentScenceCanvas.active = false;  

4.4 避免场景切换显示问题

这种方式切换场景可能导致切换后,短暂出现页面显示不正常情况,这是因为需要合理规划页面的显示顺序才能保证显示正确,建议代码:

director.loadScene('gameScene',(error, scene) => {
         this.__enabled = true;
         GameClass.currentScenceCanvas.active = false;    
 });

以上代码示例,确保在新场景已经正常加载后,再隐藏当前场景避免出现显示错误。

4.5 destroy有无必要

从以上优化和显示策略看,如果多个场景切换,有些场景缓存,有些不缓存,那么不缓存的场景调用了缓存场景后,是否需要手动释放空间呢?经过测试不太需要,系统会自己管理和回收内存,不会出现内存泄露情况;另一方面,如果强制destroy,会导致严重的报错情况!如果很多节点有相互关联和引用情况下,非常容易导致程序运行失败,建议不需要手动destroy当前场景。

下面是我的游戏示例,大家可以试试:

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值