Yesterday was the seventh installment of the Three Hour Game Development Contest, hosted on GameDev.Net by capn_midnight. The premise is that a theme is provided and contestants have three hours to design, implement and deliver a complete video game using art, libraries and technology of their choice, that is somehow related to that theme. The contest results will be revealed today.

My entry is called Harbringer of Spring, a game where you have to step on dirt tiles to make grass grow there, and step on the stone tile when there’s grass everywhere. To increase difficulty, water tiles cannot be traversed, and bridge tiles turn into water tiles once they are stepped over. It’s written in HTML-CSS-jQuery, sou can play it online. The original intent is vaguely inspired from the Bridges of Königsberg mathematical problem where you have to cross all bridges exactly once.
The technical details:
- 233 lines of JavaScript code, divided into 100 lines of level data and 133 lines of actual gameplay code.
- 53 lines of HTML
- 174 lines of CSS, divided into 103 lines for the general UI (title, links) and 71 lines for the map and tileset.
- Uses jQuery 1.4.2 to interact with the document.
- Uses the PlanetCute tileset, because I couldn’t be bothered with graphics.
Here’s the step-by-step rundown of how I developed this entry (the given time is actually a countdown to the time the game must be delivered).
3:15 (that’s 15 minutes before the contest begins): I’ve already decided that the game shall be written in HTML-CSS-jQuery, so I set up my work environment accordingly. Desktop 1 will be my development environment, with a browser on the left monitor containing documentation for jQuery and an xterm on the right monitor connected to the nicollet.net server through SSH, running an emacs with two vertically split buffers. Desktop 2 will be my testing environment, with a browser containing the game on the left monitor and a maximized Firebug on the right monitor.
I also create the index.html, style.css and game.js files, download (with wget) the latest minified version of jQuery, and create an img directory for my images. I’m a bit bored, so I decide to add the “© 2010 Victor Nicollet” footer to the document.
3:00 : apparently, the theme has already been given out a little earlier. Time to start brainstorming. A few ideas I get right off the bat: a game like Sim City where you have to build spring factories in a world covered by winter. The Silk icon set from FamFamFam contains some weather icons, but they’re really small. Perhaps I could instead build a Risk-like game by placing absolutely positioned stacks of units on a world map image? I start browsing the web for acceptable tile sets, just in case.
2:45 : I stumble upon the PlanetCute tileset (courtesy of the GameDev.Net thread on art resources). The concept seems simple enough to implement a 2D tile map quickly, and I like the grass/dirt contrast. I download (with wget) the file and unzip it into img. The water tiles are quite cute, so I’m starting to think about “Spring” in terms of “Hot Spring” or something. Anyway, I need to be drawing tiles, I might as well get that out of the way while letting my right brain think about the theme.
2:30 : through a clever combination of float:left, position:absolute and background-image CSS trickery (with some help from Firebug for empirically guessing the pixel offsets I need) I manage to render the tile map, with the possibility of a “selection” golden light overlayed on top. It’s all controlled by classes on the root tile elements, so controlling it from jQuery will be easy.
I do have a problem, however: even though the root tile elements match the flat area on top of the tile graphics, the actual tile graphics are taller, and the CSS hover property seems to detect hovering even though I’m not above the root tile per se. I have no idea about how to resolve this quickly, so I’ll give up on selecting tiles with the mouse (there are plenty of things you can do with keyboard controls, and given the time I have at my disposal, trying to fix the issue might take much too long.
In the mean time, I thought about a simple “step over tiles to paint them” gameplay similar to Q*bert. The trouble is that the existing graphical framework does not support animations, so adding enemies to the fray might be a bad idea. Yet, “paint the nodes” reminds me of graph theory, which in turn reminds me of the Bridges of Königsberg problem. I quickly decide to add non-traversable areas (I did like those water tiles) with bridges that may only be crossed once. Being able to only use a resource once means having to decide when to use it and what for, and these kinds of decisions provide a nice puzzle game design. So be it. Time to implement!
2:00 : the first half hour is the hardest, because I have to set up the general layout of the game code before I can see anything move on the screen. I go for a simple architecture in jQuery-powered JavaScript : an initialization function sets up the DOM and places references to individual DOM tiles in a 2D array. Everything related to the game will be a member of the global «g» object. The code looks like this so far:
var $world = $('#lyt-world');
g.$t = [];
for (var y = 0; y < 6; ++y ) {
var r = [];
for (var x = 0; x < 9; ++x) {
r.push($('<div class="tile"><div class="tile-img"/><div class="tile-sel"/></div>').appendTo($world));
}
g.$t.push(r);
}
If you’ve already done tile-based rendering, you will probably recognize the YX way of doing things: tile x,y can be found at g.$t[y][x]. I’ve also decided that a level array named «l» will hold the levels, in an array-of-strings fashion (space is dirt, tilde is water, plus is bridge and hash is stone). This is what the first level looks like:
{
name : '1. The beginning...',
tile : [
" ~~~~~ ",
" ~#+ ",
"~~~+~~~ ",
"~ ~~~ ~",
"~~+~~~~+~",
"~ "
],
init : [1,1]
}
Another major architectural decision was how to represent tiles that had been walked on. One possibility was to implement “on step” rules which altered the map whenever the player moved (but that would involve making a copy of the map present in the level definition). The other possibility was to store the list of all positions that had been stepped on in a way that’s easy to query for “has the player stepped there yet?”. JavaScript has dictionaries so I went with the latter, so the rendering code looked like this:
render : function() {
for (var y = 0; y < 6; ++y) {
for (var x = 0; x < 9; ++x) {
var t = this.map[y].charAt(x),
$t = g.$t[y][x];
var xy = [x,y].join();
$t.attr('class',[
'tile',
[x,y].join() == this.pos.join() ? 'show' : '',
t == ' ' && xy in this.stepped ? 'grass' : '',
t == ' ' && !(xy in this.stepped) ? 'dirt' : '',
t == '~' || t == '+' && xy in this.stepped ? 'water' : '',
t == '+' && !(xy in this.stepped) ? 'wood' : ''
].join(' '));
}
}
},
This made the “step onto tile” code exceedingly simple:
step : function(xy) {
this.stepped[xy.join()] = true;
this.pos = xy;
},
Using Firebug, it was fairly easy to test this by manually calling the step and rendering functions.
1:45 : implementing controls meant, mostly, catching keydown events on the document, detecting arrow key presses, and calling a “try step” function with the appropriate movement vector (that function would check if the movement was possible, then call the actual step function, and finally rendering the entire thing). What took me the longest was finding out what the key values were (I eventually found out by logging the key values to the Firebug console).
The game is now officially playable. I pour myself some hot Earl Grey Tea, eat a warm pancake, and give the first level a few test runs.
1:40 : it was pretty obvious that refreshing the entire page to restart the level was not very nice. In the name of polish, I add a “try again” button.
1:35 : turning a bridge into water as soon as it is stepped on feels weird. I split the “stepped” dictionary into “steppedOn” and “steppedOff” dictionaries that are filled independently, and adjust the rendering code accordingly.
1:30 : the game is quite simple. Maybe I could make it more complex if I forced the player to finish on a specific tile? I add stone tiles to the mix.
1:25 : I implement a “all tiles painted green” function and add a test in the “step” function to check the win condition (all tiles painted green and sitting on a stone tile). Winning starts the next level. The game is now officially in Alpha! Knowing that I can now deliver this simple game as is, I decide to move on to level design and design as many levels as possible.
Also, my fiancée just fell asleep. I guess I’ll plug in my headphones before I resume listening to Rammstein.
1:15 : after a bit of testing, it appears necessary to add a level selector, if only for level design purposes (I don’t want to have to solve seven levels just to test the eight). I now have two playable levels. I guess I should start designing more: aside from the game finished screen, everything’s implemented. In fact, there’s no instructions manual or tutorial yet, and the “step on the stone tile when you’re done” idea is not really that obvious.
1:00 : I write a few short text bubble to explain the game logic, place them in a layer that is only visible on the first level, and position them in Firebug. Now, the level design can start!
0:55 : level 3 (Chess) is over. It’s pretty easy to solve.
0:50 : I search for the actual Bridges of Königsberg on Wikipedia, and implement it as a (rather simple) level 4.
0:40 : I reuse the chessboard from level 3, add another stone tile to confuse players, solve it while stepping on as few bridges as possible, then turn the unused bridges into water tiles. Seems obvious to me, but apparently this ended up being the most difficult level in the game.
0:30 : Out of ideas. I’ll try a random layout and work from there. This ends up as level 6 (Detour).
0:25 : Still out of ideas. Let’s draw a happy face: level 7 (Happy).
0:15 : Still out of ideas. I randomly draw something up, test it, and that’s it. I would have liked to draw more levels, but there was some polishing left to do (namely, the game finished screen).
0:10 : Game finished screen is over. Let’s start packaging the stuff.
0:05 : Last minute bug fix: apparently the overflow:hidden on the tile map behaved badly when the try again and select level elements were floated to the right and were past a certain height (on certain browsers). I add a clear:both to the tile map.
0:00 : as expected, I don’t have zip on my server, my aptitude cache is not up to date, and I don’t want to risk spending 10 minutes updating it. I should have fixed that before the contest! Still. I tar-gzip the stuff, download it on a Windows computer, extract it then turn it into a zip file, and upload it back to the server. There’s no time hunting for capn_midnight’s mail address, so I just post the links in the thread.
-0:05 : I manage to locate the captain’s address, so I mail the file there.
-0:10 : ?????
-0:15 : Profit.
http://en.wikipedia.org/wiki/Q*bert
Recent Comments