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.
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.
answered May 14, 2010 at 09:06 PM
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.
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 ----
-------------------- MainGUI.js ----
answered Oct 25, 2010 at 04:02 AM
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:
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.
answered Jun 20, 2010 at 12:05 AM
Some useful things you can do include:
Hope that's helpful to someone, and thanks to everyone for sharing their tips.
answered Jan 29, 2011 at 07:05 AM
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.
answered Jul 08, 2010 at 10:43 AM