Tasharen Entertainment Forum

Support => NGUI 3 Support => Topic started by: Excal on May 05, 2014, 08:44:16 PM

Title: Detecting hits in NGUI
Post by: Excal on May 05, 2014, 08:44:16 PM
I'm still new to NGUI, so please bear with me.

I have a separate scene with a basic UI set up. This scene is additively loaded into my game scene to display the UI. My game prototype is an RTS, and I use raytracing to determing when the user has clicked an object in the game. With immediate mode UI, I would have to write a function to check whether the user has clicked within the UI boundaries (a box with height 200px at the bottom of the screen). Do I do anything different with NGUI? How do I determine if the player has clicked within an NGUI element, even if that element doesn't have a click-based trigger, such as a HUD overlay?
Title: Re: Detecting hits in NGUI
Post by: ArenMook on May 05, 2014, 11:58:11 PM
1. Don't do your own raycasts. NGUI will do raycasts for you if you put a UICamera on the camera that sees the objects.
2. With #1 in place, UICamera.hoveredObject tells you what's underneath the mouse at any given time. It can be a UI element or a 3D object -- whatever is on top. Events will automatically go to the top-most element, so if you have a widget covering the 3D object, and the widget has a collider, it will intercept events from going to the 3D object.
Title: Re: Detecting hits in NGUI
Post by: Excal on May 06, 2014, 12:24:38 AM
Ah, thank you so much for the clarification. Not having to code the raycasting manually is awesome. However, I'm not sure how I should be using UICamera.hoverObject:

