2024年度大赏 | UWA问答精选

2024年度大赏 | UWA问答精选

UWA每周推送的知识型栏目《厚积薄发 | 技术分享》已经伴随大家走过了419个工作周。精选了2024年十大精彩问答分享给大家,期待2025年UWA问答继续有您的陪伴。

UWA 社区主页:community.uwa4d.com
UWA QQ群:793972859


Q1:PuerTS和HybridCLR哪个更适合开发微信小游戏

PuerTS和HybridCLR哪个更适合开发微信小游戏?哪个更快?大家有做过相关的调研吗?

A1:之前测过,HybridCLR的解释器是在WASM上的,而JS用的是微信的。这俩算力估计差了50多倍。但现在市面好像没有好的Unity和TS的框架。

JS算力高,但和WASM交互比HybridCLR低几倍。

感谢子非鱼@UWA问答社区提供了回答

A2:可以参考以下文章,但综合来看应该还是HybridCLR更好一些:
https://zhuanlan.zhihu.com/p/646932579

感谢旋@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/66a70d55682c7e5cd61bf888


Q2:如何解决穿插易导致半透明物体合批失败

请问半透明Shader,距离穿插,打断SRPBatcher。有什么通用解法?比如一个火焰特效,用了ab2个粒子,分别2个Shader,那么10个火焰就是ab ab ab......这样20个DrawCall吗?但完全无法合批。

由于半透明开销比较大。而且需要渲染顺序严格导致了一些优化失效。大家有什么好的解法吗?

A1:不透明可以调RenderQueue,半透明不好调,可能会影响渲染结果。

感谢AQ(Richard Pan)@UWA问答社区提供了回答

那比如玩家丢出的燃烧瓶,多少米合并成一个?如果很远,半透明物体在火堆之间就出错明显。我之前是3米合成一次顺序,提升不明显。

A2:我是直接不同材质用不同队列,牺牲了一些顺序正确性,主要用在团战时候大量技能特效上,本身画面很乱,顺序错误感受不出来,至于场景中的常驻特效,还是要保证顺序正确性,不去调队列。

对应性能好的机器保证正确性,性能差点的保证性能,忽略点正确性。

感谢AQ(Richard Pan)@UWA问答社区提供了回答

A3:一个燃烧瓶丢出来8份火焰实例,每个实例3个粒子发射器且Shader不同,导致一堆开销。尝试燃烧瓶互相顺序不严谨,内部定死顺序看看。

感谢偶尔不帅@UWA问答社区提供了回答

强制改变渲染顺序粒子是改下图这里好:

还是材质的Queue好:

A4:我是改材质的Queue。

感谢AQ(Richard Pan)@UWA问答社区提供了回答

A5:半透明大部分情况是放弃跨发射器的合批优化。整理了以下几种办法供参考,一种办法就是将两个材质合并为一个,这样就连上了;另外就是在Batch的时候判断屏幕Bounds,不重叠的时候进行批次合并;还有种办法是粒子实时Batch成序列帧后使用,远处的粒子可以这样处理,这样这些粒子都可以一个批次画完,毕竟远处不管是大小还是帧率都很低,这样做反而可能是合算的。

感谢flashyiyi@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/675673e5682c7e5cd61bf9bf


Q3:Unity引擎关于APP后台下载支持的实现问题

最近很多游戏在Loading界面会标明支持后台下载模式,项目也计划实现一个,首先找到了Unity自带的BackgroundDownload解决方案,功能是可以的,也好接入,但项目中的文件数量比较多,有大几万个,同时建立这么多链接非常卡顿,经过简易优化,速度提升了一些,同时平滑建立连接数不再那么卡顿,但所有连接建立完还是需要很长时间,同时Android环境在创建1000+个下载服务时,会崩溃,没有明确的报错,每次会有下图中的异常!

BackgroundDownload
https://github.com/Unity-Technologies/BackgroundDownload

