1)如何优化UI中大量使用SetActive的问题
2)ASTC压缩和ETC2压缩打出的APK包的问题
3)PNG图片格式与TGA图片格式问题
4)游戏运行的崩溃问题
5)关于AssetBundle加载方式的适用环境
这是第244篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。
UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)
UI
Q:在UI的日常开发中为了显示或者隐藏某些GO使用了大量的SetActive(true)/(false)代码。但是SetActive的开销过大,所以不想使用SetActive,是否有其他解决方法?
A1:这种情况下Active/Deactive的开销主要有几个方面:
1.C#层到Native层的穿梭调用速度比C#层内的速度慢。
2.UI元素的变化导致所在的Canvas变化,触发函数Canvas.SendWillRenderCanvases()与Canvas.BuildBatch()造成高耗时。
3.UI元素的网格顶点数组改变会造成堆内存分配,触发GC,导致耗时(不过对UI元素进行位置移动不会造成堆内存分配)。因此,优化也可以从以下几点考虑:
1.在C#层设置变量来标识相应的GO处于Active还是非Active状态,避免对Active的对象进行SetActive(true),避免对非Active的对象进行SetActive(false)。对Active进行SetActive(true)时,“底层”会进行判断,但调用的时候,就已经是从C#层调用底层,导致开销较高。在C#层判断好,就避免了让底层判断。
2.将要频繁变化的UI元素与不频繁变化的UI元素放在不同的Canvas中,减少UI元素变化时的耗时。
3.通过将UI元素的坐标移动到Canvas的范围之外的方法来显示与隐藏,避免SetActive的耗时以及SendWillRenderCanvases的耗时。
4.经测试,对Component进行enabled = false的操作比对GO进行SetActive(false)的操作耗时低。
5.通过添加CanvasGroup组件设置透明度的方式来进行显示与隐藏。
感谢Prin@UWA问答社区提供了回答
A2:最近做优化,也发现了这个问题,尤其是挂Image和TMPText的在SetActive的时候耗时更差。我准备从以下方面做优化:
1.对于挂UICanvas的直接修改Layer层。
2.对于不挂UICanvas的,改成挂CanvasGroup来控制Alpha.
这个地方有个麻烦的点。因为我们项目开了很久,让拼界面的同学去到需要控制的节点上挂CanvasGroup不太现实。在运行时动态挂组件,对性能有些担忧。所以打算改成运行时遇到修改Active的节点,到对应的Prefab下增加一个CanvasGroup控件,这样Prefab就补全CanvasGroup控件了。在正式上线之后,如果有遗漏不存在的,直接使用SetActive。3.使用CanvasGroup方式有个缺点,只是改变了Alpha,依然会占有布局,所以父界面是Layout的,不能采用CanvasGroup。初步计划是对比SetScale0和SetActive的耗时,两者应该都会引起重绘。
感谢承影@UWA问答社区提供了回答
Texture
Q:在一个空工程里面,我放了几张大图2048*2048的,采用ETC2 4bits的格式压缩的时候单张大小为2MB,采用ASTC 6X6压缩的时候单张大小是1.8MB。
按照我的理解:采用ASTC压缩格式打出的APK应该更小才对,可是事实和我预想的相反:采用ETC2压缩打出的APK为21.1MB;采用ASTC压缩打出的APK为25.7MB。
为什么采用ETC2压缩的包体反而更小呢?ASTC打出的APK更大呢?
A:占用包体的大小和在Editor下的Preview界面看到的大小是两回事。
Preview界面看到的大小是ASTC或者ETC2格式的资源的大小,而打包后,会对资源进行进一步的压缩(LZ4或LZMA)。只能说明ETC2压缩成LZ4后占用的包体大小确实比ASTC压缩成LZ4后占用的大小更小,至于原因就要看具体压缩算法的实现了。
可以用AssetBundle来验证,如果打AssetBundle包时选择NoCompression,那么确实ASTC格式的比ETC2格式的AssetBundle包更小。如果选择LZ4或LZMA压缩,那么ETC2格式的AssetBundle包比ASTC格式的AssetBundle包要小。
感谢Prin@UWA问答社区提供了回答:
Texture
Q:美术说有一张带透明通道的图,必须出TGA格式,不能出PNG格式的图,缺少透明通道。请问为什么PNG格式在Unity中有些是有透明通道的?该怎么让美术在PhotoShop中出一张PNG格式图,又能满足效果的?可否详细说下这两者图在Unity中的区别原理?
A1:在PhotoShop中针对PNG并没有透明通道这一说。导出也只能导出RGB3个通道。想要修改PNG像素的透明信息需要用到蒙板。
你和美术同学说“这块的信息画在蒙版上,黑透白不透”,他就明白了。
感谢张首峰@UWA问答社区提供了回答
A2:选TGA美术比较好处理,也不用关心PNG那几种格式的区别,PhotoShop里也不用处理Alpha的事,毕竟在引擎里都要根据不同平台进行压缩处理。不在乎工程大小的情况下,流程更方便才是关键。
感谢郑骁@UWA问答社区提供了回答
Android
Q:游戏运行过一段时间后某些机器会出现以下所示的崩溃,具体Log可戳原问答查看,请问有遇到过类似的问题吗?
JNI ERROR (app bug): global reference table overflow (max=51200)
我看Unity 2018.3里面有一个是相关内容,我们现在用的版本是2019.4.10,按说应该已经修好了,望各位大佬指导迷津,谢谢!
A1:是不是JNI调用次数太多了?我之前试过,有个腾讯语音的API一直在调用JNI,运行到一定时间后就崩溃了,日志好像跟你一样。
感谢Jam@UWA问答社区提供了回答
A2:应该是AndroidJavaClass和AndroidJavaObject只频繁New没调用Dispose导致的。
感谢上山打野@UWA问答社区提供了回答
A3:参考以下信息:
2019.4.21f1 Release Notes
Fixes
- Android: Fixed Java local reference leaking when using AndroidJavaClass/Object. (1283209)
感谢littlesome@UWA问答社区提供了回答
AssetBundle
Q:关于AssetBundle加载方式的适用环境中,AssetBundle.LoadFromMemory以及AssetBundle.LoadFromStream适用环境分别是什么?
A1:AssetBundle.LoadFromMemory
1.使用UnityWebRequest下载的AssetBundle资源并且使用后不存到本地;
2.有加密需求的AssetBundle资源。AssetBundle.LoadFromStream
1.有加密需求的AssetBundle资源(内存值理论上比AssetBundle.LoadFromMemory小);
2.Android下需要Copy出StreamingAssets目录外,创建流。
感谢郑骁@UWA问答社区提供了回答
A2:当资源有加密需求时,可先把AssetBundle读取到内存当中,进行解密后再调用该AssetBundle.LoadFromMemory进行加载。该方法消耗的最大内存量将至少是AssetBundle的两倍。可参考《AssetBundle的原理及最佳实践》。
AssetBundle.LoadFromStream可进行流式加载,不需要将AssetBundle全部读到内存中再解密、加载,而是可以通过每次像Buffer中读一部分,解密一部分的方式进行加载,不会多占用一份很大的内存。如果使用该接口,需要自定义一个继承FileStream类,然后在Read和Write方法内对Byte数组进行异或加密解密处理。
感谢Prin@UWA问答社区提供了回答
封面图来源:UiFaderPro
一组使Unity引擎中的UI(4.6b + uGUI)的淡入淡出变得容易的脚本。
https://lab.uwa4d.com/lab/5b5d2aaad7f10a201feadf62
今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。
官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859(原群已满员)