以下全部是个人对ET6.0源码的分析,如有错误请读者指出。
什么是EventSystem
EventSystem用于事件通知,事件回调,走的消息监听,消息派发,消息回调的方式,是一种有效解耦各种业务逻辑代码的编程方式。
EventSystem解析
- EventSystem中的成员
//key: Entity的instanceId value: Entity
//为什么记录instanceId而不记录对象引用? Entity可能在池中。
//执行Update时根据原先的instanceid找到Entity,但是发现Entity此时已被释放,因而不能执行update事件。
private readonly Dictionary<long, Entity> allEntities = new Dictionary<long, Entity>();
//key: 程序集name value: dll
private readonly Dictionary<string, Assembly> assemblies = new Dictionary<string, Assembly>();
//记录类型fullName跟类型的映射
//每次添加dll都会清空allTypes
private readonly Dictionary<string, Type> allTypes = new Dictionary<string, Type>();
//记录attributes与type的映射。
//eg. objectSystem Event FriendClass 与标记了这些标签的类(AwakeSystem等等)
private readonly UnOrderMultiMap<Type, Type> types = new UnOrderMultiMap<Type, Type>();
//Publish参数与订阅者的映射关系
//eg. EventType.App_StartInit ---> AppStart_Init.cs
private readonly Dictionary<Type, List<object>> allEvents = new Dictionary<Type, List<object>>();
//记录生命周期与生命周期事件的映射 具体见下:
private TypeSystems typeSystems = new TypeSystems();
其中UnSortedMultiMap功能与MultiMap类似,区别在于不能根据键值排序。
关于MultiMap可以参考上一篇文章: 【ET6.0】MultiMap解析
关于TypeSystems
//using起一个别名,学到了
//eg. 我有一个TestComponent 此时key: IAwakeSystem value : TestComponentAwakeSystem实例列表
using OneTypeSystems = UnOrderMultiMap<Type, object>;
private class TypeSystems
{
/// <summary>
///Entity和他的生命周期事件的映射关系
/// </summary>
private readonly Dictionary<Type, OneTypeSystems> typesSystemsMap = new Dictionary<Type, OneTypeSystems>();
/// <summary>
///
/// </summary>
/// <param name="type">Entity的类型 eg. NumericComponent</param>
/// <returns></returns>
public OneTypeSystems GetOrCreateOneTypeSystems(Type type)
{
OneTypeSystems systems = null;
this.typesSystemsMap.TryGetValue(type, out systems);
if (systems != null)
{
return systems;
}
systems = new OneTypeSystems();
this.typesSystemsMap.Add(type, systems);
return systems;
}
public OneTypeSystems GetOneTypeSystem(Type type)
{
OneTypeSystems systems = null;
this.typesSystemsMap.TryGetValue(type, out systems);
return systems;
}
public List<object> GetSystems(Type type, Type systemType)
{
OneTypeSystems oneTyoeSystems = null;
if (!this.typesSystemsMap.TryGetValue(type, out oneTyoeSystems))
{
return null;
}
if (!oneTyoeSystems.TryGetValue(systemType, out List<object> systems))
{
return null;
}
return systems;
}
}
- 在哪里注册事件
Entity.cs
public T AddChild<T>(bool isFromPool = false) where T : Entity, IAwake
{
Type type = typeof(T);
T component = (T)Entity.Create(type, isFromPool);
component.Id = IdGenerater.Instance.GenerateId(); // 注意要为新生成的子元素设置Id
component.Parent = this; //1. 设置Domain 并且注册事件
EventSystem.Instance.Awake(component); //2.
return component;
}
当我们调用AddChild()时,也就是我们新建一个Entity并且设置父子关系后,因为Entity是新生成的(或者从对象池取出),此时 Domain(详细的后面会写博客,一般Domain会设置为离得最近的Scene)为空,会为Entity注册事件。
根据Entity实现的接口,例如IUpdate,ILateUpate,ILoad,然后为其注册对应事件。
EventSystem.cs
/// <summary>
/// 注册事件
/// </summary>
/// <param name="component">instanceId和Entity的映射关系会记录在allEntities中</param>
/// <param name="isRegister">如果Entity新生成,或刚从对象池取出为true</param>
public void RegisterSystem(Entity component, bool isRegister = true)
{
if (!isRegister)
{
this.Remove(component.InstanceId);
return;
}
this.allEntities.Add(component.InstanceId,component);
Type type = component.GetType();
OneTypeSystems oneTypeSystems = this.typeSystems.GetOneTypeSystem(type);
//热重载
if (component is ILoad)
{
if (oneTypeSystems.ContainsKey(typeof(ILoadSystem)))
{
this.loaders.Enqueue(component.InstanceId);
}
}
//压入每帧更新队列,后同
if (component is IUpdate)
{
if (oneTypeSystems.ContainsKey(typeof(IUpdateSystem)))
{
this.updates.Enqueue(component.InstanceId);
}
}
if (component is ILateUpdate)
{
if (oneTypeSystems.ContainsKey(typeof(ILateUpdateSystem)))
{
this.lateUpdates.Enqueue(component.InstanceId);
}
}
}
注册事件之后,就是调用Entity的Awake事件(如果实现了IAwake接口)。
- 一些常用生命周期事件
Update事件,每帧触发。
public void Update()
{
while (this.updates.Count > 0)
{
long instanceId = this.updates.Dequeue();
Entity component;
if (!this.allEntities.TryGetValue(instanceId, out component))
{
continue;
}
if (component.IsDisposed)
{
continue;
}
List<object> iUpdateSystmes = this.typeSystems.GetSystems(component.GetType(), typeof(IUpdateSystem));
if (iUpdateSystmes == null)
{
continue;
}
this.updates2.Enqueue(instanceId);
for (int i = 0; i < iUpdateSystmes.Count; ++i)
{
IUpdateSystem iUpdateSystem = iUpdateSystmes[i] as IUpdateSystem;
try
{
iUpdateSystem.Run(component);
}
catch (Exception e)
{
Console.WriteLine(e); //这里注意,实战中要用Log.Debug哦(我还没引入NLog)
}
}
}
//交换工作队列和待机队列
ObjectHelper.Swap(ref this.updates, ref this.updates2);
}
Destroy事件,释放Entity时触发
public override void Dispose()
{
if (this.IsDisposed)
{
return;
}
this.IsRegister = false;
this.InstanceId = 0; // isDisposed = false
// ------- 省略无关部分------- //
//触发Destroy事件
if (this is IDestroy)
{
EventSystem.Instance.Destroy(this);
}
this.domain = null;
if (this.parent != null && !this.parent.IsDisposed)
{
if (this.IsComponent)
{
this.parent.RemoveFromComponents(this);
}
else
{
this.parent.RemoveFromChildren(this);
}
}
this.parent = null;
base.Dispose();
if (this.IsFromPool)
{
ObjectPool.Instance.Recycle(this); //对象池回收
}
status = EntityStatus.None;
}