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 - electrodruid

Pages: [1] 2 3 4
1
NGUI 3 Support / Re: PixelPerfect and Atlas switching
« on: January 04, 2014, 08:48:40 PM »
To answer your question Frank, we ended up keeping the pixel perfect root, and dealing with the atlas switch by calling MakePixelPerfect, doing something like this to catch the widgets which are inactive at the time (I don't have the code in front of me, so this might not be 100% right):

  1. // This code is called from with a custom version of UIRoot - if you want to put it somewhere else, you'll need to find the UIRoot in the scene.
  2. Component[] widgets = GetComponentsInChildren(typeof(UIWidget), true);    // search for inactive children as well
  3.  
  4. foreach(UIWidget widget in widgets)
  5. {
  6.     if(widget != null)
  7.         widget.MakePixelPerfect();
  8. }
  9.  

It's slow, but you should only need to do it once. We also ended up basically replacing UIStretch with a number of custom versions, in order to stretch Colliders, UIGrid spacing, the areas in which UILabels can draw, etc. All of these could scale using "pixels" as well as/instead of the standard relative scaling. "Pixels" in this case could be adapted by some settings in our custom UIRoot, so that if you stretch something to be (say) 100 pixels wide, then that gets combined with a multiplier. When using standard def atlases, the multiplier is 1. When using HD atlases, it's 2, so the widget ends up 200 pixels wide, which is what you want.

The MakePixelPerfect call should (in theory) deal with most of this, but in practice we found that we had to attach custom anchors and stretches to pretty much everything in the scene, which then meant we had to add performance optimisations like the ability to turn all those anchors and stretches off after a set number of frames, once the screen had settled down. It was, to put it politely, a bit of a pain to get working, and something we definitely won't be doing again. As a result of all the custom code, we're a few versions behind on NGUI now, but I sincerely hope that more recent versions (or ones in the near future) support the PixelPerfect option in UIRoot properly, or remove it entirely.

If you're interested in the results, this is what I built: https://itunes.apple.com/gb/app/smash-bandits/id602403667?mt=8 - we had some praise for having a nice crisp UI, but in the end I'm not convinced that the extra effort was worth it. Better to ignore the PixelPerfect option, go with a relatively-scaled UIRoot, and if needs be write a custom component to specifically call MakePixelPerfect on any widgets that really need it. If you need to support both portrait and landscape mode, I'd suggest building a seperate UI for each orientation.

2
NGUI 3 Support / UICamera performance spikes?
« on: June 17, 2013, 07:56:29 PM »
Hi,

I've been profiling my game, and I'm seeing some really weird performance spikes. Unity says the spikes occur in UICamera. The spikes are big, seem to involve loading in some way, and occur periodically for a while and then stop. Does anyone have any idea what this is?

For what it's worth, the game was idling at the time (i.e. no player input, and very little clever stuff happening in the game logic itself). There are four UICameras in the scene (HUD, pause menu, store, options menu, all built as seperate scenes and loaded additively), but the only one that has anything to render when this screenshot was taken was the HUD, which was not changing or updating at the time.

UICamera only seems to deal with raycasting user inputs, so I'm not sure what business it has loading stuff. Is this a profiler glitch, or some weird under-the-hood camera stuff happening?


3
The HUD design for the iOS game I'm working on calls for a couple of big rotating semicircles/crescents, which form two parts of a ring that's almost the width of the screen. Surprise, surprise: it's killing the fill-rate. The first pass was an actual big semicircle texture, which was really bad. The next pass was to make a texture that was a curve representing about 1/6th of a circle, and to re-use that a few times at different angles. That's better, but I'm still drawing a lot of transparent stuff over the top of the scene and the framerate is still suffering as a result.

The texture atlas for the game UI primarily uses just white textures with an alpha channel, which are coloured when they're drawn as sprites. There are some multicoloured icons on there but I could easily move those off to another atlas. The question is, is there anything I could do with the texture settings and/or shader for this atlas which might improve performance? An obvious thing to try would be to somehow make the texture be some kind of alpha-only format. I tried turning on "Override for iPhone" and changing the format to "Alpha 8" but that makes all of the sprites black, and I couldn't find a shader in the drop-down menus on the material which worked with that.

Any other suggestions? Is any of the PVRT stuff beneficial to iOS performance without sacrificing image quality? Will it help just to reduce the texture size of the offending sprites on the atlas but stretching them to the same size? I'm not terribly experience in optimising textures for iOS, particularly through Unity, so any advice would be welcome.

4
NGUI 3 Support / Re: Animations and Anchors, again :)
« on: May 22, 2013, 06:14:35 PM »
For what it's worth, jeldrez' solution of just animating the panel rather than SpriteA worked for me.

