演讲PPT资料下载地址:https://u3d.sharepoint.cn/:b:/s/UnityChinaResources/EWvAE6oOnt1GjePtkddvPhABuwtfxSQ6rh4d7H4LXKdA9Q?e=jvjV9g
在2025年5月24日的Unity User Group北京站活动中,Unity中国游戏发行业务技术负责人李广一带来分享《团结引擎小游戏移植技术分享》
李广一:大家好,今天很荣幸借这个机会和大家分享我们利用团结引擎做小游戏移植的技术经验。
Unity中国游戏发行团队
首先向大家介绍一下我们Unity中国游戏发行团队,主要由三个子团队组成。
首先是技术团队,主要任务是做游戏移植,负责移动端、小游戏等各个平台的对接和上架,也做一些性能优化,还包括根据策划案对游戏玩法和商业化进行相应改造。
运营团队对游戏进行评测,并提供针对性的改进方案。在游戏上线后,他们会对游戏数据进行分析,并做针对性调整。
投放团队负责素材制作、买量投放、测试调优。
游戏发行技术团队是我们的一大优势和特色,很多游戏发行公司不负责技术,只负责运营和投放,游戏的技术需要由CP方自己来承担。
Unity作为引擎提供方,技术是我们最强的优势;很多开发者没有经验,或者没有足够的人力做移植,因此我们推出了游戏移植这项服务,帮助大家把更多好游戏推向更多平台,触达更多玩家。
给大家介绍一下我们做过的移植类型。
从平台上来看,PC游戏移植到移动端平台,主要是steam游戏到安卓、iOS。也有从移动端游戏往小游戏平台移植的,小游戏平台主要阵地是微信和抖音,也有其他例如小米、快手等。当然也有steam游戏直接往小游戏平台移植的情况。
从游戏类型上来分类,大部分还是超休闲游戏,但我们也有一些中等程度的模拟经营类游戏和几款重度的IAP游戏。
通过和许多开发者交流合作,我们发现一个特点,大家可能不是每个游戏都想上架移动端,但几乎每个游戏都想上架小游戏。
小游戏发展非常迅猛,这个趋势也是大家有目共睹的。近几年观察小游戏TOP榜单中,Unity游戏占比也在逐年上升。
小游戏普遍以休闲游戏为主,不过并不是只有超休闲游戏,很多中重度游戏也可以登上小游戏平台。如果大家有一些优秀的游戏,在PC和移动端上获得了成功,你的成功也可以在小游戏平台上得到延续。
小游戏的限制因素
为什么小游戏平台这么火,但大家都觉得有一些开发难度?主要是因为小游戏平台有一些技术限制因素。小游戏平台归根结底是网页端的技术栈,出于安全性或其他方面的考虑,它的限制更强。我们总结来看小游戏平台主要限制包括三方面:资源限制、内存限制、性能限制。
首先是资源限制。小游戏玩法和传统手机端游戏完全不同,手机端游戏是预装方式,玩家提前把游戏下好。小游戏是即开即玩,用户点开之后通过一个短暂的下载和加载进行游玩。用户对加载时间要求比较高,游戏加载时间越长,用户流失率越高。下载的过程一定是异步操作,提高了处理资源加载的难度。
内存限制也比较高,低版本的IOS有1GB左右的限制,高版本IOS或者安卓手机,也比原生平台限制更严,最高也只能用到1.6GB左右。
WASM编译运行会占用约10倍大小的内存,如果有90M的WASM会占用900M的内存,内存占用是相当大的。此外,托管堆扩容的时候会导致内存峰值,如果内存峰值超过内存限制,游戏也就崩掉了。
最后一点是性能限制。实际测算下来,游戏CPU运行效率约为原生平台的三分之一左右。因为JavaScript不支持多线程,所以小游戏也不支持多线程。
从渲染API来看,小游戏下能用的渲染API就是WebGL 1.0和WebGL 2.0,WebGL 2.0相当于GLES 3.0。高于3.0的feature,比如compute shader在小游戏下也是不支持的。如果用到feature后处理或者特效是无法显示的。
还有一些低端机如果使用了iOS 15以前的系统版本,可能不支持WebGL 2.0。如果使用了需要WebGL 2.0的feature,如Unity的URP管线,或一些GPU instancing的功能在低端机上也无法实现。
小游戏移植优化
针对小游戏以上限制,接下来讲一下怎样做优化。
优化包括三方面,资源优化包括首包缩减、Asset Bundle管理、同步/异步加载需要做适当的处理;内存上包括wasm的缩减、资源压缩、团结引擎优化;性能方面是避免重度运算、编译选项和团结引擎优化。
资源优化
1. 小游戏首包缩减
首先介绍小游戏的首包优化。小游戏加载时候需要下载的内容就是小游戏的首包。主要包括资源data文件和wasm文件。data文件包括in build场景及引用资源、Resources文件夹下的资源。代码方面包括引擎模块代码、package和第三方插件,以及managed code。
对首包资源进行优化,首先是尽可能减少打包进首包的场景,理想的情况是选择一个场景打包入首包。建议首场景当中只包含一个loading页面和必要的信息,其他的资源异步加载。
尽量避免使用Resources文件夹,因为这个文件夹的特性是不管有用或者没用到的资源全部会打包到首包里。所以我们通常不推荐使用。
使用图片显示必要的文字也是一个常用的策略。用到一个文字就需要字体,一个字体文件至少需要1-2M,我们通常采用一些技巧,把文字转成图片,图片的大小就要小很多。另外是使用brotli压缩。
2. Asset Bundle资源管理
首包资源要尽可能的少,剩下的资源要通过Asset Bundle加载。接下来从四个角度来介绍怎样对Asset Bundle资源进行管理。
首先是资源压缩,建议图片使用ASTC的格式,因为ASTC是GPU支持的格式,不需要额外进行解压缩。
小游戏下通常建议分辨率是1024或者更低,因为小游戏资源都需要进行下载,如果资源还像手游或者PC端那样高清,游戏资源体量就会很大。
举个例子,比如1024图片格式如果选用ASTC6×6,一张图片要400KB左右。如果有100张图片,比如贴图,一个比较大的场景100张贴图还是比较常见的现象,光图片资源就有40M。按照现在比较常见的平均网速,如果一两兆每秒,用户要下载几十秒的时间。所以大家需要在显示效果和下载速度上做一个平衡。
Read/Write,Mipmap非必要不勾选。如果没有明确的需求就不要勾,因为勾选了,要么打包的体积会变大,要么内存体积变大。
音频类资源通常会选择Compressed in Memory,小游戏下对音频的需求通常不会太高,我们可以我们选择Force To Mono,把它变成单声道,Quality尽量调低。
Asset Bundle有一些常见的组织方式,按类型分组:模型、贴图、材质。也有的游戏按功能分组:UI、角色、场景。
这些方式在小游戏下并不是非常合适。小游戏希望玩家用少的资源就能够正常进入游玩。我们建议组织方式按照进度分组,比如按照关卡,第一关资源、第二关资源;或者流程,先有一个教学关卡,然后才进行正式关卡;或者根据玩法,先推一个主玩法,玩到一定程度有一些不同的副玩法,这些副玩法资源后续再去加载。
通常推荐首先下载登录或加载界面需要的资源,显示加载界面的时候下载首关或教学关卡资源,游玩的时候加载后面的主关卡资源。
Asset Bundle加载离不开一个问题是异步的问题。下载是异步操作,加载有异步的,也有同步的。
最理想的方案是按需加载,用到资源的时候再下载。这种方式理论上加载是最快的,不会有统一的下载资源过程,玩家也不会有很长时间的等待。
但这要求玩家网速要快,如果玩家网速慢就可能会出现各种各样的问题。例如玩家会看到加载过程或者进行一定时间的等待,或者玩家播一个音效的时候发现音效播不出来,或者一个特效没有显示出来。这些都是我们需要考虑的问题,而且我们还需要注意处理时序。所以这种方式是最理想的,但也要求更精细的处理。
另外一种比较安全的方式是分阶段预知加载。在关卡或者场景之前提前收集关卡用到的资源。很多游戏在每一关前有一个Loading界面,在此时下载资源再按需加载。这种方案能保证玩家用到资源的时候资源是在的,玩家不会有需要等待的情况。缺点就是Loading时间相对长,而且需要精细管理资源,不然内存上会出现泄露的情况。
还有一个候补方案是利用文件系统。我们之前移植过一个手游,做的时候没有考虑过小游戏的情况,用了大量的同步加载,有几千处,如果全部改成异步工作量非常大。后来采用的处理方案就是把Bundle下载到小游戏文件系统,然后用文件系统的同步接口加载,这个改动量就变得可以接受。游戏上线以后发现效果还是可以的,虽然从理论上来讲同步的文件接口性能或效率没有异步好,但以不错的效果解决了游戏的移植转换问题。
如果游戏之前有大量的同步加载,改异步非常困难的时候,也可以考虑这种方案。但这种方案可能存在的问题是,微信和抖音文件系统容量有限,像微信如果超过200MB需要开通支付,游戏要有版号。
现在市面上有很多Asset Bundle框架。首先,Addressables是Unity推出的一个管理框架,功能强大,使用起来也很方便,能自动传到CDN上。唯一不太好的地方是接口是异步的,如果有大量的同步接口去改的话不太方便。如果有非常大量的资源,索引文件也会比较大,一定程度影响性能。
YooAsset是我们看到一些游戏会使用的国产开源框架,比较简单易用。但有一个问题是,资源更新是以Package为单位,Package之间的资源无法去重,不同的Package资源会有重复,导致Bundle体积变大。
AutoStreaming是我们团结引擎推出的自动加载和卸载的框架。原理是把一些体积比较大的图片、音频资源自动上传到CDN,利用自动框架需要使用它的时候帮助加载。像图片这类资源,它还会自动创建一些分辨率很低的place holder,它会先展示一个很糊的图片,当原尺寸下载图片完成以后自动替换,这个框架也非常简单易用,大家可以体验一下。有点不是很好的地方是它可能会让用户看到一些加载过程,需要做一些loading界面进行遮挡。
还有一种方案是Asset Bundle最原生的API,做自定义框架,满足特殊需求。唯一不太好的是开发量大,大家如果有比较多的游戏可以进行复用,比如我们做游戏的移植就是复用我们自己开发的框架。
3. 团结引擎的资源优化
这里是团结引擎做的一些资源优化,包括il2cpp元数据精简,大概可以缩减15%的体积。默认资源也做了精简。支持加载宿主字体,如果加载宿主字体就不要把字体打包到首包或auto streaming里。另外TextureManager是我们提供的一个管理texture的工具,可以实现一套Asset Bundle有不同的texture,既能满足移动端,也能满足小游戏的需求。
wasm代码优化方面,代码包含C#代码、unity package和第三方库代码、引擎模块代码这些部分,我们根据不同的部分做了相应的优化。
首先移除不用的Unity package和第三方库。不要勾选不用的Unity模块,比如VR、XR。还要注意开启strip engine code,如果不开启,就算没有勾选也会被打包进去。要去除不用的using,也是大家经常忽视的点,写代码的时候不小心写错,或者从哪里copy了代码过来,很多using就留在那里了,但从C# 编译器的角度来讲,这些using还是会被打进去的。另外要去除没有调用的函数,如果有些函数明确没有被用到,可以手动删掉。
尽量使用精简的第三方库,拿Json举例,json有些很重的实现,我们尽量使用轻量级的实现。像Newtonsoft.json是C#经常用到的json库,特点是为了通用性包含了很多类的序列化和反序列化的方法。如果用了一个DLL的Newtonsoft.json库,会把system.data的序列化的文件全部包含进去,对于大部分游戏来说用不到。我们在使用这个库的时候就选择用它的源码,不需要的地方剔除掉,库的体积就会小很多。
还有使用Managed Stripping Level。最后,首包的分包工具是很有用的,但也有一些缺点,需要进行非常细致的采样,才能保证在使用中不会漏掉代码,一旦漏掉带来的性能问题比较大。我们建议如果能手动把一些代码剔除掉,优先手动剔除。
团结引擎也做了一些代码优化:
首先是内联代码优化;
其次,Managed Stripping Level加了Extreme,Extreme也是一个采样式的优化,和分包工具思想有点像。但如果在使用Managed Stripping Level的时候遇到了代码无法运行的情况,通常是有一些用到的类被错误剔除掉了。这种情况一般是用Asset Bundle产生的,比如你在Asset Bundle用到一些方法,但首包场景并没有用到,就会被剔除掉。这种情况就可以用团结引擎打包Asset Bundle,它会自动生成link.xml,把用到的代码保留。
关于wasm分析工具,简单举个我们转过的游戏进行代码分析的例子。像Assembly-CSharp这才是我们自己写的业务代码,可以发现自己写的业务代码在打出来的代码当中占比非常小,很大一部分代码都是引入的库文件,如果我们清楚知道不会用到它,要把它剔除,得到的收益就非常大。
这里比较典型的首先是System.Xml,可以看到56万个指令,还有System.Data有40万个指令,这两个加起来占比就非常高了。很多情况下代码里面用不到这两个库,但有一些using用到了,需要把这些using剔除掉。像UIElement,我们需要用strip engine code把它去除。
像Sirenix.Serialization,这是odin inspector插件,可以帮我们扩展inspector。但这个插件当中的Serialization模块是一个runtime的DLL,即使代码没有用到Serialization也会被打到包里。这些细节大家在打包之前注意一下,如果有些没有用到的要去除掉,首包能获得几兆,甚至十几兆的收益。所以团结引擎这个工具很有帮助,推荐大家尝试。
内存优化
内存方面主要是WASM内存、UnityHeap和GPU显存占比较高。
怎样优化呢?首先是WASM瘦身,可以自动获得内存优化。合理保留设置的ManagedHeap的值,尽量避免扩容。资源压缩也会获得内存上的收益。另外要及时释放不用的Asset Bundle和资源,尽量使用精简的字体。再就是iOS使用performance+。
团结引擎也做了很多内存优化。首先有ill2cpp运行时的内存优化、内存分配器优化、Shader内存优化、Remapper内存优化、ACL动画压缩、降低显存的优化,大家有兴趣可以去团结引擎文档。不需要额外做设置,如果使用团结引擎自动可以获得这些优化。
性能优化
性能优化方面:
一是避免使用XML、JSON解析大文件,这也是我们在移植一些游戏中碰到的。比如一个游戏使用了json,json超过1兆大小,在一些低端机上解析就非常慢,可能要花几秒钟时间。我们把它转成一些二进制格式,就获得了几十倍的速度提升。
lua是常用的热更语言,用lua尽量避免重度的运算。
IL2CPP Code Generation这个选项我们也做过测试,对于性能影响不是很大,可以选择faster(smaller)builds。但Code optimization这个选项影响很大,建议大家选runtime speed。
另外跟其他手游或PC游戏的优化思路差不多,可以用Profiling工具寻找卡点,降低卡点的CPU消耗。
我们也发现大部分游戏在CPU运算上的瓶颈不是很大,很多游戏转到小游戏上瓶颈在于渲染方面,要采用一些常规手段,例如减面、合批做性能优化。
团结引擎提供的性能优化包括GPU Skinning支持、图形渲染优化、异步实例化、异步处理优化,这些都尽量减少了单帧卡顿的情况。另外Math库SIMD支持也可以提高一些动画方面运算的性能。团结引擎也即将发布原生渲染能力、独立渲染线程。
最后,大家如果之前做过一些好的手游或PC游戏,想在小游戏上延续它的成功,这是完全可能的。希望大家选择团结引擎,因为团结引擎对小游戏平台做了非常多的独有优化。
如果大家对游戏移植有任何问题,或有好的游戏想要找发行,都可以添加我们的帐号联系我们。Unity中国游戏发行业务开展不到一年时间,现在已经移植了将近50款游戏到小游戏平台,而且我们移植的工作不收费。谢谢大家。