Author Topic: How to detect if mouse is clicking on NGUI area?  (Read 75233 times)

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #15 on: May 12, 2012, 08:17:53 PM »
Continuous callbacks? NGUI doesn't work like that. If you want it to be continuous, use Input. Just check to see which object has focus to see if you should be processing the events or not.

NewwaveNick

  • Guest
Re: How to detect if mouse is clicking on NGUI area?
« Reply #16 on: June 17, 2012, 02:27:15 AM »
I don't mean to necro-post too badly, but there's something worth contributing to this thread for anyone that comes across it looking for a solution to this problem (like I did recently.)

We ran into this problem ourselves with our game project.  Since the input controller for our game was already well established by the time we decided to investigate NGUI, it was not practical to replace our current working input system with NGUI input handling.

In order to solve the problem of input fall-through, I made sure that all NGUI elements are on the UI layer, and I implemented the following in our game's main input controller:

  1. // This grabs the camera attached to the NGUI UI_Root object.
  2. Camera nguiCam = GameController.Instance.GameUI.NGUI_Manager.GetComponentInChildren<Camera>();
  3.  
  4. if( nguiCam != null )
  5. {
  6.         // pos is the Vector3 representing the screen position of the input
  7.         Ray inputRay = nguiCam.ScreenPointToRay( pos );    
  8.         RaycastHit hit;
  9.  
  10.         if( Physics.Raycast( inputRay.origin, inputRay.direction, out hit, Mathf.Infinity, LayerMask.NameToLayer( "UI" ) ) )
  11.         {
  12.                 // UI was hit, so don't allow this input to fall through to the gameplay input handler
  13.         }
  14. }
  15.  
This solution is really good! I was in the exact same situation where I needed to make minimal impact on an existing project, and this dropped in cleanly. So thank you for contributing this!

However, there's a small bug in the script. Instead of:
LayerMask.NameToLayer( "UI" )

It should be:
1 << LayerMask.NameToLayer( "UI" )

This caused me a bit of headache since it worked at first, but once I added a layer below UI it suddenly broke. Just wanted to note it for anyone reading because it's a good snippet otherwise.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #17 on: June 17, 2012, 06:41:43 PM »
GetComponentInChildren is a slow operation, so using it every frame is a bad idea. UICamera.mainCamera gives you the camera instead.

Casting a ray into the screen is also unnecessary, assuming "pos" is mouse position. UICamera.hoveredObject already tells you what's under the mouse.

NewwaveNick

  • Guest
Re: How to detect if mouse is clicking on NGUI area?
« Reply #18 on: June 20, 2012, 02:40:51 AM »
GetComponentInChildren is a slow operation, so using it every frame is a bad idea. UICamera.mainCamera gives you the camera instead.

Casting a ray into the screen is also unnecessary, assuming "pos" is mouse position. UICamera.hoveredObject already tells you what's under the mouse.
Ah yes, that should have been cached. Now I don't have to though, since you already have it available.

And I definitely did not know about the hover object functionality. Nice! Same basic principal though as the original script. They both will drop into my project rather cleanly.

Rafe

  • Jr. Member
  • **
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 78
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #19 on: July 21, 2012, 02:06:53 AM »
I also have a question as I attempt this. I have at least three scripts on different objects that need to handle events. Are there any delegates I can use? Otherwise it seems like I need a separate gameobject to use as the fall through receiver with a script that exposes static event delegates for my other scripts. WDYT?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #20 on: July 21, 2012, 04:25:52 PM »
The latter. Set up a single object as UICamera.genericEventHandler, and let it be your central point for event distribution. Generic event handler will receive all events, regardless of whether they were handled by the UI or not.

Rafe

  • Jr. Member
  • **
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 78
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #21 on: July 21, 2012, 06:14:18 PM »
I have been mocking up some ideas but I still feel like I am missing some information. I think I have boiled it down to a specific need...

