Unity中的UGUI源码解析之事件系统(3)-EventData
为了在事件系统中传递数据, Unity提供了EventData相关的类来封装这一类数据. 了解这些结构有助于我们对后面模块的学习.
EventData相关的类有几个, 下面一一介绍.
AbstractEventData
: 事件数据的抽象基类BaseEventData : AbstractEventData
: 基础的事件数据类PointerEventData: BaseEventData
: 指针事件数据类AxisEventData: BaseEventData
: 轴事件数据类
AbstractEventData
AbstractEventData是事件数据的抽象基类, 内容不多, 提供的接口和属性主要围绕事件数据是否已经被使用过.
在某些逻辑中, 如果事件数据在某些事件处理中被标记为已使用, 则在其它事件中不再处理.
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; }
}
}
BaseEventData
BaseEventData是基础的事件数据类,内容也不多, 主要提供了对几个事件系统角色的引用:
- EventSystem
- 当前生效的输入模块
- 当前选中的对象
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); }
}
}
AxisEventData
AxisEventData是轴事件数据类, 封装了与轴事件相关的数据, 这个轴就是Edit->Project Settings->Input
中的那个Axes, 主要在导航事件和位移事件(OnMove)的处理中使用, 提供位移向量和方向.
使用手柄等设备时主要使用这个类型来封装移动事件数据.
public enum MoveDirection
{
Left,
Up,
Right,
Down,
None
}
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;
}
}
PointerEventData
接下来就是我们的重头戏, PointerEventData是指针事件数据类, 这也是整个事件系统使用的事件数据的主要部分.
所谓指针事件, 简单说就是触摸和点击, 详情可以参考第一篇概述.
Unity将触摸和点击相关的信息都封装到了PointerEventData中. 并将触摸事件模拟为鼠标左键点击.
InputButton和FramePressState
Unity封装了InputButton, 提供了鼠标几个键的抽象, 通过FramePressState表示几个键的状态.
public class PointerEventData : BaseEventData
{
// 分别代表左右中键
public enum InputButton
{
Left = 0,
Right = 1,
Middle = 2
}
// 每个键在**当前帧**的状态
public enum FramePressState
{
Pressed, // 按下
Released, // 抬起
PressedAndReleased, // 按下又抬起
NotChanged // 与上一帧相同
}
// ...
}
基本数据和状态信息
PointerEventData提供了一些属性封装事件的基础和状态等信息.
主要有以下内容:
public int pointerId
: 键的id, 使用鼠标的情况下, -1代表左键, -2代表右键, -3代表中键, 使用触摸时未测试, 后面有机会测试后补充上.public bool eligibleForClick
: 此时事件是否是合格的点击, 后面可以看到, 如果在处理点击事件之前处理了移动事件则会取消此状态导致点击事件无法处理, 这个状态是ScrollRect能够同时滑动和点击的关键.public Vector2 position
: 当前触摸或者点击的位置, 屏幕坐标为单位public Vector2 delta
: 上次更新到此时更新间的位置变化量public Vector2 pressPosition
: 当前(或者最后一次)点击或者触摸的位置public float clickTime
: 上次点击或者触摸的时间public int clickCount
: 点击次数, 用于短时间内快速多次点击, 比如双击等public Vector2 scrollDelta
: 上次更新到此时更新间的滚动变化量public bool useDragThreshold
: 是否使用拖拽阈值, 就是之前在上一篇文章介绍的EventSystem组件上设置的值public bool dragging
: 当前是否是拖拽状态public InputButton button
: 当前事件的按键public bool IsPointerMoving
: 上次更新到此时更新间是否发生了移动public bool IsScrolling
: 上次更新到此时更新间是否发生了滚动
持有的游戏对象
每次指针数据都会涉及到一些游戏对象, PointerEventData记录了一些对象, 以便使用.
主要有以下属性保存游戏对象:
public GameObject pointerEnter
: 鼠标进入的对象, 也就是说鼠标指针的位置在某个对象区域内部public GameObject lastPress
: 上一个接收到OnPointerDown
事件的对象public GameObject rawPointerPress
: 原始按下的对象, 不论是否处理OnPointerDown
事件, 这里可能会有点疑问, 等后面我们介绍事件处理的时候就明白了public GameObject pointerPress
: 当前已接收到OnPointerDown
事件的对象public GameObject pointerDrag
: 当前已接收到OnDrag
事件的对象public RaycastResult pointerCurrentRaycast
: 与当前事件关联的 RaycastResultpublic RaycastResult pointerPressRaycast
: 与最后一按下事件关联的RaycastResultpublic List<GameObject> hovered
: 鼠标悬停时, pointerEnter和其所有父节点和祖先节点形成的对象列表public Camera enterEventCamera
: 与当前事件相关联的摄像机public Camera pressEventCamera
:与最后一按下事件关联的RaycastResult
ToString
与上一篇文章介绍的EventSystem组件的ToString
方法配合起来显示当前事件系统状态.
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 Rayast:</b>");
sb.AppendLine(pointerCurrentRaycast.ToString());
sb.AppendLine("<b>Press Rayast:</b>");
sb.AppendLine(pointerPressRaycast.ToString());
return sb.ToString();
}
如图所示, 分别是左键, 右键和中键某一帧的状态信息, 这些信息在研究事件系统时能够很好的帮助我们理解.
总结
今天介绍了事件系统的基础之一: 事件数据.
我么知道了Unity是如何定义事件和封装事件数据, 为我们研究接下来的模块打下了基础.
下一篇文章我们会介绍消息系统ExecuteEvents, 看看Unity是如何巧妙的实现常规的显得比较繁重的消息系统.
好了, 今天的内容就是这些, 希望对大家有所帮助.