Unity 事件系统

简介:

EventSystem提供了一种向游戏物体发送消息的途径,这些物体通常是输入信息,包括键盘、鼠标、触摸和自定义输入事件。它包含了一系列组件,它们互相配合,以达到管理和触发器事件的功能。

如果查看物体的EventSystem,会发现可调参数并不多,这是因为EventSystem本身被设计为一种管理器,而不是事件的具体处理者

EventSystem功能包含以下几个方面:

  1. Message System(信息分发系统)
  2. Input Modules(输入模块)
  3. 提供多种常用输入事件接口
  4. 管理各种射线,包括图形射线(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,可以通过类型转换的方法把它们转换为派生类变量,进而获取到更多有用的信息。