Search Unity

Stop tracing hits on 3D objects behind UnityGUI elements

Discussion in 'Immediate Mode GUI (IMGUI)' started by Marc, Nov 26, 2007.

  1. Marc

    Marc

    Joined:
    Oct 4, 2007
    Posts:
    499
    Greetings.

    Is there a way to stop the mouse from triggering hits on 3D object that a behind the gui elements?

    If i have a gui button and a 3D object behind the button. When i click the button a click on the 3D object will trigger aswell. I dont want that.

    Regards,
    Marc
     
  2. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    That is fixed in the next version. Just pretend you're not getting this behaviour for the moment, and soon the real world will catch up :)
     
  3. Marc

    Marc

    Joined:
    Oct 4, 2007
    Posts:
    499
    Hehe what problem?
     
  4. llavigne

    llavigne

    Joined:
    Dec 27, 2007
    Posts:
    977
    Next version meant 3.0
    (and just in case anyone else wonders, that time stamp was off by two years)
     
  5. Cor1312

    Cor1312

    Joined:
    Apr 12, 2010
    Posts:
    34
    So essentially this problem still exists with no solution in sight?
     
  6. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664
    Mmmm... I'd love to know a solution to this one.

    Anyone with any thoughts, work around or ideas?
     
  7. rsx

    rsx

    Joined:
    Nov 4, 2009
    Posts:
    87
    I asked this same question a few weeks ago and was told there was no way to easily do this.

    Instead I created a static dictionary and when ever I make a GUI area, I register it with the dictionary. My camera ignores any Rects in the Dictionary by checking to see if the mouse is in any of them before doing any work.

    I made a static bool which returns true or false if the mouse is over a rect.

    Here is my code after hours of trail and error and C# websites...

    Code (csharp):
    1.     /// <description>
    2.     ///     Uses the RegisteredRects global static Dictionary to determine
    3.     ///     if the mouse is over any registered GUI rects.
    4.     /// </description>
    5.     public static bool isMouseOverGUI
    6.     {
    7.         get
    8.         {
    9.             // Note: Not going to bother checking if there are any rects.
    10.             //       There should always be, so the check is a waste of time.
    11.  
    12.             // Check each rect to see if the mouse is over one. If it is, Quit
    13.             foreach (KeyValuePair<string, Rect> entry in registeredRects)
    14.             {
    15.                 Rect rect = entry.Value;
    16.  
    17.                 // Invert the Y so 0,0 is in the upper left of the GUI.
    18.                 Vector3 pos = Input.mousePosition;
    19.                 pos.y = Screen.height - pos.y;
    20.  
    21.                 if (rect.Contains(pos))
    22.                 {
    23.                     return true;
    24.                 }
    25.  
    26.             }
    27.  
    28.             return false;
    29.         }
    30.     }
    31.  
    To add items to the dictionary I just do (the above stuff is in a Static class called UI):
    Code (csharp):
    1. UI.registeredRects["MainMenu"] = mainMenuRect
    I can do this from any script which uses a Rect and there is only a need to register the biggest, or outer, Rect.

    Static classes and methods can be called from anywhere without getting a reference because you don't need an instance. You use them directly. They are globally accessible.

    If you aren't sure how to create a static property which returns a Singleton Dictionary, there is a tone of info on the web on this.

    Dictionaries are strongly typed so they are much faster than Hashtables (or so I've read) and you don't have to cast the type when you retrieve stuff. I hope this helps. It certainly took me a lot of effort to figure this out.

    Oh by the way, I originally used an ArrayList, but had to switch to a Dictionary so I could access and overwrite specific items. For example, in cases where a GUI Rect moves based on an object in the scene. In such a case, the Rect position changes and has to be updated in the Dictionary.

    This should all be extremely fast.
     
  8. VCCGeek

    VCCGeek

    Joined:
    Nov 17, 2009
    Posts:
    89
    Don't forget to include the library for the KeyValuePair, and the declaration for the dictionary is thus:

    Code (csharp):
    1.  
    2. using System.Collections.Generic;
    3.  
    4. ...
    5.  
    6. Dictionary<string, Rect> registeredRects = new Dictionary<string, Rect>();
    7.  
    8.  
    if you're using C#. Nice solution!
     
  9. rsx

    rsx

    Joined:
    Nov 4, 2009
    Posts:
    87
    Thanks for catching that!

    Actually I can declare without generics because I specify them in the Dictionary class (custom class). For example...

    Code (csharp):
    1. RegisteredRects registeredRects = new RegisteredRects();
    2. registeredRects["someRect"] = new Rect(0,0, 100, 100)

    Thanks to a community answer I learned how to do this yesterday, so I must share:

    Code (csharp):
    1. /// <description>
    2. ///     A Dictionary to keep track of GUI Rects which should be ignored by the
    3. ///     camera script.
    4. ///    
    5. ///     This class exists to extend Dictionary to impliment a toString
    6. ///     property to help debugging. Also, not generic, but strongly typed.
    7. /// </description>
    8. // Sealed: means this class cannot be inherited, which would risk a second
    9. //      instance
    10. public sealed class RegisteredRects : Dictionary<string, Rect>
    11. {
    12.     #region Custom Properties
    13.     /// <description>
    14.     /// Returns a string representation of this (the array)
    15.     /// </description>
    16.     public string toString
    17.     {
    18.         get
    19.         {
    20.             string output = "";
    21.             foreach (KeyValuePair<string, Rect> entry in this)
    22.             {
    23.                 output += "[" + entry.Key + ":" + entry.Value + "]";
    24.             }
    25.  
    26.             return output;
    27.         }
    28.     }
    29.  
    30.     #endregion
    31.  
    32.  
    33.     #region Override Methods
    34.  
    35.     #endregion
    36. }
    37.  
    The 'sealed' is part of the Singleton pattern. I just Googled C# Singleton and static classes and found all the info I needed. I think I used this one primarily:
    http://msdn.microsoft.com/en-us/library/ff650316.aspx

    I could even put the isMouseOverGUI method in the dictionary I suppose.
     
  10. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664
    I've been looking at solutions to this, and I've got to thank you folks for all the work you've put in to solve something that is essentially a problem (afaict) with Unity.

    That being said, I think I'm going to opt for another solution, and buy my way out of it:
    http://forum.unity3d.com/viewtopic.php?p=328623

    This is the link to the topic on EZ GUI from the maker of SpriteManager2. It's just going to solve this and some other problems and at the current price, I can't justify solving this problem myself.