咨询下各位大佬,如下几个问题:
1. 崩溃如何处理?
2. 如何平滑快速地建立起下载连接?
3. 有没有其他更好的处理类似问题的解决方案?

A1:可以试试以下方案:
方案1:把所有要下载的任务,放到1个队列,开多个线程去处理这个队列的下载任务,并且限制设定同时下载的任务数。

方案2:把对应资源,根据一些规则(如:等级1-10级会用到的资源在1个zip包,11-20级会用到的资源放在1个zip包),然后根据一些条件在不同时刻来下载不同的zip包。

感谢hejianchun@UWA问答社区提供了回答

A2:目前汇总下Android端的解决方案,帮助大家踩坑:

  1. Unity内部使用后台运行的线程来平滑控制下载量,存在的问题:APP切入后台时,线程会被挂起,中断传输;

  2. 将下载任务全部筛入原生层,使用Android的Service调起,同线程也是会被挂起;

  3. 将下载任务全部筛入原生层,使用Android的Schedule等定期任务,存在的问题:触发时间不固定,时间选择范围大,但系统会设置最小调用间隔为15分钟,没法用;

  4. 将下载任务全部筛入原生层,使用Android的前台Service中起一个线程,逐步传递给下载服务,存在的问题:目前可以持续运行,但会受到系统的限制,服务起的线程触发时间会时快时慢,执行一段时间后有概率会挂起(没有明显的输出,不明原因,就是长期不输出日志了,服务都还在)。

用服务搞定后发现Android的原生下载服务速度很慢,所以再次测试了Unity中使用C#的Thread的方案(线程设置为inbackround=true,使用HttpClient下载),发现是可以后台运行且速度可以,之前测试不清楚为什么不行,可能是哪里遗漏了。

另外补充几点:

  • 如果后台不运行了,可以在手机的电池管理处,勾选允许你的APP在后台运行选项;
  • Android是可以申请忽略电池优化权限的;
  • 但Google对这个权限有很多限制。

感谢题主Will@UWA问答社区提供了回答

A3:由于国内Android系统的各种定制化,使用BackgroundDownload方案会在某些机型上无法下载,并且无法解决。

感谢kakacoding@UWA问答社区提供了回答

A4:开个线程驱动下载队列,http下载,不要用UnityWebRequest。

感谢李晨曦@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/65e1c0b13625c22cffcb1e3d


Q4:使用SBP打AssetBundle脚本引用丢失

最近项目实验升级ScriptableBuildPipeline打包AssetBundle(之前使用的是BuildIn构建管线)。使用的Unity为2022.3,SBP版本为2.1.4。

结果发现打出的UI AssetBundle中,部分NGUI的脚本丢失引用了,丢的最多的是UIButton。但也不是所有UI都会丢失,有的就正常。BuildIn管线打包也正常。

真机上加载资源的时候会报错:
Error: A scripted object (script unknown or not yet loaded) has a different serialization layout when loading. (Read 32 bytes but expected 8136 bytes)

Did you #ifdef UNITY_EDITOR a section of your serialized properties in any of your scripts?

UnityEngine.AssetBundle:LoadAsset(String)

使用AssetStudio解包AssetBundle,发现脚本的m_PathId为0。求助,这可能是哪的问题?


A1:针对出问题的文件单独导出独立工程Demo去调试。

发现出问题的情况是AssetBundle的引用的引用也包含了相同的脚步且这个引用也是打AssetBundle的, 应该是递归引用的时候出问题了。

解决方案:

  1. 设置SBP中BuildParameters的NonRecursiveDependencies为false。
    修改方法:
    a. 将Library\PackageCache夹子下SBP的组件移动到Packages下变为本地组件,即可编辑代码。
    b. 使用SBP非兼容模式接口构建,New出BuildParameters,然后可修改此属性。

  2. 将脚本信息都写入到一个独立的Bundle中,这样所有Bundle都引用它即可,这种方式需要启用CreateMonoScriptBundle。
    修改方法:
    在SBP组件中的DefaultBuildTasks脚本Create接口内Return出AssetBundleCompatible(false, true);即可。

