UI Raycast + EventSystem data

Не сколько урок, а скорее небольшая, но крайне полезная справка. В игре может быть такая ситуация, что есть некий объект, допустим, планета, и поверх нее наложены UI элементы, и нам нужно, чтобы при наведении курсора, мы могли получать какие-то данные не только с этой планеты, но и элементов UI. В Unity есть система, которая собирает данные по UI, вопрос в том, как нам получить доступ к этим данным напрямую. Еще может возникнуть ситуация, когда нам необходимо проверить наличие или состояние, определенного UI объекта, на экране. В этом случаи, речь идет о том, как использовать рейкаст на таких объектах.

Как делается UI Raycast?


Пример кода:

using System.Collections;
using UnityEngine.EventSystems;
using UnityEngine;
using System.Collections.Generic;

public class Example : MonoBehaviour {

	void Update()
	{
		if(Input.GetMouseButtonDown(0))
		{
			var data = PointerRaycast(Input.mousePosition); // пускаем луч

			if(data != null)
			{
				Debug.Log(data); // объект куда попал луч
				Debug.Log(data.transform.parent); // родитель этого объекта
			}
		}
	}

	GameObject PointerRaycast(Vector2 position)
	{
		PointerEventData pointerData = new PointerEventData(EventSystem.current);
		List<RaycastResult> resultsData = new List<RaycastResult>();
		pointerData.position = position;
		EventSystem.current.RaycastAll(pointerData, resultsData);

		if(resultsData.Count > 0)
		{
			return resultsData[0].gameObject;
		}

		return null;
	}
}

Как видно из примера, после нажатия ЛКМ, пускается луч в указанную точку, а данном случаи это позиция мышки, и если луч попадает в какой-нибудь UI объект (текст, картинка и т.п.), то функция возвращает этот объект. При этом важно помнить, что луч попадет в конкретный объект, например, если это UI Button, метод вернет UI Text, потому что текст находится поверх кнопки. Если нам нужен родитель, то к нему мы обращаемся соответствующим образом.

Как получить данные UI EventSystem?


Когда мы добавляем на сценку какой-нибудь UI объект, то Unity автоматом добавит на сцену EventSystem:

UI Raycast + EventSystem data

Этот объект содержит необходимые для работы скрипты.

Так вот, многие наверно замечали, что если выделить EventSystem, а потом запустить сцену, то мы увидим вот такое:


Здесь у нас высвечивается окошко, где мы можем видеть некоторые данные, когда совершаем действия, например: курсор поверх UI, нажатие кнопок и так далее.

Чтобы получить эти данные, нужно кое что изменить.

Итак, на объекте EventSystem удаляем скрипт Standalone Input Module.

А вместо него, вешаем свой скрипт StandaloneModule:

using UnityEngine.EventSystems;
using UnityEngine;

public class StandaloneModule : StandaloneInputModule {

	public PointerEventData GetPointerEventData(int id)
	{
		return GetLastPointerEventData(id);
	}
}

Должно получиться следующие:


Теперь, мы можем запрашивать данные с EventSystem, примерно вот так:

using System.Collections;
using UnityEngine.EventSystems;
using UnityEngine;

public class Example : MonoBehaviour {

	void Update()
	{
		if(Input.GetMouseButtonDown(0))
		{
			var data = PointerData(-1); // -1 ЛКМ | -2 ПКМ | -3 Клик колесиком мышки

			Debug.Log(data.pointerEnter); // курсор поверх
		}
	}

	PointerEventData PointerData(int id)
	{
		var inst = EventSystem.current.currentInputModule as StandaloneModule;
		if (inst == null) return null;
		return inst.GetPointerEventData(id);
	}
}

С помощью такого нехитрого кода, можно запрашивать текущее состояние событий из окошка EventSystem, о котором говорилось выше.
Тестировалось на: Unity 2017.1.1

Комментариев 5

Офлайн
Raveoff 10 сентября 2017
Нашёл много полезно. Авторам ( автору ) респект.
......................
Ввиду адекватности происходящего - можно увидеть уроки по uScript ?
Офлайн
Light 10 сентября 2017
Цитата: Raveoff
можно увидеть уроки по uScript ?

Есть в сети. Тут не планируется ничего такого. По мне дак проще самому код писать...
Офлайн
ArturST 10 сентября 2017
добавить сюда бы еще метод блокировки прохождения луча через UI обекты
Офлайн
ArturST 17 сентября 2017
Цитата: ArturST
добавить сюда бы еще метод блокировки прохождения луча через UI обекты

void Update ()
{
PointerEventData pointer = new PointerEventData (EventSystem.current);
if (Input.GetMouseButtonDown (0)) {
pointer.position = Input.mousePosition;

List<RaycastResult> raycastResults = new List<RaycastResult> ();
EventSystem.current.RaycastAll (pointer, raycastResults);

if (raycastResults.Count > 0) {
This_is_UI = true;
foreach (var go in raycastResults) {
Debug.Log (go.gameObject.name, go.gameObject);
}
Debug.Log ("кликнули по интерфейсу юи");
}
if (raycastResults.Count == 0) {
This_is_UI = false;
Debug.Log ("кликнули не по интерфейсу юи");
}
}
if(Physics.Raycast(PlayerCamera.GetComponent<Camera>().ScreenPointToRay(Input.mousePosition), out hitinfo))
{

if ((Input.GetMouseButtonDown (0)) && (This_is_UI ==false)) { //и если ето не слой юи

дальше идет перечисление тегов с которыми может столкнться лучь.

}

Проверил работает как под пк так и под андроид не пропуская прохождение луча через слой UI интерфейса
Онлайн
siriusspark 9 ноября 2017
ArturST,
намного проще сделать так:

if (Physics.Raycast(ray, out hit)) {
if(EventSystem.current.IsPointerOverGameObject()){
return;
}
}
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Дешевый хостинг
  • Яндекс.Метрика