5
NGUI 3 Support / Animations and Anchors, again :)
« on: May 08, 2013, 09:01:47 AM »
I've read the other threads about animations and anchors, and know that you're only supposed to add animations to the children of objects with anchors (not the objects themselves or their parents). But consider this setup:

UIRoot
-- Camera
---- Anchor
------ Panel
-------- SpriteA (has an Animation which moves its position)
-------- SpriteB (anchored to Sprite A)

This should be okay, right? SpriteA doesn't have an anchor, or any children with anchors, and spriteB doesn't have any animation. SpriteA should move and SpriteB should stay anchored to SpriteA, and so should move along with it. Yes?

It almost works, but there's weirdness. There is a noticeable lag in SpriteB as SpriteA moves, and B even seems to "overshoot" and snap back into place at the end of the animation. Additionally, Unity doesn't seem to be displaying SpriteA's transform properly. If the animation just changes SpriteA's transform.position.y from 0 to 300 over two seconds, SpriteA moves just fine but all the inspector windows shows is a transform position of (-0.2119612, 18, 0) - i.e. garbage. If you click on the transform in the inspector after the animation has happened then it refreshes to the correct values (0, 300, 0).

The use case for this was our old friend the dialog box. SpriteA would be a sprite representing the box background, and SpriteB would be a widget anchored to some point inside the dialog (but not a child of it). Obviously there could be many such widgets. Having to animate every single thing in the dialog individually seems like a massive pain, but this visual lag/overshoot of the anchors is pretty sloppy-looking. What is the solution?

6
NGUI 3 Support / Re: Clipping panel animation problem
« on: April 28, 2013, 07:43:38 PM »
Everything in NGUI already messes with positioning - anchors, stretches, the lot. Adding clip regions into the bargain doesn't bother me, in fact I've already had to write custom UIStretch components to handle panel clip areas, grid spacings, colliders and label regions. And surely you can see that scaling clip bounds on a panel is not the same thing as scaling the UIPanel's actual transform? The first reveals the panel as if it's sliding out from somewhere, and the second sort of inflates it, making things look squashed until they've fully expanded.

Anyway, I wrote what I need. It's ugly and probably really slow, but it fixes the problem, in case anyone else is insane enough to want to animate panel sizes :)

  1. // To be applied to an object that contains a UIPanel component and an Animation component which changes the panel's clipping region
  2. public class UIPanelAnimFudge : MonoBehaviour {
  3.        
  4.         UIPanel         mPanel;
  5.         Animation       mAnimation;
  6.         UIWidget[]      mWidgets;
  7.  
  8.         void Start ()
  9.         {
  10.                 mPanel = GetComponent<UIPanel>();
  11.                 mWidgets = mPanel.transform.GetComponentsInChildren<UIWidget>() as UIWidget[];
  12.                 mAnimation = GetComponent<Animation>();
  13.         }
  14.  
  15.         void Update ()
  16.         {
  17.                 if(mAnimation.isPlaying)
  18.                 {
  19.                         foreach(UIWidget widget in mWidgets)
  20.                         {
  21.                                 widget.MarkAsChangedLite();
  22.                                 widget.visibleFlag = 1;
  23.                         }
  24.                 }
  25.         }
  26. }
  27.  

7
NGUI 3 Support / Re: Clipping panel animation problem
« on: April 27, 2013, 10:08:26 PM »
What do you mean? Have the panel fade in rather than open up? I'm not sure that's going to work for me. Or do you mean supplementing the clip bounds animation with a (possibly quite subtle) alpha fade just to force the panel to update?

