Author Topic: HOW TO (code): Prevent clipped items in a UIDraggablePanel from getting clicked  (Read 12866 times)

seandanger

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 2
  • Posts: 32
    • View Profile
    • Bit By Bit Studios
Hey everyone,

I've seen a few threads in the past mentioning this issue, and having struggled with it myself, I decided to post a guide on the solution that I've come up with.  I quickly want to point out that I have not yet battle tested this code or profiled it, or spent extra time optimizing, and I in no way guarantee its fitness or reliability.  So use at your own risk!  That said, it seems to be performing admirably in my game so far.  Carrying on...

The problem
Items outside of the clip area on a UIDraggablePanel are still active.  I think most people probably don't want their buttons clickable when they aren't visible.  The typical NGUI solution is to put blocking colliders around your clipping area, above (in the z dimension) your clipped content.  This works just fine but requires some extra labor and for some is annoying to deal with, especially in instances (like in my own game) where multiple UIDraggablePanels are adjacent to one another.

The code based solution
I've written a component that monitors whether or not it is within the clipping rect of a UIDraggablePanel.  When its state (in-bounds, or out-of-bounds) changes, it fires a delegate.  You also get to define the rectangle you want to use for determining whether or not your component is considered in bounds.

Here's an illustration showing how it works:


If you don't want to use delegates, you can also add in your own code here.  Either way, you can write your own code that handles what to do in this situation.  I've included some examples via in line comments.  I'm currently using it to automatically disable / enable the collider of the GameObject the component is attached to.