* My GUI camera (2D) will see things that need to be drag-and-drop. It also needs to block all events to the game, so if I click or drag on a button, the game doesn't receive any fall-through input.

* My game camera (3D) is controlled by dragging anywhere in the game. There are a lot of 3D GUI elements that receive clicks, but all drags in-game are for the camera (Our camera script is a special behaviour, so I need my current script.)

I tried to set this up by setting the 3D camera mask to nothing, or deleting it, but in both cases the fall-through hover object is "FallThrough EventHandler". Here is my debug log for the click from the code below:
  1. Clicked FallThrough EventHandler (UnityEngine.GameObject)
  2. UnityEngine.Debug:Log(Object)
  3. UIGameCamera:OnClick() (at Assets/Scripts/UI/UIGameCamera.cs:17)
  4. UnityEngine.GameObject:SendMessage(String, Object, SendMessageOptions)
  5. UICamera:Notify(GameObject, String, Object) (at Assets/NGUI/Scripts/UI/UICamera.cs:517)
  6. UICamera:ProcessTouch(Boolean, Boolean) (at Assets/NGUI/Scripts/UI/UICamera.cs:957)
  7. UICamera:ProcessMouse() (at Assets/NGUI/Scripts/UI/UICamera.cs:761)
  8. UICamera:Update() (at Assets/NGUI/Scripts/UI/UICamera.cs:623)
Here is the simple test class I am using to try this out:
  1. public class UIGameCamera : MonoBehaviour
  2. {
  3.     private void Start()
  4.     {
  5.         UICamera.fallThrough = this.gameObject;
  6.     }
  7.  
  8.     private void OnClick()
  9.     {
  10.         Debug.Log("Clicked " + UICamera.hoveredObject);
  11.     }
  12.  
  13.     private void OnDrag(Vector2 delta)
  14.     {
  15.         Debug.Log("Dragging Camera");
  16.     }
  17. }

If I could get the object that is clicked, this would be done. If I am not doing anything wrong, and I need to do a quick raycast, that is fine. I just want to know I am following nGUI methodology and not trying to fight it.

Thanks a lot!


P.S. I bought through the Unity store because I didn't have anything in our PayPal account and the current free version isn't the latest version. I would have liked to buy direct.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #22 on: July 21, 2012, 08:27:08 PM »
Assuming your event mask on the UICamera is set up correctly, all the objects seen by that camera will be receiving events (and will intercept them so they don't end up on the fallThrough object).

Rafe

  • Jr. Member
  • **
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 78
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #23 on: July 22, 2012, 02:33:50 AM »
The issue is that the hover object is always the fall-through game object, and not the gameObject that is visible under the mouse. It seems like I have a couple of choices:

1) Use UICamera on all cameras. In this case there is no fall-through, but the hover-object is always good, so I would have to check the hover object's layer against the 2D camera layer to see if it is a 2D GUI hit or a 3D game camera hit

2) I can use a UICamera on just the 2D camera. Fall-through now works, but the hover object is always this hidden fall-through gameObject, not any of my objects, so I would have to use the nGUI pos to do a ray cast and see what gets hit.

I'm going with #2 since I already have the code to do this from the old system. I am interested if I am missing something here though.
« Last Edit: July 22, 2012, 02:54:37 AM by Rafe »

