I wanted to write this post right after the submission deadline earlier last week, but I put it off due to a case of not feeling well (technical term). So instead, this shall be my last piece for the year! Hopefully I’ll be writing a little more frequently in the following months, with university and a whole bunch of projects coming up.
Background
Phoenix Rising is a JavaScript/HTML5-based puzzle game that I wrote for the second iteration of the Game Prototype Challenge, a week-long game jam. Organized by former colleague Jason Kaplan, the purpose of the challenge was to motivate game developers. And motivate me it did; I saw it as a good opportunity to try my hand at game development.
Idea
This was my first ever attempt at writing a game, so I wanted to keep things simple. Basically, this meant that I couldn’t do anything that required complex mechanics. I was also working that week and had a couple of events to attend so time was definitely an issue.
I chose to write the game in JavaScript, making use of the canvas element introduced in the HTML5 specifications. There are a couple of reasons for this. One: I’m already quite experienced when it comes to web development so I wanted to take full advantage of that knowledge. Two: I haven’t actually worked with canvas before even though I’ve seen all sorts of cool demos that others have written. This was a good way for me to get my feet wet on both fronts.
It took me a few hours to come up with a workable concept once the themes for the challenge (immortality and thin ice) were announced (I was actually up ’till 4 AM thinking while reading up on basic game development). One of the first things that came to mind was the notion of cracking tiles that would deteriorate into holes once you’ve stepped on it a couple of times; a set of such tiles would essentially be a puzzle that has to be navigated carefully. This was one of the mini-obstacles in Golden Sun, a RPG that I hold in the highest regards. In the end, it turns out that I would do something similar – a set of ice tiles that melt into a trail of impassible water. I wasn’t entirely sure how to fit immortality in at first (early ideas included obtaining an elixir of life, spiritual ascendancy, etc.), but then it hit me. Why not do something featuring one of my favourite creatures of all time, the phoenix? Everything came into place once I wrapped my head around that thought, including the melting ice (a phoenix is made of fire after all), the collection of twigs to build a nest, the mini-story…
Development
Although I fleshed out the game concept fairly early in the week, I didn’t actually start coding seriously until Thursday. In hindsight I should have started sooner, but there was a lot of material for me to read up first (as stated, I haven’t done game development before). JavaScript is pretty quirky as a language too which didn’t help much (I typically use jQuery syntax for the things that I need in the average web development project).
I started with a simple game loop using setInterval() that is first called when the DOM is ready. For this particular project, a continuous game loop was probably overkill; something based on player input would have been far more efficient. I wanted the flexibility though, in case I felt like implementing AI for enemies and whatnot. It turns out this was a rather bad decision as I overestimated the performance of JavaScript in certain browsers; FF 3.6 was quite laggy although FF 4 and Chrome 8 ran the game alright.
All of the level data is stored in separate XML files which are parsed into game objects as needed. This allowed me the flexibility of adding new levels on-the-fly as well as giving an easy way for others to create their own custom maps (in the future?). The jQuery framework makes the parsing process painless, only requiring an AJAX request and a callback function. I’m actually pretty sure it’s standard practice to store this data separately, although it was more out of intuition for me.
It turns out that drawing on the HTML5 canvas is rather simple, though you are more-or-less limited to primitive objects. I made extensive use of drawImage() since most of what I had was stored externally. The visual part of the game consists of a bunch of images hastily drawn using my trusty Wacom Bamboo tablet.
It was actually slightly challenging drawing things that would tile correctly (mainly the wall) and writing code to display the right image wasn’t a walk in the park either. I probably messed up here; there was likely a much better way of doing things (i.e. not having separate cases for everything).
Everything else is rather straightforward; I used a 2-dimensional array to store the current game state and had various checks in place for “special” events. Arkayle’s abilities were actually a last minute add-on that I felt added a lot more depth to the game (I knew something similar had to be added eventually – there is only so much you can do with a puzzle where you couldn’t normally retrace your steps). Unfortunately since I was crunched for time, I couldn’t really do too much level design. The result is a three-level game where only the last level is slightly challenging.
Lessons Learned
There were a few major issues that I ran into. I found that drawing on the canvas is pretty damn slow especially when the dimensions are large (e.g. 1000px x 500px). Especially for a game like this, it was probably a much better idea to redraw when something actually happened (e.g. player input), rather than at a constant interval. An alternative would have been to not use canvas: DOM manipulation is another path that I could have taken.
A second major issue that I found was when I was trying to import my “art” assets into the game. There is an issue with drawImage() which tries to render an image onto the canvas even if it hasn’t been loaded yet. I’m not sure if this is a bug or by design (if it is by design, I’d like to know why). One of the ways to resolve this issue was to use drawImage() on image load:
1 2 3 4 5 | var img = new Image(); img.onLoad = function() { canvasContext.drawImage(img, xStartingCoordinates, yStartingCoordinates); } img.src = "path/to/image.png"; |
Unfortunately, this caused a whole bunch of flickering due to my game loop (at least in Firefox 3.6) so I opted to preload all of my images instead.
1 2 3 4 5 6 7 8 | $(document).ready(function() { var images = ["image1.png", "image2.png", ...]; var img = []; for (var i = 0; i < images.length; i++) { img[i] = new Image(); img[i].src = images[i]; } }); |
Turns out that this works quite well.
The smart way of dealing with so many images (20 at my last count) would have been to use sprite maps to minimize the number of HTTP requests, but I didn’t want to deal with the hassle at the time (as mentioned, crunch period!).
There were a few more kinks along the way (e.g. dealing with JavaScript’s prototypical – rather than classical – inheritance), but they were pretty minor. My code base is pretty messy, though that was to be expected writing something I didn’t know how to write, using tools that I didn’t know how to use.
In hindsight, I should have introduced a lot more separation between the engine and game logic. I also should have found a way to reuse code more effectively (see the Entity object). As for the game itself, I should have added in a few more abilities for Arkayle to use, as well as more levels (right now it doesn’t seem much like a game). Ah well…
All in all, I had a great time working on this prototype. I felt like I learned a lot from the process and I hope to apply that in future projects.
I totally did not help you with the level design in the end LOL
Yeah, whatever happened to that plan? I even made the effort to draw up the game concept in Paint!