Trapping Gui clicks so they don't affect your game (solved)

EDIT: This conversation turned into one about trapping mouseclicks in GUI elements so that that your game would not be affected by them. The solution is below.

Does this code work for you?

function OnGUI (){

if (Event.current.Equals (Event.KeyboardEvent ("return")) )
            {
            print("Enter!");
            GUI.Label(Rect(10,60,Screen.width - 20,50),  "ENTER");
            }
}

When I press the enter key the print displays, but I’m not seeing the label displayed.

I have not been able to figure out a way to conditionally print the label based on whether or not the key is held down.

OnGUI runs several times per frame, and anything displayed only persists for one frame since it’s an immediate mode GUI. So in that code, your label only exists for the one cycle when you press return.

–Eric

You need to do something like:

private var showLabel:boolean = false;

function Update()
{
   if(Input.GetKeyDown("return"))
       showLabel = true;

   if(Input.GetKeyUp("return"))
       showLabel = false;
}

function OnGUI()
{
   if(showLabel)
       GUILayout.Label("hello");
}

For one thing, that is only going to display for one frame. It’s generally better to have input based code in Update() and communicate with OnGUI with variables. Maybe something like

private var keyPressed : boolean;
function Update() {
  if(Input.GetKeyUp("enter")  !keyPressed)
  EnterPressed();
}

function EnterPressed () {
  keyPressed = true;
  yield WaitForSeconds(2.0);
  keyPressed = false;
}

function OnGUI () {
  if(keyPressed)
  GUILayout.Label("Key was pressed!");
}

edit: I guess I am a slow typer. :slight_smile:

Thanks for your posts. I understand it would only appear for one frame – but it wasn’t even doing that.

The code I posted was actually simplified from something I was working on for mouse buttons.

I can’t check the mouse buttons in an update() because I’m trying to trap mouse events in GUI buttons.

Imagine a game like the sims or Diablo where you have GUI overlayed over a world. When clicking a GUI button, you don’t want to do a raycast and process it in the game world, because every time you clicked a button your little guy would also start walking.

I was thinking I could do something like this:

function OnGUI ()
{
//check state of mouse buttons, save in a var called mouseClick

//check GUIbuttons, if they're pressed clear out mouseClick
}

function Update ()
{
// check mouseClick: it should only be set when the mouse is down AND no guibuttons are being pressed

// We assume if we got this far, that it was an in-world click 
}

Seems like a reasonable process right?

However, with the way OnGUI works, this seems impossible to do, and impossible to predict how OnGUI is going to behave.

Anyone have any ideas?

Here’s a bit more of what I’m talking about:

static var buttonc = 0;

    function OnGUI()
        {
      
        if (Event.current.type == EventType.MouseDown)
            {
            buttonc = 1;
            }
       
        if (Event.current.type == EventType.MouseUp)
            {
            buttonc = 0;
            }
       
        if(GUI.RepeatButton(Rect(10,10,50,50) , "Test button"))
            {
            // Execute button code and clear out the variable so that my game world won't see it
            buttonc = 0;
            }
     }

 function Update ()
       {
       if(buttonc)
             {
             // this code should only execute when the mouse button is pressed AND the GUI button is not being clicked
            print("clicked outside the GUI!"); 
            }
        }

Clicking in the GUI button should keep the print in Update() from happening.

But instead, I see a single print() per GUI button click.

Any ideas?

I got it working. Many thanks to Jeff Craighead who helped me off-forum in figuring out the problem.

The key is to use Event.current.Use() and always test explicitly for every condition (use else-ifs instead of just else).

With this code, mouse0 gets set to 1 when the mouse button is held down and no buttons are being pressed.

	function OnGUI()
		{
		if( GUI.Button(Rect(110,10,100,50) , "Test button 1") )
			{
			print("button 1 clicked");
			Event.current.Use();
			}
		if( GUI.Button(Rect(10,10,100,50) , "Test button2") )
			{
			print("button 2. clicked");
			Event.current.Use();
			}
		
		if(Event.current.type == EventType.MouseDown  Event.current.button==0) 
			{
			print("Mouse Clicked down in the GUI.");
			mouse0 = 1; 
			}
		else if(Event.current.type == EventType.MouseUp  Event.current.button==0) 
			{
			print("Mouse Released.");
			mouse0 = 0; 
			}
		}

I’m going to edit the title of the post to make it more descriptive for people having the same problem.

I tried doing what you put for using up the mouse click, but it did not work. I believe it is because I am using the mouse click in two different scripts.
Anyway, I found another solution that doesn’t use any built in unity tools, so if it isn’t working for others this may be helpful. First I made a class called GeneralGUITools, on the off chance that I will need it for other things that come up. I gave it a public static boolean called “clicked.”
So the class looks like this:

public class GeneralGUITools : MonoBehaviour 
{
	public static bool clicked = false;
}

Then when I make my button call I just have it set “clicked” to true, and before the button I put an if statement that resets the “clicked” variable.

if (GeneralGUITools.clicked)
    GeneralGUITools.clicked = false;
if (GUI.Button(new Rect(0,0,100,30), "INV", style))
{ 
    GeneralGUITools.clicked = true;
}

Then when I am dealing with clicks in the actual game I just put this qualifier:

if (Input.GetMouseButtonUp(0)  !GeneralGUITools.clicked)
{
    GameConsole.input("You clicked!"); //This is my own GameConsole class... don't try to use this...
}

This works pretty well and I have some rather awesome menus working with it. Hope it helps!