梳理Unity EventSystem事件系统调用过程

这篇具有很好参考价值的文章主要介绍了梳理Unity EventSystem事件系统调用过程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

之前写过一个关于Button点击事件怎么被调用的,这次把EventSystem事件系统调用过程总结一下

梳理Unity EventSystem事件系统调用过程

                 图来自 UGUI源码分析:EventSystem事件系统_Vin129的博客-CSDN博客

在事件系统中,最重要的两个类是EventSystem与StandaloneInputModule,这两个类均继承自基类UIBehavior,而UIBehavior继承了MonoBehavior,因此这两个类是以组件的形式在Unity中执行逻辑的.

public abstract class UIBehaviour : MonoBehaviour
    {
        protected virtual void Awake()
        {}

        protected virtual void OnEnable()
        {}

        protected virtual void Start()
        {}

        protected virtual void OnDisable()
        {}

        protected virtual void OnDestroy()
        {}

        /// <summary>
        /// Returns true if the GameObject and the Component are active.
        /// </summary>
        public virtual bool IsActive()
        {
            return isActiveAndEnabled;
        }

#if UNITY_EDITOR
        protected virtual void OnValidate()
        {}

        protected virtual void Reset()
        {}
#endif
        /// <summary>
        /// This callback is called if an associated RectTransform has its dimensions changed. The call is also made to all child rect transforms, even if the child transform itself doesn't change - as it could have, depending on its anchoring.
        /// </summary>
        protected virtual void OnRectTransformDimensionsChange()
        {}

        protected virtual void OnBeforeTransformParentChanged()
        {}

        protected virtual void OnTransformParentChanged()
        {}

        protected virtual void OnDidApplyAnimationProperties()
        {}

        protected virtual void OnCanvasGroupChanged()
        {}

        /// <summary>
        /// Called when the state of the parent Canvas is changed.
        /// </summary>
        protected virtual void OnCanvasHierarchyChanged()
        {}

        /// <summary>
        /// Returns true if the native representation of the behaviour has been destroyed.
        /// </summary>
        /// <remarks>
        /// When a parent canvas is either enabled, disabled or a nested canvas's OverrideSorting is changed this function is called. You can for example use this to modify objects below a canvas that may depend on a parent canvas - for example, if a canvas is disabled you may want to halt some processing of a UI element.
        /// </remarks>
        public bool IsDestroyed()
        {
            // Workaround for Unity native side of the object
            // having been destroyed but accessing via interface
            // won't call the overloaded ==
            return this == null;
        }
    }

首先对于EventSystem,它其中有BaseInputModule m_CurrentInputModule与 List<BaseInputModule> m_SystemInputModules均是管理输入模块的,默认情况下Unity与含有EventSystem的物体一同生成StandaloneInputModule

对于EventSystem中List<BaseInputModule> m_SystemInputModules中的对象添加是在BaseInputModule类中

        protected override void OnEnable()
        {
            base.OnEnable();
            m_EventSystem = GetComponent<EventSystem>();
            m_EventSystem.UpdateModules();
        }

        BaseInputModule中的OnEnable()方法


        public void UpdateModules()
        {
            GetComponents(m_SystemInputModules);
            for (int i = m_SystemInputModules.Count - 1; i >= 0; i--)
            {
                if (m_SystemInputModules[i] && m_SystemInputModules[i].IsActive())
                    continue;

                m_SystemInputModules.RemoveAt(i);
            }
        }

        EventSystem中的OnEnable()方法

在BaseInputModule调用EventSystem的UpdateModules方法之后将对List<BaseInputModule> m_SystemInputModules进行填充,而StandaloneInputModule继承自BaseInputModule且StandaloneInputModule与EventSystem在同一个物体上,因此StandaloneInputModule被加入到EventSystem中的List<BaseInputModule> m_SystemInputModules中之后进行轮询访问.

在EventSystem中其内部的Update方法进行帧调用每一个BaseInputModule对应的方法

 protected virtual void Update()
        {
            if (current != this)
                return;
            TickModules();

            bool changedModule = false;
            for (var i = 0; i < m_SystemInputModules.Count; i++)
            {
                var module = m_SystemInputModules[i];
                if (module.IsModuleSupported() && module.ShouldActivateModule())
                {
                    if (m_CurrentInputModule != module)
                    {
                        ChangeEventModule(module);
                        changedModule = true;
                    }
                    break;
                }
            }

            // no event module set... set the first valid one...
            if (m_CurrentInputModule == null)
            {
                for (var i = 0; i < m_SystemInputModules.Count; i++)
                {
                    var module = m_SystemInputModules[i];
                    if (module.IsModuleSupported())
                    {
                        ChangeEventModule(module);
                        changedModule = true;
                        break;
                    }
                }
            }

            if (!changedModule && m_CurrentInputModule != null)
                m_CurrentInputModule.Process();
        }

