Archive for February, 2007|Monthly archive page
I’ve just created a new version of my Dungeon game featuring a custom user interface!!!
As I was saying the other day, the lcdui components don’t make for a very attractive user interface. Particularly for a game, it’s nice to have all of the game’s GUI components match the style and theme of the game. Rather than going with a third-party solution, it’s possible to program the entire user-interface yourself by painting it onto a canvas. One advantage to this is that you can really optimize and only add code that’s relevant to the game rather than filling your game jar with code for widgets you might have used but didn’t.
For my dungeon game (which you can download from my game page which I’ve conveniently added to my sidebar) I’ve added a bunch of new graphical features to make it more attractive. First it starts with an animated splash screen:
Then I’ve painted the timer and custom softkeys onto a full-screen canvas instead of using lcdui commands:
This includes two different sizes of graphics for different screen sizes:
Then the menu of options is painted over the current game screen. I’ve indicated which item is selected by coloring the text blue and putting stars behind it with an animated sparkling effect:
Plus, it shows the labels in French if the microedition.locale system property starts with “fr”:
As I said before, the hardest part is to get the keycodes right for the softkeys. And unfortunately, even if you have a list of key codes for a number of common handsets, it isn’t always easy for the MIDlet to identify the handset. The microedition.platform system property sometimes helps, but not always. Some manufacturers just set this property to return the generic string “j2me” and from there, there’s not a lot your MIDlet can do.
The current version of Dungeon is set so that the custom softkeys will work on the Sagem my700x and probably some other handsets. However if it doesn’t work, I’ve provided a second version with the custom softkey feature disabled. This second version still has the custom menus I’ve added, but uses lcdui commands to make the menu appear and disappear. This is what it looks like:
It’s not as pretty, but I guess it’s not the end of the world…
Suppose you’ve developed a game that starts with a menu of options using the standard MIDP lcdui menu components. It won’t be long before you notice that — on practically every MIDP handset — the lcdui menu components are, well, kind of ugly. And since the lcdui package has a “simplicity over flexibility” philosophy, there’s not a lot you can do to improve your game’s appearance without dumping the lcdui components entirely and drawing your own menu widgets onto a canvas. That’s a lot of work for an existing game, and a possible alternative strategy is to go with J2ME Polish.
J2ME Polish is a set of user-interface libraries that you can add to a MIDlet jar, plus the tools to automatically transform an existing lcdui interface into one that uses the polished user-interface libraries (for a price, of course…).
J2ME Polish works by sending your code through a pre-processing phase that transforms the lcdui calls so that they call J2ME Polish classes instead. To indicate which parts of the code you’d like to transform and how, you add pre-processing directives to your code (very much like the pre-processing directives used when programming in C). To define the precise look-and-feel you want (for example the colors and images to use), you write a series of cascading style sheets and create a hierarchy of resource directories for the various devices you’d like to support and/or for the various “skins” you’d like to use. All the bits of the build process are controlled by standard Ant build scripts.
Actually it is, but it’s a lot simpler than attempting to write your own custom user interface from scratch. Unfortunately most of the complexity comes from compensating for all of the differences from one handset to the next, and — with or without J2ME Polish — you always have to deal with this problem if you want to have graphics that look good on a wide range of handsets.
In practice J2ME Polish is pretty easy to use. I know this because I’ve used it professionally — here’s a game catalog skin we did for Orange using J2ME Polish:
I liked working with J2ME Polish because the natural complexity of the custom user interface problem is organized in a logical way, plus the online documentation is quite clear and extensive, and it’s nice that it follows standards such as css and Ant. (If you’re not already using Ant to build Java ME projects, you probably should be 😉 )
For my latest programming exercise, I decided to download J2ME Polish and see how hard it would be to customize the demo to run on my Sagem my700x. As you can see from the above photo, I’ve already done a J2ME Polish project for this very handset, but I can’t just post the EGE code here because that would be too easy (not to mention illegal…). Anyway, it’s more interesting to start from scratch.
Downloading and installing it was no problem, so I headed straight for the tutorial. The tutorial consists of building a simple sample menu midlet that illustrates how to add some basic J2ME Polish preprocessing directives to transform an lcdui menu into a polished menu. Plus a basic build script and resource directories. To build the sample, all I had to do was go into the menu directory (the directory containing the correct build.xml file) and type “ant.” (If I hadn’t had Ant already set up and configured on my machine, there would of course be an extra step here…) Ant proceeded to build a series of jad and jar files for both the English and German versions of the sample for the following handsets: Sony-Ericsson/P900, Nokia/Series60, Nokia/Series60Midp2, Generic/midp2, Generic/midp1. Naturally, my first thought was to poke around in the build.xml file to see where this list of handsets is defined so I could add my Sagem to it. It was pretty easy to find (in the “deviceRequirements” element), so — following the pattern — I added “Sagem/my700x”.
Just adding the Sagem my700x to the build file wasn’t sufficient though, since — as you might guess — the capabilities of the devices are defined in a file somewhere, and my handset wasn’t there. Grepping around for terms like “Nokia” and “Sagem” I found the capabilities of each device defined in “devices.xml” and “custom-devices.xml.” The “devices.xml” file listed a Sagem myX7, but the capabilities weren’t quite the same as my handset (notably the screen size and CLDC version were off), so I added a new entry for my handset, following the model of the others.
The “custom-devices.xml” file says in its header that you’re supposed to modify that file instead of modifying “devices.xml,” but for some reason just adding the device to “custom-devices.xml” didn’t work. I could read the manual to try to figure out why (because you know how they say “when all else fails read the manual”), but all else hadn’t failed yet since adding it to “devices.xml” worked. 😉 And anyway, for this exercise I just wanted to see how quickly I could get the project working — beautification comes later.
To find the data to use in the “devices.xml” file, I consulted the J2ME Polish device database. This is a great resource because it lists all sorts of useful data for developers about a huge list of handsets. In particular, it lists a lot of the softkey keycodes which (as I mentioned earlier) are often hard to find. It didn’t list the keycodes for my little Sagem, but fortunately I’d figured them out myself in my previous exercise about keycodes.
The reason I want to know the keycodes for the softkeys is because that allows J2ME Polish to polish the softbar — that is, to draw a pretty softbar that matches the rest of the user-interface design rather than having a mixed look that includes polished user-interface components with an ugly lcdui softbar.
Obviously I wanted the nice polished softbar since I have the data to do it, so in the “devices.xml” file I added the “LeftSoftKey” and “RightSoftKey” data to my description of my Sagem my700x, following the example of some other handset descriptions that had softkeys listed. That wasn’t sufficient to get it to use the softkey values and create a pretty softbar though, so this time I finally broke down and consulted the documentation to figure out why. Annoyingly enough, I couldn’t find anything about softkeys except a hint that in the build element of the build.xml file the “fullscreen” attribute needs to be set to “true” or “menu.” It was already set to that, though, so I figured there had to be something else. So, back to the standard troubleshooting bag of tricks, I compared the device descriptions of those devices with polished softbars and those without, and a little trial and error led to the idea that “hasCommandKeyEvents” needs to be listed in the “features” element of the device. That did the trick, and I ended up with a nice little demo for my handset.
All in all, I would say it was about a half-day’s worth of work (including some leisurely coffee-breaks 😉 ).
For a professional project, I would of course recommend reading the manual or the book first in order to set everything up right (rather than just sloppily plunging forward as I’ve done here), but as you can see from this example, J2ME Polish is a pretty quick and easy way to fix up your MIDlet’s user interface.
When you use the MIDP Canvas class, you can listen for key-press events by implementing methods such as keyPressed and keyRepeated. The platform calls these methods with a “keycode” argument that tells you which key was pressed. The key code isn’t always useful since the key code values vary from device to device. For example, the pound key # has key code 35 on my Sagem my700x, but the same key might have a different key code value on another handset. The Canvas class provides the getGameAction method that allows you to identify which key the key code corresponds to for a number of familiar keys.
Unfortunately, there are some fairly standard keys that the Canvas game action constants won’t help you to identify, notably the left and right soft-keys. If you’d like to listen for soft-key events, it can be very tricky. Setting up your MIDlet to identify the key codes on a device-by-device basis is already a lot of work, and the difficulty is compounded by the fact that for a lot of devices the key code mapping is hard to find published anywhere. Sony Ericsson has posted a developer guide which lists the complete key-mapping chart (on page 36). Many others don’t.
Googling around the Internet, I couldn’t find a key mapping chart for my Sagem my700x. But there’s one way to find out!! Write a MIDlet that will check. 😀
My “KeyCode” MIDlet (code below the fold) is a simple MIDlet that listens for key-press events and displays the corresponding key code on the screen. This exercise is a little like my earlier exercise to write a MIDlet that will tell me what optional APIs are available on the handset. One difference is that all of the information about the optional APIs (plus a bunch of other stuff about the handset’s capabilities) can be gathered automatically, without any input from the user. But for the key-mapping, I can’t think of any way of getting the information from the handset without having the user physically press the different keys and see which key codes are generated. That’s probably why MobileZoo doesn’t provide key-mapping information for the handsets in its database even though the key-mapping is useful for developers.
The result for the Sagem my700x? It had exactly the same key codes as the Sony Ericsson key-mapping except that the soft-keys were reversed: on the Sagem, the left soft-key is -7 and the right soft-key is -6. The WTK emulator has the same key-mapping as Sony Ericsson as well, which is probably not a coincidence. Still, since the soft-keys are among the keys that don’t have standard constants, it’s kind of annoying that those are precisely the ones that are less predictable…
Here’s the code for a simple MIDlet to get the key-mapping from your handset: