Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make gameplay ignore clicks on UI Button in Unity3D?

I have a UI Button (using UnityEngine.UI).

However, clicking on the Button seems to be clicking through onto the scene (in my case clicking a nav mesh).

How to solve this problem?

I've been using typical Unity3D code to get user in put in gameplay such as

if (Input.GetMouseButtonDown(0))
  {

same if I try the approach

if( Input.touches.Length > 0 )
        {

        if ( Input.touches[0].phase == TouchPhase.Began )
            {

and it seems to be the case on iOS, Android, and desktop.

It seems to be a basic problem that clicks on the UI (UnityEngine.UI.Button etc) seem to fall through to the gameplay.

like image 495
Peter Avatar asked Feb 20 '16 22:02

Peter


2 Answers

I had this problem too and I couldn't find very much useful info on it, this is what worked for me:

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

public class SomeClickableObject : MonoBehaviour
{
    // keep reference to UI to detect for
    // for me this was a panel with some buttons
    public GameObject ui;

    void OnMouseDown()
    {
        if (!this.IsPointerOverUIObject())
        {
            // do normal OnMouseDown stuff
        }
    }

    private bool IsPointerOverUIObject()
    {
        // get current pointer position and raycast it
        PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
        eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
        List<RaycastResult> results = new List<RaycastResult>();
        EventSystem.current.RaycastAll(eventDataCurrentPosition, results);

        // check if the target is in the UI
        foreach (RaycastResult r in results) {
            bool isUIClick = r.gameObject.transform.IsChildOf(this.ui.transform); 
            if (isUIClick) {
                return true;
            }
        }
        return false;
    }
}

Essentially each click checks if the click occurred over a UI target.

like image 132
S. Wilcox Avatar answered Oct 19 '22 17:10

S. Wilcox


Here's how you do it in Unity today:

  1. Naturally you'll have an EventSystem in the hierarchy - just check that you do. (You get one of those automatically when, for example, you add a Canvas; usually, every scene in an Unity project already has an EventSystem, but just check that you do have one.)

  2. Add a physics raycaster to the camera (that takes one click)

  3. Do this:

.

  using UnityEngine.EventSystems;
  public class Gameplay:MonoBehaviour, IPointerDownHandler {
   public void OnPointerDown(PointerEventData eventData) {
    Bingo();
    }
   }

Basically, again basically, that is all there is to it.

Quite simply: that is how you handle touch in Unity. That's all there is to it.

Add a raycaster, and have that code.

It looks easy and it is easy. However, it can be complicated to do well.


(Footnote: some horrors of doing drags in Unity: Horrors of OnPointerDown versus OnBeginDrag in Unity3D )


Unity's journey through touch technology has been fascinating:

  1. "Early Unity" ... was extremely easy. Utterly useless. Didn't work at all.

  2. "Current 'new' Unity" ... Works beautifully. Very easy, but difficult to use in an expert manner.

  3. "Coming future Unity" ... Around 2025 they will make it BOTH actually work AND be easy to use. Don't hold your breath.

(The situation is not unlike Unity's UI system. At first the UI system was laughable. Now, it is great, but somewhat complex to use in an expert manner. As of 2019, they are about to again totally change it.)

(The networking is the same. At first it was total trash. The "new" networking is/was pretty good, but has some very bad choices. Just recently 2019 they have changed the networking again.)


Handy related tip!

Remember! When you have a full-screen invisible panel which holds some buttons. On the full-screen invisible panel itself, you must turn off raycasting! It's easy to forget:

enter image description here


As a historic matter: here is the rough-and-ready quick-fix for "ignoring the UI", which you used to be able to use in Unity years ago...

if (Input.GetMouseButtonDown(0)) { // doesn't really work...
  if (UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject())
      return;
  Bingo();
  }

You cannot do this any more, for some years now.

like image 34
Fattie Avatar answered Oct 19 '22 18:10

Fattie