Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - drjeats

Pages: [1]
1
NGUI 3 Support / Re: Cleanly filter input events for all but one panel?
« on: November 12, 2014, 11:57:41 AM »
I kinda just let this sit for a few months since I had other things to work on, but I stumbled onto the solution today.

I changed the clipping at random and suddenly the big collider widget started blocking correctly. For reasons unknown, the UIPanel on my message box had a serialized mClipping value of 2, and I see that you've since taken 2 out of the UIDrawCall.Clipping enum.

This project has been through a few NGUI upgrades, so I imagine this isn't a common problem, but if other people have encountered a similar bug, check your UIPanel's clipping setting.

[EDIT] To clarify, explicitly re-setting the clipping to None (0) in the panel made it all work.

[EDIT2] I notice that I have to make the alpha of this mega-sprite at least 1 though, it can't be zero. Is there something I can do to make the UICamera not discard 0-alpha sprites for hit testing?

This is NGUI 3.7.6, Unity 4.5.

2
That's the same as my first attempt. Have you tried this recently? (or was this fixed in the latest 3.6.8?)

3
If I've understood you correctly, that's what's not working for me. MessageBox is its own UIPanel. I tried a few other combinations as well to no avail:

  1. My first attempt:
  2. > UIRoot
  3.     > UICamera
  4.         > GameUIHierarchyInHere
  5.         > MessageBox (UIPanel)
  6.             > MessageBoxWidgets
  7.             > BigCollider(UIWidget, BoxCollider)
  8.  
  9.  
  10. Tried these after your reply:
  11.  
  12. > UIRoot
  13.     > UICamera
  14.         > GameUIHierarchyInHere
  15.         > MessageBox (UIPanel)
  16.             > MessageBoxWidgets
  17.             > UIPanel
  18.                 > BigCollider(UIWidget, BoxCollider)
  19.  
  20. > UIRoot
  21.     > UICamera
  22.         > GameUIHierarchyInHere
  23.         > MessageBox (UIPanel)
  24.             > BigCollider(UIWidget, BoxCollider)
  25.             > UIPanel
  26.                 > MessageBoxWidgets


It specifically seems to fail this check in UIPanel.IsVisible(Vector3 worldPos): if (pos.x < mMin.x) return false; (line 774)

I also made sure to adjust both the depth and the Z so BigCollider was clear out in front of the game UI.

4
NGUI 3 Support / Cleanly filter input events for all but one panel?
« on: July 09, 2014, 05:32:59 PM »
I'm making a MessageBox type thing that I can toss up at the user at any time, so I'm looking for a way to have it consume all input events until dismissed.

Giving it a giant collider to cover all the other UI seemed like a solid bet:

http://www.tasharen.com/forum/index.php?topic=894.0

But that doesn't quite work since UICamera selects only the first visible hit (UICamera.cs:651 in the 3.6.7 asset store release), and this is supposed to be a little message box appearing over a larger panel.

If it were a matter of life and death, I could go and collect every other UI collider and temporarily disable them, but it seems like it would be easier to hack a DontCheckIfVisible flag into UICamera rather than try to manage an ever-changing list of UI colliders.

Is there a nicer way to get this done?

5
Are you talking about the fact that EventDelegates no longer take parameter that's a reference to the GameObject or UIWidget that generated an event?

I'm assuming the goal was to not have to make a dozen different callback types each with different method signatures. Instead of sending, say, a UIInput as the first parameter to the callback, you just read the static variable UIInput.current.

ArenMook posted a video recently demonstrating upcoming support for callback arguments set via the inspector, which is arguably (pun intended) more interesting and useful. You can also always set a first "sender" argument to the widget dispatching the event if polling a static variable really rubs you the wrong way.

If that's not what you meant, then... uh... Nevermind.   :-X

6
Cool, we were just playing this at work just the other day!

Feeling the same pain points: any UI that has dynamically-added child widgets usually gets mocked up as a static UI by our artist, which I then take to convert repeated things into prefabs that get dynamically instantiated. Any workflow tips on this, or is that as good as it gets?