8
NGUI 3 Support / Re: Clipping panel animation problem
« on: April 27, 2013, 09:43:48 PM »
My bad. In general, I was talking about the position. As in, the panel's position is (0,0,0), and rotation and scale are the defaults of (0,0,0) and (1,1,1) respectively. The sprite's position when there are problems is (0,-1,0), rotation is (0,0,0) and scale is (100,100,1). When I talk about making the sprite appear by editing the transform I'm talking about making changes to any aspect of the transform whilst in Play mode, after the animation has happened and the sprite has failed to appear. I was generally doing it by editing a position value, although I found that editing the rotation or scale also caused it to reappear. Just pick any number in the transform, change it to any other number, and the sprite appears. Change it back to the original value, it stays visible. Does that help?

9
NGUI 3 Support / Clipping panel animation problem
« on: April 27, 2013, 07:00:04 PM »
There is a problem when animating a UIPanel's clipping region which means that widgets on the panel which should be drawn end up not getting drawn at all.

I first encountered this in a fairly complex UI scene I was working on, although I've reproduced the problem in a very simple scene. I don't know if there's a way to send you the scene file (I can do so if you want me to), but it's probably simple enough for me to describe. It looks like this:

UIRoot
- Camera2D
-- UIPanel (with an Animation)
--- UISprite

The UIPanel is at (0,0,0) and has an Alpha Clip which is initially set up with centre (0,0) and size (100,200). The Animation is set to play automatically, has the culling type set to Always Animate, and the animation itself simply animates the Clip Range W from 1 to 200 over a second.

The UISprite is just a simple sprite which I've made 100*100, with the pivot point at the Top. This could be any widget though, I've seen the problem happen with UILabels as well. Now, when the sprite's transform starts out at (0,0,0) and you hit play, everything works as expected: The clip panel starts 1 pixel high, then expands and you see the sprite appear from the top down (like a fill sprite with an inverted vertical fill). However, if you set the sprite's transform to (0, -1, 0) or some other negative y value, then the panel expands but you never see the sprite. The Inspector view for the panel says that it contains 1 Widget but 0 Draw Calls. The only way to make the sprite appear is by editing its transform in some way, which forces a refresh and makes the sprite appear.

I've had some trouble following the ins and outs of the panel/widget visibility code, so I might be wrong here, but I think what happens is as follows:

- Scene gets created. Animation is started automatically, setting the initial clip region to (100,1)
- UIPanel.LateUpdate adds the widget(s) to the panel, but notices that the sprite is just outside the clip region (its top edge being -1), so sets it as not visible
- In subsequent frames during and after the animation, nothing changes in the sprite's material, depth or alpha, meaning it's never added to the panel's mChanged list, so is never passed to the Fill method to have its visiblity reconsidered. Only some external effect that changes the transform or material causes this to happen and the sprite to reappear.

How can I get around that? It seems to me that if a clip region is animating, the panel should consider all of its widgets to have changed, and so reprocess them every frame. Or if that's too inefficient, perhaps the panel needs to work out at which point it will be biggest, and base its calculations from that. Or should I write some custom thing than, on the first update, sets the panel to some sufficiently big size, marks all of the widgets dirty and then sets the size back to whatever the animation had set it to?

10
Hi,

I've got a UIDraggablePanel containing a grid full of full-screen elements. I want the panel to be draggable infinitely in either direction, scrolling through a large array of information and wrapping at both ends. I have a version that works pretty well, using only 3 of these elements. We start centered on m_itemInfoDisplays[1], and every time the user scrolls up to m_itemInfoDisplays[0] or down to m_itemInfoDisplays[1] my script re-centers the grid and resets all of the display elements to reflect the fact that we've just scrolled one element through the array. I do this by hooking into UICenterOnChild.onFinished. When you're scrolling through slowly it works great, but if you try to scroll quickly or continuously then UICenterOnChild doesn't always finish, so you end up scrolling to the bottom/top of the 3 ItemInfoDisplays and the UIDraggablePanel won't let you scroll any further. You have to stop, and wait for onFinished for it to reset stuff before you can carry on scrolling.

This isn't ideal. What am I doing wrong? Is there some other way I should be hooking this code up that doesn't require UICenterOnChild to have completed?

