zoukankan      html  css  js  c++  java
  • 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。

    五、参考

  • 相关阅读:
    加入创业公司有什么利弊
    Find Minimum in Rotated Sorted Array II
    Search in Rotated Sorted Array II
    Search in Rotated Sorted Array
    Find Minimum in Rotated Sorted Array
    Remove Duplicates from Sorted Array
    Spiral Matrix
    Spiral Matrix II
    Symmetric Tree
    Rotate Image
  • 原文地址:https://www.cnblogs.com/ZeroyiQ/p/13095358.html
Copyright © 2011-2022 走看看