找回密码
 立即注册
查看: 693|回复: 13

十五:Unity UGUI 点击性能优化

[复制链接]
发表于 2021-4-16 09:12 | 显示全部楼层 |阅读模式
最近在做性能优化,我们希望能力尽力做到平滑60帧,在战斗逻辑方面,已经做了不少优化。其他方面,即使是边边角角的地方,也不能放过,所以,这次分享一点个人认为有通用参考价值的优化点,并且做起来也不难。
在测试过程中,发现在进行点击UI操作的时候,EventSystem.Update()是一个很大的消耗,在我们的游戏中,安卓上大概在2ms左右,如果希望跑60帧,每帧只有16ms的空间,所以,2ms也是需要慎重对待的。
后续找到三篇文章,也谈到这个问题,罗列如下:


我主要采用了第一,第二两篇文章的优化方法,这里只谈谈和参考文章不同的几点处理,希望大家在看下面内容前,可以先看下上面的参考文章。
第一:文章有提到:unity中,我们即使不勾选raycastTarget,还是会进入raycast列表的计算。可以通过继承的方式,override一些方法,来处理掉这块的消耗。
第二篇参考文章截图
在项目中后期,我不希望通过继承Image或Text的方式,来替换掉prefab中已经使用的Image等控件,这带来很多的修改维护成本。
所以,我的思路是:当创建UI界面的prefab的时候,获取到prefab中所有的Graphic,在UI从隐藏到显示的时候,将所有没有勾选raycastTarget的Graphic,从判定列表中移除,代码简单处理如下:
private Graphic[] _allGraphics;

protected void Awake()
{
     _allGraphics = gameObject.GetComponentsInChildren<Graphic>();
}

protected void onShow()
{
     for (int i = 0; i < _allGraphics.Length; i++)
     {
         if (_allGraphics.raycastTarget == false)
         {
              GraphicRegistry.UnregisterGraphicForCanvas(_currCanvas, _allGraphics);
          }
      }
}


第二:根据隐藏界面的不同方式,注意将隐藏的界面从raycast判定中去除
当前隐藏UI界面,有几种思路:一种是设置active 为false,一种是将UI位置移动到可见范围外。
如果使用set active的方式,就不必额外担心,当Graphic OnDisable的时候,ugui会处理掉这块事情(可以看Graphic 的源码)。
如果是使用移动到可见范围外的方式来隐藏UI界面,在可见范围外的UI,也会参与raycast的计算,就需要自己处理这块的逻辑。例如在OnHide的时候,将所有Graphic 移除raycast判定,类似如下处理:
protected void onHide()
{
     for (int i = 0; i < _allGraphics.Length; i++)
     {
         GraphicRegistry.UnregisterGraphicForCanvas(_currCanvas, _allGraphics);
      }
} 这里,要根据自己的UI系统怎样组织,注意处理显示隐藏界面时候的不同处理。
如果你的UI是使用每个UI界面一个Canvas的方式,那么,只需要在隐藏和显示的时候,调整当前界面对应的GraphicRaycaster 的enable状态即可,不再赘述。


最后说下优化的效果,在unity editor下,优化前是这样:
优化前
优化后是这样:
优化后
可见,同样的操作,性能消耗,在editor下从6ms,减少到约2ms。Graphic.get_depth()的调用次数大幅度减少。
在安卓真机测试中,从2ms,减少到0.5ms,减少了1.5ms,算是个不错的优化效果,需要做的事情也不多。
我还做了一些相关的小优化,但是是基于现在项目的UI组织方式,不具有通用性,就不提了。大家如果想要尝试这个优化,注意要领会这个优化的思路本身,根据自己的项目具体处理。在一些UI相对复杂的项目,相信会有比较好的效果。
最后,需要感谢前面提到的三篇参考文章的作者,做了非常细致的工作。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-4-16 09:18 | 显示全部楼层
受教了
发表于 2021-4-16 09:22 | 显示全部楼层
通过看UE4源码的Slate处理点击的思路来看,我觉得你可以试试将屏幕分块,每块维护着当前和屏幕块有重叠的控件。
发表于 2021-4-16 09:29 | 显示全部楼层
谢谢
发表于 2021-4-16 09:39 | 显示全部楼层
不知道代价有多大,有空看看
发表于 2021-4-16 09:41 | 显示全部楼层
其实你拿到UGUI源码,直接修改GraphicRegistry.RegisterGraphicForCanvas函数,然后里面判断 if (!g.raycastTarget) return; 就好了
发表于 2021-4-16 09:47 | 显示全部楼层
我写了,不希望通过改源代码的方式来优化。如果改源码,当然可以做更多优化
发表于 2021-4-16 09:47 | 显示全部楼层
不太信任GetComponentsInChildren的性能
发表于 2021-4-16 09:53 | 显示全部楼层
这个优化是开关ui的一次性调用,不是每帧。
发表于 2021-4-16 09:57 | 显示全部楼层
可以可以
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-15 04:20 , Processed in 0.098042 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表