Rafe

  • Jr. Member
  • **
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 78
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #24 on: July 22, 2012, 03:10:04 AM »
...continuing from my last post, I have it nearly working. The issue I am having is that OnClick is being called 'on mouse up' no matter what. I can click anywhere, drag around and OnClick is called when I let go.

  1. public class UIGameCamera : MonoBehaviour
  2. {
  3.     public LayerMask layers;
  4.     public bool debug = false;
  5.  
  6.     private Camera gameCam;
  7.  
  8.     private void Start()
  9.     {
  10.         this.gameCam = this.GetComponent<Camera>();
  11.         UICamera.fallThrough = this.gameObject;
  12.     }
  13.  
  14.     private void OnClick()
  15.     {        
  16.         // Can't select anything when the game is paused
  17.         if (Time.timeScale == 0) return;
  18.  
  19.         Ray ray = this.gameCam.ScreenPointToRay(UICamera.currentTouch.pos);
  20.         RaycastHit hit;
  21.         if (!Physics.Raycast(ray, out hit, Mathf.Infinity, this.layers))
  22.         {
  23.             Debug.Log("Nothing Clicked");
  24.             return;
  25.         }
  26.  
  27.         // Cache the transform of the object hit
  28.         Transform hitXform = hit.collider.transform;
  29.  
  30.         Debug.Log("Clicked " + hitXform.name);
  31.     }
  32.  
  33.     private void OnDrag(Vector2 delta)
  34.     {
  35.         Debug.Log("Dragging Camera");
  36.     }
  37. }
  38.  

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #25 on: July 22, 2012, 01:54:48 PM »
"hover object is always the fall-through game object" that makes no sense to me. Did you mean that in reverse?

Generally when dragging you should disable the collider of whatever you started dragging, or it will be intercepting events. Also when you can always modify UICamera.currentTouch.pressed game object to be something else, and that something else will receive your OnClick instead.

Rafe

  • Jr. Member
  • **
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 78
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #26 on: July 22, 2012, 02:05:33 PM »
"hover object is always the fall-through game object" that makes no sense to me. Did you mean that in reverse?

I mean that whatever GameObject is set to UICamera.fallThrough is always returned by UICamera.hoveredObject when an event "falls through". I was hoping that UICamera.hoveredObject would always be the collider (GameObject) under the mouse. UICamera.fallThrough is already recieving the events. Having UICamera.hoveredObject returning the same thing isn't helpful (maybe it is helpful to non-fall-through recievers, but I thought I read earlier in this thread that you recommended UICamera.hoveredObject for the situation I am working with?)

Generally when dragging you should disable the collider of whatever you started dragging, or it will be intercepting events.

I am not dragging an object, I am dragging the mouse. The me explain better.... The OnClick() event is getting sent On-mouse-up no matter what. If I click and let go, I get the object that was clicked as expected. if I click, then drag the mouse over another collider, then let go, the new collider is returned. A click event should be interrupted, and not sent, when a drag event occurs after mouse-down, right?


Also when you can always modify UICamera.currentTouch.pressed game object to be something else, and that something else will receive your OnClick instead.

Cool trick, thanks!
« Last Edit: July 22, 2012, 02:07:29 PM by Rafe »

Rafe

  • Jr. Member
  • **
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 78
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #27 on: July 24, 2012, 02:54:36 AM »
I figured out the problem I was having with OnClick always being fired even after a drag. The real object being hit for fall-through is  UICamera.hoveredObject. So clicking, then dragging anywhere in the fall-through area, and then letting go, is technically releasing on the same UICamera.hoveredObject. I added my own bool to figure out if there was a drag.

While I'm happy this is taking less code than my old version, it had a steep learning curve that could be removed by giving me a hook in to what is a GUI vs non-GUI hit. Everything has been so easy except for sorting out these events...just my opinion of course.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #28 on: July 24, 2012, 03:05:59 AM »
No need for a boolean value. You can simply set:
  1. UICamera.currentTouch.clickNotification = UICamera.ClickNotification.None;
...when you start your dragging process.

pretender

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 155
    • View Profile
Re: How to detect if mouse is clicking on NGUI area?
« Reply #29 on: September 27, 2012, 09:40:40 AM »
i did this and it works, is it that easy?

  1. void OnTapHandler(Vector2 pos)
  2. {
  3.    if(UICamera.hoveredObject == null)
  4.    {
  5.         //...tap handler code
  6.    }
  7.  
  8.  

i have few places where i can check this, mostly in events, so no every update loop, is there any drawbacks in doing it this way?
thanks!