这里current为EventSystem类,对于EventSystem一个场景只能存在一个,EventSystem被自身类静态存储      private static List<EventSystem> m_EventSystems = new List<EventSystem>();

对于TickModules方法,该方法进行轮询上述的BaseInputModule的对应方法

        private void TickModules()
        {
            for (var i = 0; i < m_SystemInputModules.Count; i++)
            {
                if (m_SystemInputModules[i] != null)
                    m_SystemInputModules[i].UpdateModule();
            }
        }
        public override void UpdateModule()
        {
            if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
            {
                if (m_InputPointerEvent != null && m_InputPointerEvent.pointerDrag != null && m_InputPointerEvent.dragging)
                {
                    ReleaseMouse(m_InputPointerEvent, m_InputPointerEvent.pointerCurrentRaycast.gameObject);
                }

                m_InputPointerEvent = null;

                return;
            }

            m_LastMousePosition = m_MousePosition;
            m_MousePosition = input.mousePosition;
        }

对于EventSystem的Update方法中间部分则是为了确保该输入模块适应当前平台的保障

在EventSystem的Update方法最后执行了每个BaseInputModule的Process方法

        public override void Process()
        {
            if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
                return;

            bool usedEvent = SendUpdateEventToSelectedObject();

            // case 1004066 - touch / mouse events should be processed before navigation events in case
            // they change the current selected gameobject and the submit button is a touch / mouse button.

            // touch needs to take precedence because of the mouse emulation layer
            if (!ProcessTouchEvents() && input.mousePresent)
                ProcessMouseEvent();

            if (eventSystem.sendNavigationEvents)
            {
                if (!usedEvent)
                    usedEvent |= SendMoveEventToSelectedObject();

                if (!usedEvent)
                    SendSubmitEventToSelectedObject();
            }
        }

其中SendUpdateEventToSelectedObject方法将EventSystem中之前被选中的物体执行Selected事件

之后若鼠标可用将执行处理鼠标事件的方法即ProcessMouseEvent

        protected void ProcessMouseEvent(int id)
        {
            var mouseData = GetMousePointerEventData(id);
            var leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData;

            m_CurrentFocusedGameObject = leftButtonData.buttonData.pointerCurrentRaycast.gameObject;

            // Process the first mouse button fully
            ProcessMousePress(leftButtonData);
            ProcessMove(leftButtonData.buttonData);
            ProcessDrag(leftButtonData.buttonData);

            // Now process right / middle clicks
            ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData);
            ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData.buttonData);
            ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData);
            ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData.buttonData);

            if (!Mathf.Approximately(leftButtonData.buttonData.scrollDelta.sqrMagnitude, 0.0f))
            {
                var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(leftButtonData.buttonData.pointerCurrentRaycast.gameObject);
                ExecuteEvents.ExecuteHierarchy(scrollHandler, leftButtonData.buttonData, ExecuteEvents.scrollHandler);
            }
        }

GetMousePointerEventData方法是在抽象类PointerInputModule中,该方法进行组装鼠标指针数据,处理这一帧与上一帧的鼠标位置信息,以处理之后的拖拽事件,在组装数据时,先是组装了鼠标左键的数据,组装中还调用了EventSystem的RaycastAll方法,该方法得到该鼠标指针位置下所有射线模块能检测到的物体,之后对于鼠标右键与中键的数据是复制了鼠标左键的数据,之后进行返回该鼠标指针数据.

在得到鼠标指针数据之后ProcessMouseEvent进行各种鼠标事件调用,将调用类型与指针数据中的射线检测到的物体传递给ExecuteEvents,在ExecuteEvents中进行各种事件的触发

总结

EventSystem中保存所有输入模块,在EventSystem的Update方法中进行轮询每个输入模块的TickModules与Process方法,其中TickModules方法将EventSystem类中的保存的选中的对象进行触发Selected事件,保存的选中的对象可在Selected类中进行设置,之后在Process方法调用后进行组装鼠标指针数据,射线检测该指针下的物体,最后在ExecuteEvents中进行各种事件调用

如果觉得文章有用请关注B站EOE组合 谢谢喵文章来源地址https://www.toymoban.com/news/detail-408270.html

