# 小游戏运行性能优化建议

# 一、背景

游戏运行性能直接影响玩家体验。玩家如频繁遇到卡顿,发烫,闪退,很快就会流失。

游戏性能直接影响平台游戏推荐策略,优秀运行性能的游戏将获得平台更多流量曝光。

  • 游戏画面品质和运行性能是一个权衡。
  • 游戏流畅度,响应速度和设备发热需要权衡。
  • 要考虑不同设备,不同环境的运行兼容性。

# 二、平台推荐值和合格值

分位数 游戏启动后增加的内存(MB) fps anr crash 首帧-可交互耗时
建议值 280 50 0.08% 0.01% 8s
合格值 420 40 0.2% 0.08% 13s

# 三、优化建议

# 内存优化

# 内存调优

在开发小游戏过程中,往往会有很多内存问题,比如内存溢出、内存泄露等。使用内存超过 1G,就有内存崩溃的风险。虽然 Android 平台可用内存较多,但内存十分紧张时,可能会显著变卡。综上,当前机型分布条件下,使用内存控制在 1G 以下,较为妥当。如果游戏复杂,建议多关注线上的内存使用情况以及内存崩溃率。

# 资源纹理压缩

在游戏内存的使用中,图形内存往往是占用的大头。所以对贴图资源的优化是必要的。

最佳实践:选择 ASTC 格式进行纹理压缩。
原理:传统的图片文件格式有 PNG、JPEG 等,这种类型的图片格式无法直接被 GPU 读取,需要先经过 CPU 解码后再上传到 GPU 使用,解码后的数据以 RGB(A) 形式存储,无压缩。

而纹理压缩顾名思义是一种压缩的纹理格式,它通常会将纹理划分为固定大小的块 (block) 或者 tile,每个块单独进行压缩,整体显存占用更低,并且能直接被 GPU 读取和渲染(无需 CPU 解码)。

举例来说,一张 1024x1024 的 JPEG 图片,使用 RGBA 格式,显存占用在 4M~5.3M 左右,而如果采用 ASTC_4x4 纹理压缩格式后,理论内存占用约在 1.3M 左右,相比普通纹理,可以减少 70%+ 内存。

各个游戏引擎,COCOS,LAYA 都提供了对纹理格式的设置。

# Cocos Creator

压缩纹理 | Cocos Creator

# 运行时

# FPS

FPS(Frames Per Second) 越高,游戏感觉越流畅。如果小于30,那玩家会感觉到卡顿。所以应当争取,在绝大多数机型上,FPS保持在30帧以上。

受到手机的限制,平台的限帧是60。并且提供了限帧接口,如果游戏对画面的流畅度要求并不高,建议限制在30,以保证长时间运行下手机不发热。

# CPU 性能优化

绘制调用(draw call) 次数过多,游戏循环中计算量过大,都会造成 CPU 性能下降,尽量减少游戏中的总绘制调用次数,应该尽可能的使用批量绘制。

一般有以下几种优化方案:

  • 合并网格:将多个相同材质的网格合并成一个大的网格,减少渲染调用次数。
  • 使用图集:将多个小的纹理合并成一个大的纹理图集,减少纹理切换次数。
  • 使用批处理:将多个相同材质的物体放在一个批处理中一起渲染,减少渲染调用次数。
  • 使用GPU实例化:使用GPU实例化技术,将多个相同模型的物体实例化渲染,减少渲染调用次数。
  • 减少透明物体:透明物体的渲染需要进行混合操作,会增加DrawCall的次数,可以尽量减少透明物体的数量。
  • 使用静态批处理:将不会发生变化的物体进行静态批处理,减少渲染调用次数。

# IO操作

当玩家玩游戏时,要尽量避免 IO 操作,尽可能预加载图集、音频、TTF字体等

# 运算优化

  • 不要在游戏循环中进行繁重的计算操作,因为这可能造成每帧 60 次的大量计算,性能消耗大。
  • 考虑使用worker,利用多线程能力,进行异步计算。

# GPU 性能优化

一般来说, 2D 游戏,没有复杂的着色器,基本不会遇到 GPU 性能问题。但是过度绘制的问题仍然存在,如果过度绘制较多,将会消耗大量带宽,进而降低 GPU 性能。