感谢题主mr.Tian@UWA问答社区提供了回答

A2:感谢楼主的回答,我们项目用的Addressable,当A预设(A单独打包)引用公共预设B的时候,会出现部分脚本和Image组件丢失的情况,查看AssetBundle的信息发现丢失了脚本的相关信息,采用楼主的建议,把NonRecursiveDependencies设为false就解决了。

感谢Jeff@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/66babdd6682c7e5cd61bf8ae


Q5:升级Unity后产生的Objects内存泄露现象

项目升到2022.3.28后观察到在真机上出现了之前没有的内存泄漏状况,用Memory Profiler排查后发现除了一些正常的资源和堆内存有轻微上升外,主要是有一部分Native-UnitySubsystemsObjects-泄露很明显,但没法定位。请问有没有人遇到这个问题?怎么解决?

A1:可以参考下这篇官方论坛讨论和复现测试链接:
https://discussions.unity.com/t/memory-leak-in-scriptableobject-containingserializereference-in-android-environment/946666

https://issuetracker.unity3d.com/issues/memory-leak-when-using-serializereference-in-il2cpp-build

根据我们项目中的情况加上自己试验了下,发现触发条件比帖子中还要简单,都不用ScriptableObject+Addressable,只要任意带有[SerializableReference]特性的资源被销毁就会发生泄漏。而且看样子这个问题大概率会出现在所有2022以上及团结引擎的项目中,且目前未被修复。

考虑到使用这些Unity版本一般是基于支持鸿蒙或支持小游戏的主要目的,不大可能回退版本,那么目前处理方法可能就是要尽量避免使用这个特性。甚至像DoTween这种可能涉及该特性的插件建议都要换掉。

该问答由UWA提供

A2:Unity已经修复了该问题。遇到该问题的可以通过升级引擎到最新版本解决。

感谢Faust@UWA问答社区提供了回答

A3:Unity 2022.3.34版本修复,团结1.3.1版本修复。

感谢K@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/670c8262682c7e5cd61bf95c


Q6:Unity中如何实现草的LOD

Unity自带的Terrain中草作为Detail,无法设置LOD Group。感觉草的LOD应该是一个非常基础的功能,Unity选择不支持这个功能的原因是什么?要想实现草的LOD,我想到的几种方式,还有更好的实现方式么?
1. 手动放置。
2. 自己写Procedural工具批量生成。
3. 使用Terrain的Paint Trees功能变通实现。即把草当作一种Tree,增大种植密度。不知道这种实现会不会有副作用。

A1:LOD一般不用于草,通常大批量的草都是使用GPU Instance。如果距离远的草,你可以通过逻辑控制远距离草的显示和隐藏。

感谢qingfeng@UWA问答社区提供了回答

A2:草通常是小型和密集的,对于这些对象应用LOD机制可能并不会显著提高性能。草地的渲染通常依赖于地形的着色器和草地批处理,因此Unity可能认为不需要为这些小对象单独设置LOD。

如果要快速解决问题,可以看看Unity Store中的Infini GRASS GPU Vegetation。

感谢萧小俊@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/65fe527f5c7f5d2c5805d354


Q7:开发微信小程序游戏,有没有类似Debug真机图形的方法

开发微信小程序游戏有什么科学的Debug真机图形的方法吗?比如RenderDoc?

A1:推荐Frame Debugger,团结可用。

感谢tmp@UWA问答社区提供了回答

