IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> UIGU源码分析3 :ExecuteEvents -> 正文阅读

[开发工具]UIGU源码分析3 :ExecuteEvents

源码3:ExecuteEvents

上面在分析 输入模块的时候 都提到了会有对应的事件发送。具体的实现就在ExecuteEvents 类里面

下面我们来分析一下这个事件系统

在最上面 有一个委托定义

  public delegate void EventFunction<T1>(T1 handler, BaseEventData eventData);

带有两个参数 一个是handler 是个泛型 一个是eventData通常这个会包含位置信息 偏移量 点击物体等等

基于这个委托 在当前类定义了很多委托的实例 (下面放了部分原始代码)

private static readonly EventFunction<IPointerEnterHandler> s_PointerEnterHandler = Execute;

private static void Execute(IPointerEnterHandler handler, BaseEventData eventData)
{
	handler.OnPointerEnter(ValidateEventData<PointerEventData>(eventData));
}

private static readonly EventFunction<IPointerExitHandler> s_PointerExitHandler = Execute;

private static void Execute(IPointerExitHandler handler, BaseEventData eventData)
{
	handler.OnPointerExit(ValidateEventData<PointerEventData>(eventData));
}

private static readonly EventFunction<IPointerDownHandler> s_PointerDownHandler = Execute;

private static void Execute(IPointerDownHandler handler, BaseEventData eventData)
{
	handler.OnPointerDown(ValidateEventData<PointerEventData>(eventData));
}

private static readonly EventFunction<IPointerUpHandler> s_PointerUpHandler = Execute;

private static void Execute(IPointerUpHandler handler, BaseEventData eventData)
{
	handler.OnPointerUp(ValidateEventData<PointerEventData>(eventData));
}

从这里看出来 上面有很多具体的handler类型,这些handler 也都是一个interface 并且是继承IEventSystemHandler 。同时定义了自己的具体方法。

所以从这里就不难看出来 UI上的具体行为事件 就是通过调用这些handler接口实现的。(上面代码看不明白的就得去熟悉下c# 委托相关的类容)

Execute

具体调用上面的委托实例就是通过下面代码实现了

    private static readonly ObjectPool<List<IEventSystemHandler>> s_HandlerListPool = new ObjectPool<List<IEventSystemHandler>>(null, l => l.Clear());

    public static bool Execute<T>(GameObject target, BaseEventData eventData, EventFunction<T> functor) where T : IEventSystemHandler
    {
        var internalHandlers = s_HandlerListPool.Get();
        GetEventList<T>(target, internalHandlers);
        //  if (s_InternalHandlers.Count > 0)
        //      Debug.Log("Executinng " + typeof (T) + " on " + target);

        var internalHandlersCount = internalHandlers.Count;
        for (var i = 0; i < internalHandlersCount; i++)
        {
            T arg;
            try
            {
                arg = (T)internalHandlers[i];
            }
            catch (Exception e)
            {
                var temp = internalHandlers[i];
                Debug.LogException(new Exception(string.Format("Type {0} expected {1} received.", typeof(T).Name, temp.GetType().Name), e));
                continue;
            }

            try
            {
                functor(arg, eventData);
            }
            catch (Exception e)
            {
                Debug.LogException(e);
            }
        }

        var handlerCount = internalHandlers.Count;
        s_HandlerListPool.Release(internalHandlers);
        return handlerCount > 0;
    }

上面代码思路是:

1.定义一个对象池 每次执行前 先从对象池中获取List ,上面讲过所有的操作事件都是IEventSystemHandler接口的子类

2.获取当前对象上所有的IEventSystemHandler 返回到上面的List集合中

        /// <summary>
        /// Get the specified object's event event.
        /// </summary>
        private static void GetEventList<T>(GameObject go, IList<IEventSystemHandler> results) where T : IEventSystemHandler
        {
            // Debug.LogWarning("GetEventList<" + typeof(T).Name + ">");
            if (results == null)
                throw new ArgumentException("Results array is null", "results");

            if (go == null || !go.activeInHierarchy)
                return;

            var components = ListPool<Component>.Get();
            go.GetComponents(components);

            var componentsCount = components.Count;
            for (var i = 0; i < componentsCount; i++)
            {
                if (!ShouldSendToComponent<T>(components[i]))
                    continue;

                // Debug.Log(string.Format("{2} found! On {0}.{1}", go, s_GetComponentsScratch[i].GetType(), typeof(T)));
                results.Add(components[i] as IEventSystemHandler);
            }
            ListPool<Component>.Release(components);
          

3.遍历获取到的IEventSystemHandler ,将handler作为第一个参数,eventData作为第二个参数 执行EventFunction方法,也就是上面讲的委托实例。它会调用handler中对应接口的方法

例如在TouchInputModule中我们调用松开事件

 ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);

ExecuteHierarchy

与Execute方法类似 这里面还定义了一个ExecuteHierarchy执行事件方法

        /// <summary>
        /// Execute the specified event on the first game object underneath the current touch.
        /// </summary>
        private static readonly List<Transform> s_InternalTransformList = new List<Transform>(30);

        public static GameObject ExecuteHierarchy<T>(GameObject root, BaseEventData eventData, EventFunction<T> callbackFunction) where T : IEventSystemHandler
        {
            GetEventChain(root, s_InternalTransformList);

            var internalTransformListCount = s_InternalTransformList.Count;
            for (var i = 0; i < internalTransformListCount; i++)
            {
                var transform = s_InternalTransformList[i];
                if (Execute(transform.gameObject, eventData, callbackFunction))
                    return transform.gameObject;
            }
            return null;
        }
    private static void GetEventChain(GameObject root, IList<Transform> eventChain)
    {
        eventChain.Clear();
        if (root == null)
            return;

        var t = root.transform;
        while (t != null)
        {
            eventChain.Add(t);
            t = t.parent;
        }
    }

实际上他最终的执行还是通过Execute 方法 ,不过不同点就在与他执行前先沿着Hierarchy获取了包括当前物体以及往上的所有父对象。然后遍历查询这些对项 直到有handler为止。

不过可以想象 这样做的话 下层层级对象的事件肯定会阻挡上层层级对象的事件。

其他方法

    //判断对象能否接受对应事件
    /// <summary>
    /// Whether the specified game object will be able to handle the specified event.
    /// </summary>
    public static bool CanHandleEvent<T>(GameObject go) where T : IEventSystemHandler
    {
        var internalHandlers = s_HandlerListPool.Get();
        GetEventList<T>(go, internalHandlers);
        var handlerCount = internalHandlers.Count;
        s_HandlerListPool.Release(internalHandlers);
        return handlerCount != 0;
    }

//获取实际能接受对应事件的对象
    /// <summary>
    /// Bubble the specified event on the game object, figuring out which object will actually receive the event.
    /// </summary>
    public static GameObject GetEventHandler<T>(GameObject root) where T : IEventSystemHandler
    {
        if (root == null)
            return null;

        Transform t = root.transform;
        while (t != null)
        {
            if (CanHandleEvent<T>(t.gameObject))
                return t.gameObject;
            t = t.parent;
        }

总结

总的来说这套事件系统还是比较清晰,基于这套我们自己也能扩充更多的事件

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2022-03-04 15:48:03  更:2022-03-04 15:48:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:31:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码