游戏性能问题, 往往是我们游戏程序员最关心的问题, 对于这个问题, 我在这里总结一下我关于游戏性能优化的八个理念:
理念一: 善于从问题的表象上出发进行优化
游戏出现问题时, 最直接的表现就是卡, 造成卡顿的问题又有很多不同的情况. 在解决卡顿问题前, 我们应该最先排除是否是外部问题造成的卡顿, 外部问题: 网络差, 硬件差, 系统问题等. 排除是外部问题导致的卡后, 我们可以根据卡顿的现象来定位问题.
1. 轻微的较频繁卡顿
1) 帧率
根据游戏自身来设定帧率范围, 一般游戏建议 30 帧就够了
2)Drawcall
在了解什么是 drawcall 后, 我们知道, 过高的 drawcall 会导致卡顿, 这里就介绍一些减少 drawcall 的方法:
A. 查看 drawcall
在 layabox 中, 添加代码 DebugTool.showStatu = true;
B. 连续渲染相同图集里的图, 只会执行一次 drawcall
C.UI 上 drawcall 优化
优化的思路就是尽可能让相同图集里的图一次性连续渲染完, 举例来说: 在 layabox 中打开一个 UI, 层级窗体里看到界面里的子对象, 如下图:
我们可以看到看每一个子对象前边, 都有一个小圆点, 这个圆点的颜色代表了他来自哪个图集, 相同颜色的圆点代表是同一个图集. 渲染 UI 时, UI 上的每个子对象是按照自上而下的顺序去渲染的. 在不影响界面的情况下, 把界面里各元件的层级调整一下, 可以达到减少 drawcall 的目的. 调整后, 如图所示:
优化前: 会有 6 次 drawcall
优化后: 只有 3 次 drawcall
D. 场景上的 drawcall 优化
拿场景中的人物来举例:
假设一个人物的某套装资源在一个图集里.
那么场景里连续渲染穿这个套装的人物, 只用 1 次 drawcall. 实际上在游戏里, 穿着相同套装的人不会理想的按顺序出现. 一个场景里会有许多穿着不同套装的人物, 而每个套装在一个图集. 也就是说, 场景里, 渲染 N 个这样的人物就需要无限接近于 N 次 drawcall.
当每个人物还有影子, 影子的资源, 肯定是在不同于各个套装资源的图集里.
情况 1: 人物和影子是在同一个容器里处理, 每一个容器就是一个人物, 这种情况就会出现, 渲染单位 A, 会使用两个图集套装图集 + 影子图集有两次 drawcall. 当渲染 N 个人物, 就有 N*2 次 drawcall.
情况 2: 把渲染影子拆出来, 当渲染完所有人物后, 再根据所有人物的位置, 绘制影子. 这种情况, 渲染 N 个人物, 只会有 N+1 次 drawcall 显然情况 2 的处理方式更优.
当每个人物还有名字, 称号, 血条等等元素, 若这些元素是按照上面情况 1 的处理, 那 drawcall 就有 N*M 次. 把这些元素按照上面情况 2 的处理, 显然可以减少大量的 drawcall.
E. 其他减少 drawcall 的方法
如: 减少被遮挡的单位渲染
图集的控制
3) 有较高消耗运算, 特别是 enterframe 和 for 循环里面的
注意代码逻辑优化, 减少算法复杂度
4) 资源加载缓存有问题 / 资源太零散, 造成 I/O 过高
优化资源加载策略
5) 日志打印
减少日志打印
6) 限制底层绘制分辨率
2. 突然大卡顿
某些不定时的操作, 循环里复杂度高
可能是执行到一些复杂度高的循环处, 导致突然大卡顿
协议包过大
注意协议包优化, 优化方式诸如:
1. 删除不用字段
2. 整合小字段
如某协议中的字段
- var a:int;
- var b:int;
- var c:int;
假如上述 a,b,c 的值只会是十位数以下时, 可以整合成一个字段:
var d:int;
d 的每一位为 ABCDEF
AB 为 a 的值, CD 为 b 的值, EF 为 c 的值
比如 d = 123456
那么 a 为 12,b 为 34,c 为 56
这样做的好处, 原来需要 12 个字节的数据, 现在只用 4 个字节就可以了.
3. 字段类型选择
如用 int 还是 short
只有两个值的情况选择用 boolean
4. 尽量避免使用字符串
协议中的字符串, 尽量通过 ID 发送
ID 对应的字符串在代码里做好映射或配置
垃圾回收负荷过重
单位是否是频繁初始化, 用完后就销毁?
是否需要使用对象池
如果卡顿发生 UI 上:
面板内容初始化分帧处理
图片和特效尺寸, 图集依赖规划是否合理
UI 面板是否分页签
UI 内特效, 3D 模型等次要元素延迟初始化
List 优化, 动态初始化, 循环使用
3. 持续地越来越严重卡顿
是否有对象 / 物件用完了隐藏掉, 而没有被删除, 越积越多
如: 飘血, 事件监听等
内存泄漏, GC 越来越频繁
4. 卡顿到闪退
内存过高, 内存有泄漏
检测是否有报错或死循环等问题
理念二: 内存为主
很多能感知的较大卡顿都是垃圾回收引起的;
内存问题往往比 CPU 问题更难解决, 甚至需要大规模重构;
降低内存会使得游戏更加轻快, 可以缓解其他较小问题.
理念三: 内存使用策略比内存释放策略更重要
关于内存使用的策略, 往往在项目的初期就应该制定好, 下面有几点建议:
new 对象必须由 Factory 或者 Manager 进行统一管理, 这点做好了, 对后期排查内存问题尤为重要;
View 和 Model 要完全分离;
View 的创建细化到每帧, 根据性能情况创建;
FpsManager 按照帧率动态调整阀值;
合理地运用对象池:"频繁创建和销毁" 的 "小型" 对象采用对象池.
理念四: 重视资源压缩
游戏程序中, 大量的内存来自于资源, 合理的压缩资源是减小内存行之有效的办法. 关于资源压缩, 这里提一些建议:
重视制定制作流程, 技术标准
资源的制作不能随心所欲, 必须拥有一定的标准, 例如:
原始图片资源使用 jpg 还是 PNG
是否是可以用镜像处理的图片资源
相似的资源是否可以统一
避免程序上使用滤镜和灰化等
一些图片资源上不起眼的光效或羽化效果等是否可以不用
美术字体图片中, 相同文字的拆分与组合
九宫格拉伸图片的概念
合理优化动作, 特效等资源序列帧
许多人物动作, 特效等资源, 美术给出的效果十分精细. 在处理内存问题上, 可以考虑对这些资源做如下处理:
1. 抽帧
一些影响不大的关键帧是否可以删除.
2. 缩小再放大
一些不起眼的部位, 序列帧可以按比例缩小, 程序使用时, 再放大.
3. 砍方向
人物向左和向右的资源是否可以通过旋转其中一个动作实现?
是否所有方向的资源都要用到?
对称的资源砍半 / 四分之一镜像使用
序列帧特效用 IDE 制作替代
UI 全屏分辨率选择 1024 像素
icon 尽量使用 64*64 的格式
使用 pvrtc etc ,png8 格式
UI 背景使用最接近的某个 2 的次方的尺寸
背景图不要打到图集中, 并且尽量用 jpg
少用遮罩
音效使用单声道
理念五: 屏蔽策略
在游戏出现性能瓶颈的时候, 我们不得不考虑屏蔽一些游戏内容的显示, 比如一些次要的场景单位, 特效等. 屏蔽必然会减弱玩家的游戏体验, 但是, 比起卡顿甚至是闪退, 适当的屏蔽规则是必要的.
加入屏蔽设置, 性能差的时候自动开启
屏蔽策略要覆盖各类显示对象
某些场景使用统一模型
理念六: 不要忽略看起来小的地方
正所谓积少成多, 一些看起来小的地方, 却用了不太合理的处理方式, 往往也影响着游戏的性能, 在《大天使之剑 H5》中, 我们就对如下这些地方做了些优化:
配置表数据优化
String 数组方案
相似 String 的处理
版本号文件, 采用树形存储减少 URL 字段的重复度
数值类型广泛使用变长
解析战报, 分段解析
理念七: 深入学习开发者工具的使用
在调试游戏时, 我们往往要依赖开发者工具来获悉游戏的内存变化, CPU 的使用, 游戏内对象的整体情况, 资源的应用情况, 甚至是我们关注的变量值等等. 善于使用各种开发者工具能让我们事半功倍.
使用谷歌浏览器的开发者工具
layabox 开发的 H5 游戏默认是用谷歌浏览器调试的, 这里我们稍微讲下谷歌浏览器的开发者工具的运用. 游戏运行在谷歌浏览器时, 按 F12 可以打开开发者工具, 他的一些常用功能有:
1.console 的使用
Console 的界面如上图所示, 它主要显示着我们游戏运行时的日志等信息. 每条日志的后面, 有链接可以快速跳转到输出日志的代码处, 在 console 的下方, 有输入框功能, 我们可以通过这里输入代码改变当前游戏内的数值, 用不同方式打印日志等.
2. 调试
我们可以在工具的 Sources 选项卡下找到我们要调试的 JS, 进行断点或条件断点调试.
3.NetWork
NetWork 面板提供了有关已经下载和加载过的资源的详细信息.
在这里我们可以很直观的找到一些加载耗时较长的资源进行优化.
4.TimeLine
TimeLine 界面中, 我们可以看到关于时间开销的完整概述.
如图所示, 通常我们在游戏性能表现差的情况下, 在 TimeLine 界面点击左上角的录制按钮, 录制一段时间后, 点击完成, 它会帮我们搜集到在录制的这段时间里, 游戏每一帧的运行状况.
绿色的帧是在帧时间内处理完需求处理的事情的.
红色的帧是处理时间大于帧应该有的时间的, 也就是卡了的帧.
我们可以重点看下红的帧, 在下边可以看到是哪个方法占了多少时间, 以及这个文件里又是调用哪些方法, 分别调多少时间.
在图中左下部分, 我们还可以看到代码逻辑和渲染的比重, 可以用来判断可以做什么优化, 怎么优化. 这个功能, 对程序的参考决不止我提到这些, 这里有很多信息帮我们分析找到问题, 可以对我们优化提供很多帮助.
5.Profiles
Profiles 界面中, 我们可以使用快照功能. 最常用的还是 Take Heap Snapshot 功能. 它可以记录当前内存分布的详细信息, 多张内存快照还可进行比对, 分析在不同的时间点, 内存具体有哪些变化.
理念八: 抓大放小, 先抗住再优化
没有一个性能问题是由单一问题造成的;
单次单点修改, 注意记录便于前后对比找到关键问题;
调试崩溃的时候一定要注重日志, 一行一行看总会找到 Keyword.
转载地址: https://mp.weixin.qq.com/s/4UUM6YBf33iOpp5jQqbGcQ
来源: http://www.bubuko.com/infodetail-2867489.html