命名空间system中不存在data_我理解中的Unity DOTS

我是第一次接触到 ECS,并不是使用老手,以下仅仅是我通过浏览相关文章和实现相关 Demo,而写出的一篇分享初见文。如有错误,请您指出。谢谢。

因为本身就是忠实的 Overwatch 玩家,所以天然的对其应用的 ECS 架构有所兴趣。再加上最近在 Unity Connect 上看见一篇使用 Unity DOTS 实现的一个爆炸 Demo,所以就决定了这个分享的内容。

一、What 什么是 DOTS

DOTS(Data-Oriented Technology Stack 面向数据技术栈)是 Unity 提出的一个高性能多线程式数据导向的技术堆栈,能够充分利用多线程优势。

目前包含以下几个包。(除了 Job System 和 Burst,后面几个都是预览版本,API 一直在变化)

  • c# Job System:一个能够安全快速利用多核处理器的 System
  • Burst:一个新的基于 LLVM 的后端编译器,能够生成高度优化后的机器码
  • Entites:ECS架构的核心库,使用面向数据的方式能够更容易的提供 Job System 和 Burst 所需要的良好数据结构
  • Unity Physics:基于 DOTS 构建的新的物理系统当前依旧是很早期状态
  • Unity NetCode:基于 ECS 构建的带有客户端预测的服务器模型,可以用于创建多人游戏
  • DSPGraph:新的混音系统,c#编写,使用了 Job System,能够使用 Burst 编译,
  • Unity Animation:DOTS的动画系统,当前并不能用于商业生成

二、Why 为什么提出新的 ECS 架构

使用 OOP/传统模式开发会存在的问题:

  • 开发后期会出现大量的类,理解子类需要掌握父类
  • 数据和其处理过程耦合在一起
  • 高度依赖引用类型

虽然可以通过 Interface 来进行解耦,但是在开发中依旧需要提倡「高内聚,低耦合」,因此 Unity 和 UE4 都提出了组件的概念来解耦。一个GameObject中包含了多个组件,但是目前的组件还依旧存在有功能/行为,并不是纯粹的数据描述。

比如有个 GameObject 存在有 Location 和 Movement 组件,那么这个 GameObject 应该就可以进行移动了,那么移动这个行为/算法是放在那的?如果放在 Movement 里,那么 Movement 就与 Location 产生了关联,打破了组件之间的封闭性,并不是高内聚的,因此 ECS 提出了个组件之间的切片—— System。

ECS 将所有的行为/算法放在了不同的 System 中,而 Component 只存在数据。

因此使用 ECS 架构,并依照正确的 DO 方法论实现的游戏,获得了以下几个好处

  • 对cache友好。由原来的处置管理每个对象的状态,变为相同类型数据横向聚集管理。
  • 通过数据和行为分离,更加专注于正在解决的实际问题,也容易进行横向开发出更多的系统
  • 由于数据被单独隔离,易于做多线程并行,为 Job System 和 Burst 提供了更好的数据结构
  • 代码更容易上手,通过系统掌握行为,根据输入输出了解系统关注的数据源

当然 ECS 也不是真的就完爆原有的OO GameObject,只是 ECS 对于数据密集运算有着良好的支持。ECS 目前也有着大量的问题,这部分将会留在文章后面叙述。

三、How

3.1 ECS 是怎么实现的

91a413a2c774a5ea3b871c4e701544a7.png

C:Component 组件

与原有的挂在GameObject上的组件不同,ECS的组件就是一堆数据的集合,不存在方法,只是用来存储数据/状态。

public 

E:Entity 实例

实体只是一个概念上的定义,指的就是游戏世界里的一个物体,是一系列组件的集合。为了区分不同组件的集合,在代码层面只是使用一个 32位 的整数 ID 表示,其实并没有真正的一个 Object,存在的意义在于生命周期管理。

为了方便实例的查询,提出了一个 Archetype(原型) 的概念,能够存储记录组件组合的信息,两个实例如果有相同的组件,那么组件的信息都会被存储在一个相同的 Archetype 底下。

当组件发生增加或者删除的情况,会把当前的块移动到新的原型里,并交换原有原型里最后的实体补齐空缺。

ce472ab2359555c8b4a863800ecf8b6a.png

S:System 系统

用来处理游戏逻辑的部分,我们可以在 System 中通过 Component 快速筛选出我们需要关系的 Entity 集合。 System 中不存在数据,只有行为,数据的输入和输出都依赖 Component。

249ac9ecc13c418a4d32fa3114c1253a.png

System 其实还存在一个问题,就是 System 为了强调解耦,是不能直接相互调用的,因此对于共享代码需要抽离到单独的 Util 中。对于不同的 System 想访问唯一的 Component,可以在 World 创建唯一的Entity。比如一个叫玩家键盘的 Entity,由键盘组件组成。只需要安排一个System 不断更新这个 Component,就能使其他需要获得玩家键盘输入的 System 得到相同的数据。

目前 Unity 的 DOSTSample 项目中就是这么做的,World 中有一个唯一的 LocalPlay 实例,有一个 UserCommand 组件,被 BeforeClientPredictionSystem 不断 Update 更新本地用户输入。

3.2 ECS 工作流

如果真的将目前的游戏都改成 Data-Oriented 并不容易,目前直接放弃所见即所得的编辑器,显然不是当前最佳的方式(可以按照 DOD 重新编写编辑器,只是目前还不能)。Unity 团队提供了一种 ECS Conversion Workflow 。可以让开发者通过常规 GameObject 来实现编辑功能,在需要 ECS 高性能的部分使用 Conversion Workflow,将 GameObject 在 Runtime 的时候转成纯粹的 ECS data。

d95748dd2857c25686286809853e1248.png

四、Now

通过写相关 DEMO 和粗览 Unity DOTS Sample 源码,可以明显感觉到,为了符合 ECS 的设计理念,需要仔细考虑设计 Component 中的数据,必须其进行合理的设计和拆分。真正使用起来还是相当费劲的。

ECS 对于UI、复杂技能特性支持度也不好。由于没有办法利用起多态,不能将不同数据存放在一起,所以只能靠多增加 Component 来实现。

目前 Unity DOTS 中的包还基本都处于预览版本,还有相当多的地方都不是很完善,仅仅是只能做些小的 Demo。

五、参考

  • ECS的泛泛之谈
  • Unity DOTS 走马观花
  • ECS 真的是「未来主流」的架构吗?
  • 浅谈《守望先锋》中的 ECS 构架
  • UniteLA 2018 - ECS deep dive
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值