EntitasLite源码分析(七)

ICollector

顾名思义,ICollector是一个收集器,通过监听Group的Event事件,对相关的Entity进行收集,以供后续逻辑处理。

ICollector的结构如下:
在这里插入图片描述

Collector

Collector是ICollector的实现类,内容如下:
在这里插入图片描述
Collector的内容很简单,主要包含以下几点:

  1. Collector监听的目标是Group,收集的目标是Entity,准确来讲,是收集Group新增了哪些Entity以及Group移除了哪些Entity
  2. 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);
            }
        }
  1. 通过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();
        }
  1. Collector通常搭配Monitor一起使用,Collector负责收集,Monitor负责处理
  2. 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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值