How to use
You'll need to modify two NGUI files in order to get the component to compile:

  • Add the following function to the UIPanel class in UIPanel.cs:
  1.         /// <summary>
  2.         /// Returns a Rect which describes the clipping area of this panel in Screen (pixel) coordinates.
  3.         /// This is the same area that is drawn with a magenta outline in the Scene gizmos.
  4.         /// </summary>
  5.         public Rect ClippingRectScreen
  6.         {
  7.                 get
  8.                 {
  9.                         Rect r = new Rect();
  10.                         Vector2 size = new Vector2(mClipRange.z, mClipRange.w);
  11.  
  12.                         if (size.x == 0f) size.x = mScreenSize.x;
  13.                         if (size.y == 0f) size.y = mScreenSize.y;
  14.                                                                
  15.                         Vector3 screenPos = UICamera.currentCamera.WorldToScreenPoint(transform.position);
  16.                                                                
  17.                         r.width = size.x;
  18.                         r.height = size.y;
  19.                         r.center = new Vector2(mClipRange.x + screenPos.x, mClipRange.y + screenPos.y);
  20.                                                                
  21.                         return r;
  22.                 }
  23.         }
  24.  
  • Add the following function to the UIDraggablePanel class in UIDraggablePanel.cs:
  1.         /// <summary>
  2.         /// Returns a Rect which describes the clipping area of this panel in Screen (pixel) coordinates.
  3.         /// This is the same area that is drawn with a magenta outline in the Scene gizmos.
  4.         /// </summary>
  5.         public Rect ClippingRectScreen
  6.         {
  7.                 get
  8.                 {
  9.                         return mPanel.ClippingRectScreen;
  10.                 }
  11.         }
  12.  

    Now you're ready to use the component, which is attached.  It uses a simple Axis Aligned Bounding Box hit test (not a Raycast) to determine whether or not the component is within the clip rect of the panel.  The component's "hit rectangle" (named boundsRect) is defined explicitly on the component, though you can have the component simply match the dimensions of the collider on the same GameObject if you choose.  The rect is shown via a Gizmo -- a pink box in the scene view.  I've found that having the rect around 50-60% of the size of the collider results in the behavior I'm looking for.

    It's relatively short and fairly heavily documented in-line, so read in there if you'd like to know more about it, or modify it.  If you want to use a different type of collision test, for example, you can use my code as a starting point for how to get the 2 rectangles in question.

    I hope this helps some people!  Also feel free to check out my company's site or my twitter if you're interested, where I periodically post about Unity gamedev topics.
    « Last Edit: December 04, 2012, 12:54:49 AM by seandanger »

    dlewis

    • Guest
    I believe this was added to NGUI in the latest update.

    seandanger

    • Newbie
    • *
    • Thank You
    • -Given: 0
    • -Receive: 2
    • Posts: 32
      • View Profile
      • Bit By Bit Studios
    Doh!! Haha! Really? What's the script name?

    dlewis

    • Guest
    Doh!! Haha! Really? What's the script name?

    I'm not using the latest version so I'm not sure, but judging by the change log it seems to be a toggle on the panel so it will just ignore touches/mouse presses if the object is clipped.

    seandanger

    • Newbie
    • *
    • Thank You
    • -Given: 0
    • -Receive: 2
    • Posts: 32
      • View Profile
      • Bit By Bit Studios
    Ugh, serves me right for not checking the change log first.  Still, would be nice if any of the 4 threads here on the subject had been updated.  Thanks for pointing it out.

    I'll leave this here in case anyone finds it useful.  We probably won't change versions until the next project, so it's still useful for this current one (at least that's what I'm telling myself) :)

    ArenMook

    • Administrator
    • Hero Member
    • *****
    • Thank You
    • -Given: 337
    • -Receive: 1171
    • Posts: 22,128
    • Toronto, Canada
      • View Profile
    2.2.6c is a pretty safe update. It has been out for some time and it doesn't create any new bugs (it did but they got fixed with B and C editions).

    seandanger

    • Newbie
    • *
    • Thank You
    • -Given: 0
    • -Receive: 2
    • Posts: 32
      • View Profile
      • Bit By Bit Studios
    2.2.6c is a pretty safe update. It has been out for some time and it doesn't create any new bugs (it did but they got fixed with B and C editions).

    Thanks, that's good to know.  I'm not sure which version we have (readme wasn't added to the depot, oops) but it's at least 5 months old and has a decent amount of custom code in it, so I'll still hold off on upgrading for now.  The new feature list is attractive though so it'll probably warrant an update before release.

    nah0y

    • Sr. Member
    • ****
    • Thank You
    • -Given: 1
    • -Receive: 2
    • Posts: 430
    • \o/
      • View Profile
    Wow, 5 months old. You should DEFINITELY take time to upgrade :)

    For the amount of custom code, you should try to find a solution and have them outside the NGUI folder, you can do things like herits from NGUI base scripts for example. So when NGUI updates, you just have to adapt them (if needed) or do nothing ^^

    ArenMook

    • Administrator
    • Hero Member
    • *****
    • Thank You
    • -Given: 337
    • -Receive: 1171
    • Posts: 22,128
    • Toronto, Canada
      • View Profile
    Custom mods? You should have gotten the Pro version. Your update process would have been painless, and likely auto-merged by the system.

    nah0y

    • Sr. Member
    • ****
    • Thank You
    • -Given: 1
    • -Receive: 2
    • Posts: 430
    • \o/
      • View Profile
    Yeah, but we do not want to make that much money (even if it's nothing) for something not really crucial :)

    seandanger

    • Newbie
    • *
    • Thank You
    • -Given: 0
    • -Receive: 2
    • Posts: 32
      • View Profile
      • Bit By Bit Studios
    For the amount of custom code, you should try to find a solution and have them outside the NGUI folder

    We do that in most cases but sometimes we've fixed bugs on our own or had to expose some private methods.  Every change is marked and in perforce so when we have to merge it won't be terrible, I just don't want to until we need something from the updates.  Right now we're set.

    Custom mods? You should have gotten the Pro version. Your update process would have been painless, and likely auto-merged by the system.

    I thought the pro version just included access to the git repo, that it just basically gives access to "nightly builds", which we aren't really interested in.  I like a stable build that does everything I want more than a "cutting edge" build.  Maybe I misunderstood what the pro version offers.

    ArenMook

    • Administrator
    • Hero Member
    • *****
    • Thank You
    • -Given: 337
    • -Receive: 1171
    • Posts: 22,128
    • Toronto, Canada
      • View Profile
    I don't push changes to the repo unless it's fully stable. Pro users also have the ability to create their own modifications to NGUI and submit pull requsts for me to add their changes to the main repository.