Як виявити клік / дотик подій в інтерфейсі користувача та GameObjects


83

Як виявити об’єкт інтерфейсу користувача на Canvas on Touch в Android?

Наприклад, у мене є полотно , що є 5 об'єктів , таких як Image, RawImage, Buttons, InputFieldі так далі.

Коли я торкаюся об'єкта інтерфейсу кнопки, то зробіть щось. Кожна кнопка виконує різний процес при натисканні в залежності.

Код буде виглядати так:

private void Update()
{
    if (Input.touches.Length <= 0) return;

    for (int i = 0; i < Input.touchCount; i++)
    {
        if (Button1.touch)
            if (Input.GetTouch(i).phase == TouchPhase.Began)
                login();
        else if (Button2.touch && Input.GetTouch(i).phase == TouchPhase.Began)
            LogOut();
    }
}

То як це зробити?

По-друге: Як виявити Gameobject отримати контакт? Це те саме з тим, що вище, чи ні?

Відповіді:


172

Ви не використовуєте API введення для нового інтерфейсу. Ви підписуєтесь на події інтерфейсу користувача або реалізуєте інтерфейс залежно від події.

Це правильні способи виявлення подій у нових компонентах інтерфейсу користувача:

1 . Image, RawImageІ Textкомпоненти:

Впровадити необхідний інтерфейс і замінити його функцію. У наведеному нижче прикладі реалізовані найбільш використовувані події.

using UnityEngine.EventSystems;

public class ClickDetector : MonoBehaviour, IPointerDownHandler, IPointerClickHandler,
    IPointerUpHandler, IPointerExitHandler, IPointerEnterHandler,
    IBeginDragHandler, IDragHandler, IEndDragHandler
{
    public void OnBeginDrag(PointerEventData eventData)
    {
        Debug.Log("Drag Begin");
    }

    public void OnDrag(PointerEventData eventData)
    {
        Debug.Log("Dragging");
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        Debug.Log("Drag Ended");
    }

    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("Clicked: " + eventData.pointerCurrentRaycast.gameObject.name);
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        Debug.Log("Mouse Down: " + eventData.pointerCurrentRaycast.gameObject.name);
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        Debug.Log("Mouse Enter");
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        Debug.Log("Mouse Exit");
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        Debug.Log("Mouse Up");
    }
}

2 . ButtonКомпонент:

Ви використовуєте події для реєстрації для натискання кнопки:

public class ButtonClickDetector : MonoBehaviour
{
    public Button button1;
    public Button button2;
    public Button button3;

    void OnEnable()
    {
        //Register Button Events
        button1.onClick.AddListener(() => buttonCallBack(button1));
        button2.onClick.AddListener(() => buttonCallBack(button2));
        button3.onClick.AddListener(() => buttonCallBack(button3));

    }

    private void buttonCallBack(Button buttonPressed)
    {
        if (buttonPressed == button1)
        {
            //Your code for button 1
            Debug.Log("Clicked: " + button1.name);
        }

        if (buttonPressed == button2)
        {
            //Your code for button 2
            Debug.Log("Clicked: " + button2.name);
        }

        if (buttonPressed == button3)
        {
            //Your code for button 3
            Debug.Log("Clicked: " + button3.name);
        }
    }

    void OnDisable()
    {
        //Un-Register Button Events
        button1.onClick.RemoveAllListeners();
        button2.onClick.RemoveAllListeners();
        button3.onClick.RemoveAllListeners();
    }
}

Якщо ви виявляєте щось інше, ніж Button Клацніть на Button, тоді скористайтеся способом 1. Наприклад, Button down, а не Button Click, use IPointerDownHandlerand its OnPointerDownfunction from method 1.

3 . InputFieldКомпонент:

Ви використовуєте події для реєстрації для реєстрації для подання InputField:

public InputField inputField;

void OnEnable()
{
    //Register InputField Events
    inputField.onEndEdit.AddListener(delegate { inputEndEdit(); });
    inputField.onValueChanged.AddListener(delegate { inputValueChanged(); });
}

//Called when Input is submitted
private void inputEndEdit()
{
    Debug.Log("Input Submitted");
}

//Called when Input changes
private void inputValueChanged()
{
    Debug.Log("Input Changed");
}

void OnDisable()
{
    //Un-Register InputField Events
    inputField.onEndEdit.RemoveAllListeners();
    inputField.onValueChanged.RemoveAllListeners();
}

4 . SliderКомпонент:

