宝博体育,宝博,宝博体育官网,宝博app下载,宝博体育网址,宝博体育官方网站,宝博体育注册,宝博体育靠谱吗,宝博体育登录,宝博体育入口,宝博体育注册,宝博官方网站,宝博APP,宝博注册,宝博网址近年来,小游戏发展迅速并逐渐成为游戏公司业绩增长的新引擎之一。仅微信小游戏用户规模已达 10 亿,其中月活跃用户 5 亿。庞大的用户基数为开发者提供了广阔的市场空间。 在 2024 年 11 月 2 日的 Unity User Group 深圳站,Unity 中国引擎底层架构技术主管兼小游戏技术负责人赵亮和 Unity 中国引擎底层架构开发组长詹泽行带来分享《团结引擎小游戏开发指南》, 从实际案例的数据对比到底层优化的深入解析如何使用团结引擎 开 发加载更迅速、内容更丰富、画面更精致、运行更流畅的小游 戏。 本文为演讲全程实录, 请点击文末
![]()
很高兴跟大家分享微信小游戏开发的技术。今天会从八个方面来介绍团结引擎对小游戏的技术支持、优化和新功能。
首先讲一下游戏案例。从团结引擎今年 1 月 1 日上线多款微信小游戏上线,都是通过团结引擎开发的,其中包括重度游戏,如《诛仙手游》小游戏和《远征2》。
![]()
![]()
785MB,这个优化能够让游戏在 iPhone 8 Plus 这款设备上连续跑2个小时,帧率也都是满帧。在红米 K30 Pro 的设备上可以明显看到内存的优化,帧率也有略微的上升。
内存,微信小游戏内存在 iOS 上限制得非常严格,在比较高端的 iPhone 的峰值内存不应超过 1.4GB,如果超过 1.4GB 就会出现闪退,给用户的游戏体验不好。在优化过程中,需要注意微信小游戏上的内存布局不太一样,它除了传统的UnityHeap还有其他的内存需要关注。
CPU这边,因为微信小游戏是单线程状态,多线程加速的计算是没办法做的。可能之前不是瓶颈的地方在微信小游戏这边会成为一个新的瓶颈需要进行优化。Wasm 的执行效率不是很高,是原生的三分之一的左右。
网络通信方面,因为一些安全问题,微信小游戏没有原来的 Socket,需要用 WebSocket 进行替换,基于 Socket 实现的 TCP/UDP 这些协议也需替换为微信提供的 WXTCP/WXUDP。
文件系统,传统的 native APP 很多游戏资源放到游戏包里,或者是进入游戏之前先下载下来,后面直接读文件,都是同步操作。但是在微信小程序要进行快速启动,首包非常小,其他资源是后续通过网络进行下载,都是异步的加载,会涉及到游戏同步到异步的改造。另外关于持久化存储文件,小游戏是从 WebGL 过来,WebGL 在浏览器里是一个沙盒的环境,为了安全会限制访问设备本地的文件。所以游戏退了之后有一些想要存储的数据,必须要通过微信提供的特殊接口来存储。
![]()
工程配置,比如纹理 ASTC 压缩,能很大程度降低游戏的内存。还有 il2cpp code generation 和 code optimization 的优化选项,对微信小游戏性能的影响也是比较大的。
![]()
首包压到 15-25MB,通过 Brotli 压缩将 15-25MB 压缩到 3MB,资源包也是差不多的水平。微信给我们提供的数据是,大多数用户的大概是 2mb/s,所以一个游戏进入的时间是可以通过包体大小和网速进行反推的。
![]()
减代码包,通过把多余的 Package 和第三方插件删除掉,以及避免很多 Lua 和 Protobuf 自动生成大量代码。另外需要把引擎里面的 Managed stripping level 调高,让它裁减掉更多的代码。最后是使用 WASM 代码分包工具减低代码。
下载更快。首包资源一般就包含简单的 Logo 和登录页面,这样比较轻量。另外有些文字显示需求,推荐用微信系统字体,这样可以避免文字的下载。也推荐用一些 AutoStreaming 或者是 TextureManager 的工具自动化把资源处理掉,因为有些项目是已经做好的项目,用这些工具更方便节省开发时间。
![]()
引擎的初始化和首场景的加载。下面是 BoatAttack 的启动数据,可以看到它的启动总共是 200 多毫秒。我们推荐首场景的复杂度一定要控制好,因为引擎初始化耗时很短,控制好首场景能够让启动更快。
![]()
这里是我们对游戏进入启动的耗时分析,最多的耗时是 C# 代码的耗时。第二是渲染进程 Shader 的编译。第三是 Shader 本身的变体比较多,导致数据的解压和解析比较慢。最后是纹理上传,因为小游戏是单线程,它没有办法专门给一个线程上传资源,所以纹理、Shader 的上传会阻塞主线程。
![]()
优化 C# 代码,建议不要在 MonoBehaviour Awake 以及 Start 构造函数里放太多逻辑,这些逻辑都是在启动的时候首帧画面显示之前执行的。
纹理音频要用合适的压缩格式,可以很大程度上减少 CPU 的传输带宽,对功耗和内存都有帮助。
![]()
引擎侧的优化,比如说托管代码精简和引擎代码的剔除,会尽量让 WASM 变得更小。我们打包时加了一个 Wasm 内联优化,这样分包可以把首包分得更小。资源方面也做了默认引擎资源精简以及 il2cpp 元数据精简。还有 AutoStreaming 里面的工具可以帮助轻量的游戏快速上线微信小游戏。右边是我们在运行时加速启动过程的优化。
![]()
Dryrun的模式,在这个模式下不会真正剔除代码,而是在要被剔除的代码中打一条 log,快速收集可能会被误剔除的代码,通过 link.xml 把它保护起来。
![]()
Wasm 内联优化。微信小游戏分包是以函数为粒度,一个函数用了就会保留,没有用就被剔除,如果一个函数非常大,只用了其中一两行就会全部保留起来,这是不太合理的。因此我们做了一个内联优化的控制,通过限制内联让它变成更多的小函数,没有用到的小函数会直接被剔除掉,之后得到的首包也会更小。在一款重度的 MMO 小游戏上,首包从 25MB 降到了 23.7MB,降了 1M 多。
![]()
![]()
IL2CPP 元数据精简。IL2CPP 默认的元数据结构可以支持超过 21 亿个类型或方法,但是小游戏实际应用的大概是几万到十几万的级别。所以我们做了元数据精简,打包小游戏时,根据方法的数量自动选择满足当前要求的、精简的元数据结构,这样可以减少 global-metadata.dat 15% 的体积。
![]()
小游戏启动的时候,经常要求快速进入游戏,所以边下边玩是比较重要的功能模块。对于一些大游戏来说可能有些框架用得比较好,直接用 Asset Bundle 边下边玩也可以做到比较好的体验,但是这里有一个问题是 AB 的加载时机、拆分粒度可能不太好,比如说游戏内单个 AB 有 30-40MB,用户点击按钮后就要加载很久。依赖关系和拆分 AB 的大小、粒度都是比较重要的点。
![]()
![]()
AutoStreaming,在打包时将 AB 的重度资源放到云端上,运行时会自动把这些重度数据加载回来。这个工具主要针对比较轻量的微信小游戏,重度的游戏推荐自己通过 AB 的机制优化。
![]()
Texture Manager。微信小游戏有一个比较尴尬的难点是 PC 上和手机上支持的纹理压缩格式不一样,而且没办法兼容,PC 只能使用 DXT,手机只能使用 ASTC,如果不符合这个要求就导致内存比较多,体验不好。所以 Texture Manager 首先支持的是一个纹理可以打印多套纹理压缩格式,运行时自动选择,比如 PC 上使用 DXT,手机上使用 ASTC,不会导致性能问题。 二是 Texture Manager 会管理纹理的生命周期,纹理依旧存活但是没有使用的情况下,会把纹理的数据从 GPU 上踢下来,节省 GPU 的显存。 Texture Manager 也会在打包时做纹理重映射,我们发现不合理的 AB 组织结构或加载方式导致纹理重复造成浪费,Texture Manager 会进行重新处理,相同的纹理只会出现一张,不会重复。
![]()
小游戏独有的内存还包括 WASM 编译、音频、基础库和 Canvas。音频、GPU 显存、UnityHeap 及 WASM 编译这四块是我们比较能够控制的内容,接下来会聚焦这四块的内存优化。
![]()
Wasm 瘦身。Wasm 大小直接关系到编译的内存,如果 Wasm 是微压缩状态,10MB 的 Wasm 大概占运行时内存 70-100M,大概是 7-10 倍。我们推荐要对 WASM 瘦身,一般推荐上线游戏首包 Wasm 不要超过 20MB,这是比较上限的位置。在 AB 加载这边也经常看到用户踩到一些坑,使用 Unity 默认的 Web request 下载,导致有一部分缓存长期驻留在内存里没有清理,这里推荐直接把下载机制换成微信的WxAssetBundle,可以自动把内存没有使用的踢掉。
对音频、纹理这些资源要设置好分辨率和压缩格式。微信提供了一个 Performance+ 方 案,原来小游戏是 GPU 的显存和内存是在同一个进程里面,苹果这边是单个进程如果内存超过了 1.4GB 就给你杀掉了。而 Performance+ 会把 GPU 的渲染放到另外一个进程,相当于把把两个内存放到两个进程,单个进程的内存上限有提高,可以让小游戏被杀的概率减少。
![]()
![]()
是团结引擎特有的 backend,Unity 只有 IL2CPP,所有的 C# 都会转化成 C++ 代码,再编译成 WASM。.NET8 直接把 DLL 通过容器封装成 wasm 的格式,本质上还是 DLL,通过 WASM 上跑一个虚拟机来执行 DLL。.NET8 这个平台在内存方面优势是比较大的。
![]()
![]()
这是 Shader 内存的优化,以前引擎加载 Shader 的逻辑主要是把它所有的变体都加载进内存,为了在微信小游戏上减少内存,修改了逻辑,只是创建一个空的 Shader 变体,真正编译 shader 的时候才从 Blob 数据把 shader 加载进来,这个优化在 Boat Attack 中
![]()
内存分配器优化。Unity 引擎内存分配器,会记录每一次分配的信息,并且在这个层面引发多一次对齐,即使是在 release 版本也是如此。微信小游戏内存非常紧张,为了节省开销进行了优化,把一些Overhead去掉,对齐也从 16 字节优化为 8 字节,在中重度游戏上也能够减少 10-12MB 的内存。
![]()
Remapper的优化。Remapper 是一个表,它存的是对象序列化的位置和 InstanceID 之间的双向映射关系。这个表如果同时加载资源非常多,就会非常大,内存可能达到 70-80MB。
我们把它优化成了数组,它是紧凑的结构,每次都是线性增长。这里可以看到优化后是 3MB。可能原本的大小就是 4MB,现在不够了,如果是 MAP 就增长到 8MB 去了,但是数组可能只是4.1MB的增长幅度,不会有太多的内存空间浪费。
![]()
55MB。右边的表格是通过前面每个细节项对比拿到的数据,总计是 66MB,每次运行内存都有一些小波动,基本上和我们的数据吻合。
不到 600MB,降低了 150 多 MB。右边的表格是预估内存的收益,能解释大概 130MB 左右,其他是内存波动带来的差异。
Runtime Speed的选项,至于 LOT 推荐可以去试一下,如果有异常可以回退到 Runtime Speed。如果游戏的 WASM 真的特别大,而且性能还可以的话,也可以选择 Disk Size 这个选项,可以让 WASM 的体积变小,内存也会好一点。
![]()
Skinning的介绍,GPU-Vertex Shader和GPU-Transform Feedback是在团结上新支持的两个选项。开启方式也非常简单,Transform Feedback 直接打开就好了,Vertex Shader 就需要在 shader 代码中改一行代码。右上角的图是需要修改的操作,加入一行代码,下面的图是修改完代码,引擎的编译器就自动处理成下面的结构,自动支持 GPU Skinning。
SIMD 支持,目前引擎大多使用的还是标量运算,对一些性能不是很友好。所以我们在 Math 库上支持了 Wasm 的 SIMD。为什么选择 Math 库呢?因为引擎里包括 transform、动画、粒子等很多都依赖 Math 库,这样可以让引擎整个都能享受到 SIMD 优化的好处。需要注意的是 SIMD 在 iOS 上是 16.4 版本上才支持,如果微信小游戏用户群覆盖广,可能这个功能暂时还不能用上。
![]()
如果是用 InstantiateAsync 异步就是把这两步拆分到两帧去做完。如果它是在 native 平台,可以通过 job 加速对象的构建。但是微信小游戏的环境比较特殊,它是单线程, JobSystem 无法加速,另外上传的资源没有办法放在另外一个线程,所以 Integration 这步耗时会相对更长。所以这里针对这一步做了一些拆分,让它可以在 integration 这步分成更多帧执行。拆分的过程中,会确保子任务执行的顺序和原来一模一样,不会出现顺序的问题。
Wasm 分析工具,用户可以在打包时勾选一个选项,或者是打包之后读 Wasm 文件,告诉用户哪个模块占了多大的体积。打包时可以给用户一些选项,两次打包可以进行对比,发现哪些 Wasm 是可以优化的。
未来我们还会支持经过微信分包之后的 Wasm,并且还可以进行 wasm 差异对比,以及 wasm 函数名的排序、查找功能。
这里说一下我们的时钟精度,这是我们在微信开发者工具里面拿到的性能数据,可以看到这里有一个算矩阵的逆的操作,花的时间是 0.2ms,这是个很简单的算法,不可能花到这么多,所以说这个信息可能会对优化函数造成误导。可能只是采集性能数据时刚好采到这个点,认为后面所有的 0.2ms 都是这个函数消耗的。
![]()
这是我们对比了几个不同的平台看时间精度,微信真机上通过 Unity profiler 去连接,拿到的时间精度最多是 1ms;移动端 chrome 是 0.1ms;如果到 Dev host 宿主里面是 0.001ms。这三个图都是同一个函数的时间调用,时间精度上升之后就能看到比较细的函数的调用时间,帮助我们优化。
Frame Debugger的视频,目前支持在微信小游戏、安卓及 iOS 使用 Frame Debugger 的能力,来查看比如有没有 batch 和渲染出错等问题进行调试。
![]()
之前为什么不支持这个能力是有原因的,首先 Debug 需要有一个调试的 Agent,所以要有多进程。另外像 visual studio、Rider 接受消息都是 Socket 协议,但 WebGL 不支持 socket,只支持 Websocket,两边协议是不兼容的,没办法直接建立连接。还有一个是 Websocket 没办法监听、广播。
增加了多线程支持,让 Debug Agent 在单独的线程上运行起来。然后在小游戏宿主中新增一个中间代理,一边通过 Socket 去跟 IDE 交互,另一边通过 Websocket 跟 Debug Agent 交互。这个中间代理具备广播和监听端口的能力,让 IDE 可以方便的搜寻到需要调试的小游戏。
![]()
在打包的时候把 Script Debugging 给勾上;在宿主上需要去点一下打开 C# 代码调试按钮。同时确保 IDE 和宿主运行在同一个局域网内,就可以建立连接,进行代码调试了。
![]()
![]()
独立渲染线程。刚才提到很多小游戏上只有单个线程,带来的问题是主线程时间消耗很长、帧率比较低,而且会带来功耗的问题,不能发挥出多核优势。
动画的压缩,用了 ACL 的压缩之后,可以使 Animation clip 变得更小。
对 C# 的编译器在做一些优化。 再有就是平台渲染能力的拓展,是我们跟微信一起在探讨的,如何把小游戏平台的渲染能力进一步提升。 接下来给大家详细介绍一下这几点。
GPU Instancing的支持。这个 feature 我们预期在团结的 1.4.0 即 2024 年 12 月底可以发布出去。右侧有一个 profiler 的结果,打开了 GPU Instancing 之后,我们的 Setpass 数是差不多的,但是 Drawcall 数会大幅降低。假如不开 Instancing,对于有些场景 instance 数量特别多的情况下,drawcall 有可能到 5000 以上,打开之后可以通过 Instance 的方式绘制,这样 Drawcall 的数量降幅会非常明显,变成之前六分之一的样子。无论是 iPhone,还是安卓,高端和低端设备上都能看到 FPS 有明显的提升。
![]()
对 C# 编译器我们也做了优化。一是做更好的增量分包,比如小游戏发了一个包,隔一段时间对代码做了一个小的改动,需要再更新一个版本。这个时候我们不希望重新做一次采集分包的过程,因为采集分包比较耗时,而是想利用第一次采集的结果。这意味着做少量代码改动时重新编译生成的 WASM 里面的函数签名需要很稳定,这样原来采集的信息才是有效的。Unity 原本用的 Rosyln 编译生成出来的函数名不是很稳定,主要是 Lambda 的表达式里有一个 MethodOrdinal,编译器对于一个函数假如有重载,在里面会通过数字标识不同的重载,这个数字生成的时候不稳定,导致可能代码压根没有改动,但是两次编译函数生成的签名不一样,导致采集 broke,这一块我们打算修掉。
第二是,用 foreach 遍历 List,跟不用 foreach 来遍历 List,会发现这两个生成的 Wasm 代码差异非常大。发现 foreach 在 Rosyln 编译的时候会进行展开,里面会增加一个 try-catch。假如自己从 list 拿一个 enumerator 进行一次循环的话,生成的 WASM 大概只有 100 多条,但是如果套了 Try-catch 之后,再调取 disposable,就会有 500 多个 instruction。当一个游戏里大量使用 Foreach,会导致带来很多 Wasm 的体积膨胀及运行时内存增加。Try-catch 很多时候发现它不是必需的,所以我们准备在 Rosyln 的编译器里面给它一个选项,当你选择不需要 try-catch 的时候就可以优化掉。
![]()
动画压缩,主要是集成 ACL 库,它有更高的压缩比。用一个 animation clip 进行对比,不开启压缩占了 327K,原本通过 Keyframe Reduction 或者是 Optimal 的方式能降到 62K,用了 ACL 之后能够降到更低,是 Optimal 的六分之一,只有 10.3K。这对于小游戏特别有用,让打包的 animation clip 资产变小,使得加载更快,包体更小,同时运行时内存也有相应的降低。ACL 对于 animation clip 的 sample 也会更快。我们预计也在 12 月底发出这个 feature,性能收益也会整理出来。
![]()
这样有很多好处,可以不再受限 WebGL 2.0,也不局限使用 WebGPU。因为 WebGPU 本身走向成熟需要一定时间,而 Metal 当前就是成熟的。另外在使用 WebGPU 的情况下,手机底层驱动还是 Metal,需要一个 WebGPU 到 Metal 的转换过程,它不是 Free 的。我们跟微信探讨直接在 Performance+ 这样的方案上支持 Metal,通过这种方式,未来大家就可以在小游戏上使用上
Visual Effect Graph和GPU Resident Drawer这样的功能,小游戏上绘制的场景天花板会逐渐增高。这个功能有可能会到明年的 Q2、Q3 发布,需要我们跟平台侧把能力共建起来。
从超休闲到MMO、策略游戏等中重度游戏,小游戏的品类越来越丰富,用户体验不断提升。Unity 中国不断加大对小游戏的支持,推出的产品“团结引擎”在小游戏开发的轻量化、多平台适配、稳定性提升等方面做了大量优化。2024 年 12 月 6 日 Unity Open Day 技术开放日厦门站将聚焦小游戏及开源鸿蒙平台的技术实现及市场探索,探讨如何利用团结引擎的最新技术,为小游戏赛道、移动端游戏注入强劲增长动力。还有闭门 Round Table ,直接对话引擎研发!亮点多多,点击!