Preventing mouse clicks from passing through GUI controls

NOTE

this is issue is addressed most freshly here:


I have a GUI.Button in my game, but when I click on the button, the click also gets processed by another script; so I need a way to ignore mouse clicks in a script when the mouse is over a GUI button or other control.

http://answers.unity3d.com/questions/9328/gui-click-through asks the same question, but using the old GUIElement system. The accepted solution does not work with the immediate mode GUI system.

Use GUIUtility.hotControl.

… 2012


But be aware that “IsPointerOverGameObject” is, to some extent, the current (2015) solution to this absurd Unity problem.

http://answers.unity3d.com/questions/784617/how-do-i-block-touch-events-from-propagating-throu.htm

We encountered a similar problem, where raycasts and MouseOver/Up/Down were going "through" OnGUI windows and controls. Our solution is not terribly elegant, but once in place it works well and is easy to add to new OnGUIs.

We have a single flag (mouseOver2DGui) which is set to false each frame. Each OnGUI is responsible for setting the flag to true each frame, only if the mouse is over any of its own windows/controls. Then when raycasts perform, they just check if mouseOver2DGui first.

e.g. Each OnGUI does this (pseudo code):

mouseOverMe = myWindowRect.Contains(mousePos)
if( mouseOverMe ) SetMouseOver2dGUI()

SetMouseOver2dGUI is a static function that just sets the flag true. Make sure you clear the flag each frame. The raycasts/OnMouseOver/OnMouseDown just read the flag as needed (e.g. to ignore clicks if(mouseOver2DGui)).

I don't know much about scripting but I did use this script for a game I was making. It was attached to 3d text.

  function OnMouseEnter()
{
    //change the color of the text
    renderer.material.color = Color.red;
}

function OnMouseExit()
{
    //change the color of the text
    renderer.material.color = Color.white;
}

function OnMouseUp()
{
    Health.LIVES = 3;
    Application.LoadLevel (3);
}

The function OnMouseUp() is s only called if the mouse was pressed down while over the same GUIElement or Collider.

Here is a link to the Unity Script Reference http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.OnMouseUp.html

Hi folks, This is kind of late, but I was working on the same problem and I think I've come up with a solution which addresses the problems above. The main drawback of my solution is that it requires you to put everything in a GUI.Window - thus you can't use odd-shaped "floating" buttons with it, unless you place the buttons on top of an invisible window. Also, it's a bit complicated but it should work.

The basic idea is this:

  1. We create a UI Manager object which contains a table of Window ID (int) to Window Rectangle (Rect) mappings. The easiest way to do this, I think, is to use a C# Dictionary object.
  2. When showing the GUI, we register the GUI window rectangle with the UI manager. If we hide the GUI, we de-register the GUI window rectangle. Hence the UI manager always knows which areas of the screen are covered by GUI windows. (You may want to check and re-register the rectangle with the manager on every OnGUI call, for safety's sake - the advantage of using our C# Dictionary here is that it prevents us accidentally registering a window twice.)
  3. When processing a mouse event using Input.GetButtonDown(), we first poll the UI manager, which will check if the current mouse position is over a GUI window.

I'm pretty sure the overhead for this should be minimal - most likely 3 or 4 rectangle hit tests per frame - unless you have mouse event processing in many places, and many windows. It's a pain to set up but I expect it should work well.

http://forum.unity3d.com/threads/96563-corrected-GUI.Button-code-%28works-properly-with-layered-controls%29?p=629284

I had this same problem and then I ran across this:

UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject()

Hopefully this helps someone :slight_smile:

If the GUI has mainly rectangular buttons etc., it’s also possible to create invisible GUI.boxes in every space that isn’t a GUI element. Then you create a new var “IsOverMainView” or whatever that is set to true if the mouse cursor is over these boxes that basically contain all the not-GUI screen space. When a button is clicked, you just add another if(MouseOverMainView == false) so it only registers if the mouse is over a GUI element, and vice versa when you want to check if a click registers in teh main view. Of course, when the mouse cursor is over any GUI element the variable needs to be set to true. Depending on you GUI setup, you would need a number of rectangles for this so no space is left(technically, you only need rectangles that set the var to true around each GUI element, but that would probably make since more complicated).