1

I am currently working on a strategy game and I want to preform actions using GUI.Button on game objects. I am using ray cast and mouse click to select the object however when I click on GUI.Button to take out another action the button disappears. I want to use that button to open up another GUI.Box to show some descriptions.

I know why the button is disappearing, it is because I am projecting the ray cast to my button clicks in the update function but how can I avoid this? I also know that I have to use EventTrigger however I am not familiar with javascript event trigger, I searched online but I couldn't find any helpful javascript.

Screenshots:

enter image description here

enter image description here

Here is my script:

@HideInInspector
var isCalled:int = 0;
@HideInInspector
var scWidth:int = 0;
@HideInInspector
var scHeight:int = 0;
function Start () {
    scWidth = Screen.width;
    scHeight = Screen.height;        
}

function Update () {
    if (Input.GetMouseButtonDown(0)) {
        var ray : Ray = Camera.main.ScreenPointToRay (Input.mousePosition);
        var hit : RaycastHit;
        if (Physics.Raycast (ray, hit)) {
            if (hit.collider.tag == "House") {
                isCalled = 1;
            } else{
                isCalled = 0;
            }
        }
    }
}

function OnGUI(){
    if(isCalled==1)
        GUI.Button(Rect(scWidth/2,(scHeight/2)+(scHeight/4),120,120), name);
    }
}
6
  • can you try to explain again, what are you trying to achieve? You want to click the button, hide it and show another GUI element? Commented Aug 25, 2015 at 8:35
  • yeah, It's like the famous game clash of clans. for example when you click on upgrade button another page opens up with description. Since this is in update function the raycast keeps on checking the collision with the provided tags, that's why when I click on the button at same time a raycast is shooted from camera to the button and since the button doesnt have any tag it detects nothing and shows nothing Commented Aug 25, 2015 at 8:36
  • So, don't use the raycast to detect button click. You can normally use if(GUI.Button (...) { // do stuff when button is clicked } Commented Aug 25, 2015 at 8:41
  • the raycast is there to find what object has been clicked on for example the sphere in the center is house. let say the cube is hospital and so on. so first I need to check which object has been selected then I can perform actions base on the button linked to that object. Commented Aug 25, 2015 at 8:43
  • Oh, I see. Ok, in this case you can use event trigger component for every object (sphere, cube and so on). You should add new event (OnPointerClick for example) and choose your script to run appropriate method (OnHouseClick(), onHospitalClick()). Commented Aug 25, 2015 at 8:47

3 Answers 3

2

If I understood you right, the problem is that when you click on button the raycast is fired up before button click and you select different object or no object at all and button disappears or reappears but for another object, what you need to do is check if you clicked on GUI and if yes don't project the raycast that selects the objects. Here is how you are gonna do it.

var selectedUI : GameObject = EventSystem.current.currentSelectedGameObject;
if (Input.GetMouseButtonDown(0) && selectedUI) {
       var ray : Ray = Camera.main.ScreenPointToRay (Input.mousePosition);
       var hit : RaycastHit;
       if (Physics.Raycast (ray, hit)) {
           if (hit.collider.tag == "House") {
           isCalled = 1;
          } else{
           isCalled = 0;
           }
        }
}

I work in C#, so I might have done some syntax errors, but the logic is right.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks Neven I see the logic is correct, I think I figure out what causes the problem. it is the else statement which gives us the headache once that else is removed the problem is half solved
Is there a way to Tag a GUI element like buttons?
Of course, we have a reference to last clicked UI gameobject (EventSystem.current.currentSelectedGameObject), with that we can do anything we want. You can do some tests like if(selectedUI.name == "something) or by selectedUI.tag or selectedUI.layer, or we can write a custom script and make it access that script and check for type, you have thousands of ways to do it, pick what suits you.
2

There is a good trick when using legacy GUI system to avoid raycast when mouse is over GUI elements. Using tooltip to controll if you may cast your ray =)

Something like this (I also don't work with US so may I it needs some work):

var hover : String;

function OnGUI(){
    if(GUI.Button (Rect (10,10,100,20), "My Button"));
    hover = GUI.tooltip; 

function Update () {
    if(hover != "") {
       // raycast logic
    }
}

If you need to avoid raycast when your "popUp" window/panel is shown but you don't want a tooltip on it you may approach using a MouseOverGUI manager too.

It is just a static or singleton holding a boolean that you will set true when your mouse is over some rect that you don't want to cast rays using Rect.Contains(Event.current.mousePosition) and to false whenever it runs out of this rect.

Use this bool with or without tooltip var to allow raycast:

if(!MouseManager.MouseOverGUI) {
    // raycast logic
}

Note that creating your rect on each OnGUI cycle will difficult to catch it and control the MouseOveGUI. Also it is a bad practice for performance because OnGUI runs more than once per frame so I'll suggest you to create you rects just once (recalculate it just when needed) and pass it to your GUI elements ;)

1 Comment

This answer sounds promising, I will try it in an hour and let you know the result.
0

I think the easiest way is to create a GameObject(input blocker) which is not visible but have a collider. Place it in between the camera and level objects and deactivate it. When you select a GameObject using Raycast you enable that input blocker GameObject and place it around the area of selected GameObject and GUI. Then you have to ignore the selection if raycast is collided with Input Blocker. When you deselect the Gameobject then you deactivate input blocker You should also maintain current state of the game for example:

enum State
{
    NothingSelected = 0,
    GameobjectSelected,
    BigMenuOpen
}
State currentState;

So according to state you can define the behavior on mouse click. Like if Full screen menu is Open then raycast does not fire.

2 Comments

Yeah that seems to be a good fix however it wont work in some scenarios for example the user first select the gameobject (House) then the button for that game object appears (House Button) and we block the raycast by a hidden gameObject now the user decides to click on another gameObject rather than clicking on the button... the game stucks there cause the user has no other choice but to click the button.
Thats why i mentioned that you will block only the specific area around the selected GameObject not all screen.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.