x


GUI best pratices?

Every time I design a GUI in Unity (especially something like a menu or options screen), I feel like I'm doing something wrong by including all the textures and positions and everything in variables in the script. When the GUI becomes increasingly complicated this can get really messy, really fast.

So what's the best way to go about creating a GUI? Where should you place all your texture references? What about your strings? What's the best way to center something? What's the best way to combine a GUISkin/GUIStyles with code? I just feel like every time I code a semi-complicated GUI I'm doing something wrong.

I realize this is a lot of tiny questions in one, and I'm just sort of looking for some pointers/tips on the topics I mentioned. Thanks.

Edit: I really don't want to start a bounty on this question... noone has ANY ideas?

Semi-personal note: I had a project on hold, as I was going to wait for the answers from this question so I could do the GUI in the best practical way possible, however I can't hold it off any longer. I guess I'll just do it the old-fashioned, dirty way until someone comes up with a solid answer.

more ▼

asked May 14, 2010 at 12:39 AM

qJake gravatar image

qJake
12.6k 91 121 200

I agree this has kept me so far from coding a complicated gui.

May 14, 2010 at 01:04 AM Maltus

This isn't really answer (hence it is a comment. Sorry for some redundancy), but I find that using GUI textures just feel cleaner to use. If something was a label or a non-button, I don't have to code anything except for maybe scaling the tex to fit the screen better so that always makes it feel cleaner to me. The buttons become a little more complex and sliders are nasty to code, but it still feels better for me because everything is easily defined in OnMouseBlank so you can determine what happens on any particular user input.

Now this is just my opinion, but maybe it helps.

May 14, 2010 at 01:22 AM Peter G

Yes, it's a complex question, but also a good one - there's a lot I don't understand about GUI-building in Unity, best-practices, design principles, performance tradeoffs... I hope you get some good answers, I'm certainly also looking for them.

May 14, 2010 at 03:45 AM Cyclops

Unfortunately GUIText/GUITextures are a step backwards. UnityGUI can do everythign that GUITextures/GUITexts can do, and then some, and it handles a lot of complicated positioning and spacing for you. GUIText/GUITextures might have come first, but UnityGUI is newer, and much more robust. I'd like an answer that pertains to UnityGUI, not GUIText/GUITexture. :)

May 14, 2010 at 04:16 AM qJake

It's easier and faster to do some simple things with GUIText/GUITextures compared to OnGUI, but I definitely wouldn't try to make something complicated with them....

May 14, 2010 at 10:26 PM Eric5h5
show all comments (comments are locked)
10|3000 characters needed characters left

5 answers: sort voted first

I'm hesitant to speak on this too much since I have yet to do heavy GUI work in Unity, but from a theory standpoint there are two main mentalities I've seen at work-

1) Decide your resolution and keep to it. Having spent a few years at the fringes, and more recently diving into the Industry proper, I see a lot of artist/designers who want to know that the interface will be ~exactly~ as they design it. So they do up the interface in precisely-sized native-resolution art to fill the screen just-so and it all gets either hardcoded in as you first describe, or I think (though I have little reference) more frequently parameterized out to a config file. Each resolution the game can run at gets logged as a set of config params to select which assets to place where, and/or which asset set to use, and other resolutions get disallowed. I'd be surprised if there isn't some structure that you can socket into a script var in Unity that could hold that kind of info.

2) Everything is a percentage. Define the position and scale of assets once, normalized to the window size. This works well for vector graphics (and by extension most Flash content), but less well for bitmap assets. If the user changes the window size at runtime, the exact same layout script used at launch can put everything in its proper place after a change. As long as your interface assets themselves are scalable, and you can get their size-as-loaded, this will even let you switch out skins during development without changing too much under the hood. However, bitmaps rarely scale well, so you may need to just define positions and force a minimum window size limit.

Either way, you may get milage from defining some wrapper classes. E.g., if your interface has a health bar (with numeric readout), a magic bar (with numeric readout) and a score meter, and those are always in roughly the same place well and apart from a game timer, well and apart from a hotkey bar, rather than having each item tracked loose in one huge GUI script, try making a VitalsBox object that has your bars, gold & associated text, a MissionTimer object with game time and an optional field for e.g. a time limit or quest detail, and a HotKeysBar object with any and all finnickly little icons you may want to access. Then put an instance of each of those three in your main GUI script. It might even help to create a base class first, with tracking for total-bounding-box-size and other useful generic parameters, and spin your specific interface containers off of that. That way, your main GUI code stays small, and if you play it right, you can make new versions of each component object and socket ~them~ into vars in your main GUI as needed. Further, whenever an asset changes, if you've done your job right the number of other elements that need to move to accommodate it is limited to the scope of the container object it's part of, rather than the whole interface.

