ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Entitas实现简析

2019-05-31 23:03:51  阅读:224  来源: 互联网

标签:Group Entitas 实现 Component Unity Entity 简析 ECS Collector


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的使用上我还是一个新手,只是刚刚开始使用,如果有什么写的不对的地方,各位大佬可以留言指正。

标签:Group,Entitas,实现,Component,Unity,Entity,简析,ECS,Collector
来源: https://www.cnblogs.com/blueberryzzz/p/10957921.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有