# 内存优化

  • 使用合适的的压缩纹理,参考各引擎的纹理压缩的支持情况
  • 及时释放使用不到的资源,内存紧张时,限制资源的预加载 在场景切换的时候主动调用ks.triggerGC 主动清理内存

# 其他性能优化建议

  • 始终使用批量绘图,将同一图层中的精灵图像打包成一个大的图集
  • 为避免加载资源带来的卡顿,考虑资源预加载
  • 为避免GC带来的卡顿,对频繁使用的对象,使用对象池
  • 使用烘焙光照,而不是动态光照
  • 避免使用复杂的像素着色器

# 发热优化

# 优化的重要性和目标

发热问题是小游戏性能优化中的一个关键方面。

  • 发热会导致手机降频运行,进一步导致游戏帧率下降、卡顿,甚至出现闪退等现象。
  • 发热会极大地影响玩家的游戏体验,降低玩家游戏时长和留存。 优化发热问题的目标在于降低设备在运行游戏时的功耗,提高游戏的流畅性和稳定性。具体而言,要通过优化游戏代码、资源管理、图形渲染等方面,实现高效的性能表现,让玩家能够在长时间的游戏过程中享受流畅、稳定的体验。

# 发热原因

手机发热,都来源于硬件资源的使用,主要的有CPU,GPU,网络。对应要优化的游戏计算部分有

  • 每帧要运行的代码的效率
  • 每帧渲染的图形的处理
  • 持续的网络请求或IO请求

# 分析和优化策略

# 降低 CPU 使用率
  • 检查骨骼动画的数量及做法,是否有较多的Spine的骨骼动画更新计算;
  • 如果有较多的物理计算,考虑修改物理引擎迭代计算的参数,降低刚体迭代的数目等
  • 针对Profiler的Top10函数进行优化,根据性能堆栈定位性能根源并进行优化;
  • 使用对象池来管理对象的创建和销毁,减少频繁的内存分配和释放,避免频繁的垃圾回收。
# 降低GPU使用率
  • 看看纹理的一些设置是否合理,比如是否压缩、是否开启Mipmap(Mipmap会造成额外的内存问题,根据实际情况开启)
  • 通过LOD,减少模型细节,降低渲染质量,减少光照。
  • 合并drawcall,提前烘培,使用更简单的shader,关闭一些特效,等。根据游戏情况做优化。
# 降低IO

控制网络流量。游戏中如果有边玩边下的功能,可以控制当游戏处于战斗等本身消耗比较大的场景时,停止下载。游戏比较闲置(如只在进行一些简单的UI操作)时再重新开始下载。

# 使用分包功能

对于基于webasmmbly的游戏,编译时会占用较高的CPU,通过分包功能,减少首包,能优化发热情况。

# 首帧到可交互耗时

# 尽快渲染

所谓的尽快渲染,指的是缩短业务代码注入完成到首屏渲染指令的时间。因此除了前面提到的优化手段外,还可以:

  1. 精简初始化代码
  • 避免在游戏启动时加载过多不必要的模块和数据。例如,如果游戏中有一些非关键的辅助功能,如成就系统、排行榜等,可以将其初始化代码延迟加载。只在玩家真正需要访问这些功能时再进行初始化,这样可以减少游戏启动时的资源占用和运算量。
  • 检查并优化游戏的主逻辑初始化部分。例如,减少循环嵌套的层数。如果在启动时有一个复杂的循环用于初始化游戏对象,尽量简化循环条件和操作,以加快代码执行速度。
  1. 异步加载资源
  • 对于游戏中的大型资源,如高清图片、音频文件等,采用异步加载的方式。例如,当游戏启动时,可以先显示一个简单的加载界面,同时在后台加载主要的游戏资源。
  • 合理划分资源的加载优先级。例如,对于游戏场景中的背景图片、主角模型等关键资源优先加载,而一些装饰性的道具模型等可以稍后加载。这样可以确保游戏在最短的时间内呈现出主要的视觉元素。
  1. 图片资源优化 对游戏中的图片进行压缩。根据游戏的实际显示需求,选择合适的图片格式和压缩比例。

# 四、参考资料