Author Topic: 3.0.x Clicking Depth All Messed Up If There's Inactive UIWidget?  (Read 4176 times)

NaxIonz

  • Jr. Member
  • **
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 70
    • View Profile
Okay, seems I've noticed this behavior on a few types of objects now.

If I have a game object that has ANY children that have a UIWidget disabled, clicking will ALWAYS pick whatever box collider is behind this object.

I first noticed this with a UIToggle. Since I have a button that is more complicated than just turning on/off a single sprite, I was turning off all the UIWidgets under the "on" GameObject.

i.e.

UIToggle (This GameObject has the BoxCollider)
--ON (Blank GameObject)
----UISprite_0
----UISprite_1
----UISprite_3
----UILabel_0
--OFF (Blank GameObject)
----UISprite_0
----UISprite_1
----UISprite_3
----UILabel_0

Now, everything is fine, until I set those UIWidgets nested under "ON" to be disabled. For some bizarre reason, the current.pressed in UICamera ALWAYS thinks I am now clicking on the background, and not the button. After being frustrated at this for a while, I found that if I took "ON" and made it a sibling of the UIToggle GameObject, everything worked fine.

Later on, I am now seeing this behavior creep up again.

In another UI element, I have one button that is moved and placed over a socket of sorts. Now, both the socket and the button have BoxColliders. The button has many UIWidgets, all of which have a depth greater than all the UIWidgets of the socket. Depending on the state of the button, some of these UIWidgets are enabled, sometimes they are disabled. However, ever since updating to 3.0.2, the socket ALWAYS eats the input, even though it's BoxCollider is behind it (set by Z). I've messed with Z's, BoxCollider Z's, and the only way the button will take input over the socket is if switch all the UIWidget's to enabled.

What's going on here?!

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: 3.0.x Clicking Depth All Messed Up If There's Inactive UIWidget?
« Reply #1 on: October 15, 2013, 02:16:09 PM »
Z has no effect in 3.0.2 onwards, even for colliders -- if the UICamera is set to "UI" mode. If it's set to "World" mode, then it does. Picking is completely depth-based.

NaxIonz

  • Jr. Member
  • **
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 70
    • View Profile
Re: 3.0.x Clicking Depth All Messed Up If There's Inactive UIWidget?
« Reply #2 on: October 15, 2013, 04:07:44 PM »
Z has no effect in 3.0.2 onwards, even for colliders -- if the UICamera is set to "UI" mode. If it's set to "World" mode, then it does. Picking is completely depth-based.


I did finally track it down. Inactive UIWidgets don't have an mPanel, so when their raycastDepth was being queried, it gave a poor number. The following change in NGUITools.cs fixed the issue of having objects with inactive UIWidgets so they could be clicked on properly.

  1. static public int CalculateRaycastDepth (GameObject go)
  2. {
  3.         UIWidget w = go.GetComponent<UIWidget>();
  4.         if (w != null) return w.raycastDepth;
  5.  
  6.         UIWidget[] widgets = go.GetComponentsInChildren<UIWidget>();
  7.         if (widgets.Length == 0) return 0;
  8.  
  9.         int depth = widgets[0].raycastDepth;
  10.         for (int i = 1, imax = widgets.Length; i < imax; ++i) {
  11.         //============================ START MODIFICATION =================================
  12.                 if (widgets[i].enabled) {
  13.                         depth = Mathf.Min(depth, widgets[i].raycastDepth);
  14.                 }
  15.         //============================ END MODIFICATION ===================================
  16.         }
  17.  
  18.         return depth;
  19. }

BGL

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: 3.0.x Clicking Depth All Messed Up If There's Inactive UIWidget?
« Reply #3 on: October 16, 2013, 01:58:20 AM »
I got the same issue, but I think it also should use Max instead of Min, like in
  1. if (widgets[i].enabled) {
  2.     depth = Mathf.Max(depth, widgets[i].raycastDepth);
  3. }
  4.  

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: 3.0.x Clicking Depth All Messed Up If There's Inactive UIWidget?
« Reply #4 on: October 16, 2013, 02:11:57 AM »
@NaxIonz: Thanks, I will add this fix to the repo.

NaxIonz

  • Jr. Member
  • **
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 70
    • View Profile
Re: 3.0.x Clicking Depth All Messed Up If There's Inactive UIWidget?
« Reply #5 on: October 16, 2013, 02:49:15 PM »
@NaxIonz: Thanks, I will add this fix to the repo.

Sure thing!!

Our artists also found it helpful to have a min and max printSize for UILabels. If you're interested in that, I can post it as well.

BGL

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: 3.0.x Clicking Depth All Messed Up If There's Inactive UIWidget?
« Reply #6 on: October 29, 2013, 04:52:38 AM »
@ArenMook: I think the check to avoid considering not enabled widget is not complete.
If widgets[0].enabled is false the depth value is initialized with an invalid value.
Following code should fix
  1.                 int depth = int.MaxValue;               //NOT int depth = widgets[0].raycastDepth;
  2.                
  3.                 for (int i = 0, imax = widgets.Length; i < imax; ++i)           //NOT for (int i = 1, imax = widgets.Length; i < imax; ++i)
  4.                 {
  5.                         if (widgets[i].enabled)
  6.                                 depth = Mathf.Min(depth, widgets[i].raycastDepth);
  7.                 }

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: 3.0.x Clicking Depth All Messed Up If There's Inactive UIWidget?
« Reply #7 on: October 29, 2013, 04:33:33 PM »
You're right. But your code isn't quite complete either. We're still missing an exit clause that would not add the raycast result to the list in UICamera line 565:

  1.                                                 if (mHit.depth != int.MaxValue)
  2.                                                 {
  3.                                                         mHit.hit = hits[b];
  4.                                                         mHits.Add(mHit);
  5.                                                 }