• Unity DOTS 中的 ECS


    因为本身就是忠实的 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 是怎么实现的

    架构图

    C:Component 组件

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

    public struct CloneCube : IComponentData
    {
        public int Index;
        public float3 Postion;
        public float3 Offset;
    }
    

    E:Entity 实例

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

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

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

    Archetype

    S:System 系统

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

    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。

    Conversion

    四、Now

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

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

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

    五、参考

  • 相关阅读:
    Jquery实现无刷新DropDownList联动
    Mvc 提交表单的4种方法全程详解
    Sql Like 通配符 模糊查询技巧及特殊字符
    SQL 语句递归查询 With AS 查找所有子节点
    最常用的五类CSS选择器
    取出分组后每组的第一条记录(不用group by)按时间排序
    SpringCloud中接收application/json格式的post请求参数并转化为实体类
    SpringCloud负载均衡笔记
    iview-admin打包笔记
    SpringCloud之最大的坑
  • 原文地址:https://www.cnblogs.com/ZeroyiQ/p/13095358.html
Copyright © 2020-2023  润新知