使用ScriptableObject代替部分配置表的坑点

侑虎科技

1)使用ScriptableObject代替部分配置表的坑点
​2)加载配置内存过大问题
3)URP的UI在Android模型器下比在真机上暗
4)Unity在Windows上第一次运行Play启动很慢
5)如何正确卸载UnityWebRequest下载的图片资源


这是第231篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)

Script

Q:ScriptableObject可以通过Runtime修改,资源可以拖拽配置。这些都是Excel无法做到的优势。

所以准备尝试用ScriptableObject代替部分Excel的配置用在项目里。想知道,ScriptableObject这样用,大家有没有遇到过比较严重的坑点?例如这样的Asset的加载、解析的空间或时间上的开销是否可接受等等。

补充一下,比如装备是成组的,对每组装备做一个ScriptableObject对应的Asset拖一组装备Prefab引用,然后由外部持有ScriptableObject Asset的路径即可。像这种部分资源相关的配置走这套,粒度更细,一个Asset中包含的资源本身就是应该被同时加载的。这种情况是不是没有这种冗余加载的问题?

A1:之前的项目曾经用过这种方式做配置表,但是随着表格和配置的增加,会出现许多问题,比如以下几个:

  1. 内存:内存要比普通的加载、解析二进制文件要大不少,大概有8倍。
  2. 加载速度:加载速度比普通的解析二进制要慢十倍以上,也是个大概值,毕竟是三年前做的项目了。
  3. 卡顿:ScriptableObject的加载和解析都在主线程,会卡主线程,而自己实现的二进制可以自己写个子线程去解析,就算在主线程解析起来也很快。这块大概也是十倍的量级。
  4. 硬盘:如果二进制不压缩,其实硬盘上差距不那么大,但是稍微用zip压缩一下,就有十倍的差距了。
  5. 策划:如果面对大量的数据,Excel显然更能帮助策划高效地配置,比如现在需要配置100个道具,如果用ScriptableObject比较复杂。
  6. Runtime:Runtime修改虽然做不到,但是热重载是可以做到的,效率也不差多少。
  7. 资源可拖拽:这个功能你调查过策划是否喜欢了吗?
  8. 热更新:如果项目使用的语言是Lua,ScriptableObject会阻碍新增字段的更新,毕竟是C#声明的字段(或者后续有表格热更新增字段、表格的需求)。

以上情况如果都能接受,那么用ScriptableObject是可以的。据我所知,还是有一些上线项目是用这套方案的,并且也稳定运营了3年以上。

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

A2:举个例子,比如一个装备表关联上百个装备模型。加载直接拖上去的ScriptableObject就得同时加载这上百个装备模型。如果不用拖拽引用,这个的可编辑性远远不如Excel。

感谢欧月松@UWA问答社区提供了回答

A3:一般这种资源引用,可以考虑使用一个可加载的路径或者地址来代替,避免直接引用带来的同时加载问题。

感谢静风霁@UWA问答社区提供了回答

A4:ScriptableObject大部分时候还是没有Excel好用的,比如在公式和索引上,也无法快速定位配置错误,但是大多数Editor的编辑器功能需要用到ScriptableObject。

我们项目的方案是Excel转Protobuf + ScriptableObject转Protobuf,运行时只加载Protobuf的二进制文件即可。

感谢萧小俊@UWA问答社区提供了回答

Script

Q:配置表太多占用内存过大时,除了采用Sqlite,还有什么好的解决办法吗?FlatBuffer不用全部进内存吗?如果不全部进内存,访问速度如何呢?

A1:解答第一个问题:

  1. 可以针对重复数据进行剔除,尤其是一些字符串的配置。在配置导出时把这样的数据提取一份,其他用到的地方只是引用,会节省不少。
  2. 数据类型要合理。
  3. 可以使用类似FlatBuffer/ZeroFormatter的延迟加载的思路,在真正使用时再去反序列化。一次游戏过程中实际用到的配置量比较有限,使用这种策略可以尽可能地减少不必要数据的加载(这一条可能主要适用于C#层去读配置的,如果你们是存成Lua这条就不一定适用了)。

解答第二个问题:
我们上个项目也是到后期优化时遇到类似问题,只是参考了这种思路,并没有进行完全替换。在打包时,会对配置以行为单位,进行Offset和Length的计算;在Runtime阶段,初始加载只会加载每行的ID,对应的这一行的Offset和Length,然后后续逻辑调用配置表接口拿数据的时候,如果发现没有反序列化过,就根据Offset和Length再去构建一下相应的数据提供给上层。访问速度肯定没有开始直接全部加载的好,但我们测下来影响不大。

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

A2:字符串吃内存,尽量少用或者复用。
表格中比较多的会是哪种?攻击-1000、防御-2000、血量-3000,每个Int都是4个字节,数量多了会顶不住。这种可以考虑用一个int32/int64/uint32/uint64去存多个数值。

感谢萧小俊@UWA问答社区提供了回答

Rendering

Q:URP的UI在很多Android模型器下的明显比在手机上要暗很多。确认模拟器用的Gles3.0+ 支持Linear色彩空间,看上去就像是模拟器对UI进行了一次额外的GammaToLinearSpace,如果在导入UI图片时把sRGB勾掉,或者进行一次LinearToGamma,就能在模拟器上显示正常,但手机上就颜色太亮了,如下图:

A1:最新进展:之前用2019.3.5f1,更新到2019.4.10f1就没有这个问题了。

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

A2:Unity论坛有很多人反馈SRP + OPENGL ES + Linear Color Space在Android上面有渲染Bug。

看下Player Settings->Android->Resolution and Presentation->Blit Type设置成Auto能否解决问题呢?

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

A3:2019.3.6f1的Release Note里有说到这个是Bug。
[Mobile: [Android] [Gles3] [URP] Darker UI when using Gles3, Linear and URP]

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

Editor

Q:Unity在Windows上第一次运行Play启动很慢,但在Mac上没有这个问题。该如何进行排查呢?

A1:Mac没问题,有可能是Play启动游戏的时候在扫描各种资源文件导致,可以排查下AssetPostprocessor相关的,比如OnPostprocessAllAssets是不是每次启动的时候都在遍历。

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

A2:如果是Editor的问题可以试一下Unity官方提供的编辑器耗时分析工具Performance Tracking(2019.4+),低版本从Profiler中看看能不能定位到耗时。

Performance Tracking
ScriptableObject导致的类似的问题

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

Resource

Q:通过UnityWebRequest和DownloadHandlerTexture下载的Texture资源,下载完成后赋值到RawImage组件,如何正确卸载UnityWebRequest下载的图片资源?

A:我们上个项目此类Texture都会被专门的Manager管理起来,确保没有被其他GameObject引用后,使用Object.DestroyImmediate来销毁掉,虽然这个接口官方不推荐使用。

或者可以尝试下确保没有引用后使用Object.Destroy卸载或等待下次调用Resources.UnloadUnusedAssets时来卸载。

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

封面图来自网络


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859(原群已满员)

阅读 204

简单优化,优化简单~

13 声望
4 粉丝
0 条评论

简单优化,优化简单~

13 声望
4 粉丝
宣传栏