- Home /
Preventing mouse clicks from passing through GUI controls
NOTE
this is issue is addressed most freshly here:
http://answers.unity3d.com/questions/784617/how-do-i-block-touch-events-from-propagating-throu.html
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.
"The accepted solution does not work with the immediate mode GUI system." Can you explain what that means...?
Immediate mode is when you define your GUI in the OnGUI function, and thus calling the GUI functions every frame ins$$anonymous$$d of defining them once, as you would in retained mode GUI, i.e. the old GUIText and GUITexture system.
Has anyone had any insights to this since $$anonymous$$ay?
Answer by Veehmot · May 30, 2012 at 10:08 PM
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
wow this is great. $$anonymous$$akes it so simple. Good find.
Thanks! The accepted answer is way more complicated than your solution... if (Input.Get$$anonymous$$ouseButtonDown(0) && GUIUtility.hotControl==0) { // Non-UI mouse click }
I don't think box is actually considered a control in the classic sense. Controls are things that can take input events like keys (textboxes) and clicks (buttons sliders, checkboxes, etc)
Answer by Molix · May 07, 2010 at 05:21 PM
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)).
That sounds ok. Can you be sure that no input code is run between resetting the flag and the OnGUI that sets it on again? I had this sort of problem when I tried to detect the click on the GUI and make that disable my regular mouse input code, but what happened was that the regular mouse input code was run before the OnGUI. I had my mouse input code in an Update though, not using the event system since that'd require me to have input components running on a whole bunch of different gameobjects, while currently I make do with a single one that does raycasts.
I don't have the code in front of me at the moment, but I think if you clear it in LateUpdate, that should be after all Update/OnGUI/$$anonymous$$ouseDown events.
It does seem like this solution works. I think the edge case where it doesn't work is if you click right when the cursor moves over the GUI, in which case Update gets the input first, with the flag not set, then LateUpdate resets the flag, and then OnGUI gets the input and sets the flag, but it's too late. This is very much an edge case though. 99% of users probably won't even encounter it, and even fewer will encounter it on a regular basis.
Has Unity 3.0 addressed this at all? I have the similar problem: when my GUI text window is up, WASD keys still move the camera, and trying to drag the window also does mouselook (I have mouselook 'on' when left mouse is down). Does this mean I have to put this hack in my $$anonymous$$ouseLook and FPSWalker scripts too? There has to be an easier way....
Answer by QWERTY · May 06, 2010 at 08:28 PM
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
Well, I guess using $$anonymous$$ouseUp events ins$$anonymous$$d of $$anonymous$$ouseDown events might help since I would have the in between frames to disable the function if I detect a mousedown event on a GUI control. I'm not sure this actually solves the original problem though, as I'm not quite sure that a collider wouldn't receive these mouse events even if it was under a GUI control, and even if it were, this would require me to rethink how my input works as I'm currently not handling mouse events on specific gameobjects and colliders.
This is not really helpful in this particular case because the terrain, and other GameObjects still receive these mouse events even though they are underneath a GUI control.
Answer by 5parrowhawk_legacy · Jan 11, 2011 at 07:43 AM
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:
- 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<int, Rect> object.
- 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.)
- 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.
Your answer
Follow this Question
Related Questions
(C#) coroutines keep blocking GUI :? 0 Answers
How to set the position of a guitext using transform? 1 Answer
One Last GUI Question 1 Answer
GUI Box not showing! 1 Answer
Change GUI on mouse over 1 Answer