1.前言
本文针对UGUI事件系统进行总体陈述,可以有一个宏观上的理解。事件系统保罗各种输入、EventSystem以及各种InputModule,其实不只是UGUI的事件系统,是整个Unity的事件系统。本文只是综述,只涉及各个模块之间的关系与各个模块的功能,每个模块的具体分析在后续详解,源码链接https://bitbucket.org/Unity-Technologies/ui/downloads/?tab=tags。
2.事件系统简图
事件系统的关系简图如下:
2.1 基本流程
在整个事件系统中EventSystem是管理者,维护着所有所有去执行事件(如点击、拖动等)的模块即各种InputModules。整个事件系统的输入是EventData,而最主要的是PointerEventData,它除了存储了当前帧下鼠标坐标和点击状态外还存储了此时鼠标下对应的游戏物体以及上一帧的游戏物体,而由于移动设备的特殊性则会所差异,后续会详细说明。有了EventData,InputModule根据数据进行判断具体执行什么事件,比如是否执行click事件或者拖动事件等。InputModule判断出需要具体执行何种事件后交由ExecuteEvent去执行具体事件。
3.事件系统详图
下图为整个事件系统的详细流程:
3.1 EventSystem简介
EventSystem 维护着一个InputModule列表,所有的InputModule启动时(OnEnable)会加入到EventSystem中的InputModule列表中。EventSystem中有个RayCastAll方法,它通过射线检测获取到所有的当前鼠标下(或者移动端touch下)的游戏物体。
3.2 EventSystem工作流程
最主要的工作流程在Update方法中,即每一帧去刷新InputModule,并让当前InputModule在Process方法中去判断具体执行何种事件。
首先TickModule,此方法是通知各个InputModule去执行相关操作,目前StandaloneInputModule是更新点击位置坐标,而这个坐标只跟此模块是否激活有关。然后是根据当前各个模块状态,选择当前可以使用的InputModule。在当前Unity中只有StandaloneInputModule一个模块。这是因为TouchInputModule功能集成在了Standalone中。但在早期版本中是同时存在这两个InputModule的。最后则是调用当前激活InputModule的Process方法,去判断执行何种事件。
3.3 InputModule简介
此例以StandaloneInputModule为例,进行分析。InputModule的重点在Process方法中,其他方法都是辅助处理方法。在Process判断是否执行相关事件。而Process方法中重点方法则是ProcessTouchEvent和ProcessMouseEvent。这两个方法是处理点击,拖动等等方法的核心,区别在于前者处理移动端Touch事件,后者处理pc端鼠标事件,但是两者处理流程相同。
3.4 InputModule事件处理流程
InputModule处理事件时首先处理Update事件,通过对当前游戏物体发送update事件实现。其次是,如果开启了键盘事件如按Esc退出或者按Enter键确认等操作(也包括aswd字母键然后前后左右移动),则直接直接进行处理,相对比较简单。最后,处理点击、拖动等常用事件才是重点,也是最复杂的。此部分处理流程如下:
1)获取当PointerEventData
鼠标由于一致存在桌面上,所以每一帧都可能存在PointerEnter/Exit事件。移动端则不同,如果手指没有按在屏幕上则没有PointerEnter/Exit事件的可能性,这也导致两者在处理事件上的不同。而且鼠标还存在鼠标左键、中间、右键,所以会更加复杂。
但是不管是touch还是鼠标,都通过input获取当前点坐标以及是否clicked或者released。然后根据当前坐标信息,进行射线检测,获取当前点击到的游戏物体。
2)处理点击事件
虽然方法名字是处理点击事件,其实作用不止如此,还涉及处理当按下时各种游戏物体的处理,包括是否包含拖动事件等。其实这一步除了本身处理pointerDown、PointerUp和PointerClick事件外还为后续处理ProcessDrag以及ProcessMove准备素材。所以这一步走完,下面两步就比较容易了。
3)处理Move与Drag事件
由于上一步准备的素材,这两步处理起来则比较方便。
3.5 RayCaster模块
在通过射线检测获取点击到的游戏物体时,是由各种rayCaster去实现的。包括PhysicRaycaster2D、PhysicRayCaster和GraphicRayCaster,分别检测2D游戏对象,3D游戏对象和UI对象,但是使用时是使用三者检测结果中最前面的游戏物体,所以有时候会存在ui遮挡3D对象的问题。
4.结语
以上是各个模块的关系以及各个模块发挥的基本作用。