Unity 内部的 Event System(组件)
Event System 是 Unity 提供的内部 GameObject 响应输入(如键盘输入、鼠标输入、触摸输入等)事件的一种实现,它由多个组件组成,协同工作来实现整个事件通信。
组成 Event System 的组件包括:
EventSystem 组件(本文内容)
EventSystem 组件
EventSystem 组件主要实现以下功能:
控制哪个 GameObject 被选中响应事件
控制选择使用哪一种 Input Module(同一时刻只有一个 Input Module 能处于激活状态)
管理 Raycasting
管理更新 Input Module
在 Unity 编辑器中,可以直接为场景添加 EventSystem 组件(一个场景通常只包含一个 EventSystem 组件)。可以直接设置一些属性以达到自定义需求,如下:
属性 | 成员变量 | 描述 |
---|---|---|
First Selected | m_FirstSelected | EventSystem 中第一个被选中的对象 |
Send Navigation Event | m_sendNavigationEvents | EventSystem 是否接收处理 Navigation 事件(move / submit / cancel) |
Drag Threshold | m_DragThreshold | 可以判定为拖拽(drag)的阈值(单位: 像素) |
除了上面三个可以在编辑器中编辑的属性之外,还有很多其他特性,如: m_HasFocus
可以用来表示当前 EventSystem 是否处于拥有焦点状态,如果当前没有获得焦点,诸如 Input Module 相关的更新和激活方法不会被调用,事件处理方法 Process()
也不会进行。
EventSystem 组件也是一个 MonoBehaviour,因此它具有完整的 Unity 生命周期。除了有一些生命周期相关的回调,它也有一些其它比较重要的方法。
void UpdateModules() 方法
这个方法作用就是重新计算当前 m_SystemInputModules
中的 Input Modules,保证 m_SystemInputModules
中的 Input Module 都是出于激活状态的。这个方法会在 BaseInputModule 类的 OnEnable()
和 OnDisable()
方法中被调用,以注册或反注册对应的 Input Module。
void SetSelectedGameObject(GameObject selected, BaseEventData pointer) 方法
设置当前被选中的对象,属性 m_CurrentSelected
会被赋值为被选中的 GameObject。设置过程中,会给之前选中的对象发送 ExecuteEvents.deselectHandler
事件,给被设置的对象发送 ExecuteEvents.selectHandler
事件。这个方法会在需要设置 Selected 对象的时候被调用,如 InputField 组件接收到 Pointer Down 事件时,就会将其对应的 GameObject 设置为 Event System 当前选中对象(m_CurrentSelected)。方法代码如下:
|
|
void RaycastAll(PointerEventData eventData, List raycastResults) 方法
这个方法用来进行射线检测得到可以拦截事件的对象。方法实现很简单,使用 RaycasterManager 中的所有处于激活状态的 BaseRaycaster 进行检测,得到响应事件的对象。这个方法会在 PointerInputModule 类的 GetTouchPointerEventData
和 GetMousePointerEventData
方法中被调用,用于创建对应的可被分发拦截处理的具体事件。
bool IsPointerOverGameObject(int pointerId) 方法
用来判断指定 ID 的 Pointer 是否还在 EventSystem 的那个对象上。方法内部最终调用 PointerInputModule 类的 IsPointerOverGameObject
方法,在 PointerInputModule 类的方法实现也很简单,就是根据 pointerId 获取对应的 PointerEventData,然后判断如果 PointerEventData 中 pointerEnter
对应的 GameObject 不为空,这说明这个 ID 对应的 Pointer 还在 EventSystem 的对象上。
void Update() 方法
首先调用了
TickModules()
去更新当前 Event System 中的所有的 Input Modules (调用了对应 Input Module 的UpdateModule()
方法),这样 Input Module 中的m_LastMousePosition
和m_MousePosition
就得到了更新;如果当前
m_CurrentInputModule
不为空,就将当前 Event System 中挂载所有的 Input Modules 中的第一个可用且处于激活状态的 Input Module 设置给m_CurrentInputModule
;如果从来没有设置过
m_CurrentInputModule
,就将挂载所有的 Input Modules 中的第一个可用 Input Module 设置给m_CurrentInputModule
;最后就会调用 Input Module 组件的
Process()
方法处理输入并产生事件、拦截处理事件。
上面的第二步和第三步中设置 m_CurrentInputModule
会调用 ChangeEventModule
方法。如果是切换 Input Module,则会反激活上一个 Input Module;还会激活当前要设置的 Input Module。代码如下:
|
|
void OnDisable() 方法
在这个方法中,主要就是将当前的 Input Module (m_CurrentInputModule) 反激活,调用了对应 InputModule 的 DeactivateModule()
方法。