对于 ECS 的理解
大约 2 分钟
前言
在游戏引擎中,游戏对象的状态更新基本是由组件的生命周期来实现,比如在 update 中更新位置
但如果需要更新的游戏对象越多,各自处理自己的状态更新就会让游戏维护变的困难,比如将所有角色移动速度加快指定数值,需要在每个对象状态更新的位置修改,而 ECS 则可以统一、批量处理
结构
- E: 实体,游戏对象,由多个组件组成
- C: 组件,单一职责,比如位移,跳跃
- S:系统,负责指定类型的组件生命周期管理,比如移动系统(包含位移,跳跃)
解决了什么问题?
将分布式状态同步改为统一处理,减少游戏复杂度,增加可维护性
DOD/ECS 利用数据局部性可以让游戏性能提高
DOD:Data Oriented Design(面向数据的设计)
什么时候适合用 ECS?
游戏需要处理大量不同类型对象的状态更新时使用,如果是类似捕鱼类游戏,对象的更新基本只存在鱼和子弹上,那么就没太大必要使用 ECS,但如果类似英雄联盟,不同的角色几十个包含不同的技能,就比较适合使用 ECS
如何在 ts 中使用 DOD/ECS ?
在 ts 中我们只能使用 TypesArray,也就是 ArrayBuffer、Uint8Array、Float64Array,这些类型来保证数据局部性,当然,使用这些类型数组我们 需要自己管理内存 的大小,以保证是连续的一块内存,这样才能保证缓存命中
- 系统需要知道每个组件占用的内存(相同类型的组件使用的内存大小必须一致)
- 我们只能存储基础数据类型到内存
参考:
- TS DOD/ECS 实现:https://github.com/thi-ng/umbrella/tree/develop/packages/ecs
- JS 中的 ECS——深入了解组件存储:https://javelin.hashnode.dev/ecs-in-js-a-closer-look-at-component-storage