Tasharen Entertainment Forum

Support => NGUI 3 Documentation => Topic started by: ArenMook on November 21, 2013, 12:21:48 AM

Title: UICamera
Post by: ArenMook on November 21, 2013, 12:21:48 AM
Overview

UICamera is a somewhat poorly named component. In fact, its name is kept only for backwards compatibility purposes.

What the UICamera script actually does is sends out NGUI events to all the objects seen by the camera it's attached to. It doesn't have to have anything to do with UI though. In fact, if you wish to receive NGUI events on your in-game objects such as OnPress, OnClick, OnDrag etc, then all you need to do is attach the UICamera script to your main camera.

You can have several UICamera scripts in the scene. Most games will have one on the camera that draws the widgets, and another on the camera that draws the game.

NOTE: For UICamera to work, "Raycasts Hit Triggers" must be checked in the Physics settings.

(http://www.tasharen.com/ngui/uicamera1.jpg)   (http://www.tasharen.com/ngui/hierarchy.jpg)

The first option on the UICamera, Event Type is what determines how the script sorts whats underneath the mouse and touch events. If it's set to UI mode, then it's always based on widget's depth -- just like the draw order. Changing this option to World mode is something you should do if your UICamera is attached to your Main Camera. Doing so will sort the hit objects by their distance to the camera.

Event Mask is what determines which game object layers will be capable of receiving events. In most cases you can leave this on "Everything", as this value is combined with the UnityEngine.Camera's Culling Mask, but you can fine-tune it if you wish. If you ever change the Layer of your game object containing the UI hierarchy, make sure to adjust the Event Mask or you will suddenly find your UI no longer responding to events.

Debug option can be used to debug what's currently under the mouse. If you can't figure out what's intercepting mouse events when you click on some button, just turn on this option and you will be able to see it in the top-right corner.

Allow Multi-Touch option controls whether multiple touches will be supported. If turned off, multiple touches will all be treated as a single touch.

Sticky Tooltip option fine-tunes the tooltip behaviour. If off, the tooltip will hide as soon as the mouse moves again. If on, the tooltip will remain open while the mouse is over the same object.

Tooltip Delay controls the delay between the mouse stopping movement over some object and the OnTooltip notification being sent to that object. This value is in seconds.

Raycast Range controls the length of the raycast, and in most cases this value can be safely ignored. This value is in world units, so if your camera has the near clip of 0.3 and far clipping of 1000, you and you are finding that some far-away objects are not responding to clicks, set this value to something like 2000 (something greater than the difference between your camera's far and near clipping planes).

(http://www.tasharen.com/ngui/uicamera2.jpg)

Event Sources section controls what kind of event types will be processed. If one of the options is turned off, those events will no longer be processed. Some platforms force-disable specific events under the hood. For example targeting consoles will automatically turn off mouse and touch events.

(http://www.tasharen.com/ngui/uicamera3.jpg)

Thresholds section lets you fine-tune how the mouse and touch events behave by tweaking the thresholds of click, drag and tap events. These values are in pixels.

(http://www.tasharen.com/ngui/uicamera4.jpg)

Axes and Keys section lets you choose which axes result in which movement. These axes should match the names in your project's Input Manager (http://docs.unity3d.com/Documentation/Components/class-InputManager.html). The "Pan" axes are used for scrolling and adjusting elements like sliders. Generally using a 360 controller you would set the left thumbstick to be the "Navigate" and right thumbstick to be "Pan". This will let you navigate the UI with the left thumbstick and interact with UI elements like sliders, scroll bars and scroll views using the right thumbstick.

Pro-Tip #1

UICamera sends out the following events to colliders:

To tap into them in your own custom scripts, simply create a script with the appropriate function, such as:
  1. void OnPress (bool isPressed)
  2. {
  3.     if (isPressed) Debug.Log("I was pressed on!");
  4.     else Debug.Log("I was unpressed");
  5. }

Pro-Tip #2

You can subscribe to events from any script using delegates: UICamera.onClick, UICamera.onHover, etc. These delegates will be called just before the actual notification gets sent to the proper object. You can use this functionality to listen in for events on a script regardless of whether they would be going to that script's game object or not.

Class Documentation

http://tasharen.com/ngui/docs/class_u_i_camera.html

If you have a question regarding this component or would like me to clarify something, just post a reply here.
Title: Re: UICamera
Post by: wwwise on December 04, 2013, 05:13:27 AM
There is issue of the onScreenResize delegate in UICamera...
The UICamera checks the screen size every frame update,but it's not good enough.
For example if I resize the player screen continuously, the screen size will change more than once in a frame update.
Here's the problem:In a frame update,the onScreenResize delegate was triggered once while the screen resize several times,some script(UIAnchor,UIStretch) who subscribed this delegate only get the size when the first time the screen changed,not the latest size.
So the UIAnchor or UIStretch would not get the newest,the right Screen.size when handle onScreenResize. (The UIAnchor or UIStretch with "Run Only Once" checked.)

My suggestion is:When the screen size changed, invoke the onScreenResize delegate at the end of frame or next frame.
Title: Re: UICamera
Post by: ArenMook on December 04, 2013, 05:34:40 PM
If you are resizing the screen so frequently, write a custom tiny script that would be doing just that. At the end of the frame, or in LateUpdate, or in a coroutine, wherever you need it, call UICamera.onScreenResize(). It's public and static.
Title: Re: UICamera
Post by: sintua on January 20, 2014, 05:39:27 PM
I have a clunk 'schedule' system that lets my various classes trigger after so much time, but is there a way to use NGUI's existing comprehensive event system for such things? I saw an example of using the event system somewhere but I can't seem to find it again (most of the links just point to very outdated posts), and this is the closest thing I can find to mentioning them at all, but it says nothing about how to use the event system to add or remove your own timers/delegates/etc.
Title: Re: UICamera
Post by: ArenMook on January 21, 2014, 04:10:15 AM
There is really nothing to it. If you have a widget (or an object) with a collider, then it's capable of receiving events, provided its layer matches UICamera's event mask. If you are to then add a script with any NGUI event function such as "void OnClick ()", then your script will be receiving those events.

If you want to listen to events on a remote object, use UIEventListener.Get(targetGameObject).onClick += MyClickFunction;
Title: Re: UICamera
Post by: kromenak on January 21, 2014, 02:44:15 PM
When using the "UI" mode, how do you handle the depths of colliders that are not attached to widgets?  For example, I have some colliders that are not attached to any sort of widget, but that handle UI events - there seems to be no way to set the depth value so that they are correctly sorted.

I see that I can add a UIWidget component and that seems to fix the problem.  Is that the recommended way to resolve this sort of problem?
Title: Re: UICamera
Post by: ArenMook on January 21, 2014, 09:00:28 PM
Colliders that are not attached to widgets use the depth of their child widgets instead. I advise always using a widget for clarity as it's faster. UIWidget is invisible, and gives you a rect to work with.
Title: Re: UICamera
Post by: Lautaro on February 11, 2014, 04:54:37 PM
Hi! Am trying to move a widget half of its sprite width. Its 70pixels. But it goes way of the gui screen. How do i convert the width to width-on-guiScreen?
Title: Re: UICamera
Post by: ArenMook on February 11, 2014, 09:11:23 PM
I'm guessing you are modifying its transform.position -- which is in world coordinates.

You need to adjust its transform.localPosition.
Title: Re: UICamera
Post by: Lautaro on February 13, 2014, 05:30:02 AM
Ah i see. Which can only be done programatically?
Maybe i have missed a tutorial of some sort?
Title: Re: UICamera
Post by: ArenMook on February 14, 2014, 06:12:24 AM
Tweens work as well, and they don't require any coding. How are you doing it now?
Title: Re: UICamera
Post by: Lautaro on February 14, 2014, 12:26:50 PM
Its ok, ill do it programmatically. Thanks! :D
Title: Re: UICamera
Post by: helmesjo on April 07, 2014, 03:56:53 AM
Just noticed that when onScreenResize is invoked, I get a few miscalculations on UIRect (really not sure exactly where, GetSides maybe. Don't have the time to trace it now, just a heads up).
To make sure everything was setup before the event was sent, I added a flag (screenResized), and checked it in LateUpdate() instead (and then invoked onScreenResize from there). This worked as expected, so you might consider investigating it sometime since I get a feeling this can easily create random bugs/spam in the forum.

Cheers!
Title: Re: UICamera
Post by: Trance_Trap on May 12, 2014, 07:24:49 AM
How can we get an array or list of objects UICamera's raycast has hit? From the very first object it hits to the very last? Or does the raycast stop at the very first object it hits? Presuming all objects have colliders. And for all 3 event types.

I've attached the UICamera event system to my 3D scene in addition to the GUI and I think this would be useful.
Title: Re: UICamera
Post by: ArenMook on May 12, 2014, 02:20:02 PM
There is no single list of objects because each camera does its own raycast, and if one camera finds an object that intercepts it, the next camera won't need to perform it. If you need a full list, just do your own raycast after the fact.
Title: Re: UICamera
Post by: Fractalbase on June 16, 2014, 09:16:41 PM
I have an issue where I have a gameobject programmatically render my graphics, and those are viewed by the main camera created with the scene.  now with ngui in the picture, it seems that both main camera and ui camera are drawing my game graphics.  I tried one work around where I made the position of uiroot to be 3000,3000,0.  Is there a better way?
Title: Re: UICamera
Post by: ArenMook on June 17, 2014, 02:15:09 PM
Yes. Adjust the culling mask on each of your camera. Main camera should not be drawing the UI, and UI camera should not be drawing the world.
Title: Re: UICamera
Post by: savely00 on July 03, 2014, 01:55:17 PM
I am using NGUI for the first time on my project and I ran into a click transparency issue.
I am using a Main Camera for the 3D world and NGUI UICamera for 2D dialogs and the title bar and menus. When I click a button on my dialog, click is also propagated to 3D objects of the scene.
Is there a way to disable this behavior? I'd like the top most dialog to process and absorb the click without further propagation to dialogs underneath and to any 3D objects in the scene.
Title: Re: UICamera
Post by: ArenMook on July 04, 2014, 03:01:13 PM
The only way to stop it is to use NGUI events for both. You are likely doing your own Input.GetButton or similar checks, and that's querying Unity, not NGUI. You're bypassing NGUI. You need to attach UICamera to your main camera as well, and listen to NGUI events instead like OnPress, OnClick, etc.
Title: Re: UICamera
Post by: wwwise on September 02, 2014, 10:32:17 PM
Problems with generic delegates(UICamera.onDrag,UICamera.onScroll,etc.).
Since I update the NGUI to 3.7.1 , there are new generic delegates to replace the old genericEventHandler GameObject.(Pro-tip#2)
So I want to modify my code , I was using the UICamera.genericEventHandler gameobject to handle OnPress,OnDrag and OnScroll message notified by UICamera in old version,and it works well.
Now I change my code using the UICamera.onPress,UICamera.onDrag and UICamera.onScroll delegates and problems come in.
The UICamera.onPress works well, but the UICamera.onDrag and UICamera.onScroll did not be called when mouse dragged or hovered on empty area(with no collider).
I suspected that some other delegates in UICamera may have the same problem -- process mouse or touch with empty target(no collider), while these problem would not happen when using the old UICamera.genericEventHandler.
After my experience, the UICamera.genericEventHandler cannot be null(you can even set an empty GameObject to it),otherwise the UICamera generic delegates would not be called properly.
Title: Re: UICamera
Post by: ArenMook on September 03, 2014, 12:03:41 PM
This was brought up in the support forum. Set the UICamera.fallThrough object to something, like the UICamera's game object itself, and all events will work as expected.

There can be no null objects with the new generic system. You can still use the old approach if you like.
Title: onMouseMove delegate
Post by: Maxii on September 18, 2014, 11:50:42 AM
I'm about to start using UICamera's onMouseMove delegate. Thanks for adding it!

In reading the code, it seems that the delegate gets raised every update() whether there has been movement or not. I know I can test delta to see if there was any movement, but wouldn't it be more efficient to only raise the delegate when posChanged = true? Just curious. ???
Title: Re: UICamera
Post by: ArenMook on September 18, 2014, 05:28:36 PM
Yup, that makes sense to me. I'll add the check.
Title: Re: UICamera
Post by: deevo2004 on October 26, 2014, 01:10:58 PM
Is there a way to adjust the camera's event mask programmatically? 
UPDATE: I figured it out, if anyone is interested here is how I did it:

the "this.UICamera" points to the UICamera component of my main camera

  1.     public void LayerEventMaskOn(int layerMask)
  2.     {
  3.         this.UICamera.eventReceiverMask |= layerMask;
  4.     }
  5.  
  6.     public void LayerEventMaskOn(string layerName)
  7.     {
  8.         LayerEventMaskOn(1 << LayerMask.NameToLayer(layerName));
  9.     }
  10.  
  11.     public void LayerEventMaskOff(int layerMask)
  12.     {
  13.         this.UICamera.eventReceiverMask &= ~layerMask;
  14.     }
  15.  
  16.     public void LayerEventMaskOff(string layerName)
  17.     {
  18.         LayerEventMaskOff(1 << LayerMask.NameToLayer(layerName));
  19.     }
Title: Re: UICamera
Post by: PoN on November 10, 2014, 12:46:19 AM
I've tried use delegate instead of - UICamera.genericEventHandler = gameObject;

  1. EventDelegate.Add(UICamera.onDrag, OnDragging);
  2.  
  3. public void OnDragging(GameObject gameObject , Vector2 delta)
  4.  {
  5.         if (delta.y < 0)
  6.         {
  7.             isScrollDown = true;
  8.         }
  9.         else
  10.         {
  11.             isScrollDown = false;
  12.         }
  13.  }

And get the error

- error CS1502: The best overloaded method match for `EventDelegate.Add(System.Collections.Generic.List<EventDelegate>, EventDelegate)' has some invalid arguments.

NGUI 3.7.4
Title: Re: UICamera
Post by: ArenMook on November 10, 2014, 10:12:44 PM
It's not an NGUI delegate. It's a C# delegate.
  1. UICamera.onDrag += OnDragging;
Title: Re: UICamera
Post by: toqueteos on December 03, 2014, 07:10:51 AM
Events go to... option isn't documented. What are there drawbacks, if any, for using "Colliders" instead of "Rigidbodies" (the default value)?
Title: Re: UICamera
Post by: ArenMook on December 04, 2014, 04:27:21 AM
Collider approach is what you'd use for UI, since you generally have a rigidbody on the root (for performance reasons in Unity), and colliders on actual UI elements.

Rigidbody approach is what you'd use in the game. For example in Windward, each ship is made up of several different colliders, and when I hover over this ship I want a single object to receive the event -- the rigidbody -- rather than having to attach listener scripts to all colliders.
Title: Re: UICamera
Post by: JavaV1 on February 06, 2015, 02:33:21 AM
?? OnInput(text) is non-existence in UICamera  of  Next-Gen UI kit  3.7.2.
Title: Re: UICamera
Post by: ArenMook on February 06, 2015, 10:00:51 PM
Always update to the latest version before posting. All my support is always for the latest version.
Title: Re: UICamera
Post by: Silvalencia on February 11, 2015, 04:05:13 PM
It's good working
Title: Re: UICamera
Post by: Bradamante3D on November 26, 2015, 06:35:17 AM
I don't see the Pan X and Pan Y setting documented anywhere? Not here in the forum documentation, not on the NGUI docs page, not in the class docs. Would be cool if we got an official explanation. I understand these settings are related to setting a scroll bar via a console controller?
Title: Re: UICamera
Post by: ArenMook on December 01, 2015, 07:53:03 AM
I've added an explanation to the original post.
Title: Re: UICamera
Post by: Diego on December 04, 2015, 12:42:49 PM
Hi.

One question about the methods OnPress(), OnClick(), OnSelect() ...;
This methods are called every frame like the method Update(), or they are called only once when they are triggered by the camera?

Thanks in advance.
Title: Re: UICamera
Post by: ArenMook on December 09, 2015, 01:40:46 PM
Only when the event gets triggered, and only on the game object that they were triggered on. Doesn't need to be a widget.
Title: Re: UICamera
Post by: Diego on January 17, 2016, 08:13:55 AM
Thanks for your answer ArenMook.

I understand that then, from a performance point of view, is better to use this methods than the Update method, isn't it?

Thanks again.
Title: Re: UICamera
Post by: The-Arrival on January 20, 2016, 07:13:56 AM
Hello ArenMook,

is it possible to easy up your event system, by only implementing certain events in a trigger using interfaces? The Unity EventSystem provides Interfaces:  Unity.EventSystem
 (http://docs.unity3d.com/ScriptReference/EventSystems.EventTrigger.html)
I found this tutorial on how to only implement certain Events from the system: Tutorial (http://www.hammerandravens.com/mouse-pointer-handler-system-onpointerenter-onpointerexit-for-unity3d-ui/)

Is it possible to do something similar with your eventsystem?

Another thing i recognised is that while a mousebutton is pressed, no OnHover is getting triggered. Though for most cases this behavior is totally fine, is it possible to override you event-behaviors with a custom one?
Title: Re: UICamera
Post by: ArenMook on January 20, 2016, 08:20:28 AM
@Diego: The update method? If you mean doing your own Input checks, I would say so, yes.

@The-Arrival: I never liked the interface-based approach personally. From coding point of view it's more neat to not have to derive from some specific class. Much less code too -- no need to register anything either. The performance cost of relying on SendMessage in this case is negligible to the point of being invisible. The only downside is no native way of letting certain events fall through, but that can be remedied inside the desired function itself by forwarding the event to a sub-object if desired.

The full sequence of events when trying to press on something is:
- Hover(true)  <-- Initially hovering over an object
- Press (true)  <-- Pressed on an object
- Press (false) <-- Released the button
- Hover (true) <-- Restoring state to "hover" (won't happen if released outside the object)
- Click

I'm not sure why you'd want to overwrite this with something custom...
Title: Re: UICamera
Post by: The-Arrival on October 17, 2016, 07:29:20 PM
Hey...
i have a weired problem lately and no idea were this came from. I´m running Unity 5.4.x and NGUI 3.10.2

Setup:
- I have a UICamera with the EventMask set to the UI Layer
- My MainCamera also has the UICamera Component set to some a "GameObject layer" wich is set on some clickable objects in my scenes.
- I´m in Debug mode to follow which objects get triggered while hover.

In one Scene everything is working as intended: if the mouse is on an UI element, i get the UI-widget. If the button is over an object i get that object. When i hover over nothing i get the root UI object. Thas basically what i want

In a second scene everthing is setup similar, but if i hover nothing it detects the MainCamera itself. The other strange thing (besides two similar scenes have diffrent behaviors) is that the maincamera object is on "default" layer which is not included in any events mask.

Any idea what might be wrong here?
Title: Re: UICamera
Post by: ArenMook on October 17, 2016, 10:16:57 PM
If you want events to go to a specific object when there is no collider hit, set UICamera.fallThrough to your target.
Title: Re: UICamera
Post by: Dune on October 19, 2016, 12:43:40 PM
How to get rid of the giant MickyMouse camera in the middle of NGUI's Editor's UI?

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

Also, how to get custom prefabs to render to the Prefab Toolbar?
Title: Re: UICamera
Post by: Dune on October 19, 2016, 05:05:40 PM
Figured out that I could change size of icon via the drop down Gizmos.
Title: Re: UICamera
Post by: asims on September 27, 2018, 07:48:42 AM
Hello,

we are using multiple displays in our systems. System is working perfect if Camera target display is 1 ( camera means UICamera on the NGUI ). When i change the camera target display 1 to 3 i lost the button events from NGUI. GUI paints but i lost all events. Its working when i return to display 1 ?

Is there any solutins for this  ?
Title: Re: UICamera
Post by: asims on October 02, 2018, 05:01:23 AM
Hello,

we are using multiple displays in our systems. System is working perfect if Camera target display is 1 ( camera means UICamera on the NGUI ). When i change the camera target display 1 to 3 i lost the button events from NGUI. GUI paints but i lost all events. Its working when i return to display 1 ?

Is there any solutins for this