Unity 事件系统
简介:
EventSystem提供了一种向游戏物体发送消息的途径,这些物体通常是输入信息,包括键盘、鼠标、触摸和自定义输入事件。它包含了一系列组件,它们互相配合,以达到管理和触发器事件的功能。
如果查看物体的EventSystem,会发现可调参数并不多,这是因为EventSystem本身被设计为一种管理器,而不是事件的具体处理者
EventSystem功能包含以下几个方面:
- Message System(信息分发系统)
- Input Modules(输入模块)
- 提供多种常用输入事件接口
- 管理各种射线,包括图形射线(Graphic Raycaster,用于UI系统)、物理射线和2D物理射线
一、常用输入事件
Unity至少支持17种常用输入事件,如下图所示
事件名称(接口名称) |
说明 |
IPointerEnterHandler |
鼠标进入 |
IPointerExitHandler |
鼠标离开 |
IPointerUpHandler |
鼠标抬起 |
IPointerDownHandler |
鼠标按下 |
IPointerClickHandler |
鼠标单击(按下再抬起) |
IInitializePotentialDragHandler |
发现可拖拽物体,可用于初始化一些变量 |
IBeginDragHandler |
开始拖拽 |
IDragHandler |
拖拽中 |
IEndDragHandler |
拖拽结束 |
IDropHandler |
拖拽释放 |
IScrollHandler |
鼠标滚轮 |
IUpdateSelectedHandler |
选中物体时,反复触发 |
ISelectHandler |
物体被选择 |
IDeselectHandler |
物体被取消选择 |
IMoveHandler |
物体移动 |
ISubmitHandler |
提交按钮按下 |
ICancelHandler |
取消按钮按下 |
上篇文章介绍UI控件时,我们知道每种控件仅有一两个可自定义的事件函数,如按钮控件仅包含OnClick事件,输入框控件仅包含OnValueChanged(内容改变)事件和OnEndEdit(结束编辑)事件。那么能否加入更多事件以响应函数呢?
答案是可以的,不仅是控件,而且每个物体都可以支持十多种输入事件。
EventSystem不仅支持UI系统,而且也支持场景中的3D、2D物体。
只要给摄像机增加一个组件——Physics Raycaster(物理射线发射器),就可以支持3D和2D物体了。
二、常用输入事件的参数
上面介绍的多种输入事件,它们的参数类型有所不同。目前有BaseEventDate、PointerEventData和AxisEventData这三种。
其中BaseEventData是所有事件数据的基类;
PointerEventData是用于表示指针滑动、单击的数据;
而AxisEventData则是所有的轴类输入数据,如常见手柄的摇杆就属于轴类输入。
PointerEventData和AxisEventData都是BaseEventData的派生类。
这三个类中,有一些属性比较常用,下面列出:
BaseEventData属性 |
数据类型 |
说明 |
currentInputModule |
BaseInputModule |
当前输入模块 |
selectedObject |
GameObject |
当前选中的物体,也就是“焦点”物体 |
PointerEventData属性 |
数据类型 |
说明 |
button |
InputButton枚举 |
触发此事件的按钮,鼠标的左、中、右键 |
clickCount |
int |
短时间内连击按钮的次数 |
clickTime |
float |
上次发送OnClick事件的时间 |
delta |
Vector2 |
鼠标指针坐标在这一输入帧的变化量 |
dragging |
bool |
是否为拖拽状态 |
enterEventCamera |
Camera |
最后一个与指针进入事件关联的摄像机,可能为空 |
hovered |
List<GameOnject> |
悬停的对象,可能有多个悬停对象,用列表表示 |
lastPress |
GameObject |
记录上一次单击的物体 |
pointerCurrentRaycast |
RaycastResult |
指针当前射线检测的信息 |
pointerDrag |
GameObject |
当前触发拖拽事件的物体 |
pointerEnter |
GameObject |
当前触发指针移入事件的对象 |
pointerld |
int |
指针ID,例如-1,-2,-3对应鼠标左、中、右键,手机多点触摸也有对应ID |
pointerPress |
GameObject |
被单击的游戏物体 |
PointerPressRaycast |
RaycastResult |
单击时的射线检测信息 |
position |
Vector2 |
当前鼠标指针位置 |
pressEventCamera |
Camera |
最后一个与OnClick事件关联的摄像机,可能为空 |
pressPosition |
Vector2 |
按下事件的指针位置,同一次OnClick事件只有一个 |
rawPointerPress |
GameObject |
原始的被单击物体,不管该物体是否响应OnClikck事件 |
scrollDelta |
Vecto2 |
滚轮的滚动量(有一些滑轮支持横向滚动) |
AxisEventData属性 |
数据类型 |
说明 |
moveVector |
Vector2 |
输入的 原始值。横向、纵向的值 |
moveDir |
MoveDirection枚举 |
将原是输入转化为上下左右或无方向这五种情况 |
三、动态添加事件响应方法
之前介绍的方法都有一个共同点,需要事先将每个物体和响应函数对应起来。但某些时候需要在运行游戏时,给控件动态指定方法,例如在游戏中,当玩家选择不同技能时,按下攻击按钮会调用不同的技能函数。
可以在运行游戏时动态地给控件指定调用方法,也可以删除、改变和添加响应方法。
四、事件触发器(Event Trigger)
我们知道,Unity支持至少17种输入事件,用脚本可以用到所有这些事件。但是编写专门的绑定事件函数,还是比较复杂,这里介绍一个更方便的方法:使用Event Trigger。
可以为任意物体添加Event Trigger组件,添加该组件后,单击Add New Event Type按钮,就可以添加任意组件了。几乎可以为物体添加所有的输入事件类型,鼠标进入、离开、按下、滚轮和单击等功能皆可直接指定
添加事件类型后,响应函数的指定方法和按钮、输入框等控件是类似的。只是响应函数多了一个BaseEventData类型的参数,可以用它获取相关的事件信息,例如以下的响应函数
public void OnBtnEvent(BaseEventData evt)
{
Debug.log("当前焦点物体为:"+evt.selectedObject);
//将基类变量转为派生类变量
PointerEventData pest=evt as PointerEventData;
//如果不是鼠标相关的事件,转换会失败
if(pest==null)
{
Debug.log("转换PointerEventData失败");
return;
}
//Pointer类型的事件有更多信息,如位置等
Debug.log("事件坐标:"+pest.position);
BaseEventData类型的参数,本身的信息十分有限,仅有CurrentInputModule(当前输入模块)与SelectedObject(当前焦点物体)两个。
⚠️⚠️⚠️:而很多时候需要注意的都是鼠标或触摸事件,如单击、拖拽、进入物体或离开物体的事件,这类事件往往都属于派生类PointerEventData,可以通过类型转换的方法把它们转换为派生类变量,进而获取到更多有用的信息。