【问题标题】:How to detect click/touch events on UI and GameObjects如何检测 UI 和 GameObjects 上的点击/触摸事件
【发布时间】:2017-05-14 11:41:59
【问题描述】:

如何在 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 触摸?和上面的一样吗?

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

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

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

    1.ImageRawImageText 组件:

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

    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 Click,则使用方法 1。例如,Button down 而不是 Button Click,请使用方法 1 中的 IPointerDownHandler 及其 OnPointerDown 函数。

    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)
    {
    
    }
    

    非 UI 对象:

    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
    }
    

    事件系统故障排除:

    在 UI、2D 对象(Sprite 渲染器/任何 2D 碰撞器)和 3D 对象(网格渲染器/任何 3D 碰撞器)上未检测到点击:

    A。检查您是否有 EventSystem。如果没有 EventSystem,它根本无法检测到点击。如果没有,请自行创建。


    转到 GameObject ---> UI ---> 事件系统。如果 EventSystem 尚不存在,这将创建它。如果它已经存在,Unity 将忽略它。


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

    这仅适用于 UI 对象。它适用于 2D(Sprite 渲染器/任何 2D 碰撞器)或 3D 对象(网格渲染器/任何 3D 碰撞器)。


    C。如果这是一个 3D 对象,PhysicsRaycaster 不会附加到相机。确保PhysicsRaycaster 已连接到相机。有关详细信息,请参阅上面的 #6


    D。如果这是一个 2D 对象,Physics2DRaycaster 不会附加到相机。确保Physics2DRaycaster 已连接到相机。请参阅上面的#7 了解更多信息。


    # 1 然后带有检测代码的脚本必须附加到您要检测点击的 UI 对象

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

    要验证这不是问题,请禁用 Canvas 下的每个对象,除了您要检测点击的对象,然后查看点击是否有效。

    【讨论】:

    • UI API 适用于移动设备和桌面设备。这是它好的一面,这根本不是问题。我稍后会更新它以包含其他 3D(Mesh Renderer/Collider)和 2D(Sprite/2D Collider)。
    • 添加了滑块和 3D、2D 示例。这就是您现在应该使用的输入系统或旧的 Raycast 方式。
    • 太棒了@Programmer。这就是我所需要的。谢谢:)
    • OnClick() 不是界面中的函数。您可能是指使用IPointerClickHandler 接口的OnPointerClick。请再次阅读我的回答。我的答案中的 一切 都应该适用于桌面和移动设备。我已经看到一些答案告诉人们将OnPointerClick 用于 Button 组件。这是大错特错了。它会起作用,但是当你这样做时,他们不知道有一个错误。要检测何时单击按钮,请使用我的答案中使用AddListerner 的事件。不要使用OnPointerClick 检测按钮单击。 OnPointerClick 用于其他不是 Button 的组件。
    • 了解将这些脚本附加(或不附加)到哪些游戏对象会很有用。有些很明显(按钮),但我应该把#1放在我想点击的对象上吗?在相机上? #7 是在我的游戏对象还是相机上?还是在别的地方?
    【解决方案2】:

    您可以将EventTrigger Componenet 添加到您的 UI 元素中,这些元素已经具有这些 Events,您只需在特定事件上传递 method/Function

    【讨论】:

    • 谢谢,我想明白了。
    【解决方案3】:

    您也可以使用 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
    
        }
    }
    

    【讨论】:

      【解决方案4】:

      不要不要将 OnMouseDown() 用于移动性能和多点触控问题。

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

      在我的回答中,我使用带有“Button”标签的 Image 元素,它有一个带有 ButtonDown 的 ButtonController 脚本() 用户触摸图像元素时应调用的公共方法。

      注意:图像元素有一个 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();
                  }       
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        相关资源
        最近更新 更多