• 产品手册
  • 性能优化

火焰图与ECA优化

功能简述

  • 火焰图主要用于针对ECA逻辑进行性能的查看和分析

  • 通过观察每个逻辑的ECA耗时,可以帮助我们快速定位到出现性能问题的原因,再根据合适的优化策略进行优化,从而实现性能的提升。

火焰图使用说明

  • 开启方式

    • 编辑器主界面顶部菜单栏中,点击【调试】-【触发器火焰图】即可打开界面

    • FlameGraph1

  • 界面说明

    • FlameGraph2

    • 在编辑器运行地图后,火焰图中会如上图所示

    • 火焰图界面可分为三个区域:

      • 柱状图区域

        • 以柱状图的形式展示各帧的消耗,点击可选中该帧
      • 导航栏区域

        • 可拖动帧的显示区域
      • 详细信息区域

        • 选中某一帧后,会显示该帧的具体消耗信息,以甘特图形式显示
  • 定位消耗点

    • 1、找到耗时过高的帧

      • 在进行性能调试时,首先需要在柱状图或导航栏区域观测各帧的耗时情况

      • 在其中找到波峰位置的帧,点击该帧

      • FlameGraph3

    • 2、查看耗时过高的函数

      • 在详细信息区域中,查看各函数色块,找到耗时过高或与预期严重不符的函数色块

      • 鼠标悬浮于甘特图色块上时,会显示该色块对应函数的信息,包含函数名和耗时

      • FlameGraph4

      • 点击色块可跳转至该函数所在ECA

  • TODO针对Lua的性能问题,接入Lua的Tracy-profiler工具

常用ECA性能优化思路

  • 1、【分帧执行】将高开销行为,分摊到各帧,形成平滑体验

    • 在地图实际运行中,如果有个别帧耗时过长,则会给玩家带来卡顿的体验。如果这个卡顿还是周期性的,那将是灾难性的体验。

      • 比如周期性的刷怪,或在玩家做出某个操作后,一次性创建大量单位或特效。
    • 针对这类情形,我们可以考虑在不影响游戏逻辑的情况下,将大量的高消耗行为分散到多帧中执行,比如每帧创2-3个单位。

  • 2、【对象池】将重复创建的单位进行复用,减少开销

    • 对于一些割草类玩法的地图来说,会需要大量创建重复的单位,使玩家有割草般的战斗体验

    • 在普通做法中,单位创建后,被击杀,走系统回收机制销毁,新的怪物再走一次创建。而创建单位行为的开销是比较大的,大量创建会导致游戏始终处于一个卡顿状态。

    • 在优化方案中,我们可以在怪物死亡后,不让系统回收销毁,而是自己将其移动至地图角落,并添加休眠等状态。而在需要创建该单位时,再将其移动至需要创建的位置,并重置属性。从而避免了创建单位的开销。

    • 并且,可以根据需要,提前分帧创建未来可能需要的单位,放在对象池中待命。

  • 3、【合并执行】将一帧内会重复执行多次的逻辑合并为一次

    • 这是在制作界面逻辑时常见的性能问题。

    • 比如监听了受到伤害事件去刷新界面。这个事件在敌方单位较多时,很可能一帧触发2次甚至多次,而用户只能看到帧结束前最后一次刷新的结果,造成了不必要的性能开销。

    • 对于这个情况,

      • 我们可以通过增加一个全局参数:界面需要刷新。

      • 当触发受到伤害时间时,将该全局参数设置为true。

      • 在帧计时器中判断,如果界面需要刷新=true,则刷新界面,并将其设置为false。

      • 通过这样的设计,就可以保证界面每次最多只被刷新一次,减少了不必要的开销。

  • 4、【增量更新】只刷新需要更新的界面控件

    • 在一些需要高频刷新界面信息的情景,或单次刷新的控件数量较多时,可以使用增量更新的思路,只刷新值发生了变化的控件。

    • 可以通过变量将控件当前的数据状态进行缓存,在刷新时,将新数据与缓存数据比较,如果数据不一致,才对控件进行刷新操作。

    • 但是要注意,大量的拼接字符串行为也会造成不小的开销。

  • 5、【预创建】避免在高性能压力的环境下动态创建触发器、元件等

    • 创建子触发器、创建元件都是有一定性能开销的行为(目前消耗很高)

    • 如果在战斗逻辑已处于高性能开销的情况下,频繁地去创建,极有可能导致卡顿。

    • 针对这类行为,我们可以提前创建好触发器、拼制静态界面等,让开销转移至游戏启动时或加载界面时。

  • 6、【巧用加载界面】通过加载界面,遮掩卡顿

    • 在前文有提到分帧执行的优化策略,但有些业务逻辑不允许我们使用这个策略。

    • 比如在进入副本时,不希望用户明显看到怪物是一批批刷出来的,而是希望进入副本后怪物就都刷出来了。

    • 这时候,我们可以在进入副本前使用加载界面遮挡一下,全部创建完成后,隐藏加载界面。

    • 如果整个时长不长,加载界面可以是没有进度条的展示界面。比如当前副本的宣传画+背景介绍文字。

  • 7、尽可能使用简易普攻代替自定义普攻

    • 使用简易普攻代替自定义普攻可以减少不必要的ECA和事件消耗,有效提升战斗性能。
  • 8、尽可能使用最简存储方式(数组《表《自定义键值)

    • 5000次存取,性能比例大约为:1:5:20

    • 所以业务逻辑允许的话,优先使用全局数组,其次是一维表