more ▼

answered May 14, 2010 at 09:06 PM

sean gravatar image

sean
326 29 22 29

Your first point is moot. Unity handles resolution-independence extremely well, and it's not really something I'm worried about at all. Your second point, Unity already does for the most part. You can define layouts and all sorts of things, and it basically acts like CSS for Unity. And your last point is somewhat useless, as UnityGUI has "containers" that serve the purpose (And are more efficient) than wrapper classes. My question was pertaining specifically to code, and how you can marry code and GUIskins so that your GUI is clean and efficient, but still easy to understand and functional.

May 14, 2010 at 09:15 PM qJake

Sorry, but I was looking for less of "GUI Theory 101" and more of Unity-specific information about how to build a functional, effective, clean GUI from code/GUIStyles.

May 14, 2010 at 09:16 PM qJake

No offense taken. Still, if your concern is that you're setting too many things explicitly in your main GUI, bottom line is they need to be defined somewhere, so reducing the setting bloat likely means using containers in some form to consolidate elements, or using settings-collection objects to group params more human-readably. The rest may just come down to taste :-/

May 14, 2010 at 09:28 PM sean

... and if you're really that curious, the better question might be "Who has examples of GUIs they'd be willing to share so I can get a feel for what tricks are out there?" :)

May 14, 2010 at 09:30 PM sean
(comments are locked)
10|3000 characters needed characters left

This post may go unnoticed because it's 3 months late, but my GUI design theory is as follows:

Disclaimer: I'm new to unity and its GUI, so this is just my method du jour.

My Main GUI is fairly intense, there are numerous areas with scrolling data, others are just buttons with images (via skins), some are drop down menus with sub menus and of course, a large scrolling text area. With that said, it's obvious that I have a lot of separate GUI Elements on screen at one time and all of that GUI Coding can get REALLY messy. My approach is to create a single OnGUI function within a script called "GameManager.js". Along side of this script, I create a separate JavaScript file for each GUI Element I use throughout and then reference them in my GameManager file. It keeps things simple, compact (code wise) and I can have other developers modify the "ListOfStuff GUI Element" while I work on the main control for the other elements .. or the main layout script.

If a GUI element isn't "worthy" of its own script, I'll create a separate function for that piece and then reference that function within the OnGUI for display.

Here's an example that includes both techniques: (hope this helps!)

------------------- GameManager.js ----

var mainGUI;    
var defaultSkin:GUISkin;    

function Start()    
{    
    mainGUI = this.GetComponent("MainGUI");    
}


function OnGUI ()     
{       
    GUI.skin = defaultSkin;    
    mainGUI.display();    
}

-------------------- MainGUI.js ----

private var GMgr:GameManager;

function Start()
{
    GMgr = this.GetComponent("GameManager");
}    

function display()
{
    createMainGUI();
}    

function createMainGUI()
{
    // Top GUI
    displayTopGUI();    

    // Bottom GUI
    displayBottomGUI();
}    

function displayTopGUI()
{
    GUILayout.BeginArea (Rect(0,0,Screen.width,200));
        GUILayout.BeginHorizontal ();
            topMenu_File_Button();
            topMenu_Window_Button();
            topMenu_Header();
        GUILayout.EndHorizontal();
    GUILayout.EndArea();
}
more ▼

answered Oct 25, 2010 at 04:02 AM

GlennHeckman gravatar image

GlennHeckman
400 19 17 29

(comments are locked)
10|3000 characters needed characters left

This might not be the optimal answer, but... I guess it really just depends on your project, and how "messy" you want things to be. GUI Helper classes are always a plus, for instance, I just wrote this for my game, because I had found I would always want to anchor some GUI element to a spot on the screen easily:

using UnityEngine;
using System.Collections;

public enum AnchorType
{
    TopLeft,
    TopCenter,
    TopRight,
    MiddleLeft,
    MiddleCenter,
    MiddleRight,
    BottomLeft,
    BottomCenter,
    BottomRight
}

public static class GUIAnchor
{
    public static Rect PositionFixed(Vector2 size, Vector2 offset, AnchorType type)
    {
        return PositionFixed(size.x, size.y, offset.x, offset.y, type);
    }

    public static Rect PositionFixed(float x, float y, Vector2 offset, AnchorType type)
    {
        return PositionFixed(x, y, offset.x, offset.y, type);
    }

    public static Rect PositionFixed(Vector2 size, float xOffset, float yOffset, AnchorType type)
    {
        return PositionFixed(size.x, size.y, xOffset, yOffset, type);
    }

