Всем привет! Давно ничего не писал, но сейчас захотелось рассказать про очень удобную штуку, о которой многие не знают. Это Event System в Unity. Многие, для задач в которых EventSystem очень удобен, используют обычный Raycast. Я расскажу про то, как пользоваться частью функционала EventSystem (его на самом деле очень много) и как этот инструмент позволяет быстро решать многие задачи связанные с обработкой событий интерфейсов и объектов. Как всегда с репозиторием с примерами. Если вам интересно — добро пожаловать под кат!



В данной статье я разберу и предоставлю примеры работы с событиями 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)


  1. Power911
    22.05.2018 15:48
    -1

    годнота!


  1. Areek
    22.05.2018 17:54

    Зашел в статью, думал, будет откровение или хотя бы анализ разных решений с цифрами, а тут глава из методички: «EventSystem для самых маленьких». Для тех, кто побольше, есть официальный мануал.


    1. DyadichenkoGA Автор
      22.05.2018 17:55
      +1

      Совершенно верно. Возможно я слишком плохо написал название. Его суть в том, что мне надоело видеть в большинстве решений Physics.Raycast на физические объекты для банального hover'а мышкой, поэтому я написал статью о том, что есть такая великолепная штука, как EventSystem


    1. DyadichenkoGA Автор
      22.05.2018 17:59
      +1

      Собственно об этом написано до ката. Возможно стоило вписать пример с физикой, а не вынести его в репозиторий. А так, эта статья именно для новичков, чтобы они знали что существует такой инструмент и представляли, как им можно пользоваться.


  1. alex_zzzz
    22.05.2018 21:28

    Прекратите использовать рейкасты там, где это не нужно!

    Не раскрыты критерии нужности и ненужности. IxxxHandler ? полезная альтернатива рейкастам, но возникает два вопроса: так ли объектам нужно знать, что по ним кликнули, и кто должен обрабатывать эти клики?


    Допустим, есть дверь. По двери можно кликнуть, чтобы её выделить, чтобы её удалить, чтобы дать команду персонажу её открыть, закрыть, отпереть, запереть, атаковать. А ещё пользователь может кликнуть по двери в момент, когда никакой реакции на такое действие не предполагается вообще.


    Имхо, скрипт двери должен уметь её открыть, закрыть, хранить текущее состояние и, может быть, список подходящих ключей. А о существовании персонажей или когда по двери можно кликать, а когда нельзя, скрипту знать не надо. Пусть лучше пользовательским вводом и его обработкой занимаются другие подсистемы.


    имплементация

    Реализация.


    интеракции

    Взаимодействия.