EventSystem系统
看似名字很大,其实EventSystem处理和管理的是点击、触摸、键盘输入等事件,叫做InputEventSystem更为合适。
//系统输入模块
private List<BaseInputModule> m_SystemInputModules = new List<BaseInputModule>();
//当前输入模块
private BaseInputModule m_CurrentInputModule;
//当前选择GameObject
private GameObject m_CurrentSelected;
//处理的所有输入的EventSystem
private static List<EventSystem> m_EventSystems = new List<EventSystem>();
继承关系:
BaseInputModule抽象类
PointerInputModule抽象类
StandaloneInputModule类,面向“PC, Mac& Linux Standalone”这个平台的输入模块
TouchInputModule类,面向“IOS Android”等可触摸移动平台的输入模块
(注:在最新的2017.4UGUI源码中,TouchInputModule已经被弃用,触摸输入已经被集成到StandaloneInputModule。)
void Update()
- EventSystem会在Update里每帧执行TickModules方法,调用每一个InputModule。
- 遍历m_SystemInputModules,判断这些module是否支持当前平台IsModuleSupported(),并且是否可激活ShouldActivateModule()。
- 如果m_CurrentInputModule为空,激活InputModule,设置m_CurrentSelected,实际上就是调用eventSystem.SetSelectedGameObject,然后有把符合条件的module便赋值给m_CurrentInputModule(当前输入模块)并break。
- 如果m_CurrentInputModule不为空,调用每一个InputModule的Process方法,先发送事件给被选择的GameObject(m_CurrentSelected),SendUpdateEventToSelectedObject,然后先处理触摸的一些事件ProcessTouchEvents(),再处理鼠标的一些事件ProcessMouseEvent()。
- m_CurrentSelected大部分情况是Selectable组件(继承它的Button、Dropdown、InputField等组件)设置的。设置m_CurrentSelected,实际调用eventSystem.SetSelectedGameObject,会通过ExecuteEvents这个类对之前的对象执行一个被取消事件,且对新选中的对象执行一个被选中事件。这就是OnSelect和OnDeselect两个方法的由来。
EventSystem的RaycastAll方法
使用射线从相机到某个点(设为点E)投射到UI上,然后对所有投射到的对象进行排序,大致是远近排序。
RaycastAll会在PointerInputModule类的GetTouchPointerEventData和GetMousePointerEventData中调用,如果发生点击(或触摸)事件时,该事件影响的对象也会改变,通过RaycastAll方法(传入的PointerEventData的position作为点E)获得到第一个被射线照射到的对象,如果与之前的对象不同,则变更对象。(选择了新的对象,取消旧的对象)
ProcessTouchEvents()
- 遍历所有的inputTouch输入
- 调用RaycastAll方法,获得第一个被射线照射到的对象
- ProcessTouchPress,触发触摸事件
- 如果一直长按,触发ProcessMove和ProcessDrag方法。否则RemovePointerData
- 之后在Process()方法中,传入相应的事件接口类型,由ExecuteEvents.Execute()调用目标对象上的事件接口方法,执行事件。
ProcessMouseEvent()
- 获取鼠标的input输入
- 调用RaycastAll方法,获得第一个被射线照射到的对象
- ProcessMousePress,依次触发左键,右键,中键的点击事件
- 之后在Process()方法中,传入相应的事件接口类型,由ExecuteEvents.Execute()调用目标对象上的事件接口方法,执行事件。
IsPointerOverGameObject
是EventSystem类里特别常用的一个方法,用于判断是否点击在UI上,具体是在PointerInputModule中实现的,判断最后一次点击的EventData数据是否为空,不为空即在UI上。
EventSystem current
最后我们注意到EventSystem有一个static属性:
public static EventSystem current
get { return m_EventSystems.Count > 0 ? m_EventSystems[0] : null; }
当一个EventSystem组件OnEnable的时候会将这个对象加入到m_EventSystems。
m_EventSystems.Add(this);
OnDisable的时候会将current从m_EventSystems移除
m_EventSystems.Remove(this);