Entitas实现简析
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实现简析的更多相关文章
- 简析.NET Core 以及与 .NET Framework的关系
简析.NET Core 以及与 .NET Framework的关系 一 .NET 的 Framework 们 二 .NET Core的到来 1. Runtime 2. Unified BCL 3. W ...
- 简析 .NET Core 构成体系
简析 .NET Core 构成体系 Roslyn 编译器 RyuJIT 编译器 CoreCLR & CoreRT CoreFX(.NET Core Libraries) .NET Core 代 ...
- RecycleView + CardView 控件简析
今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...
- Java Android 注解(Annotation) 及几个常用开源项目注解原理简析
不少开源库(ButterKnife.Retrofit.ActiveAndroid等等)都用到了注解的方式来简化代码提高开发效率. 本文简单介绍下 Annotation 示例.概念及作用.分类.自定义. ...
- PHP的错误报错级别设置原理简析
原理简析 摘录php.ini文件的默认配置(php5.4): ; Common Values: ; E_ALL (Show all errors, warnings and notices inclu ...
- Android 启动过程简析
首先我们先来看android构架图: android系统是构建在linux系统上面的. 所以android设备启动经历3个过程. Boot Loader,Linux Kernel & Andr ...
- Android RecycleView + CardView 控件简析
今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...
- Java Annotation 及几个常用开源项目注解原理简析
PDF 版: Java Annotation.pdf, PPT 版:Java Annotation.pptx, Keynote 版:Java Annotation.key 一.Annotation 示 ...
- 【ACM/ICPC2013】POJ基础图论题简析(一)
前言:昨天contest4的惨败经历让我懂得要想在ACM领域拿到好成绩,必须要真正的下苦功夫,不能再浪了!暑假还有一半,还有时间!今天找了POJ的分类题库,做了简单题目类型中的图论专题,还剩下二分图和 ...
随机推荐
- POJ 3620 Avoid The Lakes(dfs算法)
题意:给出一个农田的图,n行m列,再给出k个被淹没的坐标( i , j ).求出其中相连的被淹没的农田的最大范围. 思路:dfs算法 代码: #include<iostream> #inc ...
- Dom vs Canvas (译)
原文:dom_vs_canvas 在web上做动画我们有很多选择:svg,dom,canvas,flash等等.但是根据业务场景我们一定能找到最优的技术解决方案,但是何时选择dom,何时使用canva ...
- labview初步理解
1.labview是NI公司开发的一款以图形方式开发程序(G语言)的程序开发环境软件.它的作用与VS一样,是一种程序开发环境.只是vs是以文本语言开发环境而已. 2.labview最广泛应用于开发测试 ...
- tf.stack和tf.unstack
import tensorflow as tf a = tf.constant([1,2,3]) b = tf.constant([4,5,6]) c1 = tf.stack([a,b],axis=0 ...
- jQuery精华
第一章:入门 选择元素: $() css() $("li").css():可以省略原生的循环操作 $ == jQuery jQuery方法函数化: click() html() J ...
- js跨域请求方式 ---- JSONP原理解析
这篇文章主要介绍了js跨域请求的5中解决方式的相关资料,需要的朋友可以参考下 跨域请求数据解决方案主要有如下解决方法: 1 2 3 4 5 JSONP方式 表单POST方式 服务器代理 H ...
- 重学JAVA基础(一):PATH和CLASSPATH
我想大多数Java初学者都会遇到的问题,那就是怎么配置环境,执行java -jar xxx.jar 都会报NoClassDefFindError,我在最开始学习的时候,也遇到了这些问题. 1.PAT ...
- python list列表sort、sorted、reverse排序
列表排序:sort是修改原列表,sorted提供原列表的一个有序副本 li=[2,1,4,5,0]li.sort() #默认从小到大print li结果:[0, 1, 2, 4, 5] li=[2,1 ...
- 错误:(26, 13) Failed to resolve: com.android.support:appcompat-v7:27.+
小编也是初学安卓,今天配置环境的时候遇到这个问题了,搞了半天终于找到了问题 在build.gradle中添加 allprojects { repositories { jcenter() maven ...
- java之数学方法
参考http://how2j.cn/k/number-string/number-string-math/319.html java.lang.Math提供了一些常用的数学运算方法,并且都是以静态方法 ...