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.


Topics - electrodruid

Pages: [1] 2
1
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?


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

3
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?

4
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?

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

6
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?

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

8
NGUI 3 Support / Atlas/Font switching and multiple scenes?
« on: April 09, 2013, 05:54:07 AM »
My game has a few different UI scenes - a splash/loading screen, the main frontend, the ingame HUD, the pause menu (incorporating a few different screens in one scene), etc. I'm using reference atlases and fonts to be able to switch to HD on some platforms. The only way I know how to do this is to have each scene contain an instance of each atlas and font I want to use in the game (1 atlas and 4 fonts, at the moment). I've made a prefab called AtlasAndFontReferences, which contains the atlas and the fonts and the scripts which change the references when Start() is called. There's one of these prefabs in each scene. This works fine so long as everything in the scene points to the corresponding AtlasAndFontReferences for the scene. Where it falls down is (for instance) when a scene loads prefabs at runtime (HUD text score popups, shop/inventory items, etc). The code then has to "manually" change all the sprites and labels in the prefab to point towards the atlas/fonts in that scene's AtlasAndFontReferences, otherwise they end up pointing to the original prefab, which I don't think I should be changing at runtime. This is a bit messy and problematic.

My question is this: Am I completely insane? It really doesn't make sense to try to shoehorn the entire UI for the whole game into a single scene, but do I really need to maintain a set of reference atlases and fonts for each scene? Or is there some way to have some kind of static, central set of them which can exist in every scene?

9
NGUI 3 Support / Prefab instances not saving atlas references?
« on: April 05, 2013, 06:40:44 AM »
I have a weird problem. So, my GUI is split across a few different scenes (a frontend, a HUD to load additively over every level, a pause menu, etc), and all the sprites in all of the scenes all use the same reference atlas. Well, sort of... In order to have a script be able to actually change the reference atlas to point at the right SD/HD version, I have to have an instance of the reference atlas in each scene. All of the sprites in that scene point to the scene's reference atlas, and there's a script attached to the atlas in each scene to change the reference depending on the device resolution. With me so far?

