Search Unity

Raycast into GUI?

Discussion in 'UGUI & TextMesh Pro' started by iossif, Aug 20, 2014.

  1. iossif

    iossif

    Joined:
    Mar 4, 2011
    Posts:
    332
    when i used ngui, i used raycasts a lot to detect what gui elements are "under" my mouse.
    how can i do that with the new gui system since there is no camera i can shoot my raycast at?

    thanks for your help!
     
    vexe likes this.
  2. quitebuttery

    quitebuttery

    Joined:
    Mar 12, 2011
    Posts:
    329
    Right now I'm using a World Space Canvas and attached colliders to the GUI objects (a single button, for now) I want to hit with a raycast. It works. But now I can't figure out how to use the Event system to broadcast selection events etc. to the UI system. Keeps freaking out over wrong type of the object I'm passing to it.
     
    TwinCrows likes this.
  3. User340

    User340

    Joined:
    Feb 28, 2007
    Posts:
    3,001
    For 3D colliders attach the PhysicsRaycaster to your camera. This will then allow the objects (cubes, spheres, etc..) to receive events such as OnDrag, OnPointerDown, and all the rest.
     
  4. iossif

    iossif

    Joined:
    Mar 4, 2011
    Posts:
    332
    i do not want 3d colliders. i just want to detect if there is for example a button under my mousecursor. i added 2d boxcolliders to my gui items and the physics 2draycaster to my camera but my raycasthits stay empty.
     
  5. elbows

    elbows

    Joined:
    Nov 28, 2009
    Posts:
    2,502
    I've only been poking at the 4.6 beta for a few minutes but it might be worth trying to add, for that scenario, an Event trigger component to the UI button, then click its 'add new' button, and choose 'Pointer Enter'. Then click the plus to decide what you want to communicate with when that event is triggered.

    I can't say I've actually done anything with the new Event components yet but thats my initial hunch.

    edit - tried it quickly and it worked as I expected, yay.
     
    Last edited: Aug 20, 2014
  6. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    You want to call: IsPointerOverEventSystemObject on the Event system. It will return true if the cursor is over an event system object.
     
    Crimx likes this.
  7. mavasher

    mavasher

    Joined:
    Nov 20, 2013
    Posts:
    13
    I would still like to know how to do this with a Raycast. I am using a different input method that doesn't use a mouse but I have screen coordinates and I want to be able to call "highlight" or "pressed" events on buttons that are raycast from those screen coordinates.
     
  8. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
  9. mavasher

    mavasher

    Joined:
    Nov 20, 2013
    Posts:
    13
    Thanks so much for the reply. It's unclear to me when the functions in the pointer module are getting called (e.g. GetMousePointerEventData(), GetTouchPointerEventData(Touch input, out bool pressed, out bool released)) Presumably to write a custom InputModule I'd need to have these functions registered/called somehow.
     
  10. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    Well you don't need to call them, you just need to create a valid event data (they are mostly helper functions). So for example you need to populate one with the delta and other data since last frame. We do it like this:

    Code (csharp):
    1.  
    2.         protected virtual PointerEventData GetMousePointerEventData()
    3.         {
    4.             PointerEventData pointerData;
    5.             var created = GetPointerData (kMouseId, out pointerData, true);
    6.  
    7.             pointerData.Reset ();
    8.  
    9.             if (created)
    10.                 pointerData.position = Input.mousePosition;
    11.  
    12.             Vector2 pos = Input.mousePosition;
    13.             pointerData.delta = pos - pointerData.position;
    14.             pointerData.position = pos;
    15.  
    16.             eventSystem.RaycastAll (pointerData, m_RaycastResultCache);
    17.             var raycast = FindFirstRaycast (m_RaycastResultCache);
    18.             pointerData.pointerCurrentRaycast = raycast;
    19.             m_RaycastResultCache.Clear ();
    20.             return pointerData;
    21.         }
    22.  
    So we just create a PointerData, and populate it with position and delta then use it for a raycast. What you want to do is the same but instead of using a mouse use your screen point. You may not even need / supoort delta, but you could do it if you wanted.
     
  11. AntFitch

    AntFitch

    Joined:
    Jan 31, 2012
    Posts:
    243
    I'm still pretty confused about how to do what the original poster requested. With NGUI, I used RaycastAll to get an array of hits under my mouse. With the new UI, I cannot seem to do this. I've looked over this thread and many more, but I'm just not getting it.

    In NGUI, this is what I use to get all game objects under the mouse:
    Code (CSharp):
    1. int layer = 1 << 15;
    2. Ray myray = UICamera.currentCamera.ScreenPointToRay(Input.mousePosition);
    3. RaycastHit[] hits = Physics.RaycastAll(myray, 1000.0f, layer);
    Tim, I see the links to the two scripts and the sample above, but I'm not sure how to actually implement these. Are the two scripts functionality that is coming in a future version of 4.6?
     
    AndrewGrayGames likes this.
  12. katoun

    katoun

    Joined:
    Dec 26, 2012
    Posts:
    91
    It is already in 4.6. It's the source code of the TouchInputModule and StandaloneInputModule that are found on the "EventSystem" game object that gets created when you first create the uGUI in your scene. Those classes coupled with EventSystem script is responsible for the event handling of the uGUI.
     
    AntFitch likes this.
  13. AntFitch

    AntFitch

    Joined:
    Jan 31, 2012
    Posts:
    243
    Okay, thanks! I almost have everything set up, but I'm getting an error. Here is my code. When I call RaycastMouse from another class, the debugger throws a System.NullReferenceExeption when it hits the line with GetMousePointerEventData. (I've not added a return value yet)

    Code (CSharp):
    1. internal class MyPointerInputModule : PointerInputModule
    2. {
    3.     public override void Process()
    4.     {
    5.     }
    6.  
    7.     public void RaycastMouse()
    8.     {
    9.         PointerEventData ped = GetMousePointerEventData(); // I get a System.NullReferenceExeption here
    10.      
    11.         eventSystem.RaycastAll(ped, m_RaycastResultCache);
    12.         List<RaycastResult> results = m_RaycastResultCache;
    13.     }
    14. }
     
  14. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    Well you would be getting the error somewhere inside that function.... Do you have a stack trace?
     
  15. Tiberius1701

    Tiberius1701

    Joined:
    Sep 16, 2014
    Posts:
    71
    Btw, I created a very simple C# script that does test for mouse over using the event system, and it works great on my Mac, but when I export to an iOS device, it doesn't...seems like a bug somewhere in the software.

    Here is the script:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.EventSystems;
    4.  
    5. public class touchTest : MonoBehaviour {
    6.  
    7.     public int overUI = 0;
    8.  
    9.  
    10.     public int ReturnUIState (){
    11.         return overUI;
    12.     }
    13.  
    14.     void Update () {
    15.         if (EventSystemManager.currentSystem.IsPointerOverEventSystemObject ()) {
    16.             // we're over a UI element... return 1
    17.             overUI = 1;
    18.             }
    19.         else{
    20.                 overUI = 0;
    21.             }
    22.     }
    23. }
     
    Crimx and laryk_ua like this.
  16. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    Ah! That's because the function takes an Id for which pointer. 1 is first finger, 2 is second finger ect. By default if you don't specify an argument it uses the mouse left click id (-1)
     
    laryk_ua likes this.
  17. erictang

    erictang

    Joined:
    Jul 28, 2012
    Posts:
    15
    How to determine a non-rectangular button click event accurately
     
  18. laryk_ua

    laryk_ua

    Joined:
    Jul 26, 2014
    Posts:
    9
    That is work! Thanks so much.
     
  19. Foxxis

    Foxxis

    Joined:
    Jun 27, 2006
    Posts:
    1,108
    That code appears to be obsolete, or am I doing something wrong?
    http://forum.unity3d.com/threads/standalone-input-module-sources.273066/#post-1839473
     
  20. DarkAnvil

    DarkAnvil

    Joined:
    Jun 7, 2014
    Posts:
    102
    Hi,

    I need to do the same, a simple raycast to know the Rect Transform based on a position in the screen.

    Does anyone have a simple code to do this?

    I am horrified to see that such a simple thing is so complicated to do. I asked more and more questions about the new GUI...

    I hope that the documentation will be more explicit in the official release, with examples ...
     
    Jroel and vexe like this.
  21. DarkAnvil

    DarkAnvil

    Joined:
    Jun 7, 2014
    Posts:
    102
    Hi,

    I finally succeeded with the information provided by Tim C in this post.

    But it might be interesting to have a simple method to obtain a PointerEventData

    my script
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.EventSystems;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class Mypointer : PointerInputModule{
    7.  
    8.     public override void Process()
    9.     {
    10.     }
    11.    
    12.     public List<RaycastResult> RaycastMouse(){
    13.  
    14.         PointerEventData pointerData = null;
    15.  
    16.         if (!m_PointerData.TryGetValue (-1, out pointerData) ){
    17.             pointerData = new PointerEventData (eventSystem)
    18.             {
    19.                 pointerId = -1,
    20.             };
    21.             m_PointerData.Add (-1, pointerData);
    22.            
    23.         }
    24.  
    25.         pointerData.position = Input.mousePosition;
    26.  
    27.         eventSystem.RaycastAll(pointerData, m_RaycastResultCache);
    28.         List<RaycastResult> results = m_RaycastResultCache;
    29.            
    30.         Debug.Log( results.Count);
    31.  
    32.         return results;
    33.     }
    34. }
     
  22. Marcellus_Wilson

    Marcellus_Wilson

    Joined:
    Jul 19, 2013
    Posts:
    12
    I am trying to do this same thing. I want to hit a new UI button with a raycast. I am using Java, and I have no idea what you guys are talking about. I would request unity add that to the UI. Beside that I would also love some explanation of this work around in java. Just a little more breakdown I not understanding how to really get started with this problem as I have only done java. Any help would be greatly appreciated.
     
  23. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Just wanted to share what worked for me in my case, where I had an item and an inventory and I needed to cast a ray from the item to the slots in the inventory to determine if it fits or not, here's the question with the answer http://forum.unity3d.com/threads/raycast-towards-ui-elements.284264/ - I just needed eventSystem.RaycastAll(pointer, results) where pointer is a PointerEventData with its position set to where you want to raycast from.
     
    Marcellus_Wilson likes this.
  24. Marcellus_Wilson

    Marcellus_Wilson

    Joined:
    Jul 19, 2013
    Posts:
    12
    Perfect!! Thanks a lot vexe, got it.
     
  25. Galactic_Muffin

    Galactic_Muffin

    Joined:
    Aug 14, 2013
    Posts:
    67
    You need to read the post throughly before wasting time writing a insultingly basic answer that you assume is the thing everyone is looking for.

    We are asking if there is a way to use ray-casts to select UI elements. Not 3D objects in the scene. A reason we may want this is to support such functionality as Multi-touch which UnityEngine.EventSystems does not support to my knowledge.
     
    Lord-Megabite likes this.
  26. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @Galactic_Muffin

    Hi, IMHO, I don't think raycasting to select UI elements has that much to do with having or not having multi touch. You can also get both:

    You can iterate through list of UI images or buttons you get with eventSystem.RaycastAll, and get the suitable object from there, if it matched your item.

    For touch, you can also iterate through Input.touches, and if you find suitable, you can deal with it.
     
  27. eelstork

    eelstork

    Joined:
    Jun 15, 2014
    Posts:
    221
    Sorry to resurrect an old thread as I am just wondering if any simplification to the above is now available?

    In reply to @eses raycasting to select UI elements does not have anything to do with multi-touch per se. The reason people bump into this when they are dealing with multitouch is that the first step towards correct multi-touch support involves disabling mouse pointer emulation:

    Input.simulateMouseWithTouches = false

    What happens then in my experience is a Button won't even respond to a tap.
    So, developers are unwittingly exposed to a mix of low level and/or sophisticated APIs. Compared to what? Compared to, say, associating a handler with a Button which with a mouse (or mouse emulation aka single touch) does not even require programming.

    It would be nice if simple things (such as rect transforms being tapped/clicked and generating related events) were handled consistently, with or without mouse emulation.