询问Unity专家:在ECS和MonoBehaviours工作流程之间进行选择。

在本系列文章的第二篇中,我们将在 针对Unity SpatialOS游戏开发工具包(GDK) 的背景下比较ECS和MonoBehaviours工作流, 并探讨它们可以为您的游戏做什么。

正如我们在关于Unity的实体组件系统的第一个博客中所述,GDK提供了两个工作流程选项:

  1. 以MonoBehaviour为中心的工作流程,可与Unity完全开发的MonoBehaviour工具,工作流程和API配合使用。
  2. 充分利用新的ECS开发范例和相关性能改进的ECS工作流程。

适用于Unity的SpatialOS游戏开发套件(GDK)基于此ECS构建。 但是,在深入了解这一点之前,请务必记住,这些工作流不是互斥的。 大多数使用SpatialOS的Unity游戏开发人员开始使用以MonoBehaviour为中心的工作流程,然后使用ECS工作流程优化他们的游戏。 无论选择哪种方法,您的游戏仍将利用我们使用ECS编写的GDK核心模块。

ECS的好处

在上一篇文章中,我们概述了ECS的主要性能优势。 让我们详细看一下如何实现这些性能优势。

“与MonoBehaviours生成的代码相比,ECS生成的代码在内存地址之间执行的跳转要少得多。”

通过将要连续操作的字节存储在同一块内存中,可以避免在内存地址之间跳转。 以Unity的ECS如何诱导实现此目标的内存布局为例,让我们想象一个健康系统,该健康系统会在每个更新循环中从健康组件中减去损坏组件的值:

Unity的ECS将出现在实体中的每种组件类型的唯一组合归类为原型。 ECS在运行时动态定义原型,因此可以对新出现的组件组合进行分类。 将被定义为原型的一种独特组合是健康和损害。 另一个是,例如,健康,伤害和法力值。

一旦被归类为原型,没有其他组件的实体上存在的所有健康和损坏组件都将存储在同一块中。 同样,所有孤立的生命,伤害和法力值都将存储在一个块中。 唯一的例外是,如果存在的实体多于一个块可以容纳的实体,在这种情况下,它们将溢出到下一个块中。

当ECS遍历组件时,块内组件的内存访问始终是完全线性的。 这导致我们的健康系统需要运行的所有组件都存储在相对较少的块中,并连续存储在这些块中。 这需要较少的内存跳转。

“此外,由ECS生成的内存布局允许进一步利用缓存预取进行代码优化”

Unity的ECS生成的块包含紧密打包的连续数据。 这种布局与以MonoBehaviour为中心的工作流生成的稀疏分配的堆内存相反,它使CPU的硬件预取器可以更轻松地预测和获取正确的对象,以预期需要它们。

Unity的ECS能够引入这种内存布局,因为组件在内存中表示为可漂白类型。 可托管类型是托管和非托管代码在内存中具有相同表示(表示它们占用相同字节数)的数据类型。 使用这些,ECS可以将可Blittable类型写入一个块中,直到该块填满为止,然后立即移至下一个,并将每个紧密地打包。

“通过将数据(实体和组件)和逻辑(系统)分离,ECS还可以生成更多的模块化,易于阅读的代码。”

Unity ECS的结构鼓励使用更简洁的代码库。 它的模块化设计使您可以编写易于阅读,重用和重构的模块化代码。 除了易于维护之外,这在概念上还反映了SpatialOS的核心概念(SpatialOS实体,SpatialOS组件以及对其进行操作的工作人员),使其非常适合我们的G​​DK。

下图描绘了ECS世界。 世界是一组实体和系统; 实体是一组组件,并且系统对实体及其组件进行大量操作。

使用Unity的ECS构建的世界。

以下代码段是ECS组件的非常基本的示例。 您可以在此处看到更复杂的示例。

 公共结构MyComponent:IComponentData 
{
public int myValue;
}

ECS的当前缺点

Unity的ECS用实体代替GameObjects,并用组件(用于存储数据)和系统(用于对该数据进行操作)的组合来替代MonoBehaviours。 它还取消了“场景”的概念,转而支持世界,后者是轻量级的世界,由一组实体和在这些实体上运行的一组系统组成。

尽管这些更改释放了上面列出的好处,但Unity目前在设计时考虑了GameObject和以MonoBehaviour为中心的工作流程。 这意味着,如果您仅使用ECS,则以前可以使用的许多功能(物理,音频和渲染系统)需要更多的工程设计才能工作。 在Unity致力于将其适应或替换为ECS使用的这些系统之前,情况就是如此。

这就是为什么我们构建GDK来支持两个工作流程的原因。

我们的200名FPS入门项目是使用以MonoBehaviour为中心的工作流程专门编写的。

以MonoBehaviour为中心的工作流程

以MonoBehaviour为中心的工作流程的主要好处是,作为Unity开发人员,您已经知道如何使用它。 您可以使用所有惯用的工具,概念和内置系统(例如:物理,音频和渲染)。

以MonoBehaviour为中心的工作流程的主要缺点是,它生成的代码的性能优于ECS代码。 也就是说,所有在GDK上构建的游戏都使用了我们使用ECS编写的GDK核心模块。 这意味着即使您自己不编写任何ECS代码,您也将享受ECS带来的性能提升。

GDK还带有许多功能模块。 功能模块是可选功能,您可以选择将其包括在游戏中或从游戏中排除(例如,玩家生命周期)。 它们既可以为您提供游戏开发的先机,也可以作为编写自己的功能时可以使用的最佳实践的参考材料。 功能模块是使用最适合该特定功能的工作流程编写的,并且与所有GDK一样,该代码是可公开获得的并且可以完全自定义以满足游戏的确切需求。

您可以使用GDK上的MonoBehaviours制作以前不可能的游戏,这由我们的200个玩家的FPS入门项目证明,该项目是完全使用以MonoBehaviour为中心的工作流程编写的。

资源资源

以下是一些资源,可帮助您开始使用Unity的ECS和Improbable的SpatialOS GDK for Unity。

  • Unity的ECS入门:通过缓存预取提高速度
  • Unity的ECS样本存储库
  • 适用于Unity的SpatialOS GDK入门
  • GDK工作流程:MonoBehaviour或ECS工作流程