ICollector
顾名思义,ICollector是一个收集器,通过监听Group的Event事件,对相关的Entity进行收集,以供后续逻辑处理。
ICollector的结构如下:
Collector
Collector是ICollector的实现类,内容如下:
Collector的内容很简单,主要包含以下几点:
- Collector监听的目标是Group,收集的目标是Entity,准确来讲,是收集Group新增了哪些Entity以及Group移除了哪些Entity
- Collector收集的手段是为Group的 OnEntityAdded 和 OnEntityRemoved 事件添加委托,在Group触发这两个事件时,通过添加的委托回调至Collector的 addEntity 方法中
void addEntity(IGroup group, Entity entity, int index, IComponent component)
{
var added = _collectedEntities.Add(entity);
if (added)
{
entity.Retain(this);
}
}
- 通过Activate() 方法和 Deactivate() 方法激活和休眠Collector,激活和休眠时,会分别向Group添加委托和移除委托
/// <summary>
/// 激活收集器
/// 作用是将AddEntity方法注册进所有被观察组的对应回调事件中
/// 遍历所有被观察的组和groupEventType数组,根据GroupEventType决定要将AddEntity方法注册到该Group的哪个回调中
/// </summary>
public void Activate()
{
for (int i = 0; i < _groups.Length; i++)
{
var group = _groups[i];
var groupEvent = _groupEvents[i];
switch (groupEvent)
{
case GroupEventType.Added:
group.OnEntityAdded -= _addEntityCache;
group.OnEntityAdded += _addEntityCache;
break;
case GroupEventType.Removed:
group.OnEntityRemoved -= _addEntityCache;
group.OnEntityRemoved += _addEntityCache;
break;
case GroupEventType.AddedOrRemoved:
group.OnEntityAdded -= _addEntityCache;
group.OnEntityAdded += _addEntityCache;
group.OnEntityRemoved -= _addEntityCache;
group.OnEntityRemoved += _addEntityCache;
break;
}
}
}
/// <summary>
/// 休眠收集器
/// 会将自身的AddEntity方法从所有被观察组的回调事件中移除
/// 同时清空所有收集到的Entity
/// </summary>
public void Deactivate()
{
for (int i = 0; i < _groups.Length; i++)
{
var group = _groups[i];
group.OnEntityAdded -= _addEntityCache;
group.OnEntityRemoved -= _addEntityCache;
}
ClearCollectedEntities();
}
- Collector通常搭配Monitor一起使用,Collector负责收集,Monitor负责处理
- Collector提供了 ClearCollectedEntities() 方法供外部调用,在处理逻辑执行后手动清空收集到的Entity,避免重复处理。
Group快速创建Collector
在GroupExtension中,为Group扩展了几个创建Collector的方法,我们可以通过这些方法为Group快速创建Collector
public static ICollector CreateCollector(this IGroup group, GroupEventType groupEvent = GroupEventType.Added)
{
return new Collector(group, groupEvent);
}
public static ICollector OnAdded(this IGroup group)
{
return new Collector(group, GroupEventType.Added);
}
public static ICollector OnRemoved(this IGroup group)
{
return new Collector(group, GroupEventType.Removed);
}
public static ICollector OnAddedOrRemoved(this IGroup group)
{
return new Collector(group, GroupEventType.AddedOrRemoved);
}
ICollector _collector = _group.OnAdded();
IMonitor
IMonitor与ICollector搭配使用,负责对Collector收集到的Entity进行逻辑处理。
IMonitor的结构如下:
其中涉及到的Delegate:
Monitor
Monitor是IMonitor的实现类,内容如下:
可以看到,Monitor 和 Colletor 是深度绑定的。Monitor中不仅记录着自己关联的Collector,并且Monitor提供的 Activate() 、Deactivate() 和 Clear() 方法也只是为了能够对Collector的对应方法进行调用。
/// <summary>
/// 每个Monitor对应一个Collector
/// </summary>
readonly ICollector _collector;
public void Activate()
{
_collector.Activate();
}
public void Deactivate()
{
_collector.Deactivate();
}
public void Clear()
{
_collector.ClearCollectedEntities();
}
Excute() 方法是 Monitor 的核心方法,该方法会在 ReactiveSystem 类型的 System 中被自动调用,负责执行实际的处理逻辑。ReactiveSystem 会在下一篇中介绍。
public void Execute()
{
if( 0 == _collector.count) return;
// 从Collector收集到的Entity中筛选出满足条件的Entity
// 并清空Collector收集到的Entity,避免重复处理
foreach (var e in _collector.collectedEntities)
{
//通过 _filter 对Collector收集到的Entity进行进一步筛选
if (_filter == null || _filter(e))
{
e.Retain(this);
_buffer.Add(e);
}
}
_collector.ClearCollectedEntities();
if(0 == _buffer.Count) return;
// 对筛选出的最终Entity列表进行实际处理
if (_processor != null) _processor(_buffer);
for (int i = 0; i < _buffer.Count; i++)
_buffer[i].Release(this);
_buffer.Clear();
}
在 Excute() 中,Monitor会通过 _filter 对Collector收集到的Entity再进行一遍过滤,将过滤到的Entity加入到自身的缓存列表_buffer中,然后通过 _processor 对缓存列表 _buffer 执行实际处理。
_filter 和 _processor 分别通过下面的方法进行指定:
/// <summary>
/// 指定 filter
/// </summary>
/// <param name="filter"></param>
/// <returns></returns>
public IMonitor Where(MonitorFilter filter)
{
_filter = filter;
return this;
}
/// <summary>
/// 指定 processor
/// </summary>
/// <param name="processor"></param>
/// <returns></returns>
public IMonitor Trigger(MonitorProcessor processor)
{
_processor = processor;
return this;
}
MonitorList
对Monitor列表 List<IMonitor> 的封装,重载了 + - 操作符:
public class MonitorList : List<IMonitor>
{
public MonitorList() {}
public MonitorList(int capacity) : base(capacity) {}
public MonitorList(IEnumerable<IMonitor> collection) : base(collection) { }
public static MonitorList operator +(MonitorList c, IMonitor monitor)
{
c.Add(monitor);
return c;
}
public static MonitorList operator -(MonitorList c, IMonitor monitor)
{
c.Remove(monitor);
return c;
}
}
Monitor的创建
通过Collector实例创建Monitor
在上面Collector的结构图中提到,Collector扩展了快速创建Monitor的方法:
public static IMonitor CreateMonitor(this ICollector collector) => new Monitor(collector);
public static IMonitor Where(this ICollector collector, MonitorFilter filter) => new Monitor(collector).Where(filter);
public static IMonitor Trigger(this ICollector collector, MonitorProcessor processor) => new Monitor(collector).Trigger(processor);
我们使用Monitor,主要是为了用它来对Collector收集的Entity进行逻辑处理,也就是说主要是用它的processor,所有上面三个方法中,最常用到的其实是第三个(Trigger)的方法。
于是,我们可以先创建出一个Collector,然后调用Trigger方法,将处理Entity的委托 _processor 传入,创建一个Monitor:
IMonitor _monitor = _collector.Trigger(_processor);
通过Group实例创建Monitor
结合Group创建Collector,就可以定制一个Monitor,对新加入某个Group的Entity进行指定的逻辑处理:
IMonitor _monitor = _group.OnAdded().Trigger(_processor);
在 GroupExtension 中也为Group扩展了直接创建Monitor的方法:
public static IMonitor OnAdded(this IGroup group, MonitorProcessor processor)
{
return new Collector(group, GroupEventType.Added).Trigger(processor);
}
public static IMonitor OnRemoved(this IGroup group, MonitorProcessor processor)
{
return new Collector(group, GroupEventType.Removed).Trigger(processor);
}
public static IMonitor OnAddedOrRemoved(this IGroup group, MonitorProcessor processor)
{
return new Collector(group, GroupEventType.AddedOrRemoved).Trigger(processor);
}
因此,我们可以跳过中间商,通过Group实例直接定制Monitor:
IMonitor _monitor = _group.OnAdded(_processor);
通过Context直接创建Monitor
那么Group实例是哪来的呢?当然是从Context的 GetGroup(IMatcher matcher) 方法中获得的。于是我们可以构建一个 Matcher,然后从Context中获取对应的Group实例,最后为Group实例定制Monitor:
IMatcher _matcher = Matcher.AllOf(ComponentIndex<Default, PositionComponent>.value).
AnyOf(ComponentIndex<Default, VelocityComponent>.value).
NoneOf(ComponentIndex<Default, ViewComponent>.value);
IMonitor _monitor = Context<Default>.Instance.GetGroup(_matcher).OnAdded(Process);
其实在实际的System中,一般不需要对这么复杂的Matcher规则的Group定制Monitor(如果真出现,更可能System规划的问题),通常都是简单的AllOf或者AnyOf规则,所以框架在 Context<C> 静态类中,提前为 AllOf 和 AnyOf 分别封装了至多6个泛型参数的静态方法,可以直接获取Group实例
public static IGroup AllOf<T1>() where T1 : IComponent
{ return Instance.GetGroup(Matcher<C, T1>.All()); }
public static IGroup AllOf<T1, T2>() where T1 : IComponent where T2 : IComponent
{ return Instance.GetGroup(Matcher<C, T1, T2>.All()); }
public static IGroup AllOf<T1, T2, T3>() where T1 : IComponent where T2 : IComponent where T3 : IComponent
{ return Instance.GetGroup(Matcher<C, T1, T2, T3>.All()); }
public static IGroup AllOf<T1, T2, T3, T4>() where T1 : IComponent where T2 : IComponent where T3 : IComponent where T4 : IComponent
{ return Instance.GetGroup(Matcher<C, T1, T2, T3, T4>.All()); }
public static IGroup AllOf<T1, T2, T3, T4, T5>() where T1 : IComponent where T2 : IComponent where T3 : IComponent where T4 : IComponent where T5 : IComponent
{ return Instance.GetGroup(Matcher<C, T1, T2, T3, T4, T5>.All()); }
public static IGroup AllOf<T1, T2, T3, T4, T5, T6>() where T1 : IComponent where T2 : IComponent where T3 : IComponent where T4 : IComponent where T5 : IComponent where T6 : IComponent
{ return Instance.GetGroup(Matcher<C, T1, T2, T3, T4, T5, T6>.All()); }
public static IGroup AnyOf<T1>() where T1 : IComponent
{ return Instance.GetGroup(Matcher<C, T1>.Any()); }
public static IGroup AnyOf<T1, T2>() where T1 : IComponent where T2 : IComponent
{ return Instance.GetGroup(Matcher<C, T1, T2>.Any()); }
public static IGroup AnyOf<T1, T2, T3>() where T1 : IComponent where T2 : IComponent where T3 : IComponent
{ return Instance.GetGroup(Matcher<C, T1, T2, T3>.Any()); }
public static IGroup AnyOf<T1, T2, T3, T4>() where T1 : IComponent where T2 : IComponent where T3 : IComponent where T4 : IComponent
{ return Instance.GetGroup(Matcher<C, T1, T2, T3, T4>.Any()); }
public static IGroup AnyOf<T1, T2, T3, T4, T5>() where T1 : IComponent where T2 : IComponent where T3 : IComponent where T4 : IComponent where T5 : IComponent
{ return Instance.GetGroup(Matcher<C, T1, T2, T3, T4, T5>.Any()); }
public static IGroup AnyOf<T1, T2, T3, T4, T5, T6>() where T1 : IComponent where T2 : IComponent where T3 : IComponent where T4 : IComponent where T5 : IComponent where T6 : IComponent
{ return Instance.GetGroup(Matcher<C, T1, T2, T3, T4, T5, T6>.Any()); }
这样,在大部分应用场景中,我们都可以通过这些泛型方法快速为需要的Group定制Monitor了。
IMonitor _monitor = Context<Default>.AllOf<PositionComponent, ViewComponent>().OnRemoved(Process);