图中可以看到一个Context具有多个Entity,每个Entity可能会被N个Group所关心。
Group
一个Context中可能会同时存在很多个Entity,但是有些时候我们只需要处理某些Entity,那么我们可以通过Group来快速访问,每个Context内部维护一个Group对象集合,调用GetGroup()方法可以拿到Group,相同得Matcher参数拿到得是相同得Group对象。
Group是实时更新的一个具有相同筛选条件的Entity的组合,它会自动添加具有筛选条件的Entity,并删除失去筛选条件的Entity,以提高下一次的访问速度。
public IGroup<TEntity> GetGroup(IMatcher<TEntity> matcher)
{
if (!_groups.TryGetValue(matcher, out IGroup<TEntity> group))
{
group = new Group<TEntity>(matcher);
TEntity[] entities = GetEntities();
for (int i = 0; i < entities.Length; i++)
{
group.HandleEntitySilently(entities[i]);
}
_groups.Add(matcher, group);
for (int j = 0; j < matcher.indices.Length; j++)
{
int num = matcher.indices[j];
if (_groupsForIndex[num] == null)
{
_groupsForIndex[num] = new List<IGroup<TEntity>>();
}
_groupsForIndex[num].Add(group);
}
if (this.OnGroupCreated != null)
{
this.OnGroupCreated(this, group);
}
}
return group;
}
可以通过GetEntities()拿到Group中得所有Entity。通过ContainsEntity()接口判断Group中是否包含某个Entity。
Gorup提供了OnEntityAdded,OnEntityRemoved,OnEntityUpdated事件委托监听Group内部得Entity变化。
gameContext.GetGroup(GameMatcher.Position).OnEntityAdded += (group, entity, index, component) => {
// Do something
};
Matcher
Matcher是Group的筛选条件,筛选条件就是Context中所拥有的Component。
例:
我们有MoveComponent和AttackComponent两个组件存在Game Context中。则我们可以有一下几种查询方式:
//查找所有有MoveComponent的Entity
var moveEntitys = contexts.game.GetGroup(GameMatcher.Move);
//查找所有有AttackComponent的Entity
var attackEntitys = contexts.game.GetGroup(GameMatcher.Attack);
//查找所有有MoveComponent和AttackComponent的Entity
int[] allMatcher = { GameComponentsLookup.Move,GameComponentsLookup.Attack };
var AllEntitys = contexts.game.GetGroup(GameMatcher.AllOf(allMatcher));
//查找所有有MoveComponent或AttackComponent的Entity
int[] anyMatcher = { GameComponentsLookup.Move, GameComponentsLookup.Attack };
var AnyEntitys = contexts.game.GetGroup(GameMatcher.AnyOf(anyMatcher));
Collector
通过Group和Matcher已经可以拿到所有符合条件的Entity,例如所有具有MoveComponent的Entity。也说过了Group会实时更新,但是如果我们需要知道Group中当前哪些Entity是新加进来的。则可以通过Collector来找到。
例:
//查找所有有MoveComponent的Entity
var moveEntitys = contexts.game.GetGroup(GameMatcher.Move);
//找到哪些Entity是刚刚获得了MoveComponent然后被添加到Gorup中的
var collect = moveEntitys.CreateCollector<GameEntity>(GroupEvent.Added);
GroupEvent
+ Added 添加到Gorup中的
+ Removed 从Group中移除的
+ AddedOrRemoved 所有变化的(包含添加的和移除的)
总结:
前面说过了空军指挥部(System_3)可以指挥拥有开飞机(Component_3)技能的士兵(Entity)飞往指定的地方完成任务A,那么就需要通过Group拿到所有能开飞机(Component_3)的士兵(Entity)。
但是可能所有能开飞机(Component_3)的士兵(Entity)都在执行任务B,这时候可以加班训练新的士兵(Entity)让其拥有开飞机(Component_3)的技能,然后通过Collector找到这些刚刚学会开飞机(Component_3)技能又不在出任务的士兵(Entity)去完成任务A。