Author Topic: UICamera  (Read 105532 times)

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
UICamera
« 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.

   

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).



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.



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.



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. 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:
  • OnHover (isOver) is sent when the mouse hovers over a collider or moves away.
  • OnPress (isDown) is sent when a mouse button gets pressed on the collider.
  • OnSelect (selected) is sent when a mouse button is first pressed on a game object. Repeated presses on the same object won't result in a new OnSelect.
  • OnClick () is sent with the same conditions as OnSelect, with the added check to see if the mouse has not moved much. UICamera.currentTouchID tells you which button was clicked.
  • OnDoubleClick () is sent when the click happens twice within a fourth of a second. UICamera.currentTouchID tells you which button was clicked.
  • OnDragStart () is sent to a game object under the touch just before the OnDrag() notifications begin.
  • OnDrag (delta) is sent to an object that's being dragged.
  • OnDragOver (draggedObject) is sent to a game object when another object is dragged over its area.
  • OnDragOut (draggedObject) is sent to a game object when another object is dragged out of its area.
  • OnDragEnd () is sent to a dragged object when the drag event finishes.
  • OnInput (text) is sent when typing (after selecting a collider by clicking on it).
  • OnTooltip (show) is sent when the mouse hovers over a collider for some time without moving.
  • OnScroll (float delta) is sent out when the mouse scroll wheel is moved.
  • OnKey (KeyCode key) is sent when keyboard or controller input is used.

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.
« Last Edit: December 01, 2015, 07:52:29 AM by ArenMook »

wwwise

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 2
    • View Profile
Re: UICamera
« Reply #1 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.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UICamera
« Reply #2 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.

sintua

  • Jr. Member
  • **
  • Thank You
  • -Given: 7
  • -Receive: 0
  • Posts: 63
    • View Profile
Re: UICamera
« Reply #3 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.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UICamera
« Reply #4 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;

kromenak

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 14
    • View Profile
Re: UICamera
« Reply #5 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?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UICamera
« Reply #6 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.

Lautaro

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 1
  • Posts: 44
    • View Profile
Re: UICamera
« Reply #7 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?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UICamera
« Reply #8 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.

Lautaro

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 1
  • Posts: 44
    • View Profile
Re: UICamera
« Reply #9 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?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UICamera
« Reply #10 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?

Lautaro

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 1
  • Posts: 44
    • View Profile
Re: UICamera
« Reply #11 on: February 14, 2014, 12:26:50 PM »
Its ok, ill do it programmatically. Thanks! :D

helmesjo

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 116
    • View Profile
Re: UICamera
« Reply #12 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!
« Last Edit: April 07, 2014, 07:08:52 AM by helmesjo »

Trance_Trap

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 1
  • Posts: 5
    • View Profile
Re: UICamera
« Reply #13 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.
« Last Edit: May 12, 2014, 07:30:29 AM by nbr1ninrsan »
One Person can make a difference, and Every Person should Try. ~John F. Kennedy

My avatars' text: "You wouldn't like me when I'm angry... Because I Always backup my rage w/Facts & documented sources" ~The Credible Hulk(he's wearing glasses) ... Lol I just thought it was hilarious ^_^

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UICamera
« Reply #14 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.