7
I don't seem to be making myself clear. The hack is no longer in our code (it was a temporary measure while the rest of our UI code was being refactored). There is no longer any need to break this consistency. There is no problem I need help solving here.

I'm providing feedback, suggesting that your API contract for EventDelegate,

Quote
All callbacks must be in the same state as whatever class you have them registered with (scroll bar in this case).

could be a little more flexible for the sake of usability and consistency with how .Net delegates behave.

Right now if someone, either inadvertently or through  deliberate recklessness (that would be me  ;)), does this little add/change/remove dance or any variation on it, there's a fairly strong chance that Unity will get caught in an infinite event dispatching loop and lock up.

How do you stop it from locking up? The answer is obviously, "Don't do that." Unfortunately, that doesn't really help someone once they've gotten themselves into this mess. That also doesn't mean that NGUI shouldn't be made resilient to this kind of silly user behavior.

I think making the EventDelegate.Execute immune to this problem is the right approach, but it's also reasonable for NGUI to detect the loop, stop executing callbacks, and throw an exception.

It's just a suggestion. Take it or leave it.

8
A flag in this case is really just a hack of a different sort. Adding another bit of state introduces a technical burden to the class using EventDelegate, while making EventDelegate robust against add/change/remove during dispatch adds a technical burden to EventDelegate. It's a wash.

I'm not seeking to use this behavior, but I think it's worth your consideration.

9
Hey man, I never said I was proud that this little nugget exists in the codebase. :P Just saying it's there, and that this use case isn't inconsistent with standard delegate behavior.

Also, the effect is not void:

Quote
EventDelegate.Remove itself from onChange, change the widget value, then EventDelegate.Add itself back to onChange

There's an if branch in onChanged handler where it had to change the widget value without re-entering itself. Like I said, this is being rewritten, but NGUI provides more value if it's robust in spite of QFE hacks like this one.

[EDIT]

For reference, here's roughly what it looks like pre-refactoring sans irrelevant details, with the coroutine workaround:

  1. private void OnScrollBarChanged()
  2. {
  3.     MuckWithOtherViewObjectsAndStuff();
  4.  
  5.     if (extraScrollContentSize == 0) {
  6.         EventDelegate.Remove(scrollBar.onChange, OnScrollBarChanged);
  7.         scrollBar.scrollValue = 0f;
  8.         StartCoroutine(ReAddScrollBarEvent());
  9.     }
  10. }
  11.  
  12. private IEnumerator ReAddScrollBarEvent()
  13. {
  14.     yield return new WaitForEndOfFrame();
  15.     EventDelegate.Add(scrollBar.onChange, OnScrollBarChanged);
  16. }

10
We're upgrading from NGUI 2.7 to 3.5.5. A big jump, but the most complex UIs in our game were already slated to be redone anyway, and the new sprite manipulation and widget anchoring tools were too good to pass up. Well done on that.

After upgrading, one of our older scripts seemed to be creating an event loop since it would EventDelegate.Remove itself from onChange, change the widget value, then EventDelegate.Add itself back to onChange.

This thread suggests this might have already been a problem before, but was handled by copying the EventDelegate list on execute:

http://www.tasharen.com/forum/index.php?topic=7740.msg37556#msg37556

Doesn't seem to handle this case though.

Removing then re-adding callbacks is kinda janky and gross, so that's getting refactored out of our code (and adding the event handler back after yield return new WaitForEndOfFrame provides a temporary solution until the refactoring gets done).

However, I think the EventDelegate API would be better off if it made a guarantee that the a list is always copied on execute, or if it used some other means to ensure that adding or removing delegates in a handler doesn't affect the execution of the EventDelegate list since this is closer to the behavior of regular C# multicast delegates.

I realize Unity serialization might make this tricky to do without the cost of a list copy, but is this something on your roadmap?

11
As we were laying out UI, we found that on Play, UIImageButton would resize Simple sprites back to what their actual pixel size.