    public static Rect PositionFixed(float x, float y, float xOffset, float yOffset, AnchorType type)
    {
        float top = 0;
        float left = 0;

        switch (type)
        {
            case AnchorType.BottomCenter:
            case AnchorType.MiddleCenter:
            case AnchorType.TopCenter:
                left = Screen.width / 2 - x / 2;
                break;
            case AnchorType.BottomRight:
            case AnchorType.MiddleRight:
            case AnchorType.TopRight:
                left = Screen.width - x - xOffset;
                break;
            case AnchorType.BottomLeft:
            case AnchorType.MiddleLeft:
            case AnchorType.TopLeft:
                left = xOffset;
                break;
        }

        switch (type)
        {
            case AnchorType.TopRight:
            case AnchorType.TopLeft:
            case AnchorType.TopCenter:
                top = yOffset;
                break;
            case AnchorType.MiddleRight:
            case AnchorType.MiddleLeft:
            case AnchorType.MiddleCenter:
                top = Screen.height / 2 - y / 2;
                break;
            case AnchorType.BottomRight:
            case AnchorType.BottomLeft:
            case AnchorType.BottomCenter:
                top = Screen.height - y - yOffset;
                break;
        }

        return new Rect(left, top, x, y);
    }

    public static Rect PositionScaled(Vector2 size, Vector2 offset, AnchorType type)
    {
        return PositionScaled(size.x, size.y, offset.x, offset.y, type);
    }

    public static Rect PositionScaled(float x, float y, Vector2 offset, AnchorType type)
    {
        return PositionScaled(x, y, offset.x, offset.y, type);
    }

    public static Rect PositionScaled(Vector2 size, float xOffset, float yOffset, AnchorType type)
    {
        return PositionScaled(size.x, size.y, xOffset, yOffset, type);
    }

    public static Rect PositionScaled(float x, float y, float xOffset, float yOffset, AnchorType type)
    {
        if (x < 1)
        {
            x /= 100;
        }
        if (y < 1)
        {
            y /= 100;
        }
        x = Screen.width * x;
        y = Screen.height * y;

        return PositionFixed(x, y, xOffset, yOffset, type);
    }
}

It's not great, it doesn't do much, but it's an example of some GUI code that can be wrapped up statically in another class, making your other code less sloppy.

Anyone else have any other examples like this? And perhaps someone could give me some feedback on this class, perhaps things that could be added to it, or potential bugs.

more ▼

answered Jun 20, 2010 at 12:05 AM

qJake gravatar image

qJake
12.6k 91 121 200

Why not just use the existing TextAnchor enumeration?

Jan 29, 2011 at 06:45 AM yoyo

From your experience should I be using GUITexture and GUIText components for an iOS game or OnGUI for best performance? My game has 2 GUIText objects and 6 GUITexture objects (for buttons and icons). Cheers

Feb 25, 2012 at 04:06 AM numberkruncher

@kruncher: Why do you post this question here as comment?

Anyway, there's not much difference between using GUIText / GUITexture or UnityGUI. Both methods produce a lot drawcalls. A single button in UnityGUI has 2 drawcalls (background image + text).

It's better to use a custom GUI solution like EZGUI which combine everything into one drawcall. Unfortunately those solutions aren't for free.

If this is not an option, try to minimize your GUI elements and avoid text + image elements. Buttons can be created without text. Just create the button texture with text, use a style without background images and use the Button() function which takes a Texture2D as parameter.

Feb 25, 2012 at 05:00 AM Bunny83

No, it uses a procedurally generated Mesh for everything ;). You could do something like that yourself. Not as advanced as EZ but as long as it fits your needs...

Take a look at the SpriteManager from the UnifyCommunity wiki. It can also display multiple simple rectangular sprites with a only one drawcall.

edit
If you just need the GUI for your main menu, don't bother about performance. If you need alot in-game GUI stuff that's a different story.

Feb 25, 2012 at 02:36 PM Bunny83

