UGUI的输入与事件模块
- Unity
- 28天前
- 120热度
- 0评论
前言
UGUI把输入事件分为四个模块。分别是
- 事件数据模块
- 输入事件捕获模块
- 射线碰撞检测模块
- 事件逻辑处理以及回调模块

一、事件数据模块
事件数据模块主要是获得数据,提供数据服务。主要存储了事件发生的位置、事件对应的物体、事件的位移大小。触发事件的输入类型。以及事件的设备信息等。
主要为三个类:BaseEventData、PointerEventData、AxisEventData,分别为事件数据基类,点位事件数据类、滚轮事件数据基类。其中PointerEventData和AxisEventData都继承于BaseEventData。
1.1 BaseEventData类
事件数据的基类,有EventSystem(事件系统)、currentInputModule(当前输入模块)、selectedObject(当前选择物体)、used(该事件是否被使用)
namespace UnityEngine.EventSystems
{
public abstract class AbstractEventData
{
protected bool m_Used; // 是否被使用
public virtual void Reset()
{
m_Used = false;
}
public virtual void Use()
{
m_Used = true;
}
public virtual bool used
{
get { return m_Used; }
}
}
public class BaseEventData : AbstractEventData
{
private readonly EventSystem m_EventSystem; // 事件系统
public BaseEventData(EventSystem eventSystem)
{
m_EventSystem = eventSystem;
}
public BaseInputModule currentInputModule // 当前输入模块
{
get { return m_EventSystem.currentInputModule; }
}
public GameObject selectedObject // 当前选择物体
{
get { return m_EventSystem.currentSelectedGameObject; }
set { m_EventSystem.SetSelectedGameObject(value, this); }
}
}
}
1.2 AxisEventData类
其主要存储滚轮的移动方向和移动距离。
namespace UnityEngine.EventSystems
{
public class AxisEventData : BaseEventData
{
public Vector2 moveVector { get; set; } // 移动距离
public MoveDirection moveDir { get; set; } // 移动方向
public AxisEventData(EventSystem eventSystem) : base(eventSystem)
{
moveVector = Vector2.zero;
moveDir = MoveDirection.None;
}
}
}
1.3 PointerEventData类
using System;
using System.Text;
using System.Collections.Generic;
namespace UnityEngine.EventSystems
{
/// <summary>
/// 每次点击事件都会创建一个此类实例
/// </summary>
public class PointerEventData : BaseEventData
{
// 输入按钮
public enum InputButton
{
Left = 0,
Right = 1,
Middle = 2
}
/// <summary>
/// 按键按下的状态
/// </summary>
public enum FramePressState
{
// 此帧按下了按键。
Pressed,
// 此帧释放了按键。
Released,
// 此帧按下并释放了按键。
PressedAndReleased,
// 与上一帧相同。
NotChanged
}
public GameObject pointerEnter { get; set; }
private GameObject m_PointerPress;
// 最后一个按下事件的原始 GameObject。这意味着即使它本身不能接收按下事件,它也是“被按下”的 GameObject。
public GameObject lastPress { get; private set; }
// 发生按下事件的对象,即使它不能处理该按下事件。
public GameObject rawPointerPress { get; set; }
public GameObject pointerDrag { get; set; }
public GameObject pointerClick { get; set; }
// 与当前事件关联的射线检测结果。
public RaycastResult pointerCurrentRaycast { get; set; }
// 与指针按下事件关联的射线检测结果。
public RaycastResult pointerPressRaycast { get; set; }
public List<GameObject> hovered = new List<GameObject>();
// 当前帧是否可以进行点击。
public bool eligibleForClick { get; set; }
// 此指针事件来源的显示器索引。
public int displayIndex { get; set; }
// 指针的 ID(触摸 ID)。
public int pointerId { get; set; }
// 当前指针位置。
public Vector2 position { get; set; }
// 自上次更新以来的指针移动量。
public Vector2 delta { get; set; }
// 按下时的位置。
public Vector2 pressPosition { get; set; }
/// <summary>
/// World-space position where a ray cast into the screen hits something
/// </summary>
[Obsolete("Use either pointerCurrentRaycast.worldPosition or pointerPressRaycast.worldPosition")]
public Vector3 worldPosition { get; set; }
/// <summary>
/// World-space normal where a ray cast into the screen hits something
/// </summary>
[Obsolete("Use either pointerCurrentRaycast.worldNormal or pointerPressRaycast.worldNormal")]
public Vector3 worldNormal { get; set; }
// 上次发送点击事件的时间。用于处理双击。
public float clickTime { get; set; }
// 连续点击的次数。
public int clickCount { get; set; }
// /// 自上次更新以来的滚动量。
public Vector2 scrollDelta { get; set; }
public bool useDragThreshold { get; set; }
// 当前是否正在进行拖拽操作。
public bool dragging { get; set; }
// 此事件的 EventSystems.PointerEventData.InputButton。
public InputButton button { get; set; }
// 当前触摸施加的压力大小。
public float pressure { get; set; }
// 应用于触控笔上附加压力敏感控件的压力。
public float tangentialPressure { get; set; }
// 触控笔相对于表面的角度(以弧度表示)。
public float altitudeAngle { get; set; }
// 值为 0 表示触控笔与表面平行。值为 pi/2 表示它与表面垂直。
public float azimuthAngle { get; set; }
// 触控笔相对于 x 轴的角度(以弧度表示)。
public float twist { get; set; }
// 指定触控笔相对于 X 和 Y 轴的角度(以弧度表示)
public Vector2 tilt { get; set; }
// 指定触控笔的状态。例如,触控笔是否与屏幕或数位板接触,触控笔是否倒置,以及是否有按键被按下。
public PenStatus penStatus { get; set; }
// 触摸半径的估计值。
public Vector2 radius { get; set; }
// 触摸半径的精确度。
public Vector2 radiusVariance { get; set; }
// 在指针退出的情况下,指定指针是完全退出了区域还是刚刚进入了子对象。
public bool fullyExited { get; set; }
// 在指针进入的情况下,指定指针是进入了一个新区域还是在离开子对象后刚刚重新进入了父对象。
public bool reentered { get; set; }
public PointerEventData(EventSystem eventSystem) : base(eventSystem)
{
eligibleForClick = false;
displayIndex = 0;
pointerId = -1;
position = Vector2.zero; // Current position of the mouse or touch event
delta = Vector2.zero; // Delta since last update
pressPosition = Vector2.zero; // Delta since the event started being tracked
clickTime = 0.0f; // The last time a click event was sent out (used for double-clicks)
clickCount = 0; // Number of clicks in a row. 2 for a double-click for example.
scrollDelta = Vector2.zero;
useDragThreshold = true;
dragging = false;
button = InputButton.Left;
pressure = 0f;
tangentialPressure = 0f;
altitudeAngle = 0f;
azimuthAngle = 0f;
twist = 0f;
tilt = new Vector2(0f, 0f);
penStatus = PenStatus.None;
radius = Vector2.zero;
radiusVariance = Vector2.zero;
}
// 指针是否正在移动。
public bool IsPointerMoving()
{
return delta.sqrMagnitude > 0.0f;
}
// 输入设备是否正在滚动。
public bool IsScrolling()
{
return scrollDelta.sqrMagnitude > 0.0f;
}
// 与最后一次 OnPointerEnter 事件关联的摄像机。
public Camera enterEventCamera
{
get { return pointerCurrentRaycast.module == null ? null : pointerCurrentRaycast.module.eventCamera; }
}
// 与最后一次 OnPointerPress 事件关联的摄像机。
public Camera pressEventCamera
{
get { return pointerPressRaycast.module == null ? null : pointerPressRaycast.module.eventCamera; }
}
// 接收到 OnPointerDown 事件的 GameObject。
public GameObject pointerPress
{
get { return m_PointerPress; }
set
{
if (m_PointerPress == value)
return;
lastPress = m_PointerPress;
m_PointerPress = value;
}
}
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine("<b>Position</b>: " + position);
sb.AppendLine("<b>delta</b>: " + delta);
sb.AppendLine("<b>eligibleForClick</b>: " + eligibleForClick);
sb.AppendLine("<b>pointerEnter</b>: " + pointerEnter);
sb.AppendLine("<b>pointerPress</b>: " + pointerPress);
sb.AppendLine("<b>lastPointerPress</b>: " + lastPress);
sb.AppendLine("<b>pointerDrag</b>: " + pointerDrag);
sb.AppendLine("<b>Use Drag Threshold</b>: " + useDragThreshold);
sb.AppendLine("<b>Current Raycast:</b>");
sb.AppendLine(pointerCurrentRaycast.ToString());
sb.AppendLine("<b>Press Raycast:</b>");
sb.AppendLine(pointerPressRaycast.ToString());
sb.AppendLine("<b>Display Index:</b>");
sb.AppendLine(displayIndex.ToString());
sb.AppendLine("<b>pressure</b>: " + pressure);
sb.AppendLine("<b>tangentialPressure</b>: " + tangentialPressure);
sb.AppendLine("<b>altitudeAngle</b>: " + altitudeAngle);
sb.AppendLine("<b>azimuthAngle</b>: " + azimuthAngle);
sb.AppendLine("<b>twist</b>: " + twist);
sb.AppendLine("<b>tilt</b>: " + tilt);
sb.AppendLine("<b>penStatus</b>: " + penStatus);
sb.AppendLine("<b>radius</b>: " + radius);
sb.AppendLine("<b>radiusVariance</b>: " + radiusVariance);
return sb.ToString();
}
}
}
二、输入事件捕获模块
输入事件捕获模块主要由四个类组成,BaseInputModule(抽象基类)、PointerInputMoudle、StandaloneInputModule、TouchInputModule
PointerInputModule继承了BaseInputModule,拓展了关于点位的输入逻辑,也增加了输入的类型和状态StandaloneInputModule继承了PointerInputModule,并向标准键盘、鼠标方向拓展。TouchInputModule向触控板输入方向拓展。
2.1 ProcessMouseEvent函数
StandaloneInputModule的主函数ProcessMouseEvent(主要由PointerInputModule和StandaloneInputModule):从鼠标键盘输入事件上扩展了输入的逻辑,处理了鼠标的按下,移动,滚轮,拖拽的操作事件。其中ProcessMousePress、ProcessMove、ProcessDrag。从EventSystem中调用的
protected void ProcessMouseEvent(int id)
{
// mouseState: 鼠标状态
MouseState mouseData = GetMousePointerEventData(id);
// MouseButtonEventData:鼠标按钮状态(包括PointerEventData)
MouseButtonEventData leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData;
// 左键点击的物体设置为当前聚焦物体
m_CurrentFocusedGameObject = leftButtonData.buttonData.pointerCurrentRaycast.gameObject;
// 处理鼠标左键按下,移动,拖拽事件
ProcessMousePress(leftButtonData);
ProcessMove(leftButtonData.buttonData);
ProcessDrag(leftButtonData.buttonData);
// 处理鼠标右键和中间按下,拖拽事件
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);
}
}
ProcessMousePress:处理鼠标按下事件的代码,同时也处理鼠标抬起的操作,以及处理了拖拽抬起与结束的事件。在调用处理相关句柄的前后,事件数据都会被保存在 pointerEvent 中,然后被传递给业务层中设置的输入事件句柄。
protected void ProcessMousePress(MouseButtonEventData data)
{
var pointerEvent = data.buttonData;
var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject;
// 如果当前按下是当前帧时
if (data.PressedThisFrame())
{
pointerEvent.eligibleForClick = true;
pointerEvent.delta = Vector2.zero;
pointerEvent.dragging = false;
pointerEvent.useDragThreshold = true;
pointerEvent.pressPosition = pointerEvent.position;
pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast;
DeselectIfSelectionChanged(currentOverGo, pointerEvent);
var resetDiffTime = Time.unscaledTime - pointerEvent.clickTime;
if (resetDiffTime >= doubleClickTime)
{
pointerEvent.clickCount = 0;
}
// 搜索将接收按压的控件
//如果找不到按压处理程序,则将按压处理程序设置为会接收点击的控件。
var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);
// 判断当前gameobject是否有IPointerClickHandler接口
var newClick = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
if (newPressed == null)
newPressed = newClick;
float time = Time.unscaledTime;
// 计算连击次数
if (newPressed == pointerEvent.lastPress)
{
var diffTime = time - pointerEvent.clickTime;
if (diffTime < doubleClickTime) // doubleClickTime: 0.3f
++pointerEvent.clickCount;
else
pointerEvent.clickCount = 1;
pointerEvent.clickTime = time;
}
else
{
pointerEvent.clickCount = 1;
}
// pointerEvent赋值
pointerEvent.pointerPress = newPressed;
pointerEvent.rawPointerPress = currentOverGo;
pointerEvent.pointerClick = newClick;
pointerEvent.clickTime = time;
// 获取IDragHandler接口
pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo);
// 执行拖拽启动事件
if (pointerEvent.pointerDrag != null)
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag);
m_InputPointerEvent = pointerEvent;
}
// 抬起鼠标通知
if (data.ReleasedThisFrame())
{
ReleaseMouse(pointerEvent, currentOverGo);
}
}
ProcessDrag(PointerInputModule)拖拽句柄处理函数,拖拽开始事件处理,判断结束拖拽事件,以及拖拽句柄调用。
protected virtual void ProcessDrag(PointerEventData pointerEvent)
{
if (!pointerEvent.IsPointerMoving() ||
Cursor.lockState == CursorLockMode.Locked ||
pointerEvent.pointerDrag == null)
return;
// 开始拖拽句柄
if (!pointerEvent.dragging
&& ShouldStartDrag(pointerEvent.pressPosition, pointerEvent.position, eventSystem.pixelDragThreshold, pointerEvent.useDragThreshold))
{
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.beginDragHandler);
pointerEvent.dragging = true;
}
// 拖拽通知
if (pointerEvent.dragging)
{
// 如果按下的物体和拖拽的物体不是同一个则视为抬起拖拽,并清除前面按下时的标记
if (pointerEvent.pointerPress != pointerEvent.pointerDrag)
{
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
pointerEvent.eligibleForClick = false;
pointerEvent.pointerPress = null;
pointerEvent.rawPointerPress = null;
}
// 执行拖拽中句柄
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.dragHandler);
}
}
ProcessMove 则相对简单点,每帧都会直接调用处理句柄(IPointerMoveHandler)。
protected virtual void ProcessMove(PointerEventData pointerEvent)
{
var targetGO = pointerEvent.pointerCurrentRaycast.gameObject;
HandlePointerExitAndEnter(pointerEvent, targetGO);
}
2.2 ProcessTouchEvents函数
TouchInputModule触屏模块的主要函数ProcessTouchEvents
// 处理所有触屏事件
private bool ProcessTouchEvents()
{
for (int i = 0; i < input.touchCount; ++i)
{
Touch touch = input.GetTouch(i);
if (touch.type == TouchType.Indirect)
continue;
bool released;
bool pressed;
var pointer = GetTouchPointerEventData(touch, out pressed, out released);
ProcessTouchPress(pointer, pressed, released);
if (!released)
{
ProcessMove(pointer);
ProcessDrag(pointer);
}
else
RemovePointerData(pointer);
}
return input.touchCount > 0;
}
2.3 ExecuteEvents类
ExecuteEvents类主要是用来获得对应的句柄,然后执行对应的接口。主要依靠 ExecuteEvents.ExecuteHierarchy,ExecuteEvents.Execute,其会获得该物体所有父物体(包括自己),然后依次获得对应IHandler,执行句柄。
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;
}
public static bool Execute<T>(GameObject target, BaseEventData eventData, EventFunction<T> functor) where T : IEventSystemHandler
{
var internalHandlers = ListPool<IEventSystemHandler>.Get();
GetEventList<T>(target, internalHandlers);
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;
ListPool<IEventSystemHandler>.Release(internalHandlers);
return handlerCount > 0;
}
三、射线碰撞检测模块
射线碰撞检测模块主要工作是从摄像机的屏幕位置上,做射线碰撞检测并获取碰撞结果,把结果返回给事件逻辑处理类,由事件处理模块处理事件。
射线碰撞检测模块主要为3个类,分别作用于2D射线碰撞检测,3D射线碰撞检测,GraphicRaycaster图形射线碰撞检测。
2D和3D射线碰撞检测主要为Physics2DRaycaster和PhysicsRaycaster,用射线的形式进行碰撞检测,区别在2D碰撞结果里预留了2D的层级次序以便在后面的碰撞结果排序时,以这个层级次序为依据做排序,而3D的碰撞检测结果则是以距离大小为依据排序的。
GraphicRaycaster是 为UGUI元素点位检测的类,放在Core渲染模块中,主要针对ScreenSpaceOverlay模式下输入点位(位置进行判断)做碰撞检测,不依赖于射线碰撞。而是遍历所有可点击的UGUI元素来检测比较。
GraphicRaycaster对每个可以点击的元素(raycasterTarget是否为true, 并且depth不为-1,为可点击元素)进行计算,判断点位是否落在该元素上,再通过depth变量排序,判断最先落在那个元素上。
public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
{
if (canvas == null)
return;
// 获得canvas下注册过raycaster事件的Graphic
var canvasGraphics = GraphicRegistry.GetRaycastableGraphicsForCanvas(canvas);
if (canvasGraphics == null || canvasGraphics.Count == 0)
return;
int displayIndex;
var currentEventCamera = eventCamera;
if (canvas.renderMode == RenderMode.ScreenSpaceOverlay || currentEventCamera == null)
displayIndex = canvas.targetDisplay;
else
displayIndex = currentEventCamera.targetDisplay;
// 进行多平台检测
Vector3 eventPosition = MultipleDisplayUtilities.RelativeMouseAtScaled(eventData.position);
if (eventPosition == Vector3.zero)
{
eventPosition = eventData.position;
#if UNITY_EDITOR
eventPosition.z = Display.activeEditorGameViewTarget;
#endif
#if ENABLE_INPUT_SYSTEM && PACKAGE_INPUTSYSTEM
eventPosition.z = eventData.displayIndex;
#endif
if ((int) eventPosition.z != displayIndex)
return;
// Convert to view space
Vector2 pos;
if (currentEventCamera == null)
{
float w = Screen.width;
float h = Screen.height;
if (displayIndex > 0 && displayIndex < Display.displays.Length)
{
w = Display.displays[displayIndex].systemWidth;
h = Display.displays[displayIndex].systemHeight;
}
pos = new Vector2(eventPosition.x / w, eventPosition.y / h);
}
else
pos = currentEventCamera.ScreenToViewportPoint(eventPosition);
// If it's outside the camera's viewport, do nothing
if (pos.x < 0f || pos.x > 1f || pos.y < 0f || pos.y > 1f)
return;
float hitDistance = float.MaxValue;
Ray ray = new Ray();
if (currentEventCamera != null)
ray = currentEventCamera.ScreenPointToRay(eventPosition);
if (canvas.renderMode != RenderMode.ScreenSpaceOverlay && blockingObjects != BlockingObjects.None)
{
float distanceToClipPlane = 100.0f;
if (currentEventCamera != null)
{
float projectionDirection = ray.direction.z;
distanceToClipPlane = Mathf.Approximately(0.0f, projectionDirection)
? Mathf.Infinity
: Mathf.Abs((currentEventCamera.farClipPlane - currentEventCamera.nearClipPlane) / projectionDirection);
}
#if PACKAGE_PHYSICS
if (blockingObjects == BlockingObjects.ThreeD || blockingObjects == BlockingObjects.All)
{
if (ReflectionMethodsCache.Singleton.raycast3D != null)
{
var hits = ReflectionMethodsCache.Singleton.raycast3DAll(ray, distanceToClipPlane, (int)m_BlockingMask);
if (hits.Length > 0)
hitDistance = hits[0].distance;
}
}
#endif
#if PACKAGE_PHYSICS2D
if (blockingObjects == BlockingObjects.TwoD || blockingObjects == BlockingObjects.All)
{
if (ReflectionMethodsCache.Singleton.raycast2D != null)
{
var hits = ReflectionMethodsCache.Singleton.getRayIntersectionAll(ray, distanceToClipPlane, (int)m_BlockingMask);
if (hits.Length > 0)
hitDistance = hits[0].distance;
}
}
#endif
}
m_RaycastResults.Clear();
Raycast(canvas, currentEventCamera, eventPosition, canvasGraphics, m_RaycastResults);
int totalCount = m_RaycastResults.Count;
for (var index = 0; index < totalCount; index++)
{
var go = m_RaycastResults[index].gameObject;
bool appendGraphic = true;
if (ignoreReversedGraphics)
{
if (currentEventCamera == null)
{
var dir = go.transform.rotation * Vector3.forward;
appendGraphic = Vector3.Dot(Vector3.forward, dir) > 0;
}
else
{
var cameraForward = currentEventCamera.transform.rotation * Vector3.forward * currentEventCamera.nearClipPlane;
appendGraphic = Vector3.Dot(go.transform.position - currentEventCamera.transform.position - cameraForward, go.transform.forward) >= 0;
}
}
if (appendGraphic)
{
float distance = 0;
Transform trans = go.transform;
Vector3 transForward = trans.forward;
if (currentEventCamera == null || canvas.renderMode == RenderMode.ScreenSpaceOverlay)
distance = 0;
else
{
// http://geomalgorithms.com/a06-_intersect-2.html
distance = (Vector3.Dot(transForward, trans.position - ray.origin) / Vector3.Dot(transForward, ray.direction));
// Check to see if the go is behind the camera.
if (distance < 0)
continue;
}
if (distance >= hitDistance)
continue;
var castResult = new RaycastResult
{
gameObject = go,
module = this,
distance = distance,
screenPosition = eventPosition,
displayIndex = displayIndex,
index = resultAppendList.Count,
depth = m_RaycastResults[index].depth,
sortingLayer = canvas.sortingLayerID,
sortingOrder = canvas.sortingOrder,
worldPosition = ray.origin + ray.direction * distance,
worldNormal = -transForward
};
resultAppendList.Add(castResult);
}
}
}
四、事件逻辑处理模块
事件逻辑处理模块主要在EventSystem类中,其余的类都是对他起辅助作用。
EventInterfaces,EventTrigger,EventTriggerType 定义了事件回调函数,ExecuteEvents 编写了所有执行事件的回调接口。
EventSystem 主逻辑里基本上都在处理由射线碰撞检测后引起的各类事件。判断事件是否成立,成立则发起事件回调,不成立则继续轮询检查,等待事件的发生。
EventSystem 是事件处理模块中唯一继承 MonoBehavior 并且有在 Update 帧循环中做轮询的。也就是说,所有UI事件的发生都是通过 EventSystem 轮询监测到的并且实施的。EventSystem 通过调用输入事件检测模块,检测碰撞模块,来形成自己主逻辑部分。因此可以说 EventSystem 是主逻辑类,是整个事件模块的入口。