Code (stripped down and generalised a bit, but hopefully representative of what I'm doing)
  1. public class MyInfinitePanel : MonoBehaviour
  2. {
  3.         class ItemInfo
  4.         {
  5.                 public int m_index;
  6.                
  7.                 public string m_someInfoText;
  8.                 public float m_someMoreInfo;
  9.                 // You get the idea :) 
  10.         }
  11.        
  12.         // These components references are set via drag & drop in Editor.
  13.         // Our grid contains 3 ItemInfoDisplays because each ItemInfoDisplay fills the panel's clip region, but it
  14.         // should work in case where we display N items simultaneously and there are N+2 ItemInfoDisplays in the array
  15.         public ItemInfoDisplay[]                        m_itemInfoDisplays;            
  16.         public UIDraggablePanel                         m_draggablePanel;
  17.         public UICenterOnChild                          m_centerOnChild;
  18.        
  19.         // A large array of ItemInfo (which contains "info" about an "item", which can be fed
  20.         // to a ItemInfoDisplay which will update to display this info).
  21.         // Not shown: how we populate this array, but it's not important really.
  22.         ItemInfo[]                                      m_items;
  23.         int                                                     m_currentItemIndex = 0;
  24.  
  25.         void Start()
  26.         {
  27.                 // Hook up to onFinished, so we can rearrange the display to keep the scrolling infinite
  28.                 if(m_centerOnChild)
  29.                 {
  30.                         m_centerOnChild.onFinished += OnCenterOnChildFinished;
  31.                 }
  32.         }
  33.  
  34.         void OnCenterOnChildFinished()
  35.         {
  36.                 if(m_centerOnChild != null)
  37.                 {
  38.                         GameObject go = m_centerOnChild.centeredObject;
  39.                        
  40.                         if(go != null)
  41.                         {
  42.                                 ItemInfoDisplay centeredDisplay = go.GetComponent<ItemInfoDisplay>();
  43.  
  44.                                 if(centeredDisplay != null)
  45.                                 {
  46.                                         // Get the index from the currently-selected ItemInfoDisplay, and set that
  47.                                         // as the currently selected item index
  48.                                         int selectedIndex = centeredDisplay.m_index;
  49.                                        
  50.                                         if(selectedIndex != m_currentItemIndex)
  51.                                         {
  52.                                                 m_currentItemIndex = centeredDisplay.m_index;
  53.                                        
  54.                                                 // Re-center panel if necessary
  55.                                                 if(m_draggablePanel)
  56.                                                 {
  57.                                                         int lastIndex = m_itemInfoDisplays.Length - 1;
  58.  
  59.                                                         if(centeredDisplay == m_itemInfoDisplays[0])
  60.                                                         {
  61.                                                                 BumpEntries(centeredDisplay.entryPanelHeight, -1);
  62.                                                         }
  63.                                                         else if (centeredDisplay == m_itemInfoDisplays[lastIndex])
  64.                                                         {
  65.                                                                 BumpEntries(centeredDisplay.entryPanelHeight, 1);
  66.                                                         }
  67.                                                 }
  68.                                         }
  69.                                 }
  70.                         }
  71.                 }
  72.         }
  73.        
  74.         // Bump all the display entries along 1 (either up or down), so we
  75.         // can maintain an infinitely-scrolling carousel
  76.         void BumpEntries(float panelHeight, int bumpDir)
  77.         {
  78.                 // This is for a vertically-scrolling panel
  79.                 m_draggablePanel.MoveRelative(new Vector3(0, -panelHeight * bumpDir, 0));
  80.                                                                
  81.                 for(int i = 0; i < m_itemInfoDisplays.Length; ++i)
  82.                 {
  83.                         ItemInfoDisplay itemInfoDisplay = m_itemInfoDisplays[i];
  84.                        
  85.                         if(itemInfoDisplay != null)
  86.                         {
  87.                                 int nextIndex = (int)Mathf.Repeat(itemInfoDisplay.m_index + bumpDir, m_items.Length);
  88.                                
  89.                                 // ItemInfoDisplay has this SetDisplay method which takes the information from an ItemInfo
  90.                                 // and applies it to the relevant widgets so that the display reflects the information. Also
  91.                                 // tells the itemInfoDisplay the index of the item its displaying.
  92.                                 itemInfoDisplay.SetDisplay(m_items[nextIndex], nextIndex);
  93.                         }
  94.                 }
  95.         }
  96. }
  97.  

11
I do this sort of thing quite a lot in the UI I'm building. I deal with it by having a component on the root of the prefab has something like the following:

  1. class MyAchievementDisplay : MonoBehaviour
  2. {
  3.     public UILabel nameLabel;
  4.     public UILabel descriptionLabel;
  5.     public UILabel pointsLabel;
  6.     public UILabel targetLabel;
  7. }

In the editor, you just drag and drop the reference to each label to the appropriate place and apply it to the prefab. Then when you've instanced each prefab you just need to do this:

  1. MyAchievementDisplay display = achievePrefab.gameObject.GetComponent<MyAchievementDisplay>();
  2. display.nameLabel.text = Achievements[j].name
  3. display.nameLabel.description = Achievements[j].decription
  4. // ... etc....
  5.  

12
NGUI 3 Support / Re: NGUI Free
« on: April 18, 2013, 04:28:10 AM »
This has happened to me with the Pro version from time to time (not 3 times in a day, but maybe 3 times in the last 3 months). I can't remember how I fixed it each time, but likely some combination of Assets/Sync MonoDevelop Project, deleting the Library folder for the project so that it rebuilds everything on the next startup, restarting Unity and rebooting the machine. I don't know exactly which combination of these things fixes the issue for me - Unity crashes and oddities like this are depressingly common for me (10 - 20 crashes a day, and some weird brokenness like this at least once a week), but it's hard to know which things are  problem with Unity, or MonoDevelop, or NGUI, so I generally just have to shake my head and try to carry on  :(

13
NGUI 3 Support / Fix 3D object to widget position
« on: April 15, 2013, 05:47:57 AM »
I'm looking for something that basically does the opposite of UIFollowTarget in the HUD Text package does. UIFollowTarget converts a position in a 3D scene to the corresponding position in the 2D camera used by a HUD (and it works great, by the way!). What I also need to be able to do is to take the 2D position of a UI element and use it to position a 3D object so that it will appear to be fixed relative to that UI element. Obviously when converting from 2D to 3D you'd get a ray rather than a single point - that's fine, I can just choose a point that's a suitable fixed distance along that ray.

Has anybody done this before? Any code or examples that can be shared?

14
NGUI 3 Support / Re: UIFilledSprite for semi-circular bar?
« on: April 09, 2013, 06:32:29 PM »
Of course I meant UIFilledSprite - stupid me... I've edited the subject and my post to avoid confusing anyone else  ::)

I tried your suggestion but it didn't seem to help. Scaled panel X by -1, which flipped the sprite, but then the pivot point flipped to match (so I was looking at the right-hand side of a clock face, with the fill pivoting around 3 o'clock). I tried inverting the X scale of the sprite, hoping that would display the sprite the way I wanted it whilst leaving the pivot on the right-hand edge, but no luck - it flipped back, the double-negatives in the transforms cancelled out, and I was back where I started.

