
В данной статье я разберу и предоставлю примеры работы с событиями IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler, IPointerClickHandler, IDragHandler, IBeginDragHandler, IEndDragHandler (полный список событий можно посмотреть тут).
Что же такое EventSystem? EventSystem — это система отвечающая за обработку разных событий в сцене. В основном она позволяет:
- Определять какой GameObject “выбран”
- Управлять способами ввода которые используются
- Управлять рейкастингом
Подробнее всего в данной статье мы разберём третий пункт, так как он самый простой и удобный в использовании.
С точки зрения рейкастов в EventSystem доступны три основных компонента:
- Graphic Raycaster — используется для работы с UI
- Physics 2D Raycaster — используется для взаимодействия с физическими объектами в 2D
- Physics Raycaster — используется для взаимодействия с физическими объектами в 3D
Важная деталь для всех взаимодействий будь то физика или ui необходимо чтобы объект EventSystem присутствовал на сцене.

Начнём с самого простого — с UI системы. С ней EventSystem работает проще всего и лучше всего. Дело в том, что при создании Canvas юнити сразу добавляет на сцену все необходимые компоненты, такие как сам EventSystem и Graphic Raycaster.
В случае с UI, событийная система позволяет легко создавать свои кнопки и базовые взаимодействия с разными UI элементами. Для примера разберём IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler, IPointerClickHandler, IDragHandler, IBeginDragHandler, IEndDragHandler.
Чтобы UI элемент реагировал на события входа (IPointerEnterHandler), выхода (IPointerExitHandler) курсора мыши необходимо имплементировать эти интерфейсы в необходимый объект. Это помогает во многих случаях, когда нужно что-то выбрать, подсветить и т.п. На примере с тестовой сценой и Image это позволяет сделать интеракции вроде такой в несколько строк кода:
public void OnPointerEnter(PointerEventData eventData)
{
_Image.color = Color.blue;
}
public void OnPointerExit(PointerEventData eventData)
{
_Image.color = Color.white;
}

Для обработки событий нажатия на UI элемент есть два других интерфейса IPointerDownHandler, IPointerUpHandler.
Их имплементация позволяет в удобном виде обрабатывать события нажатия на объект мышью или тача на мобильных платформах:
public void OnPointerDown(PointerEventData eventData)
{
_Image.color = Color.green;
}
public void OnPointerUp(PointerEventData eventData)
{
_Image.color = Color.red;
}

EventSystem работает с любым компонентом UI системы, который может быть RaycastTarget. Для примера Text и событие клика IPointerClickHandler (важно, это событие похоже на IPointerUpHandler, то есть срабатывает в момент поднятия мыши, но отличие заключается в том, что “отпускание” курсора должно происходить строго в границах объекта):
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[RequireComponent(typeof(Text))]
public class UITextExample : MonoBehaviour, IPointerClickHandler
{
private Text _Text;
private bool _IsClicked;
private void Start ()
{
_Text = GetComponent<Text>();
}
public void OnPointerClick(PointerEventData eventData)
{
_Text.text = _IsClicked ? "Hello there!" : "General Kenobi";
_IsClicked = !_IsClicked;
}
}

Самыми интересными ивентами на мой взгляд, являются те, что позволяют удобно делать Drag. Это набор интерфейсов IDragHandler, IBeginDragHandler, IEndDragHandler. С ними так же всё очень просто. Визуальный эффект сильно зависит от способа обработки, но эти три события позволяют делать самые разные взаймодействия за несколько минут. В случае, если элемент, который вы собираетесь двигать состоит из разных UI элементов, важно отключать галочку RaycastTarget на тех элементах, которые не являются интерактивными. (Важно: в случае с UI системой нужно использовать screenPosition из PointerEventData которая приходит во всех методах событийной системы связанных с мышью/тачем)
public class UIDragExample : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
{
[SerializeField] private Text _Text;
public void OnDrag(PointerEventData eventData)
{
transform.position = eventData.pointerCurrentRaycast.screenPosition;
}
public void OnBeginDrag(PointerEventData eventData)
{
_Text.text = "You dragging!";
}
public void OnEndDrag(PointerEventData eventData)
{
_Text.text = "Drag me!";
}
}

В общем то по UI системе всё, на самом деле там есть ещё несколько полезных штук с точки зрения Event System, но про них я может напишу в будущих статьях.
Работа с физическими объектами отличается лишь двумя пунктами. Первое — надо внимательно следить, чтобы объект EventSystem был на сцене, чтобы это работало. Второе — надо повесить компонент PhysicsRaycaster на основную камеру, чтобы всё это так же работало по коллайдерам. В остальном почти тоже самое, простенький пример вы можете найти в репозитории.
В общем EventSystem крутой и удобный инструмент, который позволяет многие вещи делать в разы быстрее нежели обычными рейкастами. Кроме того в EventSystem есть очень много полезного функционала вроде того, что там можно переопределять инпуты (к примеру вас интересует специфичный контроллер, скажем Leap Motion) и многое другое, о чём я может напишу в будущих статьях.
Спасибо за внимание!
Комментарии (5)
Areek
22.05.2018 17:54Зашел в статью, думал, будет откровение или хотя бы анализ разных решений с цифрами, а тут глава из методички: «EventSystem для самых маленьких». Для тех, кто побольше, есть официальный мануал.
DyadichenkoGA Автор
22.05.2018 17:55+1Совершенно верно. Возможно я слишком плохо написал название. Его суть в том, что мне надоело видеть в большинстве решений Physics.Raycast на физические объекты для банального hover'а мышкой, поэтому я написал статью о том, что есть такая великолепная штука, как EventSystem
DyadichenkoGA Автор
22.05.2018 17:59+1Собственно об этом написано до ката. Возможно стоило вписать пример с физикой, а не вынести его в репозиторий. А так, эта статья именно для новичков, чтобы они знали что существует такой инструмент и представляли, как им можно пользоваться.
alex_zzzz
22.05.2018 21:28Прекратите использовать рейкасты там, где это не нужно!
Не раскрыты критерии нужности и ненужности. IxxxHandler ? полезная альтернатива рейкастам, но возникает два вопроса: так ли объектам нужно знать, что по ним кликнули, и кто должен обрабатывать эти клики?
Допустим, есть дверь. По двери можно кликнуть, чтобы её выделить, чтобы её удалить, чтобы дать команду персонажу её открыть, закрыть, отпереть, запереть, атаковать. А ещё пользователь может кликнуть по двери в момент, когда никакой реакции на такое действие не предполагается вообще.
Имхо, скрипт двери должен уметь её открыть, закрыть, хранить текущее состояние и, может быть, список подходящих ключей. А о существовании персонажей или когда по двери можно кликать, а когда нельзя, скрипту знать не надо. Пусть лучше пользовательским вводом и его обработкой занимаются другие подсистемы.
имплементация
Реализация.
интеракции
Взаимодействия.
Power911
годнота!