如何在UI和GameObjects上检测单击/触摸事件


79

如何在Android中的Canvas on Touch上检测UI对象?

例如,我有具有5个对象,诸如帆布ImageRawImageButtonsInputField等。

当我触摸Button UI对象时,请执行一些操作。每个按钮在单击时都会执行不同的过程。

代码如下所示:

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接触?与上面相同吗?

Answers:


165

您不会为新的UI使用Input API。您订阅UI事件或根据事件实现接口。

这些是检测新UI组件上的事件的正确方法:

1ImageRawImageText组件:

实现所需的接口并覆盖其功能。下面的示例实现了最常用的事件。

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");
    }
}

2Button零件:

您使用事件来注册按钮单击:

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();
    }
}

如果您检测到按钮以外的其他东西,请单击按钮,然后使用方法1。例如,按下按钮而不是按钮单击,请使用方法1中的按钮IPointerDownHandler及其OnPointerDown功能。

3InputField零件:

您使用事件进行注册以注册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();
}

4Slider零件:

要检测拖动期间滑块值何时改变:

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

5Dropdown零件

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到main中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到main中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进行故障排除:

在UI,2D对象(Sprite Renderer /任何2D Collider)和3D对象(Mesh Renderer /任何3D Collider)上未检测到点击:

。检查你有的EventSystem。没有EventSystem,它根本无法检测到点击。如果没有,请自己创建。


进入游戏对象---> 用户界面- >事件系统。如果尚不存在,则会创建一个EventSystem。如果已经存在,Unity只会忽略它。


B .UI组件或带有UI组件的GameObject必须在之下Canvas。这意味着aCanvas必须是UI组件的父级。否则,EventSystem将无法运行,并且不会检测到点击。

这仅适用于UI对象。它并不适用于2D(精灵渲染器/任何2D撞机)或3D对象(网格渲染器/任何3D撞机)。


C。如果这是3D对象,PhysicsRaycaster则未连接到相机。确保已将PhysicsRaycaster其连接到相机。有关更多信息,请参见上面的#6


D。如果这是2D对象,Physics2DRaycaster则未连接到相机。确保已将Physics2DRaycaster其连接到相机。有关更多信息,请参见上面的#7


Ë。如果这是您要检测与接口功能,如点击一个UI对象OnBeginDragOnPointerClickOnPointerEnter和中提到的其它功能#1然后与检测代码的脚本必须附加到UI对象要检测点击。


F。此外,如果这是您要检测点击的UI对象,请确保前面没有其他UI对象。如果您要检测点击的前面有另一个UI,它将阻止该点击。

要验证这不是问题,请禁用“画布”下的所有对象,但要检测的对象除外,请单击并查看其是否有效。


1
UI API可以在移动设备和台式机上使用。那是它的好处,而这根本不是问题。我将在稍后对此进行更新,以包括其他3D(网格渲染器/对撞机)和2D(Sprite / 2D对撞机)。
程序员

1
添加了Slider和3D,2D示例。这是您现在应该使用的输入系统或旧的Raycast方式。
程序员

1
太好了@Programmer。这就是我所需要的。谢谢:)
丹尼斯·刘

2
OnClick()不是接口中的函数。您可能是说OnPointerClick使用哪个IPointerClickHandler接口。请再次阅读我的答案。一切都在我的答案应该在桌面和移动工作。我已经看到一些答案,告诉人们使用OnPointerClickButton组件。错了 它将起作用,但是当您这样做时,他们不知道有一个错误。要检测单击按钮的时间,请在使用的答案中使用该事件AddListerner。不要使用来检测按钮单击OnPointerClickOnPointerClick适用于不是Button的其他组件。
程序员

1
知道将这些脚本附加(或不附加)到哪些游戏对象会很有用。有些是显而易见的(按钮),但是我应该在要单击的对象上放置#1吗?在相机上?#7放在我的游戏对象或相机上吗?还是在其他地方?
meed96

5

您可以将EventTriggerComponenet添加到已经具有这些元素的UI元素,而Events只需要传递method/Function特定事件即可。


谢谢,我想明白了。
丹尼斯·刘

5

您也可以使用OnMouseDown。当用户在GUIElement或Collider上方按下鼠标按钮时,将调用OnMouseDown。此事件发送到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事件()的移动性能和多点触摸的问题。

此代码适用于多点触摸的UI对象

在我的回答,我用图片元素与“按钮”标签,它有一个ButtonController脚本有个buttonDown()的公共方法当用户触摸图像元素应该被调用。

注意:图像元素具有2D对撞机。

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();
            }       
        }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.