Entitas实现简析

  这里主要讲Entitas的执行原理,不讲Entitas的代码生成方面。

ECS简介

  ECS(实体-组件-系统)是一种常用于游戏开发的架构模式。

  实体: 实体只是一个ID或一个容器,用来标记或存储一系列组件。

  组件: 没有任何逻辑,单纯用来存储数据。

  系统: 循环处理特定的组件。

  ECS主要强调了两个方面:

  1.用数据的组合去描述对象,而不是继承。

  2.数据和逻辑的分离。

Unity中的EC

  Unity采用了EC的设计思路,和传统ECS不同,Unity的Component除了存储数据,还保留了操作Component中数据的方法。

  Unity中的Entiy就是GameObject,Component就是GameObject上挂载的组件各种组件,如Transform。

  GameObject是各种Component的容器,本身并没有实际意义(与ECS中Entity的定义略有不同,GameObject包含了tag、name、activeSelf等属性。如果是在纯粹的ECS系统中,tag等属性应该作为Component挂载在GameObject)。

  比如场景中的一个Cube,由Transform、MeshFilter、MeshRenderer、BoxCollider四个组件组成。我们能在场景中看到这个Cube是因为Unity从MeshFilter得到了Mesh信息,告诉了GPU这是一个立方体,从MeshRenderer中的到了渲染这个Mesh的信息,告诉GPU这个Mesh上的UV对应的是哪张贴图的坐标,渲染成什么颜色等信息。从Transform中得知了该将这个Cube渲染在哪个位置,旋转多少度等。Unity通过BoxCollider和Transform信息去做碰撞检测。(在Cube的渲染这个例子中,可以把Unity自身看作ECS中的System的集合,因为Unity中的各个模块获取了这个Cube中特定Component中的信息,根据这些信息做一些事情)

  Unity中的EC与传统ECS最大的两个区别就是:

  1.Entity上带着一些属性数据name、tag等,Component不仅有数据,还集成了大量的方法。比如在Unity中希望旋转一个Transform会直接调用Transform的Rotate方法,而在传统ECS中,很可能是在Cube这个Entity上挂载一个Rotate组件,然后由专门的RotateSystem去处理这个转动。

  2.没有System对Component进行统一的处理。

Entitas简介

  Entitas是一个用C#实现的ECS框架,提供了方便的代码生成功能。

  用法的介绍官方项目写的比较详细,这里就不多做介绍。

Entitas运行流程



  也就是说整个ECS系统的内部数据维护(Group、Collector、EntityIndex)复杂度主要放在Entity的修改上了。

  在给一个Entity添加一个Component时,不仅仅是对Entity进行了修改,还会通过事件将这个添加传递给Context,Context遍历所有Group,找到满足这次修改条件的Group,对所有受到影响的Group进行修改。然后再通过Group将这次修改事件分发到Collector或其他监听该Group的模块中去。

  这种方式带来的好处十分明显,那就是获取一种类型的Entity(也就是一个Group),只有第一次会遍历所有的Entity生成这个Group,之后再获取该类型Entity的复杂度就只有O(1)。

  但是也有一定的隐患,当Group和Collector比较少时,这不是一个高消耗操作,但是Group、Collector很多,且在每一帧对Entity进行频繁修改的时候。这可能会成为一个高消耗操作。

Tips

  1.在销毁一个Entity时,会移除Entity身上所有的Component,然后再进行回收。在移除Component时可能会通过Group把这个移除事件发送到监听Remove行为的Collector中,Collector会持有这个被销毁的Entity。所以在filter、或execute时不能直接依赖Collector的收集条件,还需要对Entity的Component做独立的判断。

  其实任何时候filter都需要对Entity的Component做判断,因为Collector收集的Entity很可能在其他地方被改变。

  2.Entity不应该被ECS系统外的模块持有,因为系统外对Entity的持有不会被自动引用计数(可以自己添加)。可能会导致一个Entity被销毁然后又从池子中重新取出来, 外部模块对这个Entity的引用没有改变,但已经可能不是自己持有的那个Entity了。

  需要避免在外界持有Entity或通过持有uuid间接从context中持有这个Entity。

  3.在replaceComponent时,发送了Remove、Add、Update三个事件,而不是只发送了Update事件。

  4.在代码生成时,对单Componet的Matcher进行了缓存,如游戏中常用的Postion和Name等Component,但是对组合Component的Matcher没有进行缓存。所在在两个不同的ReactiveSystem中使用Matcher相同的Collector时,如:

