近期在游戏demo中试验ECS, 深入研究Unity官方的ECS框架和第三方Entitas框架, 分享下使用ECS的心得。
Unity在2018版中加入了ECS系统, 但处于小白鼠阶段。默认不是Unity的一部分, 需要手动下载代码并导入Packages(新特性)。官方提供海豚例子, 但除此之外例子和资料非常少。所以完全无法,也不敢在demo中贸然引入这种系统,所以放弃官方ECS系统。
第三方的Entitas(https://github.com/sschmid/Entitas-CSharp)ECS框架从2015年就开始在各地演讲中介绍。整体框架基于代码生成, 能解决一部分的代码爆炸问题, 而且性能也要好一些。例子,介绍非常丰富,例子虽然基于不同版本的Entitas,特性支持和最新版差不太多, 只是写法有细微差异, 对于理解来说无碍。
经过1~2天的改造, 终于将demo从传统Unity写法改造为ECS标准写法,新增了46个文件, 而传统逻辑一共只有16个文件,大概对比下ECS的特点和差异。
Entitas的ECS系统
1. 本来在一个对象中添加一个类字段的过程,ECS需要添加一个类代表Component,并且代码生成。
这个字段一般用于描述对象的资源,处理显示的GameObject, 表示对象的类型等。
2. 本来一个对象的业务逻辑处理过程直接用方法解决的, ECS需要新加一个System,而操作对象需要使用Filter或Group查询获得。
3. 一系列的操作, 需要拆分为多个System和Component拆分处理。如果System顺序不对, 会造成一些诡异的bug。
4. Component不仅仅是Model承载体, 也可以是参数的数据结构。参数Component通过Entity传递到System处理。 例如: 通过ECS创建一个方块的过程,使用CreateTileComponent,包含创建Tile的位置, 创建Entity并添加CreateTileComponent, 在CreateTileSystem中处理就创建了Tile,处理完成时, 需要将传入的Entity.Destroy掉。
6. Entity上修改Component的过程, 会触发事件。修改的过程需要使用RelaceXXX,XXX表示组件名。组件可以频繁修改, 不用担心添加和删除组件过程的性能, Entitas底层处理性能只相当于指针赋值的性能。
ECS像什么?
1. ECS中的System类似触发器系统(Event-Condition-Action),其中,Event对应Entitas的GetTrigger+Collector,表示触发事件。Condition对应Filter表示在事件来源对象中找到需要的对象。 Action对应Execute,表示实际的操作。
2. ECS中的Component类似不用lua扩展的Redis或者不用存储过程的MySQL, 纯粹纯数据, 而不能对数据有任何封装操作。没有lua和存储过程支持的db写起来还是比较费劲的,但ECS就是那么的纯。
3. ECS中的Entity很尴尬,因为Component是按类别连续存储的以保证性能。 逻辑又需要Entity组合成逻辑需要的复合对象。 两边都要照顾,所以这种设计就让代码量巨增,可读性下降。
ECS企图用一套框架灭掉设计模式
1. 单件(Singleton)在Entitas用Unique标签标记Component, 在Context中就是唯一的, 其实也就是Singleton。
2. ECS干掉了传统的工厂模式,底层统一对对象(Entity)和属性(Component)统一管理。需要按Component中的值找回Entity时, 可以使用EntityIndex。
3. Entity携带不同的组件时,整个创建和销毁过程被记录并恢复,其实就是Command模式
ECS适合做UI框架(类似MVVM,MVC,MVP)么?
ECS不是专用的UI框架,但是可以对不同系统和数据间解耦。传统代码中数据修改后的Callback,ECS也可以用Listener做, 但Listener因为能保存数据, 就需要用Component保存。 所以你需要面对的是,一个Button,响应创建一个参数用的Component和System,还要为数据改变写一套ListenComponent和Listener处理的System,酸爽吧?
Minecraft适合ECS来做么?
可以,性能应该能提升不少,但是代码会更繁琐,特别像Java这种啰嗦语言配上ECS这种啰嗦框架,估计代码量翻翻还是很轻松的。MC属于特殊类型的游戏,适合特殊领域特别优化,也就是专门为方块做出特别的设计来做优化。ECS属于通用框架,即便性能OK,但是代码未必能有良好的可读性。
体量小的游戏适合用ECS来做么?
可以,但不建议。特别是只有几个人维护的工程,贸然上ECS系统,会让系统变的极为复杂。当然你会说,如果开发到后期,传统开发模式会导致代码会乱,ECS会好些吧。掌握ECS也不是一天两天的事情,不熟悉ECS的程序员设计出来的系统获得的优势可能还不如用传统设计方法好呢。
架构解决的是人的问题, 人都有问题,用什么框架都没办法。
到底什么项目适合用ECS?
1. 大量的小个体不断的生成和销毁以及显示,例如: 攻城战中,要体现每个角色的移动,战斗。
2. 多于5个人编写核心战斗逻辑。互相协作和模块切分,需要一个大家都能信服的框架,ECS可以选择。
P.S.
不要造ECS的轮子!
很多同学看了ECS基本原理,在没有深入使用过任何ECS系统时马上操刀造轮子。ECS系统确实看起来简单。实际造下来你会发现,性能非常糟糕以及不知道一些逻辑如何用ECS来解决。
总结:
1. ECS确实为性能而生,没有并发加持性能的ECS都是耍流氓,要快就要快到极致。
2. Unity中,ECS并发能扩展CPU的利用率,但是GPU的性能依然还是DrawCall优化那一套,别期望ECS会颠覆Unity,性能也不会快到飞起,关键还是要看具体的项目和人。
3. ECS是万能框架,但不全能。传统架构和设计思想也不是一无是处,熟啥用啥,怎么快怎么来!
无耻的广告链接,请各位支持
《Go语言从入门到进阶实战(视频教学版)》(徐波)【摘要 书评 试读】- 京东图书