Investigation led me to this thread and explanation from ArenMook:

You didn't mention using an image button. Yes, image button forcefully changes the size of your sprite to make it pixel-perfect when it changes sprites -- and this is the intended behaviour. You shouldn't stretch simple sprites, it just causes them to look blurry and distorted. Consider using a sliced sprite instead.

That makes sense, blurry sprites make me sad. But in this case we're actually reusing a larger sprite and scaling it down to fit another part of the UI. Seems pointless to make a small version for just a few use cases when the full-sized version is being used in other parts of the same UI. After looking into the UIImageButton and UISprite source I saw and remembered that a MakePixelPerfect call on a simple sprite sizes it back up to the actual pixel imensions of the image.

This isn't a big deal since we've got two workarounds:

  • Render as a Sliced sprite
  • Parent the sprite to an otherwise-empty GameObject and scale that parent

But this was driving our artist crazy for a good half an hour since this behavior is a bit of a surprise. It's pointless attempting to discourage scaling simple sprites because it's trivial to circumvent, and I'm not convinced that you can characterize the opposite use case--scaling down and reusing larger sprites--as an objectively bad or suboptimal use case. Are there deeper reasons for requiring a MakePixelPerfect call on every image button state change other than to discourage upscaling images?

12
Okay, it's easy to break it up into the two prefabs then.

The reason I had the two different anchors was because I wanted some elements to be anchored center and some anchored top-left. Is this their intended use, or did I assume something that I shouldn't have?

What's weird is that I can pull the prefab (including anchors) out of the project explorer and drop it into the scene hierarchy and everything attaches no problem. Is there some other operation not included in NGUITools.AddChild that is required to hook everything up properly? The gizmos of the child elements seemed to appear in logical positions. I'd need to double check the actual positions but it doesn't look like that's the problem.

If you have any other hints (docs to read, specific code sections to read, etc.) about how the elements get rendered and how the anchors affect I'd really appreciate it. It's not a showstopper since I can have the anchors in the scene already like you suggested, but our team's about to do a massive amount of UI work in the next few weeks and I'm kinda the guy responsible for educating the rest of the team about the intricacies of NGUI. and I can see this question coming up again as we start making UI prefabs.

Oh, and thanks for making NGUI! The team was very happy to switch over from EZ GUI.

13
I suppose complicated is relative, but it's mixed objects in here. I'm creating a UI prefab and having trouble getting it to render when I instante it via NGUITools.AddChild.

My test scene consists of MainCamera, GUICamera, and a SceneHUD gameobject which contains the UIRoot component.

I'm instantiating the prefab like this:

  1. var go = NGUITools.AddChild(sceneHUD, (GameObject)Resources.Load("RacingHUD"));
  2. foreach (var anchor in go.GetComponentsInChildren<UIAnchor>()) {
  3.         anchor.uiCamera = uiCamera; // this is a ref to GUICamera set in the inspector
  4. }

The prefab spawns, and the transforms of each element looks as though it should, but nothing is rendering.

If I include the toplevel SceneHUD (with UIRoot) in the prefab and instantiate that whole thing, everything works fine.

Is there something about including anchors or non UI-gameobjects in the prefab that I'm not picking up on?

The prefab's hierarchy:

SceneHUD (part of Scene, not in the prefab, the first argument to NGUITools.AddChild)
---RacingHUD (empty G.O.)
------CenteredAnchor
---------Panel
------------CountdownLabel (UILabel)
------TopLeftAnchor
---------Pane
------------FirepowerLabel (UILabel)
------------PrimaryPowerups (empty G.O.)
---------------Bomb (non-UI object with MeshRenderer)
------------SecondaryPowerups (empty G.O.)
---------------Boost (non-UI object with MeshRenderer)
------------powerupBOx (SlicedSprite)
------------powerupBOxActivated (SlicedSprite, with the sprite component disabled with the intentioning of enabling/disabling in code)
---------PowerupSelector (G.O. with display logic script attached)

Pages: [1]