TiledMap 地图有哪些优化方法?Cocos Creator 带你从这4个方面入手,实现深度优化...

本文介绍了Cocos Creator中TiledMap地图的优化方法,包括裁剪区域共享、Sprite颜色数据去除、多图集渲染合批和分帧寻路。通过这些策略,实现了20%的渲染耗时降低。文章提供了详细的实现过程和优化效果展示,适用于复杂地图场景的性能提升。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言:如何进行 TiledMap 地图优化?开发者 Bool Chen 将分享一套行之有效的 TiledMap 地图优化方案,其中包括了渲染、解析、寻路方面。

当项目里的地图越来越庞大和复杂,一些性能上的问题也开始逐渐出现。本文将从裁剪区域共享、Sprite 颜色数据去除、多图集渲染合批和分帧寻路四个方面,分享关于 TiledMap 地图的优化以及实现。

d6c85b3b76c59fc33abfc1e4e77ee46d.png

测试用例

本次的测试用例是这样的一张地图,有6个图层,其中4个图块层、2个物件层。测试的数据来源是在浏览器环境下,利用 console.timetimeEnd 函数,打印对应的逻辑耗时或渲染耗时,需要注意的是每次运行的耗时并不是一致的,但是在取均值后,可以认为是相对可靠的。

3b1609e32128d343781e6bfb9690d16c.png

优化前后(注:横轴是游戏运行的帧数,纵轴是在该帧数下,对应的耗时,单位是毫秒)

上图是我们最后将裁剪区域共享+Sprite 颜色数据去除+多图集渲染合批一起使用后的优化效果,测试显示渲染耗时大约降低了20%左右。其实这张地图并不算复杂,如果物件数量、图层数量增加的话,优化效果会更加明显。

本次的主要优化方案参考自大城小胖的《如何重绘<江南百景图>》,文章介绍了很多性能优化技巧,强烈推荐大家去看看。项目基于 Cocos Cocos Creator 2.4.3,不过大部分优化思路在 v3.x 依旧适用。限于篇幅,本文仅呈现部分核心代码,完整代码及测试项目源码下载见文末。

裁剪区域共享

玩家操控人物在地图上移动的时候,地图显示的内容也需要跟随人物的位置发生改变。此时,为了优化性能,引擎会计算屏幕的可视范围,只有在可视范围内的图块才会被渲染。

研究引擎中 TiledMap 地图的渲染流程后我们发现,其实 TiledMap 本身并不是渲染组件,地图的渲染是通过图层 TiledLayer 实现的,其对应的渲染器是 TmxAssembler。渲染时,渲染流会逐个调用 TmxAssemblerfillBuffers 函数进行渲染数据填充,此函数中会调用 CCTiledLayer_updateCulling 函数进行可视范围,只有可视范围发生改变才会进行渲染。

但是,在计算的时候,由于每个图层都有对应的 Assembler,所以每个图层都会单独计算一次。而一般情况下我们每个图层显示的范围是一致的,所以我们希望它只计算一次就好了。

接下来我们就来实现裁剪区域共享(Share Culling),让不同 TiledLayer 间,共享可视区域的裁剪计算结果,以此节约性能。

实现过程

首先我们继承 TiledMap,重写创建图层的 _buildLayerAndGroup 函数,实现创建自定义的 ShareCullingTiledLayer

因为相对来说记录第一个图层实现起来更方便,所以我们缓存第一个图层,并将首个 TieldLayer 传递给后面的图层,方便后面去读取计算结果。

_buildLayerAndGroup() {
  for (let i = 0, len = layerInfos.length; i < len; i++) {
    if (layerInfo instanceof cc.TMXLayerInfo) {
      // 创建自定义的ShareCullingTiledLayer
      let layer = child.getComponent(ShareCullingTiledLayer);
      // 传递、记录首个TiledLayer
      layer._init(layerInfo, firstLayer);
      firstLayer = firstLayer || layer;
    }
  }
}

接着修改 TiledLayer 的裁剪函数,一样通过重写的方式实现。

这里我们进行判断,如果是首个图层,我们才让他进行计算,并把结果缓存起来;如果不是首个图层,我们就直接读取首个图层的计算结果。

最后重写 TiledLayer 的裁剪函数,实现复用裁剪区域的功能。

_updateCulling() {
  // this._firstLayer为空时 表示为首个layer
  let firstLayer = this._firstLayer;
  if (!firstLayer) {
    // 进行裁剪区域计算
    this._updateViewPort(); 
    this._cacheCullingDirty = this._cullingDirty;
  } else {
    // 直接复用firstLayer的结果
    this._cullingRect = firstLayer._cullingRect;
    this._cullingDirty = firstLayer._cacheCullingDirty;
    return; 
  }
}

很简单地我们就完成了这个优化。Share Culling 实现起来并不麻烦,但效果是显著的。

优化效果

a684c4f7ed352d4a6f92fb98f9225c3f.jpeg

优化前后

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值