1.Entity的大致说明
Entity就是实体,它不包括数据和执行逻辑,只是一个id标识,但它可以添加组件以及移除组件来行成一个Group组。
1.1.Entity的添加
其中Entity实体的生成只能通过上下文来生成
contex.CreateEntity();
当生成实体后,可以根据实体来进行组件的添加和移除,但这里的移除并不是真正的移除,而是会添加到上下文的对象池中
2.Entity对组件的操作说明
如何添加移除组件,当组件写出后,可以进行代码生成,代码生成会自动为实体生成一个partial类,这个类会根据组件的标签来确定名字。
2.1示例
比如我们创建了一个InterationExampleView组件继承了IComponent,它的标签是Game,那么生成代码就会生成一个内部类GameEntity,这个内部类只负责处理PositionComponent组件的操作,比如加这个组件或者替换这个组件这里只关注Add和Replace,我们发现它们的前三行代码都相同,大概意思就是先从一个类中拿到index,以及创建这个组件,并且给新的组件赋值,然后才是具体的添加或者代替的操作
public void AddInterationExampleView(UnityEngine.Transform newViewTrans) {
var index = GameComponentsLookup.InterationExampleView;
var component = (InterationExample.ViewComponent)CreateComponent(index, typeof(InterationExample.ViewComponent));
component.viewTrans = newViewTrans;
AddComponent(index, component);
}
public void ReplaceInterationExampleView(UnityEngine.Transform newViewTrans) {
var index = GameComponentsLookup.InterationExampleView;
var component = (InterationExample.ViewComponent)CreateComponent(index, typeof(InterationExample.ViewComponent));
component.viewTrans = newViewTrans;
ReplaceComponent(index, component);
}
两个重要属性,分别是得到实体的具体组件以及是否有这个组件,这两个属性一般用于反应式系统中的Filter和GetTrigger中来得到一个收集器以及筛选需要进入Execute方法的实体集合
public InterationExample.ViewComponent interationExampleView { get { return (InterationExample.ViewComponent)GetComponent(GameComponentsLookup.InterationExampleView); } }
public bool hasInterationExampleView { get { return HasComponent(GameComponentsLookup.InterationExampleView); } }
3.Component说明
Component是ECS中的数据重要的载体,也是System与Entity操作的对象。它只包含数据,当然这个数据可以是一个引用,也可以只是单纯的数据,甚至可以没有数据(这里即使没有数据,继承的接口也会给一个数据,一般用于标志变量)。
3.1 Component的基本形式
①首先可以选择给不给若干个标签,这个标签是自己定义的,不同的标签会对生成的代码的去向造成影响,其中有一个Unique定义全局唯一的组件数据,其中还有一种标签为[Event(EventTarget.Any/Self)]当有这个标签时,我们自动生成代码会生成一个接口,当这个组件数据改变时会调用实现接口的方法
②其次对数据也可以打上标签,比如[EntityIndex]标签,如果打上这个标签,则生成代码是会自动生成两个扩展方法,在其他任何类中,哪怕是继承了Mono的或者是Input中,都可以根据这两个方法来查找实体。其中一个方法可以为根据一个二维的向量来获取有这个实体的组件,可以是某个点或者其他的。还有一个是根据名字找。这两个方法返回的都是哈希表。
[Game,Event(EventTarget.Any)]
public class NameComponent : IComponent
{
[EntityIndex]
public string name;
}
该示例就是一个组件类的写法
3.2 Component组件的替换与添加
组件替换与添加离不开实体,这里可以在2.1看到,实体会操控这两个函数以实现添加或者移除组件,当数据更新时要调用.示例可以看4.1.2
4.System说明
System是实现逻辑的地方,在Entitas中可通过响应式系统来实现逻辑操作。
4.1 ReactiveSystem说明
它是响应式系统,通常我们自己写的某些System需要继承它,只有当满足某些条件时才会执行,它有三个抽象方法必须实现,分别是
protected abstract ICollector<TEntity> GetTrigger(IContext<TEntity> context);
protected abstract bool Filter(TEntity entity);
protected abstract void Execute(List<TEntity> entities);
其中GetTrigger()返回一个收集器,这个收集器会返回所有上下文匹配的实体的集合,它会在系统初始化时调用
Filter()是筛选器,它进一步筛选符合条件的实体去执行Execute,这个一般都会用到自动生成代码的两个属性进行筛选
Execute()就是对所有符合条件的实体进行组件数据的更新的方法,也是逻辑核心执行的地方
4.2 示例
public class AddViewSystem : ReactiveSystem<GameEntity>
{
//父物体的Transform
private Transform parent;
//上下文
private Contexts contexts;
public AddViewSystem(Contexts contexts) :base(contexts.game)
{
parent = new GameObject("ViewParent").transform;
this.contexts = contexts;
}
protected override void Execute(List<GameEntity> entities)
{
foreach(GameEntity entity in entities)
{
//实例化一个物体
GameObject go = new GameObject("View");
//设置父物体
go.transform.SetParent(parent);
//将物体 与实体与上下文联系起来
go.Link(entity, contexts.game);
//添加View组件,因为筛选器是筛选的没有这个组件的实体
entity.AddInterationExampleView(go.transform);
//设置实体MoveComplete的数据
entity.isInterationExampleMoveComplete = true;
}
}
protected override bool Filter(GameEntity entity)
{
//一般has。。。表示有无这个组件,is。。。表示是否是这个状态,它只是一个表示变量,当Component没有数据时自动生成
return entity.hasInterationExampleSprite && !entity.hasInterationExampleView;
}
protected override ICollector<GameEntity> GetTrigger(IContext<GameEntity> context)
{
//收集匹配的实体并且返回
return context.CreateCollector(GameMatcher.InterationExampleSprite);
}
}