A2:1. 游戏可以在浏览器跑的话,可以用SpectorJS(https://github.com/BabylonJS/Spector.js/)。

  1. RenderDoc曾经也可以抓Chrome,但后来官方禁了,可能需要自己魔改编译一个RenderDoc。
  2. 也可以用MuMu模拟器+RenderDoc抓微信,MuMu需要开启Vulkan模式,RenderDoc开全局Hook,Attach到MuMu的进程上,但是抓到的是Vulkan的API。

感谢littlesome@UWA问答社区提供了回答

A3:RenderDoc可以考虑,但需要旧版本的RenderDoc。或者配合模拟器截帧,或者Root的手机都可以,或者用浏览器都行,方式很多,个人推荐模拟器+截帧。

感谢司马老师@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/677250003d306f3e9d594de3


Q8:MemoryProfiler中Graphics/No Name内存怎么排查

移动端项目,发现某个场景里内存上升很快、但切场景又能回落回去。在Memory Profiler里看发现是Graphics下面的,怎么排查?Unity版本是2022.3.37。

A:这个我们之前也遇到过,可以看下这个场景是不是用了发射Mesh的粒子?应该是临时生成的网格都造成了内存占用,虽然没有引用,但要在下次场景切换RUUA的时候才自动卸载。

该回答由UWA提供,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/673af015682c7e5cd61bf994


Q9:移动平台纹理压缩格式选择ASTC,美术出图还需遵守POT吗

移动平台纹理压缩格式选择ASTC,美术出图大小还有要求吗?
1. 美术出图还需要遵守POT(2的幂次方)吗?
2. 如果使用NPOT(非2的幂次方),性能方面有多大影响?

A1:如果是作用于3D场景中物体的贴图而需要开启Mipmap的纹理,则仍需要满足POT。否则,ASTC+Mipmap+NPOT,仍然会导致纹理在真机上被解析为RGBA32未压缩格式;以ASTC4*4为例,变为RGBA32则内存占用变为四倍,且相应的包体大小、加载耗时、带宽开销等其他内存开销也都会显著上升。

如果不需要开启Mipmap的呢,性能方面有影响吗?

A2:3D场景物体贴图(模型甚至特效和Spine等只要和相机有距离变化或者纵深的物体)理论上开启Mipmap都有利于降低带宽开销;若确实不需要开启Mipmap的纹理(如UI元素用到的纹理),关闭Mipmap后使用NPOT分辨率理论上对性能不会有什么影响。

感谢Faust@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/672edc1f3d306f3e9d594d88


Q10:Application.lowMemory在什么时候会生效

Application.lowMemory这个方法大家有测过吗?如何生效?

A1:由于Application.lowMemory仅在内存极其紧张时触发,因此不应该过度依赖这个回调来管理内存,尤其可能比较常见但其实有问题的、在回调中调用RUUA回收Unused资源的做法,不但降低内存的效果有限还会触发卡顿。正确的做法是通过优化资源管理、减少不必要的内存占用等方式来预防内存问题;或调用Resources.UnloadAssets或AB.Unload(True)的方式定向卸载内存。

该问答由UWA提供

A2:Application.lowMemory说明如图:

iOS系统,比如普通4G设备,闪退内存也大概为2G左右,通过Xcode可以看到一个红线,到了红线即触发闪退,在2G前的一定内存回收到lowMemory,下图的蓝色骤降的地方就是收到lowMemory释放内存,可以作为内存释放的保底方案,只要不是突然申请比较大的内存应该都可以(像最右端的就是突然一大块内存达到了Limit直接闪退)。

Android的触发时机就有点不确定了,这是官方文档:
https://developer.android.com/reference/android/app/Application.html#onLowMemory%28%29

上图说的是系统内存不足会触发,通常是在所有后台进程被杀死时候(但是也说了没有明确的触发时机,只是通常是所有后台进程被杀死)。

但是测试下来发现,后台APP被杀的时候是能收到lowMemory的,但是可能根据不同厂商,可能不是所有后台APP都被杀之后才收到lowMemory。

感谢范世青@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/66f8cd1a682c7e5cd61bf8e6

封面图来源于网络


今天的分享就到这里。生有涯而知无涯,在漫漫的开发周期中,我们遇到的问题只是冰山一角,UWA社区愿伴你同行,一起探索分享。欢迎更多的开发者加入UWA社区。

UWA官网:www.uwa4d.com
UWA社区:community.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859