最近DOTS终于发布了正式的版本, 我们来分享一下DOTS中ECS的几个关键概念与结构,方便大家上手学习掌握Unity DOTS开发。
ECS中的World
Unity DOTS ECS架构中所有的Entity都是被放到了World对象里面,每个Entity在World里面都有唯一的Id号。Unity DOTS 可以同时支持很多个World, DOTS会在运行的时候创建一个默认的World。World包含了它所需的所有System, System迭代计算的时候,使用World里面的Entity中的Component数据。如果不想要一运行就创建一个默认的World,我们可以通过以下宏开关来控制:
#UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP_RUNTIME_WORLD
关闭运行模式下启动的时候,创建一个默认的World
#UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP_EDITOR_WORLD
关闭编辑器模式下创建默认的World对象
#UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP
关闭掉编辑器模式/运行模式下的默认的World的创建
EntityManager对象
每个World, 有且只有一个EntityManager对象。EntityManager对象负责Entity的管理,包含但不限于: 创建Entity, 销毁Entity, 修改Entity中的数据等。
Entity对象
DOTS 中的每一个实体,我们称为Entity, 它本身是一个容器,可以理解为一个轻量级的gameObject, 它的数据全部存放在它的对应的组件里面。Entiy里面的所有组件数据内存会并行一起排布。这样保证了Entity 数据内存的高效访问与Cache命中。相当于把Entity所包含的所有组件数据的内存打包到一个内存块中。比如一个A类Entity, 它包含了有M,N两个组件数据,当我们给Entity来分布组件数据内存的时候,是把M+N两个组件的内存看作一种类型,线性排布在一起分配。存储数据的时候M,就操作这个内存块的M的部分。操作N组件数据的时候,就操作这个内存块的N的部分。Entity中的所有组件组成的内存块看作的这个类型,我们叫做ArchType。相同类型的Entity(所有组件的组成结构相同)属于同一种ArchType。
ArchType与Chunk高效的内存分配器
高效的内存分配器需要具备几个特点:
-
高效地分配与释放;
-
避免大量的分配与释放后造成的内存碎片;
上文提到,Entity中的所有组件数据是排布在一块内存里面的,每一种不同的排布,就会对应一种"类型"ArchType, DOTS 高效的内存分配器只需要基于ArchType所对应的内存块大小来进行分配就可以了。DOTS的entity组件数据的内存分配器基于Chunk设计,每个Chunk的大小为16kb,每个Chunk只会分配同一种类型的ArchType, 根据ArchType的组件组合,我们就可以计算出它们一共所需要的内存大小,我们就从Chunk中固定分配对应的内存大小就可以了,这样Entity对应的所有组件内存非常高效的分配与释放,同时每种Chunk只存放一种ArchType类型的内存块,每次分配的内存大小都是一样,这样可以避免内存碎片。基于ArchType的内存排布如下所示:
=============================== ArchType1: chunk1【e1(c1c2),e2(c1c2),e3(c1c2)】 chunk2【e4(c1c2),e5(c1c2),e6(c1c2)】 ... ====================== ArchType2: chunk1【e1(c3c4),e2(c3c4),e3(c3c4)】 chunk2【e4(c3c4),e5(c3c4),e6(c3c4)】 ... =============================== ArchType3: chunk1【e1(c5c6),e2(c5c6),e3(c5c6)】 chunk2【e3(c5c6),e4(c5c6),e5(c5c6)】 ... ===============================
System与JobSystem
我们学C语言的时候,听到过一句名言,程序=数据结构+算法。Entity解决了数据存储的问题,System就是算法。算法所需要的数据,来源于Entity中的Component。DOTS提供机制,System可以访问到entity中的组件数据,拿到这些数据后再做逻辑迭代计算与处理。默认System是运行在Unity的main thread上的,为了发挥多核优势,把可以用多线程处理的任务使用多线程,Unity 还提供了JobSystem机制,通过多线程的线程池来迭代计算JobSystem,不放main thread上提升程序的效率。
总结如下:
DOTS中会有一个World对象,每个Word对象会有一个EntityManager负责Entity的管理,内部使用了高效的基于ArchType与Chunk机制的内存分配。所有的system会加入到World里面来进行统一迭代,System可以访问Entity中的Component数据。同时JobSystem可以让我们的算法迭代基于多线程处理。配上总结图如下:
今天的DOTS系列就分享到这里了,下一节继续。
尊敬的准VIP客户:
我们Unity DOTS课程也正式发布了,我们课程经过9年多的更新与迭代,已经涵盖了Unity 开发中遇到的绝大部分问题,涵盖了Unity主程序进阶,升职加薪所需要的系统的知识体系,主流游戏类型的重点难点技术解决方案。我们的老师10:00~23:00提供实时解答与回复,包含但不限于客户端+服务端。相信我们提供的游戏开发技术服务能很好的帮助到您。选择我们的VIP课程,您肯定不会后悔!有兴趣请 + 企.鹅.裙 428 540 563
下面是DOTS的VIP课程前18节视频,免费观看
Unity DOTS进阶与项目实战(B站18集)
第008课Baking系列之BakingSystem与BakingWorld详解
第009课FilterBakingOutput与PrefabsInBaking
第013课Managed与Unmanaged Component详解与性能分析