iPhone game to iPad – User interface considerations

I recently began porting my iPhone game SpringFling to iPad. The most time consuming part so far has been working with the art assets to make them work on the new screen size. I had stupidly designed most of the UI for the game at native resolution (480 x 320 px) which forces me to now re-do much of the art at 1024×768. Instead of just re-creating the exact menus at a higher resolution, I’m taking this chance to re-design certain areas of the menus.

I’ve noticed an issue with some iPad games that have been ported from the iPhone version. It seems the developer, in an attempt to reuse the same art assets, keeps HUD and UI elements the same size but ends up with huge areas of empty space and useless padding. Contexts with very little info end up taking the whole screen, making the overall composition feel lonely and awkward, like sparsely placed townspeople in a model train set.

By forcing myself to re-design certain areas, it will (hopefully) help ensure a smooth and appropriate user experience on the iPad.

Here is my progress so far:

And no, I haven’t gotten around to fixing the in-game HUD imagery yet. I’ll get to it soon, nagging Nancy.

5 Comments

SpringFling – Main Menu UI Mockup

A quick mockup of the UI. Grass and sky were painted in Photoshop. I plan on having the sun come up over the gray UI element as a subtle tip of the hat to the geniuses at Popcap.


I’ve been using the name ‘SpringFling’ as one word throughout development but people frequently put the space after spring so I don’t feel too bad wrapping the name on two lines in the main menu.

Comments Off on SpringFling – Main Menu UI Mockup Comments

Wrangling GUIs with Unity iPhone

Dealing with GUI creation is both a rewarding and frustrating venture. While working on my iPhone game SpringFling, I’ve come across some GUI conundrums. I wanted to achieve a UI effect like this:


The height bar would dynamically fill up based on the y-height of the player. It seemed simple to do, as I would just modify the scale attribute of an overlaid half transparent plane that would represent the filled portion of the bar. I could then rotate the bar slightly to match the 10 degree angle on which the ruler is set and all would be well. That doesn’t quite work out as simply though. When you’re working with GUI in Unity, it is a special graphics layer that is rendered last. That means that no 3d elements can ever go in front of your UI. I knew of this limitation and thought that I would just use two GUITextures and scale the red bar dynamically. Unfortunately, you are not able to rotate GUITextures so I first moved to a much more dynamic solution: Render textures. Using render textures in the Unity editor without touching a script, I was able to achieve the GUI element below:

Due to the awkward size of the video, you can also view the source .mov here:
http://gtproductions.net/projects/springFling/springfling_heightbar.mov

Behind the scenes, this progress bar consists of two planes, one with the ruler texture and height text, and a separate single poly plane positioned over the ruler. The shader is then set to additive and the scale is modified in the playerScript. The y-height of the player directly affects the scale of the red bar. The single poly plane used for the red bar needed to scale from the left side so the pivot point had to be manually moved in my DCC app (Maya) in order to get scaling to happen in the correct location. Once this setup was working, I moved it out of view of my main camera and created a second camera and pointed it at my height bar. This second camera would look at the UI setup I created out in space to the side of the main level geometry. I then created a new render texture and in the properties dialog of this second camera, I added my render texture into the ‘target texture’ field. Lastly I positioned my render texture near the bottom of my main camera and voila, a 3d UI overlaid on my game scene. This unfortunately is a Unity Pro-only feature so I needed to find another way to do this.

EDIT: Thanks to Dreamora and Matt for the guidance. It also seems that render textures do not actually work on iPhone hardware so this solution is wonderful for Unity Pro desktop games but for the iPhone, another solution can be used. You can accomplish the same result using two cameras and no render texture. Just set everything up as I mentioned above but instead of using the render texture, set the “Clear flags” on camera2 to ‘none’ so basically the background of will be transparent and camera2 will be rendered first and then the main level camera second. This allows the gui to be overlaid on top of the scene while allowing 3d geometry to come BEFORE the gui elements. This is key for any type of crazy/interactive gui in almost any game. Hey we’re using this technique at work for rendering a 3d UI over a background scene.

One other thing I’m experimenting with is the use of Unity’s great new GUI system known as UnityGUI vs the old tried and true method of GUITextures and GUITexts and manual UI development. Instead of event driven GUI development, UnityGUI uses an Immediate Mode GUI system, or ‘IMGUI’ which basically boils down to the fact that you work with the GUI in a separate GUI-specific update loop where you use logic to change GUI elements dynamically. This makes fades, slides, transforms, and other animated GUI operations much simpler and mirrors the regular Unity update loop in almost every way. Below is a basic example of a flashing button:

//flashing button example
function OnGUI () {
if (Time.time % 2 < 1) {
if (GUI.Button (Rect (10,10,200,20), "Meet the flashing button")) {
print ("You clicked me!");
}
}
}


Those familiar with Unity iPhone development will note that it is not advised to use Unity’s built in UnityGUI system and instead opt for GUITexts and GUITextures due to performance reasons. This is a valid concern as Unity’s GUI system does have a significant overhead associated with it but it really only comes into play with HUD UIs where UI elements are rendered over a 3d scene that requires a high framerate for gameplay. In a dedicated menu scene, UnityGUI works perfectly on the iPhone but as I move forward with custom UI art, I might switch over to the old GUITexture method to save resources. The last week of development will surely be focused on performance testing so I’ll be able to give more solid statistics on the impact of UnityGUI compared to single UI element placement. If you’re planning on using UnityGUI on the iPhone make sure to turn of automatic layout by putting this line in your Start() or Awake() method:

useGUILayout = false;


It will reduce your GUI overhead to an almost acceptable level for iPhone use but as I mentioned before, it’s not a great idea for a HUD where the game scene runs behind the UI. :)

Lastly, I stumbled across a post about iPhone optimizations and learned that string comparisons are much more expensive than int comparisons. Previously I was managing both game and GUI states with a static state string variable in my main game script. All all other scripts would query this state during the update loop ala:

if(game.state == "flying"){
//do stuff
}


This worked for me as I was able to easily see which state was being addressed by the string name, but after after hearing about the performance hit, I decided to switch over to enumeration. I also rely on a second state variable which I have named guistate to keep track of my different (for a lack of a better term) GUI states. These, for example, consist of ‘mainmenu’, ‘highscores’, ‘shop’, ‘stats’, and of course ‘none’. With the ability to get and set these global states at any time from any script, I can determine where the user is in the logical flow of the game and exactly what they are doing there. Then my onGUI function contains each of my GUIs and wraps each one in a quick if statement ala:

if(guistate == aguistate.death){ //player has died
GUI.BeginGroup ( blah blah GUI creation for death screen goes here);
}


Well there you have it. And if I can leave you with some words of wisdom, GUI takes twice as long as you think it will, even if you know this fact to be true.

7 Comments