I guess I could make it work by flipping the actual texture on the texture atlas and then flipping the panel/sprite. It would be a bit weird to make art changes in future though, unless I also flipped all of the textures for the surrounding/background elements so that every matched. Right now I've got it working by having a normal sprite carefully positioned inside a clipping panel, and rotating the sprite to make it fill and empty. It works, but I was hoping that UIFilledSprite might let me do the same thing but more neatly, without having to worry that the alignment has accidentally gone wrong or something.

15
NGUI 3 Support / UIFilledSprite for semi-circular bar?
« on: April 09, 2013, 05:51:39 PM »
Hi,

I've got a bar (of the energy/health type variety, not the beverage-selling type). It uses a semicircular sprite - imagine something like the left-hand side of a clock face, where "empty" is 6 o'clock, and it has to fill clockwise up to "full" at 12 o'clock. I'd like to use a UIFilledSprite for this, because seems like the kind of thing they're designed for. Unfortunately, I can't get it to do what I want. With a Radial 180 fill dir, the "pivot point" for the fill is on the left-hand edge of the sprite, i.e at 9 o'clock. I need it to be on the right-hand edge (what would be the centre of the clock face if my sprite was a full circle)for it to look right. Invert Fill doesn't work, since that just inverts the fill vertically, not horizontally. Similarly, a Radial 360 fill doesn't cut it, because the pivot is in the centre of my semicircular sprite. A vertical fill sort of works, but for a curved bar it's not quite right either.

Am I missing something? Is there a way to move the "pivot point" around which the radial fills happen? Or is the only way to waste texture page space by having the sprite take up the space of a full circle and using half of the range of a Radial 360?

Pages: [1] 2 3 4