В этой статье мы поговорим о Event System – «Системе событий», состоящей из трех компонентов, один из которых мы и рассмотрим сегодня, а именно – Raycasters. Для начала определение. Вот что говорит нам мануал Unity:
Event System (Система событий) – способ отправки событий к объектам в приложении, основанный на вводе с клавиатуры или мыши; с помощью касаний или персональных устройств. Система состоит из нескольких компонентов, работающих вместе. Эта система с помощью «лучей добра» Unity определяет, что находится под указателем. Но для ее работы требуется два условия: в сцене должен присутствовать объект Event System, а на объекте, с которым мы хотим взаимодействовать с помощью этой системы, класс с интерфейсами событий.
Приступим. Для начала нам надо добавить в сцену Event System:
Game Object=> UI=>Event System
Затем добавим в сцену объект. Например, Image:
Game Object=> UI=> Image
Ну, и, наконец, создадим скрипт, который назначим на наш Image.
Подготовка закончена, и мы переходим к написанию скрипта. Откроем наш свежесозданный скрипт в редакторе, у меня это Visual Studio. Для этого дважды кликнем на скрипте. Первое, что нам надо сделать, это добавить библиотеку Event System. В шапке скрипта напишем строку:
using UnityEngine.EventSystems;
Отлично. Теперь мы можем работать с Event System прямо из скрипта. Первое, что мы рассмотрим, это метод OnPointerEnter. Он отслеживает находиться ли курсор или касание над объектом.
Полностью этот метод выглядит так:
public void OnPointerEnter(PointerEventData eventData)
{
}
Добавим в него функцию для наглядности, к примеру, смену цвета:
GetComponent<Image>().color = Color.red;
Здесь мы получаем компонент Image нашего объекта и меняем его цвет на красный. И в целом наш метод будет выглядеть так:
public void OnPointerEnter(PointerEventData eventData)
{
GetComponent<Image>().color = Color.red;
}
Теперь главное – не забыть добавить интерфейс, требующийся для работы метода OnPointerEnter. Возвращаемся в начало скрипта и после MonoBehaviour через запятую добавляем IPointerEnterHandler. Должно получиться, что-то вроде этого:
public class MyScript : MonoBehaviour, IPointerEnterHandler
Сохраняем наш скрипт и проверяем. В редакторе жмем Play и наводим мышку на наш объект.
Отлично. При наведении курсора наш объект меняет цвет на красный, но, увы, когда курсор покидает объект, цвет остается тем же. Давайте добавим еще один метод, который будет назначать цвет объекту, когда его покидает курсор:
public void OnPointerExit(PointerEventData eventData)
{
GetComponent<Image>().color = Color.white;
}
И не забудем добавить еще один интерфейс – IPointerExitHandler
Проверяем. Опять сохраняем скрипт и жмем Play.
Все прекрасно работает, и мы переходим к событиям нажатия кнопки на объекте.
Их три:
- Метод, отслеживающий одиночное нажатие:
public void OnPointerClick(PointerEventData eventData)
{
GetComponent<Image>().color = Color.blue;
}
- Метод, отслеживающий событие нажатой кнопки:
public void OnPointerDown(PointerEventData eventData)
{
GetComponent<Image>().color = Color.green;
}
- Метод, отслеживающий, когда кнопку отпустили:
public void OnPointerUp(PointerEventData eventData)
{
GetComponent<Image>().color = Color.black;
}
Для каждого из них требуется добавить свой интерфейс:
IPointerDownHandler, IPointerUpHandler, IPointerClickHandler
Добавляем все в скрипт, сохраняем и опять Play.
И напоследок рассмотрим еще одну очень интересную возможность, предоставляемую нам EventSystems. А именно – возможность перетаскивать мышкой элемент UI, чем и является наш Image. Первый метод отслеживает перемещение курсора при зажатой кнопки мыши или при таче на экран устройства:
public void OnDrag(PointerEventData eventData)
{
}
В нем мы пишем строку, которая собственно и будет перемещать Image:
transform.position = eventData.position;
В ней все просто. Позиция Image равна позиции курсора или тача в экранных координатах. То есть, Image будет перемещаться за курсором. Вместе все это выглядит так:
public void OnDrag(PointerEventData eventData)
{
transform.position = eventData.position;
}
И второй метод отслеживает момент, когда мы перестаем перетаскивать объект. Либо остановив движение мыши, либо перестав нажимать на кнопку. Вот и он. Какой либо функции в нем сейчас нет. Да и не нужна она. Но не упомянуть о нем было бы неправильно:
public void OnEndDrag(PointerEventData eventData)
{
}
Сохраняем скрипт и жмем Play. Отлично.
Все работает. В дополнении хотим добавить, что event data так же хорошо работает с физическими объектами. Достаточно добавить компонент PhysicsRaycaster на основную камеру EventSystems на сцену и Collider со скриптом на объект в сцене, с которым мы планируем взаимодействие.
С другими компонентами Event System, такими как Input Modules и Messaging System, мы ознакомимся в следующих материалах.
Я делаю tower defence 2d и возникла проблема с отправлением GameObject tower в построение башни и не могу понять в чем проблема. Вот часть скрипта создания башни: public void BuildTower(GameObject tower) { Instantiate(tower, transform.position, transform.rotation); hasTower = true; } И часть скрипта самой панели: public GameObject tower; public void OnPointerClick(PointerEventData eventData) { if(MoneyManager.Instance.allMoney >= towerPrice) { selfCell.BuildTower(tower); <- Скорее всего тут (или раньше) проблема т.к. деньги попросту не снимаются. MoneyManager.Instance.allMoney -= towerPrice; } } Выдает ошибку: NullReferenceException: Object reference not set to an instance of an object ShopItem.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at Assets/Scripts/ShopItem.cs:17)
Проконсультируйтесь пожалуйста через my.first.unity.help@gmail.com
Здравствуйте, как заставить этот метод работать в UI Button On Click () ???
public void OnPointerClick(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left && useDeleteUI.activeSelf)
{
Debug.Log(“Работает”);
}
}
Что Вы имеете ввиду под «работать в UI Button On Click ()»? Данный метод обрабатывает событие нажатия на объект, к которому добавлен скрипт. То есть при нажатии будет срабатывать данный метод.
Возникла проблема с IPointerClickHandler. С IPointerDownHandler, IPointerUpHandler всё хорошо, а как только я добавил в строку
public class Girya : MonoBehaviour, IPointerClickHandler
сразу выходит ошибка: Assets\Girya.cs(8,82): error CS0535: ‘Girya’ does not implement interface member ‘IPointerClickHandler.OnPointerClick(PointerEventData)’
Проконсультируйтесь через почту и покажите скриншот уведомления support@unity3dschool.com
решил проблему – void OnPointerClick был написан с опечаткой в имени
Полезный материал.
Одно не понял, как бы так отобразить объект при перетаскивании что бы он отрисовывался над пальцем. Например, перетаскиваем меч из слота рюкзаке в руку персонажа. Держим палец на экране и тащим – transform.position = eventData.position+new Vector3(0, 4, 0); – Такой метод, если я правильно понимаю, переместит объект над пальцем, вроде как, нарисует его. А что бы бросить меч в нужный слот, как я понимаю, придется в методе – public void OnEndDrag(PointerEventData eventData) – написать уже transform.position = eventData.position;
Все верно?
Первое – верно, второе – не совсем. Во втором случае Вам надо получить ссылку на слот, что у вас под пальцем и уже тогда transform.position = slot.position; плюс требуется еще сохранить в этот слот информацию о мече. Но это наверное больше для отдельной статьи про создание инвентаря.