Recently I've been doing a lot of UI (user interface, or menu) work, specifically for console and mobile video games. This hasn't turned out to be nearly as easy as I originally thought it would be. To my relief, others have confided in me that even seasoned veterans of the gaming and mobile app industries find it difficult to engineer UI without things getting pretty kludgy. There are lots of problems to solve along the way, so I thought I'd share some of what I've learned along the way about designing and building game UI.
I want to concentrate on state-based menus. One of the easiest ways to navigate between screens, elements, and submenus of a user interface is using states. If you don't know what that means, my goal today is to try to explain it. I have seen it explained many times in terms that I, as a junior developer, did not understand, so I want to revisit the topic in a way that is as easy as possible to understand for beginners.
So, what is a state? Let's build an analogy using a very simple example. A light in your home has two states. One state, on, represents the light's status when it is (hopefully) powered and glowing. The other state, off, represents the light when it is unpowered and dark. The user can choose from these two states to tell the light how to behave. A simple, state-based interface! Of course, in computer programming terms, even this simple two-state interface can begin to look complicated. Obviously, if the light is off and the user attempts to turn it on, we apply power. If the light is on and the user tries to turn it off, we remove power. But what happens if the user tries to turn the light on when it's already on? What happens if the user tries to turn the light on, but there is no power? We have to account for these possibilities and more.
In the case of a menu system like one you might see in a video game, you might have a "Main Menu" state, a "Load Game" state, an "Options" state, and others. The "state" itself is stored somewhere as a variable. This can be conveniently handled with an enumerated index, which makes it easier for you (and other people working in your project) to read. Using enumeration at the lower level can be a bit intimidating for beginners, but think of it like this: you have a variable, an int called menuState, which is our state variable. Then you have a collection of words that represent constant values that menuState might represent. If your menuState integer matches one of the constant values you defined (an enumerated value), the menu is in a state that it recognizes! Consider the following snippet, defining (enumerating) some constant integer values that represent a menu's states, and setting up a menuState variable.
To connect this to our light bulb analogy, consider the menu system to be the light bulb itself - it can be switched from one state to another. For example, when your program is first loaded and the UI is initialized, the application might take the user to the Main Menu state automatically. But the user can then switch to another state, just as you can switch a light from "off" to "on." Just as you would use a switch to change a light's state from "off" to "on," you can use UI controls to change a menu's state from "Main Menu" to "Options Menu"! For a more concrete example of what I'm talking about, consider this next snippet. Read the comments if the code is a bit confusing right now.
For a more complex example, I'll take the case of a project I was recently assigned. One feature of a game we are making is an image gallery. One of the greatest challenges in building this gallery has been organizing the functions of the menu so that each element is only visible when I want it to be - in other words, when the menu is in the proper state! In organizing the gallery menu into states, the first step was to look at the features and functions the gallery needed to have.
According to the project specifications, the gallery needed to be separated into categories, with a set of buttons to select each category; a grid of selectable image thumbnails filling the rest of the screen; a popup window to display selected images full size; a dialog window for providing extra information to the user; a confirm window for making selections; and an alert pop-up to warn the user when trying to select an item that is not available. If that sounds like a lot of things to manage in one menu, I agree. I felt the same way the first time an assignment like this was handed to me. But using states, breaking these menu elements into manageable chunks was a breeze! I'll talk through my process to make it a little easier to see.
The first step I took was to break each function of the gallery apart into pieces, to be grouped into states based on when the functions would be available. For example, when the category buttons needed to be active, nothing else in the menu could be. The game needed to know that when the category buttons were active, arrow key and button presses would only affect the category buttons themselves. The solution is to tell the gallery menu that it is in the CategoryButtons state!
When the menu is in a given state, input should only effect the part of the menu that corresponds to the current state. For example, when the user presses the down arrow, if the menu is in the CategoryButtons state, the cursor should move down the list of category buttons. The cursor in the thumbnail grid should not move; in fact, it probably shouldn't be visible at all! Then, when the player finally presses a button to confirm a category selection, the state of the menu is changed from CategoryButtons to ThumbnailButtons. Now, the game sees the state change, makes the category button cursor disappear, and makes a cursor appear on the thumbnail grid. Now, control input makes the thumbnail cursor move, instead of the category button cursor! See the following snippet for an example of how this would look in code. Again, I've tried to add a lot of comments to make it clear what I'm doing in the code.
Obviously, there is a lot more to state-based UI development than just managing the states themselves. And of course, states can be used for a plethora of other tasks that I haven't begun to delve into, and there is a lot of other stuff to worry about when you are putting a UI together. States are just the beginning and help to organize your menu and control flow throughout the menu navigation process. But hopefully this will help you understand the fundamental state-based strategy for menu management!
Thanks for reading!
- Steven Kitzes
No comments:
Post a Comment