So the problem comes when I have prefabs in my scene. Say I've got a prefab that contains a sprite. If I created the prefab in Scene A, then it will work just fine in Scene A, but if I try to use it in Scene B it won't work because the sprite needs to be referring to Scene B's atlas. I've got an editor script which automates the process of changing sprites in a scene to point at that scene's atlas, which appears to work fine. So I can open Scene B, import my prefab, run my editor script to make the prefab sprites use Scene B's atlas, look at the prefab in the inspector to confirm that the atlas has been changed, and then save the scene. The problem is if I then load up different scene and then go back to Scene B (or quit and re-open Unity), it hasn't saved the changes and the prefab sprite is using the wrong reference atlas again. Normally when you change something the new value shows up in bold, but that doesn't seem to happen with atlases :( Any ideas?

10
NGUI 3 Support / PixelPerfect and Atlas switching
« on: March 20, 2013, 10:35:19 AM »
Hi,

Apologies for all my atlas switching questions recently - I've been having trouble getting to grips with it all  :-[

Here's my setup: UIRoot is set to PixelPerfect, and although I'm using UIStretch (and several custom variants of it) to scale panels made from UISlicedSprites, anything involving a UISprite is set to the same size as the resolution of the texture it uses in the editor (i.e. by pressing the SetPixelPerfect button). Likewise with UILabels - we don't scale text. The artist I'm working with is very particular about not wanting any scaling to muddy up any of his textures. Having the UIRoot set to PixelPerfect is a difficult path to take, since a lot of the stuff that "just works" in NGUI only works if you have a fixed size set.

The problem is that there doesn't seem to be a way to automatically rescale UISprites and UILabels after switching over to a HD atlas. So, a button image that's 150*50 pixels in the SD atlas is 300*100 in the corresponding HD atlas - but when the game decides to use the HD atlas and changes the reference, the widgets don't resize. If I call NGUITools.Broadcast("MakePixelPerfect"); after setting the atlas the active widgets resize properly, but the inactive widgets in the scene don't and will still look small when they get activated.

Is broadcasting the MakePixelPerfect the only (or the recommended) way of doing this? And if I do it that way, will I have to broadcast the message every time I activate something, just in case it has been inactive since the atlases switched over? Or do I need every active object that holds a reference to an inactive one to use that reference to try to walk through the children trying to rescale everything?

11
NGUI 3 Support / Font Maker and HD Atlases
« on: March 14, 2013, 06:12:14 AM »
Hi,

So I'm switching my UI over to use a reference atlas so I can do the SD/HD stuff. As I understand it, the SD and HD atlases should have the same layout, and the sprites on them should have identical names. The tools the artist uses to generate the textures ends up spitting them all out into the same folder, with the HD textures having "@2x" stuck on the end, so it's a bit of work to seperate them out into seperate SD and HD folders and then renaming them all back to the original names, but I realise that's not NGUI's fault and that it's probably not trivial to support atlas sprites having different names on different atlases. But when it comes to creating the fonts, it all goes a bit weird.

For SD, I drag the SD version of MyAwesomeFont.png and MyAwesomeFont.txt into the Font Maker tool, and it dumps a MyAwesomeFont.prefab into the root of the Assets folder. I go and find it, and manually move it to where I actually wanted to create it (say, in Assets/Prefabs/UI/SD), because the Font Maker and Atlas Maker tools don't let you specify where you want to create stuff. Then I go to do the same for the HD version, but because there is now already a font called MyAwesomeFont, the Font Maker doesn't want to create a new version for me, it wants to replace the existing version. So as far as I can see, there's no way to have two versions of a font with the same name, because the Font Maker doesn't allow it. Do I have to create them with different names, move them into the correct folders and rename them by hand? Seems like a bit of an icky workflow. Or am I missing something?

12
NGUI 3 Support / Textureless widget?
« on: March 12, 2013, 10:47:40 AM »
Right now, the UI I'm working on has a very "clean" design: Most of it is just text and coloured boxes. Right now we're just using UISlicedSprites with a plain white texture, and tinting them to the colours we want. It works fine, but I'm just wondering whether it would be worth me trying to write a custom widget that's nothing more than a coloured rectangle. We'd save a little bit of texture memory, but is it worth it? Do panels rely so much on having a single texture atlas and a set shader that trying to draw some widgets that didn't have a texture would be slower than just drawing tinted sprites? I don't really understand the inner workings of NGUI or Unity, so I'm curious.

13
NGUI 3 Support / Feature request: More generalised UIStretch
« on: March 12, 2013, 10:39:54 AM »
... Or, possibly, just a bit more control over a UIDraggablePanel? I think the former would give more flexibility, but whatever works best.

UIStretch does a good job of stretching transforms to proportions of the screen size, but it's not really enough when you're dealing with different aspect ratios and resolutions. For my current project, I've had to copy/paste and adapt UIStretch to create several new but very similar components:

  • UIAspectStretch - to stretch widgets (particularly non-sliced sprites) whilst maintaining their original aspect ratio (because using UIStretch alone, a sprite that looks normal on an iPhone will look squashed on an iPad because of the different aspect ratios)
  • UIPixelStretch - Like UIStretch but with an additional pixel component in addition to relativeSize, so you can say "I want this to be 0.75 of the screen width, minus 20 pixels". Again, this allows for more precise layouts when building something to run in different aspect ratios, by making the horizontal and vertical gaps between things always be consistent
  • UIPanelStretch - changes a UIPanel's clipping region, rather than an object's Transform. This is essential if you want to have a UIDraggablePanel that's clipped to some proportion of the screen size rather than an absolute amount
  • UIGridStretch - Also for UIDraggablePanels, but for any use of grids in which the grid elements are scaled: Changes the grid spacing depending on the size of some scaled widget, and updates the grid positioning. Means that if you have a grid of things on (say) an iPad2, and you stretch them to be the same relative size on an iPad3, the grid doesn't leave them overlapping but spreads them out properly
  • UIColliderStretch - Again, made necessary by having a scaled UIDraggablePanel. Scales the BoxCollider for an object to keep all the collision working properly

None of that was difficult to do, but it was a bit annoying that it was necessary, and it involved a lot of copy/pasting of the code. In general, they all calculate the rectangle size in the same way as UIStretch, but then all do different things with them. In future, I'm wondering if it's possible to have UIStretch be able to adjust these things as well as just the transform, or for it to be refactored in such a way that the code to calculate the scaling rectangle is more re-usable.

Also, it would be brilliant if stretching didn't have to happen every Update, but only when something external has changed (i.e. the window the game is running in, or the size of some object that the stretch is using as a reference). It would save a lot of unnecessary processing, although I admit that it doesn't sound easy to properly propagate the information that relevant reference points have changed.

14
NGUI 3 Support / Best way to resize collider?
« on: March 12, 2013, 07:33:08 AM »
I got a scene with a UIDraggable panel which I'm using to scroll through a series of full-screen elements (I'll call them "pages" here). Each page has a background sprite, scaled with a UIStretch to be as big as the screen, and then the other widgets are anchored to points relative to this background sprite. So far so good, except I'm trying to run this on a range of devices and resolutions, including iOS. The UIStretch manages to change the scale of the background sprite for the page and the anchors reposition everything correctly, but nothing causes the BoxColliders to recalculate. Obviously when going from an arbitrarily-sized window in the Editor to, say, an iPad 3 or 4, the effect can be pretty severe. You have to hunt around the screen for the area which is still covered by the un-resized collider in order to get things to scroll.

So, questions:

What's the generally-accepted way to make a collider recalculate after a UIStretch has resized its child element(s)? I guess you'd call NGUITools.AddWidgetCollider, but where and when do you call it? Is there a way of knowing (some kind of callback?) when a UIStretch has caused an element to resize? Or do I have to create a custom component that just resizes the collider every Update? If so, isn't that crazily inefficient? Why doesn't UIStretch already contain the functionality to optionally rescale colliders in the parent object? It seems like a pretty significant oversight that it doesn't, because it means you can never stretch an item which you want to be touchable and have it work properly.

15
NGUI 3 Support / NGUITools.AddChild and composite objects
« on: March 04, 2013, 09:09:34 AM »
Hi,

I've got a scene not unlike Example 7 - there's a UIDraggablePanel containing a UIGrid of objects (I'll call these "items") which have a BoxCollider and a UIDragPanelContents, and then a selection of children which are sprites and labels. Additionally, elsewhere on the screen, I've got a number of sprites representing "slots". The idea is that when you click on an item in the draggable panel, it gets duplicated and positioned in an empty "slots" to show that you've selected the item. I thought that something like this would work:

NGUITools.AddChild(slotObjects[freeSlotIndex], selectedItemObject);

i.e. clone selectedItemObject, position the clone in the same place as the appropriate slotObject, and set the slotObject as the parent of the selectedItemObject. This works, but doesn't give the result I wanted or expected, since although the whole composite item is cloned, it gets broken apart. Only the root of the item ends up correctly positioned and parented. All of its child widgets get left behind and just sit in the top of the screen hierarchy, which obviously looks very wrong.

Am I missing something about how AddChild works? Is there an easy way to use it without breaking cloned composite objects apart? Or do I have to write some recursive function of my own to hold these objects together as I move them around in the hierarchy?

Pages: [1] 2