Щоб визначити, коли значення повзунка змінюється під час перетягування:

public Slider slider;

void OnEnable()
{
    //Subscribe to the Slider Click event
    slider.onValueChanged.AddListener(delegate { sliderCallBack(slider.value); });
}

//Will be called when Slider changes
void sliderCallBack(float value)
{
    Debug.Log("Slider Changed: " + value);
}

void OnDisable()
{
    //Un-Subscribe To Slider Event
    slider.onValueChanged.RemoveListener(delegate { sliderCallBack(slider.value); });
}

Для інших подій використовуйте метод 1 .

5 . DropdownКомпонент

public Dropdown dropdown;
void OnEnable()
{
    //Register to onValueChanged Events

    //Callback with parameter
    dropdown.onValueChanged.AddListener(delegate { callBack(); });

    //Callback without parameter
    dropdown.onValueChanged.AddListener(callBackWithParameter);
}

void OnDisable()
{
    //Un-Register from onValueChanged Events
    dropdown.onValueChanged.RemoveAllListeners();
}

void callBack()
{

}

void callBackWithParameter(int value)
{

}

ОБ’ЄКТИ, ЩО НЕ ПІДКЛАДУЮТЬСЯ:

6 .Для 3D-об’єкта (візуалізатор сітки / будь-який 3D-коллайдер)

Додайте PhysicsRaycasterдо камери, а потім використовуйте будь-яку з подій із способу 1 .

Код нижче буде автоматично доданий PhysicsRaycasterдо основного Camera.

public class MeshDetector : MonoBehaviour, IPointerDownHandler
{
    void Start()
    {
        addPhysicsRaycaster();
    }

    void addPhysicsRaycaster()
    {
        PhysicsRaycaster physicsRaycaster = GameObject.FindObjectOfType<PhysicsRaycaster>();
        if (physicsRaycaster == null)
        {
            Camera.main.gameObject.AddComponent<PhysicsRaycaster>();
        }
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        Debug.Log("Clicked: " + eventData.pointerCurrentRaycast.gameObject.name);
    }

    //Implement Other Events from Method 1
}

7 .Для 2D-об’єкта (Sprite Renderer / будь-який 2D Collider)

Додати Physics2DRaycasterдо камери, а потім використовуйте будь-яку з подій із способу 1 .

Код нижче буде автоматично доданий Physics2DRaycasterдо основного Camera.

public class SpriteDetector : MonoBehaviour, IPointerDownHandler
{
    void Start()
    {
        addPhysics2DRaycaster();
    }

    void addPhysics2DRaycaster()
    {
        Physics2DRaycaster physicsRaycaster = GameObject.FindObjectOfType<Physics2DRaycaster>();
        if (physicsRaycaster == null)
        {
            Camera.main.gameObject.AddComponent<Physics2DRaycaster>();
        }
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        Debug.Log("Clicked: " + eventData.pointerCurrentRaycast.gameObject.name);
    }

    //Implement Other Events from Method 1
}

Усунення несправностей системи EventSystem:

Жодних клацань на користувацькому інтерфейсі, 2D-об'єктах (Sprite Renderer / будь-який 2D Collider) та 3D-об'єктах (Mesh Renderer / будь-який 3D Collider):

A Перевірте, чи маєте ви систему EventSystem. Без EventSystem він взагалі не може виявляти кліки. Якщо у вас його немає, створіть її самі.


Перейдіть до GameObject ---> UI ---> Система подій . Це створить EventSystem, якщо вона ще не існує. Якщо воно вже існує, Unity просто проігнорує його.


Б. Компонент інтерфейсу користувача або GameObject з компонентом інтерфейсу користувача повинен знаходитись підCanvas . Це означає, що Canvasmust повинен бути батьківським компонентом інтерфейсу користувача. Без цього EventSystem не працюватиме, а клацання не виявлятимуться.

Це стосується лише об’єктів інтерфейсу користувача. Це не стосується 2D (Sprite Renderer / будь-якого 2D Collider) або 3D-об'єктів (Mesh Renderer / будь-якого 3D Collider).


C. Якщо це 3D-об'єкт, PhysicsRaycasterвін не прикріплений до камери. Переконайтеся, що PhysicsRaycasterприкріплено до камери. Дивіться No6 вище для отримання додаткової інформації.


D. Якщо це 2D-об'єкт, Physics2DRaycasterвін не прикріплений до камери. Переконайтеся, що Physics2DRaycasterприкріплено до камери. Для отримання додаткової інформації див. No7 вище.