@Bunny83 I just came across Prime31 UIToolkit which is free (http://forum.unity3d.com/threads/87917-Prime31-UIToolkit-Multi-Resolution-GUI-Solution-Ready-for-Use...and-it-s-free) Not sure how it performs yet but maybe worth a look for people!

Feb 26, 2012 at 03:45 AM numberkruncher
(comments are locked)
10|3000 characters needed characters left

Some useful things you can do include:

  • Decide on your "canonical" screen resolution and scale things accordingly based on your actual runtime resolution -- designers can create art for your primary resolution (say 1024x768, if you're an iPad fan, or maybe you prefer 1920x1080 for full HD support), but you can resize all your art on the fly to fit 480x320 in your iPhone build.
  • Know your audience and target platform -- review Unity's web player statistics and the Steam hardware survey and decide how your application will most commonly be viewed.
  • Yes, textures get slightly fuzzy when they are resized, and yes, you will use more disk space/download time/memory than necessary -- when the time comes to publish a build, you can resize artwork in the pipeline, but design-time flexibility is very handy for speeding up iteration.
  • Althought Unity does handle resolution independence well, you still need to consider change in aspect ratio -- are you going to show more on one side? crop the other side? or squash things? (4:3 is common, or 16:9 for HD).
  • Use skins to consolidate constants, colours, and texture references -- GUISkin is a good example, and you can get plenty of mileage from GUISkin itself, but you can also use the same concept for your own "skin" classes -- create a class that's nothing but public fields, create (typically) one instance of it in your scene, and reference it from any OnGUI method that needs to know those icons/colours/fonts/offsets/scale parameters/etc.
  • Save these skins as assets, rather than components in the scene -- you can put a GUISkin in your Project view directly, or a prefab that references your custom skin. The benefit of this is that a skin tweak does not require a scene change, a definite boon to your version control issues if you are using Unity Free on a multi-member team.
  • Learn how to use the capabilities of the GUI API to full advantage -- for example, use GUI.color to tint a font or grayscale texture, so you don't have to create multiple fonts/ textures; use GUI.matrix for sub-pixel positioning when you have moving elements; use GUI.matrix also for font resizing (but don't stretch a font up by more than about 1.5x).

Hope that's helpful to someone, and thanks to everyone for sharing their tips.

more ▼

answered Jan 29, 2011 at 07:05 AM

yoyo gravatar image

yoyo
8.1k 59 67 124

To which I'd add, investigate 3rd party GUI add-ons and see if there's one that fits your needs and saves you some time. On my current project we've decided to use EZGUI (http://anbsoft.com/middleware/ezgui).

Apr 12, 2011 at 05:42 AM yoyo
(comments are locked)
10|3000 characters needed characters left

For me this is a question of where is the info that is displayed in the GUI coming from or related to? So in some ways it is analogous to arranging your assets folder. You could put all your textures in a textures folder, all your models in a models folder etc, but is that a sensible arrangement? As the project gets larger you end up with folders full of stuff only related by the fact they are textures models etc.

So back to the GUI. I have a guiscript that manages drawing the GUI and contains references to the standard assets used for the static or non specific elements of the GUI. However a reasonable Chunk of GUI code and asset references are in scripts attached to the gameobjects they relate to.

Eg. A leaderboard for a race. It has a standard frame but each player in the race has a different logo and distinctive colour, plus it has player specific values that get printed in the leaderboard entry for that player.

So, the guiscript has a reference to the leaderboard frame and the code to iterate through the players in the race and get their leaderboard entries let's say by calling the getLeaderBoardEntry(x:int,y:int) function on each player. Each player will have a reference to their color, logo image and of course it's data. That function will take in the screen origin point of the leader board entry and draw textures text and colour the entry appropriately returning let's say the width And height of the entry as a vector2 so that the guiscript can pass the correct coords to the next player.

That's a fairly specific example about how I go about things in general but this approach has quite a few advantages in general I think.

It becomes easier to reuse your guiscript code because it is more general since the specifics are called elsewhere. It is easier to search for things to debug because they are somewhere relevent. It is easier to customise. Ie. In the above I could have all sorts of players with different leaderboard entry code meaning each leaderboard entry could be quite different depending on what the player was.

Hope this is sort of helpful in some way.

more ▼

answered Jul 08, 2010 at 10:43 AM

cncguy gravatar image

cncguy
1.1k 57 45 59

As nice as this may work, it's not really very design-conscious in terms of programming... typically you'd want all the GUI code in one place so it's easier to manage (instead, grabbing the raw data from other objects and having either one large, or a set of, GUI class(es) that draw it all at once). Splitting your code up into random places in your project can get really messy, and it can get really easy for someone to become lost (i.e. "Where does this get drawn?"). It's a good idea, but it's fundamentally flawed imo.

Jul 08, 2010 at 09:08 PM qJake

While I see your point SpikeX I maintain there are situations where my approach is desireable. And the code is not in random places all over the show it is in a clearly thought out script on the applicable object.

To back this up, you wouldn't put all your behaviours for all your gameobjects in one script and then apply them to references of the gameObjects. The behaviours are best coded on scripts attached to the gameObjects they relate to. I see that as analogous - you may not:)

Jul 08, 2010 at 10:04 PM cncguy

I think that applies to game logic code, not GUI code, which is typically very messy... therefore, it should be in its own separate area so as not to clutter everything else up. :P

Jul 09, 2010 at 06:29 AM qJake

splitting up your GUI code to make it more readable is never a bad idea.

Mar 05 at 03:53 PM emalmud
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x5452
x220
x80

asked: May 14, 2010 at 12:39 AM

Seen: 27670 times

Last Updated: Mar 05 at 03:53 PM