Skip to content

ECS

Entity-Component-System, 高性能编程中逃不开的。

Why ECS

OO 指导的代码,庞大的继承树,虚函数指针等,使得缓存命中率极低,降低运行效率。

而 ECS 中,把各种纯数据打包成 Component,然后在 System 中统一进行处理,指令集和数据集中性非常高,提升缓存命中率,可以快速的运行,同时如果结合 JobSystem,把没有依赖的可并行的 System 并行运算,那么运行效率可以再大幅提升。

DOTS

Unity 下的 ECS 框架,主要分为 “ 三座大山 ”

  • ECS
  • Job System
  • Brust Compiler

ECS

首先是 ECS 这个部分,它使用了 Archetype —— 理解成为一种 Tag 系统,比如 Enemy, AI, Bullet, NPC 等都有自己不同的 Component 组合,所以把他们分别都划成不同的 Archetype, 这样可以快速获得同一个 Archetype 下的所有数据。

与此同时,在建立 Chunk (数据存储的最小单位)时,每一个 Chunk 一定只会存放一种 Archetype 的数据 —— chunk 是固定大小,比较符合 Cache Line 的读取

Job System

(非 ECS 情况下也可以使用)

并发运行子任务(Job),但是它被限制只能访问其内部定义的数据,所以同时也规避了数据竞态等问题,

Brust Compiler

由于 C# 跑在虚拟机上,各种高级的GC等机制会使得内存分配与位置不太可控,于是 Unity 自己实现了一套编译器,

理解

OOP 感觉还是难以抛弃 —— 比如一个复杂的角色控制系统 —— “ 跳跃的时候先播放一个动画再停两帧然后在空中旋转一周对周围半径 5m 范围内的敌人造成 10 点伤害之后召唤 2 个友方单位,最后在落地的时候触发斯安威斯坦( ” 这样一个莫名其妙的指令,如果拆成 ECS 上的纯数据和 System,都不敢想象有多复杂。

所以面向对象和数据驱动应当是并存 —— 正常使用依旧是基于继承和多态等的优雅实现,同时业务逻辑也比较好写。

在一些明确的情况或者非常高压的情况 —— 比如场景中大量的草、群体寻路之类

Released under the MIT License.