【ET6.0】 EventSystem(一) 生命周期事件

以下全部是个人对ET6.0源码的分析,如有错误请读者指出。

什么是EventSystem

EventSystem用于事件通知,事件回调,走的消息监听,消息派发,消息回调的方式,是一种有效解耦各种业务逻辑代码的编程方式。

EventSystem解析
  1. 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;
    }
}
  1. 在哪里注册事件
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接口)。

  1. 一些常用生命周期事件

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;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
EventSystem是Unity引擎中的一个重要组件,用管理和处理游戏事件。它的作是允许不同的游戏对象之进行通信和交互,以便实现戏的各种功能和逻辑。 具体来说,EventSystem可以用于以下几个方面: 1. 输入管理:EventSystem可以接收鼠标、键盘触摸等输入事件,并将其传递给合适的游戏对象进行处理。比如,点击按钮、拖拽物体等操作都可以通过EventSystem来响应和处理。 2. UI事件处理:Unity的UI系统依赖于EventSystem来处理UI元素的交互事件,比如按钮点击、滚动条滑动等。EventSystem会根据用户的输入将事件传递给正确的UI元素,并调用相应的回调函数。 3. 事件广播:EventSystem可以用于广播游戏内的自定义事件,以实现游戏对象之间的通信和互动。比如,当玩家进入某个区域时,可以通过EventSystem发送一个自定义事件,其他关联对象可以通过监听这个事件来执行相应的逻辑。 4. 物理射线检测:EventSystem可以与Unity的物理系统结合使用,用于检测物体之间的碰撞和触发事件。比如,当一个射线与某个物体发生碰撞时,EventSystem可以触发相应的事件,并通知相关的游戏对象做出反应。 总之,EventSystem在Unity中起到了很重要的作用,它是游戏事件处理和交互的重要桥梁。通过合理地利用EventSystem,可以实现更加灵活和交互丰富的游戏逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值