It’s finally out… The game I and others at FinBlade have been working on for the last 7 months is available to buy on the iTunes App Store, just in time for the new series of Deadliest Catch too. Of course, 7 months doesn’t just get you an iPhone game, there’s Android, J2ME, BREW, Blackberry and others coming.
I’ve been so busy at work over the last couple of months I’ve not managed any postings to this blog, as you can of course see from the sorry state of the updates. My logs show that people are actually looking at this site, and the numbers have remained small but steady, so I will be continuing postings as I can.
I have a week off work at this very moment with an interesting project I’m actually excited to be doing, so I shall be posting updates on that as I go. There are also plenty of things still to write about on my list, so with some nice weather finally here, maybe I can get a bit of posting momentum going again.
Finally, here’s the last of the embedded Nokia Series 40 “Games I’ve Coded”, Adventure Race (AR).
Originally available on the Nokia 5140i, a beefed up successor to the 5100 that came with Sky Diver. The 5140i was one of the newer breed of Series 40 2nd Edition devices, which included increased heap memory (up from 200k to 500k), bigger jar file size limits (up from 64k to 128k) and the MIDP 2.0 specification programming interfaces. It still had a 128×128 pixel display with a pretty slow refresh, but we’d gotten used to that by now!
The device was aimed at outdoor type people, with a splash proof case, digital compass, thermometer and built in flash-light. Nokia at the time were sponsoring and entering teams into Adventure Sports events, and wanted a game on their ‘sporty’ device to reflect this, so we (Iomo) proposed Adventure Race, and it was my job to code it. From the outset, with the extra memory to fill, the scope of AR was bigger than my previous games, and this was the first one that I was going to code completely from scratch. Almost none of the game’s ideas had been prototyped by someone else first, or coded for other devices, so this was my first completely ‘solo’ programming project.
The game concept involved bringing together 3 sports, cycling, running and kayaking, into ‘iron man’ like events, with some orienteering thrown in for good measure. I’ll write about each sport game here including any coding high (and low) points that I can remember. But first, here’s a video…
There’s another video at the end of the post if you’d like to see some more
Cycling
The cycling game was based around rhythmic button presses to move the bike forward (pedalling), with interspersed downhill sections (free-wheeling) where the player was required to move left and right, or in and out of the screen, avoiding obstacles. At the bottom of the hills the action back to the rhythmic pedalling again. The correct rhythm was key to moving along at a decent pace, and avoiding obstacles so as to not crash got you the best time for the section.
The interesting bit of code that came out of this game was the algorithm to generate a terrain to cycle along, with hills and flats. I found details on the net for midpoint displacement, and it was so simple, and exactly what I wanted for a 2D terrain that coding it was a no brainer. The concept is simple:
Take a straight horizontal line.
Find the mid point, then displace that point vertically by a random amount.
Then repeat for the two new line segments, and so on.
By varying the ranges of the random numbers, and the number of times you repeat the iteration, you end up with very realistic looking mountain ridge lines, it’s awesome. Here’s the code I ended up with:
course_line_segments = 1;
course_map = new int[4];
course_map[course_map_x1] = 0;
course_map[course_map_h1] = 0;
course_map[course_map_x2] = (256<<8);
course_map[course_map_h2] = 0;
int roughness = 32; // Should be between 0 and 128
int iterations = 4; // 4 gives a good value
int displace = 32768; // +/-
for(i = 0; i < iterations; i++) {
new_course_map = new int[course_line_segments << 3]; // (course_line_segments*2) * 4
// for each course line segment, we output 2 new segments
for(int j = 0; j < course_line_segments; j++) {
int x1 = course_map[(j<<2)+course_map_x1];
int h1 = course_map[(j<<2)+course_map_h1];
int x2 = course_map[(j<<2)+course_map_x2];
int h2 = course_map[(j<<2)+course_map_h2];
// first new segment
new_course_map[(j<<3)+course_map_x1] = x1;
new_course_map[(j<<3)+course_map_h1] = h1;
new_course_map[(j<<3)+course_map_x2] = x1 + ((x2-x1)>>1);
int rn = random(displace);
int mid_height = (h2>h1?h2-h1:h1-h2)>>1;
new_course_map[(j<<3)+course_map_h2] = mid_height + (rn - (displace>>1));
// second new segment
new_course_map[4+(j<<3)+course_map_x1] = new_course_map[(j<<3)+course_map_x2];
new_course_map[4+(j<<3)+course_map_h1] = new_course_map[(j<<3)+course_map_h2];
new_course_map[4+(j<<3)+course_map_x2] = x2;
new_course_map[4+(j<<3)+course_map_h2] = h2;
}
course_map = new_course_map;
new_course_map = null;
course_line_segments <<= 1;
displace = (displace*(roughness+128))>>8;
}
I’ve created a simple demo using this code and packaged it up into a Java class that just displays a window on the screen 128×128 pixels in size, and continuously creates new displacement ridge lines. It looks a bit like an audio monitor or something! Change the iterations to 8 and you get something even more like the output from a speech synthesizer.
Drawing the terrain in the game turned out to be pretty easy too. After scaling the data to something appropriate (smoothing out steep slopes, that sort of thing), simply draw a rectangle on the right hand side of the screen, shift the screen buffer left by the width of the rectangle, then draw another one a bit taller or shorter, depending upon the current slope. This approach is very easy to tune for performance too. By drawing larger rectangles, you need fewer of them (which means drawing a screen is faster), however the trade off is that the terrain looks blockier. If you look at the screenshot below, you can see all the rectangles for a screen coloured differently. The best speed/visual trade off turned out to be about 24 rectangles or so by the looks of things.
Running
Having sorted out the terrain for the cycling game, reusing it for the running was the obvious thing to do. Rather than duplicate the rhythm mechanic though, we decided to go with a more resource management approach. The runner has energy that gets used up the faster he runs, and the faster he runs uphill, running downhill uses less energy. You directly control the speed of the runner, and have to manage his energy so he gets to the finish line in the best time. Obviously sprinting flat out isn’t going to work because he’ll quickly get tired and slowly jog along knackered! Since the running mechanic doesn’t involve constantly pressing keys, we reused the left/right dodge oncoming objects idea from the cycling game and made it a core part of the running, so the player can’t just sit back and watch. There are also sprint sections where other runners come up and attempt to overtake you, and you must button bash to keep ahead of them. For fairness, the sprint sections work independently of the energy levels, and there are also energy drinks you can collect on the way.
From the code point of view, there is lots of reuse between the cycling and running games. The colour palettes are changed, and the control schemes differ, but due to both games using the same core, the game specific bits are quite small. Even combined, they are still smaller than the kayaking game!
Kayaking
The 3rd game in the sequence was a top down, vertically scrolling kayak game. I’m pretty sure that this was the 3rd game I implemented too, sorting out the running and cycling first with their similar code, then moving onto the more involved kayaking. I say more involved because there turned out to be several elements to this game that were (at the time) new to me and things I’d not done before.
As you might be able to see from the screenshot (and the earlier video), this game needed the following major elements:
Collision detection for both the water obstacles and the river bank edges.
A procedurally generated river bank.
A large number of animated sprites.
Collision Detection
The front of the kayak sprite is pointed, and as it’s moving down the river, simple bounding rectangle collision didn’t look all that great. It was frustrating to get stuck on objects when the point of the kayak was clearly free. I ended up creating a pixel perfect collision system based on pre-generated bit masks for all the sprites. Using bit masks, and performing shifts and logical & operations after two sprites had failed a bounding rectangle collision test worked very well. All I had to do was write a simple tool that took a sprite PNG file and generated mask bytes for each pixel row based on the non-transparent pixels. Skimming edges of the river and the rocks felt nice after that.
Spline Curve River Bank
The best way to generate the river bank turned out to be using two natural cubic spline curves (one for each bank). By generating the curve in sections as the river scrolled up the screen, only a few calculations needed to be performed each frame to keep things moving along. Obviously the first screen had to all generated before display, but that was done during the loading phase. To get the graduated blue to yellow effect, I simple scaled the x value of the spline calculation, so getting a decent looking ‘shallows’ effect.
I was really proud of that spline curve shoreline. It’s segmented calculation and subsequent rendering using only (fast) horizontal lines worked really well. I’d like to post some of the spline code, but it’s quite awkward to understand with all the fixed point maths, and the specialised segmented calculations. If I get any requests to see it, and I can be bothered to tidy it into something I’d be prepared to post (like the midpoint displacement example above) then I might do it!
Animated Sprites
The kayak sprite itself has 52 frames of animation, the wake 24, rolling log 16 (+16 for it’s water splash), 6 frames for the weir, 9 leaping fish frames 15 different rock frames and an 8 frame finish line flag animation. Not only is that a lot of pixels for one quarter of a 4 game pack that needs to fit into a 128k jar file, but that’s a lot of runtime heap when you needs 2 bytes per pixel. Here is the kayak sprite animation the artist created:
It’s only pointing one direction since the Nokia UI was used to draw the sprite horizontally flipped when moving to the right.
I ended up compressing the sprites into a palettised format that squashed 3 or 4 pixels into a byte depending upon the number if colours in the image, then RLE compressing this data. Then, rather than loading the data into individual pixel buffers for each sprite, which would take up 2 * width * height bytes for each sprite, I actually decompressed each sprite frame into a single small buffer as it needed drawing, each render cycle. Because the actual number of operations to decode a sprite wasn’t huge, and there weren’t very large numbers of sprites on the screen at any one time, the 5140i coped perfectly well. This technique saved loads of heap memory and I allowed for a really richly animated game in total, not just for the kayaking section.
Orienteering
Finally, the ‘filler’ section was a bit of orienteering. This involved seeing a sort of first person view from a position on a map, and you had to guess where you were. The concept had already been done by iomo as a WAP game, and I found a screen grab!
The code for this was a simple perspective projection of a 2D bitmap I borrowed from one of the other programmers at iomo. Since this was done last, it ended up being a bit squeezed for development time and only 4 maps were included in the end, with some rotation for variation. Still, it was a nice enough short diversion in between the other fairly long and involved sections of the game.
Finally
Whilst looking over the bits of my old project (remember this dates back to around mid 2003) I also happened upon probably the most reused bit of code I’ve ever wrote. The ending sequence for AR was a podium animation with the player getting 1st, 2st or 3rd, and a failure screen where they were weeping for their loss. In the background of the podium animation I added some simple particle fireworks, which you can see in this video:
That small particle routine has been reused in a considerable number of my games since then, and it’s still included in my very latest project, that’s being coded this minute. Having also showed it to Mike Tucker, another iomo original programmer and all round awesome guy, he reused it all over the place too. I wouldn’t be surprised if the same code is the basis for the particles you see in the very latest Flash stuff Mike does!
Finally finally, thanks for reading this far and as a treat here’s my original programmer art splash screen. Much better than the professional artist created one if you ask me
My next game in the “Games I’ve Coded” series is Snake EX2, originally available with the Nokia 3300.
From what I remember, I’m going pretty much in chronological order of Nokia embedded ‘white label’ games at the moment. There’s one more game to go for Nokia and one more application that wasn’t a game but more of a handy utility. I wish I could find the time at the moment to write more, and I’d love to get a post in about my companies latest product as soon as it’s available and I can talk about it publicly. I’m probably going to jump around a bit then with games I’ve coded and cherry pick the good ones that will make for some interesting writing.
I’m really glad I can say I wrote a Snake game on mobile. Even today, when I tell almost anyone what I do for a living, they know what Snake is. It’s one of those milestone beacons in the mobile game industry that shines out into the wider media and public consciousness. Of course, I didn’t come up with the Snake idea, and even the code base for Snake EX2 was an iteration of the J2ME version of Snake 2, done by my then colleague Nick Slaven, but at least I can truthfully answer yes when anyone says “You do mobile phone games eh? Like Snake?”.
There nothing very technically interesting to say about the Snake code really. It consists of the usual small number of J2ME essentials, a MIDlet, Canvas, TimerTask, a game engine class and a couple of extras like a custom gauge canvas for picking the difficulty level and two classes for the sound code. The game was designed to use the (then new) Multimedia API for J2ME which was included with the 3300, but it also needed to work on phones without the MMAPI, so it had a fallback using old style Nokia ringtone audio. Total lines of code came to ~5000. As you can imagine, Snake isn’t very heavy on the resources either. 12 midi files for the audio effects and 8 differnet PNG images for the graphics, not including the title screen, were all that was needed.
One thing that I do remember is the way that the game only updated the screen where necessary each frame. These days, it’s pretty common to do a full screen refresh each frame on mobile games, but on the older devices, it was worth being careful about full screen updates. In Snake, only the head, tail and any food that popped in or out needed to be updated each frame. Doing this meant the frame rate would keep to a steady 15 fps no matter how long the snake got.
You might notice there isn’t a background ‘texture’ to the playing area, it’s a plain colour. We originally had a sand like background tile, but when we finally got a real device to test with, the screen quality was quite poor. It couldn’t cope with the background pattern and there was a noticeable pixel crawl that occurred, so we had to get rid of it before the game was finished.
If you search YouTube, you can find various videos of people getting massive scores on Snake games, including EX2. One even shows a nice bug where the food spawns over the snake when it’s really long and fills the screen. It doesn’t seem to crash the game or cause a problem, except for having to keep moving the snake until the food gets free before eating it! Nokia QA must have missed that one.
I enjoyed writing about Triple Pop so much, I’m going to continue straight on with the next game I coded at iomo, Sky Diver. Sky Diver was another white label game for Nokia, this time targeted initially at the 5100, but also later the 3510i. The 5100 is technically very similar to the 7210, it’s another Series 40 v1 device, but is aimed at the ‘outdoor sports’ type person. It has a rugged rubber jacket that’s splash proof and the promo material at the time showed people climbing mountains using it! A game about sky diving was ideally suited to the device.
This time, the game was entirely new, there wasn’t an existing mobile game to base things on. However, if you look closely, you’ll notice a vague similarity to Pilot Wings for the SNES!
At the time, we created designs for games in one or two pages, and it was Glenn Broadway, iomo founder and creative director who visualised the ideas. Indeed, they were mostly his initially, even if they were refinements of existing ideas or games.
Technically, creating a sky diving game for a mobile device actually turned out to be fairly straightforward. My collegue Nick Reed (an amazing programmer who later became technical director of iomo and my boss at Infospace) wrote a few lines of code that demonstrated scaling and rotation on a set of points. By rendering lines between the points it looked like flying down from a height onto an airfield. The MIDP 1.0 specification has basic line drawing methods, but Nokia added an additional API with functions beyond the standard. The early Series 40 devices didn’t have Mode 7 hardware sprite scaling and rotation, but they did have an API with 2D polygon drawing methods. My job was to take the simple idea and along with artist Cameron Kerr, more input from Glenn, and QA from Nokia, flesh it out into the game it became.
Polygon Clipping
You can probably stop reading now if you don’t care about technical details! I didn’t post any code from Triple Pop because basically there wasn’t anything generally useful. In Sky Diver however, there turned out to be an interesting problem that needed to be solved. When the points that described the ground polygons were scaled too much, as happened at low altitudes, the large values passed to the drawLine and drawPolygon methods caused them to become really slow. I imagine there wasn’t any internal clipping performed on the geometry, only pixel clipping to the current screen clip region when attempting to rasterise the line to pixels. This meant if you did drawLine (0,0,10000,10000), it look a long time!
To the rescue came the seminal Computer Graphics, Principles and Practice by Foley, van Dam, Feiner and Hughes. It goes into great detail about line and polygon clipping, and gives algorithms in Pascal or C (depending upon the edition). I wrote these Java routines directly from the algorithms in the book:
To use the routines, you call them with arrays of points, and arrays to put the clipped polygon points into.
if(land_type <= Land_Runway || land_type == Land_Ground) {
c = SutherlandHodgmanPolygonClip(num_points,
poly_x,poly_y, // input verts
clip_x,clip_y, // output verts
TOP
);
if(c > 0) {
c = SutherlandHodgmanPolygonClip(c,
clip_x,clip_y, // input verts
poly_x,poly_y, // output verts
LEFT
);
if(c > 0) {
c = SutherlandHodgmanPolygonClip(c,
poly_x,poly_y, // input verts
clip_x,clip_y, // output verts
BOTTOM
);
if(c > 0) {
c = SutherlandHodgmanPolygonClip(c,
clip_x,clip_y, // input verts
poly_x,poly_y, // output verts
RIGHT
);
}
}
}
if(c > 2) {
// Draw the polygon as a series of triangles.
// Here we assume that the polygon is convex, because the triangle
// decomposition for concave polys is much more complex and probably
// more time consuming than the poor performance of fillPolygon!
for(j = 1; j < c-1; j++) {
dg.fillTriangle(poly_x[0],poly_y[0],
poly_x[j],poly_y[j],
poly_x[j+1],poly_y[j+1],
colour);
}
}
} else {
c = LiangBarskyPolygonClip(num_points, // count
poly_x,poly_y, // input verts
clip_x,clip_y); // output verts
if(c > 2) {
dg.drawPolygon(clip_x,0,clip_y,0,c,colour);
}
}
The code above picks the clipping routine to use based on the land type of the current shape being drawn, the comments for the clipping routines explain the best ways to use them. The fillPolygon and fillTriangle methods come from the Nokia DirectGraphics interface, but you could replace them with drawLine calls for wireframe rendering. If you’re looking for some clipping routines and find these useful, let me know with a comment. I might even put together a standalone J2SE demo if anyone shows any interest
Triple Pop was the first Java J2ME game I coded at iomo, back in about 2002. It was a white label game for Nokia Series 40 devices, initially the 7210, but it found it’s way onto dozens of similar devices. The 7210 was one of the first colour screen Nokia J2ME devices. Until then, they had the 3410 and 6310i with Java embedded, but these had 96×65 1 bpp screens (that’s 2 colours, black and white, or dark grey and light grey on the phone!). The 7210 had a 128×128 colour display, could run jar files that were up to 64k and had 210k of runtime heap. It’s CPU was actually pretty nippy too, maths and game logic almost never turned out to be bottlenecks, it was always the screen updating that took time. The LCD response time was pretty slow, any attempt at animation over about 10 frames per second blurred terribly.
Triple Pop was already available as a Symbian application for the Series 80 communicator range, and we got the contract to write a Java version. I had the C++ Symbian code available to refer to when writing the Java version, which helped a lot. I lifted the algorithms for the heap of bubbles collapsing and rotating directly from the Symbian code. I still had to write the Java code from scratch, but there was no need to invent everything myself.
I won’t write too much about the game play, a video is worth way more than some words to show you what it’s about.
To be honest, there’s nothing very interesting to say about the development cycle of the game. The concept was simple and an implementation already existed to set the standard, there wasn’t much need for innovation or fancy coding. Early on we didn’t have actual devices, but the emulator turned out to be a pretty accurate model for the real thing, something Nokia sadly didn’t continue in later years! The game didn’t tax the device to any great length, it ran in about 60k of memory, jar size was less than 32k in the end, and it loaded quickly. Looking back, the aspect of development that strikes me the most is the similarity with how I do things today.
My basic development tools in 2003 were SlickEdit (v4 I think then), CVS, Java v1.3, Apache Ant and an obfuscator, at the time I used JODE. Today I use SlickEdit 2009 (v14 in old numbers), Perforce, Java 6 (or 1.6 in relation to 1.3), Ant and Proguard as an obfuscator. Basically the same tools, but there’s one difference. Today I code on top of a middleware framework that is the culmination of 7 years of mobile phone development experience. When I wrote Triple Pop, it was meant for a single class of very similar devices. Today, the codebase of a J2ME title must support hundreds of devices from many manufacturers. The specifics of doing this are the subjects for another time though.
Anyone developing a commercial J2ME application or game today needs to have a framework in place that assists with device fragmentation and porting. This could be an in house system built up over time, or a middleware platform bought from a 3rd party. Triple Pop had no underlying technology of note, it was just over 5000 lines of Java code and some PNG images. Later on, we used a system of pre-processing the source code for different devices and SKUs, but this early approach only scaled so far. Further to that, as iomo was acquired by Infospace and game production really stepped up, we adopted a full featured in house framework developed by Elkware (another Infospace acquisition). Today, at FinBlade, we use Bedrock from Metismo, which allows us to target both J2ME and numerous other systems such as iPhone and Google Android, all from a single source code base.
Mobile development has moved on a lot since 2002. Soon, I hope to write about more games I’ve been involved with, if for no other reason than to have a record for myself. Going back and playing Triple Pop again to make the video above made me think ‘that’s really quite fun, it’s worth remembering’, so I have