(http://i.imgur.com/yAFp76I.png)

This shouldn't resort to null.

  1. void Update () {
  2.                 if(OurPlayer.IsHuman) {
  3.                         MouseActivity();
  4.                 }
  5.         }

MouseActivity checks for left or right mouse click. In left mouse click, which is the only action I've taken in the image above:

  1. private void LeftMouseClick() {
  2.                 Debug.Log (UICamera.hoveredObject);
  3.                 if (UICamera.hoveredObject != null)
  4.                         OurPlayer.SelectedObject = UICamera.hoveredObject.GetComponent<WorldObject>();
  5. }

But UICamera.hoveredObject always equals null no matter how many times I click the tank, which is named 'Tank'. In some older posts, I see you recommend switching entirely to NGUI's event system, but I'm not quite sure what I should be doing to grab game objects that aren't part of the UI.
Title: Re: Detecting hits in NGUI
Post by: Nicki on May 06, 2014, 07:38:16 AM
NGUI will give you not null, if the collider you try to hit is in the UICamera's EventMask. But generally, you'd want to have a component on object you want to hit, that has OnClick, OnPress, OnHover etc in it, which will be called automatically by the event system.
Title: Re: Detecting hits in NGUI
Post by: Excal on May 06, 2014, 03:25:17 PM
Do you mean OnMouseDown instead of OnClick?
Title: Re: Detecting hits in NGUI
Post by: ArenMook on May 06, 2014, 10:00:38 PM
No. OnMouseDown is a Unity event. OnPress / OnClick etc is an NGUI event. Check the documentation page for the UICamera. It has a list of all the events NGUI sends out.
Title: Re: Detecting hits in NGUI
Post by: Excal on May 07, 2014, 01:31:48 AM
Suppose the camera that is on my UI layer has a UICamera script. If I also want to be able to click game objects, should I add a UICamera script to my main camera as well? I'm having a bit of trouble wrapping my head around how to prevent a user from clicking a game object "underneath" my UI overlay.

I'm also a bit unsure as to how I should be using OnSelect (using it over OnPress since I want to support drag-select later on). I've attached a UICamera script to my Main Camera and set the Event Type to 'World'.

Each object in my game has a Unit.cs script with the following function:

  1.         void OnSelect(bool selected)
  2.         {
  3.                 if (selected)
  4.                 {
  5.                         Debug.Log (UICamera.selectedObject);
  6.                         OurPlayer.SelectedObject = UICamera.selectedObject.GetComponent<WorldObject>();
  7.                 }
  8.         }

My debug log never shows anything, however. Is there something I'm missing here?
Title: Re: Detecting hits in NGUI
Post by: Excal on May 07, 2014, 06:08:41 PM
NGUI will give you not null, if the collider you try to hit is in the UICamera's EventMask. But generally, you'd want to have a component on object you want to hit, that has OnClick, OnPress, OnHover etc in it, which will be called automatically by the event system.

This isn't working for me. Either that, or I'm not sure what I'm doing wrong. I have a UICamera script attached to my main camera, with Event Type set to 'World'. I also have a UICamera script attached to my UI camera on a separate layer called 'UI'. Every object in my game has a script called 'Unit.cs' with a void OnSelect function. Right now all that OnSelect function is print something to the debug log. However, when I click an object, nothing shows up in the console. Am I missing something here?

EDIT: Someone else has told me that I can only use the NGUI event system with NGUI widgets, and not objects in my game world. Is this true?
Title: Re: Detecting hits in NGUI
Post by: ArenMook on May 08, 2014, 02:34:25 AM
You can use it with any object that has a collider. Either 2D or 3D.

When putting a UICamera script on your main camera, be sure to use "World" event type, not "UI" (which you've done) and that the event mask includes the layer of the object you're trying to interact with.

OnSelect is sent to each object only once. Repeated clicks on the same object won't result in a new OnSelect. Clicking away will get OnSelect(false) before the new object gets OnSelect(true).

P.S. Character inventory example has the 3D character respond to events using this method. Drag & drop example does too with the cube.
Title: Re: Detecting hits in NGUI
Post by: Excal on May 08, 2014, 06:58:35 AM
I think I've finally figured out what's up, but I still need some help getting things right.

It turns out my UICamera events are firing from my UI camera and not my main camera. How do I change it so that the UICamera events fire from my main camera, which has Event Type set to World and Culling Mask = Everything, instead of my Camera that's on my UI layer?
Title: Re: Detecting hits in NGUI
Post by: ArenMook on May 09, 2014, 05:06:52 AM
Make sure that each layer can only be seen by one camera, not both (adjust the culling mask).
Title: Re: Detecting hits in NGUI
Post by: Excal on May 09, 2014, 06:01:19 AM
I adjusted both culling masks. My main camera can see everything but the UI, while my UI camera can only see the UI. I'm still not getting any hits unless I enable the UI camera to see everything, and then I am only getting OnSelect() returns from objects seen by this camera.
Title: Re: Detecting hits in NGUI
Post by: ArenMook on May 09, 2014, 06:16:23 AM
Well, did you actually attach UICamera to the main camera as well? Events won't work without it.
Title: Re: Detecting hits in NGUI
Post by: Excal on May 09, 2014, 06:23:30 AM
Yes, the problem is that both cameras have UICamera script attached, but it seems like both cameras have to be seeing something for OnSelect() to fire.
Title: Re: Detecting hits in NGUI
Post by: ArenMook on May 09, 2014, 06:43:03 AM
Both have to be seeing something? Not sure what you mean. You can try attaching this script to a plain game object for debugging:
  1. using UnityEngine;
  2.  
  3. public class Test : MonoBehaviour
  4. {
  5.     void Start()
  6.     {
  7.         UICamera.genericEventHandler = gameObject;
  8.     }
  9.  
  10.     void OnSelect (bool isSelected)
  11.     {
  12.         if (isSelected) Debug.Log("Selected " + UICamera.selectedObject.name);
  13.         else Debug.Log("Deselected");
  14.     }
  15. }
Title: Re: Detecting hits in NGUI
Post by: Excal on May 09, 2014, 07:35:31 AM
Your example works perfectly. Do I need to have this line:

  1. UICamera.genericEventHandler = gameObject;

in the Start() of all my objects?
Title: Re: Detecting hits in NGUI
Post by: ArenMook on May 09, 2014, 08:49:12 PM
No... there can be only one generic event handler. It means that the object you're choosing is going to get a copy of all the events that NGUI sends out. I meant that script as a tool for debugging, to see which object is getting the event. If you are seeing the correct object come up, then the collider you're selecting should already be getting the same exact event. You can also enable "Debug" on the UICamera to see what NGUI is hovering over.
Title: Re: Detecting hits in NGUI
Post by: Excal on May 09, 2014, 09:02:06 PM
If I remove that line, nothing seems to show up as a selected object for me. In debug mode, I see feedback indicating the raycasts are hitting things. However, this line of code is in every object and my debug log constantly shows null:

  1.         void OnSelect(bool isSelected)
  2.         {
  3.                 if (isSelected)
  4.                 {
  5.                         Debug.Log("Selected " + UICamera.selectedObject.transform.root.name);
  6.                 }
  7.                 else Debug.Log("Deselected");
  8.         }
Title: Re: Detecting hits in NGUI
Post by: ArenMook on May 09, 2014, 11:36:27 PM
There is no magic here. If the Debug mode shows you hovering over objects, those objects will receive events. You can try using simple functions like "void OnClick () { Debug.Log("Clicked!"); }" as well. Remember, Select event is only sent out once. Repeated clicks on the same object won't send a Select event.

Also not sure why "UICamera.selectedObject.transform.root.name" is there. If this function is on a script attached to the object with a collider, then Debug.Log("Selected " + name); is enough.
Title: Re: Detecting hits in NGUI
Post by: Excal on May 10, 2014, 01:18:34 AM
I have several objects that combine to create a single object. For example, two cubes that represent the first floor and second floor of a building. These are parented to a single game object that has the name of the object as a whole, such as 'building'.
Title: Re: Detecting hits in NGUI
Post by: ArenMook on May 10, 2014, 01:33:58 AM
Well, the event will go to the object with the collider on it.
Title: Re: Detecting hits in NGUI
Post by: Excal on May 10, 2014, 02:07:55 AM
Should I remove the colliders for the individual objects that make up the overall object and just have a single collider? When I click, I get stuff like 'floor1' and 'floor2' when both are part of 'building', even though 'building' also has a collider on it.
Title: Re: Detecting hits in NGUI
Post by: ArenMook on May 10, 2014, 11:53:10 PM
That, or have a script on the "floor" that would do something else, like select the building.