//1,2代表Postion和Name的Index
//在使用代码生成时会生成类似Matcher.Position、Matcher.Name的静态函数,方便开发者使用
context.CreateCollector(Matcher.AllOf(1,2));

  这样会生成两个Matcher相同的Group实例。

  如果在意这一点的话可以自己对Matcher进行缓存。

写在后面

  在对ECS架构模式的理解和Entitas的使用上我还是一个新手,只是刚刚开始使用,如果有什么写的不对的地方,各位大佬可以留言指正。

Entitas实现简析的更多相关文章

  1. 简析.NET Core 以及与 .NET Framework的关系

    简析.NET Core 以及与 .NET Framework的关系 一 .NET 的 Framework 们 二 .NET Core的到来 1. Runtime 2. Unified BCL 3. W ...

  2. 简析 .NET Core 构成体系

    简析 .NET Core 构成体系 Roslyn 编译器 RyuJIT 编译器 CoreCLR & CoreRT CoreFX(.NET Core Libraries) .NET Core 代 ...

  3. RecycleView + CardView 控件简析

    今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...

  4. Java Android 注解(Annotation) 及几个常用开源项目注解原理简析

    不少开源库(ButterKnife.Retrofit.ActiveAndroid等等)都用到了注解的方式来简化代码提高开发效率. 本文简单介绍下 Annotation 示例.概念及作用.分类.自定义. ...

  5. PHP的错误报错级别设置原理简析

    原理简析 摘录php.ini文件的默认配置(php5.4): ; Common Values: ; E_ALL (Show all errors, warnings and notices inclu ...

  6. Android 启动过程简析

    首先我们先来看android构架图: android系统是构建在linux系统上面的. 所以android设备启动经历3个过程. Boot Loader,Linux Kernel & Andr ...

  7. Android RecycleView + CardView 控件简析

    今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...

  8. Java Annotation 及几个常用开源项目注解原理简析

    PDF 版: Java Annotation.pdf, PPT 版:Java Annotation.pptx, Keynote 版:Java Annotation.key 一.Annotation 示 ...

  9. 【ACM/ICPC2013】POJ基础图论题简析(一)

    前言:昨天contest4的惨败经历让我懂得要想在ACM领域拿到好成绩,必须要真正的下苦功夫,不能再浪了!暑假还有一半,还有时间!今天找了POJ的分类题库,做了简单题目类型中的图论专题,还剩下二分图和 ...

随机推荐

  1. tflearn 在每一个epoch完毕保存模型

    关键代码:tflearn.DNN(net, checkpoint_path='model_resnet_cifar10', max_checkpoints=10, tensorboard_verbos ...

  2. Java_Path_01_路径问题

    二.参考资料 1.java 路径问题 2.Java路径问题最终解决方案—可定位所有资源的相对路径寻址 3.Java获取文件的路径 4.Thread.currentThread().getContext ...

  3. Java中内部类中使用外面变量为什么final修饰?

    所以final从语法上约束了实际上两个不同变量的一致性(表现为同一变量). 我的理解: 例如这样的代码: public void test(String str){ str="abc&quo ...

  4. unreal network

    frame move buffer: save move position recive server sync:All moves earlier than the ClientAdjustPosi ...

  5. ACM学习历程—Codeforces 446C DZY Loves Fibonacci Numbers(线段树 && 数论)

    Description In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence ...

  6. DataGrid 滚动特定的行或者列

    DataGrid 滚动特定的行或者列. DataGrid.ScrollIntoView Method (Object, DataGridColumn) .NET Framework 4.5 Silve ...

  7. kindle 3 webbrowser破解,

    首先下载破解: http://183.60.157.10/down_group83/M00/06/31/tzydCk3MyHYAAAAAAUTLHFYI-wk8562757/webpatch.7z?k ...

  8. Jenkins安装配置简单使用

    安装启动是十分简单的,直接去https://jenkins.io/download/下载对应的rpm包就好了,需要注意的是我们的机器上要提前有java环境,相对应要选择你java环境可以支持的jenk ...

  9. UDK性能优化

    转自:http://www.cnblogs.com/NEOCSL/p/3320510.html 优化问题有很多内容可讲,涉及林林总总.今天我总结一下优化注意的地方. 1.从AnimTree和Skele ...

  10. Word直接发表博客测试

    这是我现在使用的VSCode! 这是另一段测试内容!