到了这里,关于梳理Unity EventSystem事件系统调用过程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • unity UGUI系统梳理 -交互组件

    unity 中的交互组件可用于处理交互,例如鼠标或触摸事件以及使用键盘或控制器进行的交互 Button详解 Background:背景图片,控制toggle组件的背景颜色改变,从而展示此物体是否被选中的效果; Checkmark:就是我们界面看到的对号勾选框,对号图片可以替换,也可以删除不用。

    2024年02月17日
    浏览(40)
  • Unity UGUI2——Canvas与EventSystem

    ​ Canvas 的意思是画布,它是 UGUI 中所有 UI 元素能够被显示的根本,它主要负责渲染自己的所有 UI 子对象 ​ 如果 UI 控件对象不是 Canvas 的子对象,那么控件将不能被渲染 ​ 我们可以通过修改 Canvas 组件上的参数修改渲染方式 ​ 场景中允许有多个 Canvas 对象,可以分别管理

    2024年02月12日
    浏览(54)
  • Unity–UI框架-Canvas-EventSystem-Panel

    画布canvas是控制一组UI元素如何呈现的组件, 所有UI元素必须是画布的子项 ,场景中可以有多个画布,但是UI元素至少需要一个可用的画布canvas, 每个画布都有不同的渲染模式,渲染模式可以使用Render Mode进行设置, 1.Screen Space-Overlay 其中,第一种是最常见的渲染模式,也是

    2024年02月03日
    浏览(53)
  • Unity Canvas、Canvas Scaler、Graphic Raycaster、EventSystem 组件详解

    https://blog.csdn.net/qq_33789001/article/details/117781577 https://blog.csdn.net/q764424567/article/details/119923544 属性 功能 Pixel Perfect 使UI元素像素对应,效果就是边缘清晰不模糊 Sort Order 多个Canvas时,数值越大越后渲染。值大的 画布,会挡住值小的 Target Display 目标显示器,如果有多个屏幕的话可

    2024年01月21日
    浏览(62)
  • 【工具插件类教学】Unity运行时监控变量,属性,事件等的值和调用Runtime Monitoring

    目录 一、介绍 二、安装方式 三、入门 1.实例化和静态成员

    2024年02月21日
    浏览(52)
  • Unity 事件系统

    简介: EventSystem提供了一种向游戏物体发送消息的途径,这些物体通常是输入信息,包括键盘、鼠标、触摸和自定义输入事件。它包含了一系列组件,它们互相配合,以达到管理和触发器事件的功能。 如果查看物体的EventSystem,会发现可调参数并不多,这是因为EventSystem本身

    2024年02月08日
    浏览(33)
  • Unity UI点击事件系统

    在Unity 的UGUI开发过程中,我们经常需要对UI图片进行操作响应各种处理比如:点击,长点击,长按,拖拽等多种功能的实现,这时原本的Button组件就不够用了 我们需要自己实现一个简单的点击事件系统来响应用户的各种操作,下面可以分析一下思路。 首先你需要提前了解点

    2024年01月17日
    浏览(42)
  • Unity基础 - 封装一个好用的事件系统

    在游戏开发过程中,我们会大量使用事件系统。很多时候,比起直接调用对象组件的方法,使用事件触发将很大程度上降低系统的耦合度,从而实现更为优雅的系统设计。 封装一个好用的事件系统将对我们的开发起到很大的帮助。 本文将基于Unity提供的ScriptableObject和UnityEv

    2024年02月02日
    浏览(45)
  • CAN接口:Ubuntu系统下CAN接口使用python调用过程

    介绍在Ubuntu系统中通过python程序使用CAN接口。 NVIDIA小型边缘设备NX,(Orin NX和Xavier NX都可以),系统采用Ubuntu,(18.04版本和20.04版本都可以),目的是通过python程序调用CAN接口接收数据。 首先使用命令查看是否有CAN接口 说明现在是没有办法使用CAN接口的,需要通过几部操作

    2024年02月11日
    浏览(48)
  • stable diffusion推理过程代码梳理

    最近在看stable diffusion,想梳理一下代码流程,以便之后查阅 从txt2img.py开始看 1.首先是对文本进行编码 (1)调用的是 stable-diffusion/ldm/models/diffusion/ddpm.py的get_learned_conditioning函数 (2) 第555行表示使用CLIP的文本编码器对输入的文本进行编码,调用的是stable-diffusion/ldm/modules

    2024年02月11日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包