还在用难用的AssetBundle?快来运用Unity新的可寻址资源系统,助力游戏开发
Unity Addressables可寻址资源系统是一个强大的Unity资源包,它能够帮助解决游戏开发中最重要的一些挑战:高效率和轻松的内容管理。
在管理游戏资源时,往往很难维持好的标准,从而避免让项目变得杂乱无章。最主要的问题在于不同职责的资源管理系统之间的耦合。而且,项目中资源的存储,加载和载入后资源的使用方法都有紧密的联系。
例如:我们可能要在Resources文件夹存储某个精灵。这会让Unity在构建版本时,把精灵存到特定的存档文件中。由于精灵存在了这样的位置,我们必须通过Resources API来加载该精灵。
项目变得混乱的速度比你想象的更快,一种方法的选择将造成项目长期的结果。一个好的系统会避免我们轻易犯下草率的错误,一个优秀的系统也会易于学习和使用。
通过使用Unity Addressables可寻址资源系统,我们可以将资源管理问题分离。我们的目标是保持灵活性,同时让项目具有可维护性。
本文,我们将介绍开发者使用Unity Addressables可寻址资源系统创作游戏时,会获得的三个好处。
好处1:减少游戏的内存压力
在发布游戏时,大多数平台都会让开发者提供玩游戏所需的最低硬件配置要求,以便玩家在购买时参考。
原因很简单:要求的硬件配置越高,购买游戏的玩家会越少。而从另一个角度看,实现的内存管理越好,我们便可在游戏提供更多内容和乐趣。
Unity Addressables可寻址资源系统的第一个好处便是:高效的内存管理。
为了大致了解其效果,我们可以把这些代码:
public class CharacterCustomization : MonoBehaviour { [SerializeField] private List<Material> _armorVariations; [SerializeField] private MeshRenderer _armorRenderer; public void ChangeArmorVariation(int variationId) { _armorRenderer.material = _armorVariations[variationId]; } }
转化为下面的代码:
using UnityEngine.AddressableAssets; public class CharacterCustomizationV2 : MonoBehaviour { [SerializeField] private List<AssetReference> _armorVariations; [SerializeField] private MeshRenderer _armorRenderer; public IEnumerator ChangeArmorVariation(int variationId) { var loadProcess = _armorVariations[variationId].LoadAssetAsync(); yield return loadProcess; _armorRenderer.material = loadProcess.Result; } }
转化后实现的效果如下图所示,我们可以轻松节省内存使用。
了解使用可寻址资源系统实现更好内存管理的内容,请阅读:《使用Unity Addressables可寻址资源系统》。
好处2:轻松快捷地加入DLC内容
使用Unity Addressables的第二个好处:可以让开发者完全控制存储和加载游戏资源,从而有助于开发者添加和出售可下载内容(DLC)。
即使目前不考虑发布DLC内容,只要在项目中使用Addressables系统,我们就已经提前为这项工作做好了准备。
我们也有其它方法来出售DLC内容,例如:使用Asset Bundles,但这些方法在实现相同作用的同时,会带来更高的开销,因此这些方法会逐渐被弃用。维护正常运行的Asset Bundle管线非常消耗时间和精力,需要大量复杂的专业知识。
在Unity中有很多方法可以实现DLC内容,但对于初学者来说,下面代码是很好的学习起点:
public class DlcManager : MonoBehaviour { // ... public IEnumerator TryDownloadDlc() { if (_hasBoughtDlc && _dlcDownloaded == false) { var operationHandle = Addressables.DownloadDependenciesAsync("DLC-Content"); while (operationHandle.IsDone == false) { _progressText.text = $"{operationHandle.PercentComplete * 100.0f} %"; yield return null; } } } }
通过以上代码,你应该了解其中的原理。我们能够使用Unity Addressables,通过少量成本为玩家带来更多乐趣,何乐而不为?
好处3:减少迭代时间
使用Unity Addressables会减少在多个过程的等待时间。
我们都体验过按下Unity的Play按钮后,等待约半分钟的时间。如果把构建版本部署到移动平台或WebGL平台,那么情况还会更糟。这种等待时间会大幅增加迭代所花的时间。
任何玩家都不喜欢等待,Addressables系统会提供以下帮助:
减少构建大小
游戏往往有很多内容,玩家喜欢体验内容,而开发者喜欢创作内容,并将把游戏内容提供给玩家。但这并不意味着,我们创作的每个资源都要包含在玩家安装的构建版本中。实际上,我们要尽可能移除不必要的内容。
玩家都希望尽快开始玩游戏。如果游戏需要2GB的数据流量,以及半小时的下载时间,玩家会对此感到不满。这样,玩家可能会更倾向于下载《Candy Crush》这类大小低于50MB的游戏。
其中一种应对策略是:只在安装程序包含主菜单等运行游戏所需的资源,然后在后台下载剩余游戏内容,首先要下载的是游戏的关卡内容。
这也会使开发期间的部署速度变得更快。我们将能够每天迭代更多次数,这个好处会在长期时间中累积效果。
减少加载时间
作为游戏开发者和玩家,我们都讨厌等待。等待会让我们失去玩游戏的状态,我们的游戏时间可能在不经意间就结束了。
Unity正在努力通过改善编辑器和游戏的发布方式,减少玩家开始玩游戏的时间。未来有很多值得期待的功能,例如:Unity 2019.3中避免域重载(domain reloads)的功能很值得期待,但如今它仍处于Beta版。
假设我们正在开发中世纪题材的游戏。数月前,我们为游戏实现了护甲类型。开发过程非常顺利,我们生成了超过100MB的游戏内容。
接下来,我们继续开发其它内容,例如:刀剑对决。我们发现,每次按下Play按钮测试功能时,都会从已开发功能中加载大量数据,而且加载这些数据也需要大量时间。
按下Play按钮测试“刀剑对决”的动画时,由于要加载之前实现的护甲功能,我们会额外等待5秒时间。由于内存带宽有限,因此加载过程耗费的时间大多发生在I/O过程中。此外,CPU也要对该过程进行处理。
作为开发者,我们会在Unity编辑器中耗费相应的时间。而玩家则要在已发布的游戏中等待更多时间。
了解到这个情况带来的影响后,我们要使用什么方法解决该问题呢?
Unity Addressables能够通过两种方法帮助我们。
1
减少玩家的加载时间
我们可以减少玩家的等待时间。使用资源的间接引用而不是直接引用,这样会大幅改善加载时间。
通过使用间接引用,即AssetReference,Unity不会同时加载所有内容,而只在必要时加载部分内容。更重要的是,我们可以直接控制加载内容的时间。
2
减少Unity编辑器上的迭代时间
你对Unity Addressables窗口中的Play Mode Script有多少了解呢?Play Mode Script会定义Unity编辑器如何加载标记Addressable的资源。
选中Packed Play Mode,Unity会直接加载预构建的可寻址资源,仅使用少量处理开销,从而有效减少Unity编辑器中的迭代时间。
使用该功能前,请记得先点击Build Player Content来构建玩家内容。
我们可以试想一下,把这些方法应用到最急需的内容时会产生怎样的效果。
小结
本文,我们了解了Unity Addressables能够帮助进行更好的创作,并给玩家提供更多内容。 我们将从中受益,让项目在未来数月或来年得到提升。