我曾经担任两款Unity 2D游戏的首席程序员:Anomaly Collapse Thank You For Your Application. Anomaly Collapse已经发布了很多年,而在那时我们也成功地在NS1上运行它,这个机器真的是非常糟糕的。另一个游戏尚未正式发布,但QA已经基本完成,而且到目前为止,它在Windows、macOS和Steam Deck上都没有明显问题。

对于这两个项目,我并没有在资源加载系统上投入太多的设计工作。它们都是2D游戏,内容相对较少,所以我使用了一个非常简单的,甚至有些粗暴的方法。

我们使用ScriptableObjects作为配置文件。然后我们将整个配置文件夹Addressable化,并为其分配一个标签。当游戏启动时,我们调用Addressables.LoadAssetsAsync来加载该标签下的所有配置文件。加载后,我们使用定义在SO中的ID和实例化的SO对象来构建一个字典,这个字典存储在一个配置单例中。之后,游戏需要数值配置、Sprites、Prefab或其他资源时,它们都直接从这个配置系统中获取。

这个方法非常简单、直接、易于使用。没有复杂的动态加载逻辑,也几乎没有卸载逻辑。对于这两个项目来说,这足够好了。至少在我们的目标平台上,它们工作得很好。唯一痛苦的就是NS1。为了让游戏在该平台上运行得更流畅,我花了很多时间将加载过程尽可能地移到后台,并延迟它直到游戏真正启动之前。但核心思想并没有真正改变。

然而,我并不认为这个设计足够好,以便在更大的项目中进行缩放。

在我的当前方法中,很多ScriptableObjects直接引用Sprites、Prefab或其他艺术资产。所以,当我在启动时加载所有配置SO时,我可能也会将大量依赖的资产加载到内存中。实际上,这几乎是“启动时加载大部分游戏内容”的情况。如果项目有更多的内容,启动时间和内存使用量可能会变得无法接受。

我知道AssetReference可以避免由直接引用引起的问题,并且我理解它在Addressables工作流中的价值。但我的关注点更多的是团队协作而不是API本身。我的大多数项目都是协作项目,设计师经常编辑配置数据。如果资源系统的正确性依赖于每个人始终使用AssetReference而不是直接拖拽Sprites、Prefab或其他资产引用,我觉得这个规则很容易被绕过或滥用。

我并不是寻求一个完整的AAA级别的资产管道,也不是要求一个单一的“正确”答案。我想听听人们的真实项目经验:如果一个项目比小型2D游戏更大,但仍然远远没有AAA规模,通常如何设计资源加载和管理结构?

任何有用的信息都将被感谢。例如,遇到的陷阱、后来需要改变的设计、对项目结构的工作经验、Addressables使用经验、如何防止资产引用在团队中失控的方法或甚至只是一般原则。

在这两个项目之后,我变得更加意识到资源加载系统的重要性。对于小型项目,一个简单的方法可以很好地工作。但如果我想要在未来制作更大的东西,我不想等到开发过程的后期,内存和加载问题已经变得严重之前才尝试修复整个结构。