E .Якщо це об'єкт призначеного для користувача інтерфейсу ви хочете , щоб виявити кліки з функціями інтерфейсу , таких як OnBeginDrag, OnPointerClick, OnPointerEnterта інші функції , згадані в # 1 , то скрипт з кодом виявлення повинні бути прикріплені до цього об'єкта призначеного для користувача інтерфейсу ви хочете , щоб виявити натиснути на кнопку.


F. Крім того, якщо це об’єкт інтерфейсу, який ви хочете виявити, клацання, переконайтеся, що перед ним немає жодного іншого об’єкта інтерфейсу. Якщо перед тим, за яким ви хочете виявити клацання, є інший інтерфейс, він буде блокувати цей клік.

Щоб перевірити, що це не проблема, відключіть усі об’єкти під полотном, крім того, який ви хочете виявити, клацніть, а потім перевірте, чи це працює.


1
API інтерфейсу призначений для роботи як на мобільних, так і на настільних комп'ютерах. Це хороша сторона цього, і це зовсім не проблема. Я оновлю це для включення інших 3D (Mesh Renderer / Collider) та 2D (Sprite / 2D Collider) за мить.
Програміст

1
Додано слайдер та 3D, 2D приклад. Це те, що ви повинні використовувати зараз, оцінюючи систему введення або старі способи Raycast.
Програміст

1
Це чудово @Programmer. Це все, що мені потрібно. Дякую :)
Денніс Лю

2
OnClick () не є функцією з інтерфейсу. Ви, мабуть, мали на увазі, OnPointerClickхто використовує IPointerClickHandlerінтерфейс. Будь ласка, прочитайте мою відповідь ще раз. Все, що в моїй відповіді, має працювати на настільних комп’ютерах та мобільних пристроях. Я бачив деяку відповідь, яка говорить людям використовувати OnPointerClickкомпонент Button. Це так неправильно. Це спрацює, але є помилка, про яку вони не знають, коли ви це робите. Щоб виявити натискання кнопки, використовуйте подію в моїй відповіді, яка використовує AddListerner. Не виявляти натискання кнопки за допомогою OnPointerClick. OnPointerClickдля інших компонентів, що не є кнопкою.
Програміст

1
Було б корисно знати, до яких ігрових об’єктів прикріплювати (чи не вкладати) ці сценарії. Деякі з них очевидні (кнопка), але чи повинен я поставити No1 на об’єкт, на який я хочу натиснути? На камеру? No7 йде на моєму ігровому об’єкті чи камері? Або це десь ще?
meed96

5

Ви можете додати EventTriggerкомпонентну мережу до елементів інтерфейсу, які вже є, Eventsвам потрібно передати method/Functionконкретну подію.


Дякую, думаю.
Денніс Лю

5

Ви також можете використовувати OnMouseDown. OnMouseDown викликається, коли користувач натискає кнопку миші, перебуваючи над GUIElement або Collider. Ця подія надсилається до всіх сценаріїв Collider або GUIElement.

using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement; // The new load level needs this

public class ExampleClass : MonoBehaviour
{
    void OnMouseDown()
    {
        // Edit:
        // Application.LoadLevel("SomeLevel");
        // Application.LoadLevel() is depreciating but still works

         SceneManager.LoadScene("SomeLevel"); // The new way to load levels

    }
}

0

є НЕ використовувати OnMouseDown () з питань мобільного продуктивності і мультитач.

Цей код працює на об'єктах інтерфейсу для мультитач

У своїй відповіді я використовую елемент Image із тегом " Button ", і він має сценарій ButtonController із загальнодоступним методом ButtonDown (), який слід викликати, коли користувач торкається елемента Image.

Примітка : Елемент Image має 2D Collider.

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

public class TouchScript : MonoBehaviour
{
    void Update()
    {
        PointerEventData pointer = new PointerEventData(EventSystem.current);
        List<RaycastResult> raycastResult = new List<RaycastResult>();

        foreach (Touch touch in Input.touches)
        {
            if(touch.phase.Equals(TouchPhase.Began))
            {
                pointer.position = touch.position;
                EventSystem.current.RaycastAll(pointer, raycastResult);

                foreach(RaycastResult result in raycastResult)
                {
                    if(result.gameObject.tag == "Button")
                    {
                        result.gameObject.GetComponent<ButtonController>().ButtonDown();
                    }              
                }
                raycastResult.Clear();
            }       
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.