I've been looking forward to entering the js13k competition this year, because it's one of my favourite game jams.
TLDR: play Road Blocks (don't forget to like and share :P)
Set over a month-long period, the js13k challenge is to create a compelling game within 13 kilobytes. This doesn't sound like much, but you can do a lot with it if you get creative.
Last year I dreamed fairly small, with a space invaders clone set to polar coordinates. I had fun making it, but it wasn't especially playable and this year I wanted to do something completely different and come up with a mobile friendly touch-based game.
The Concept
The concept had been rattling around in my head for a while. I've a very soft spot for city builders, and I love isometric art. While an outright city builder probably wouldn't be feasible, a subset thereof might just work.
My main inspiration was an old DOS/Windows game called Pipe Dream, in which you're given an infinite number of puzzle pieces and need to connect the start pipe to the edge of the map somewhere before the liquid spills out. Mash this concept up with the city building theme and you've got a basic connect-the-infrastructure sim.
When the theme of the jam came out as “reversed” I really struggled to find a way to align the concept with the theme, so I had to mix it up.
Ultimately I landed on the puzzle-style "arrange the pieces to fit" theme, in which you need to strategically destroy or reverse the order of the tiles as they come off the queue. It's a little less "world buildy" and a little more constrained, but I think the gameplay works, and it gives me the opportunity to expand the game with new puzzles in the future.
The Tech
The tech is also an idea that's been bouncing around in my head for a while. I've long been a fan of isometric art (pixel art as well as more recently isometric vector art and voxel art) so I wanted to do something in that style.
I had a play around in CodePen and came up with a crazy simple plan; draw everything in voxels. The algorithm to draw an isometric cube isn't all that difficult. You've got three visible sides, each side consisting of four lines and a fill colour. Turn that into a function and you can start making some cool stuff.
See the Pen HTML5 Canvas isometric cube demo by Ash Kyd (@AshKyd) on CodePen.
You can adjust the sliders on the example above to modify the cube.
Drawing voxel sprites
With the idea down, the next step was to draw a game world. There's a bunch of sites out there that have isometric code examples. I had Clint Bellanger's isometric math tab pinned in my browser for a good week, though in reality there were only two functions I really needed:
- Convert isometric position to screen/pixel position
- Convert screen/pixel position to isometric position
These two functions let me both draw isometric boxes to the appropriate location on the screen, and then detect where those boxes were stacked when the user interacted with them.
From there, the trick was to come up with sprites made from boxes. While it was possible to sort of work it out in your head, this was often a trial-and-error process, placing boxes and seeing where they land in the output.
See the Pen HTML5 Canvas isometric cube demo by Ash Kyd (@AshKyd) on CodePen.
In the above example you can see a road tile with three components, rendered from an array:
var sprite = [
[-0.25,.9, 0, 0.1, 1, 0.25, '#aaaaaa'],
[-0.25,.1, 0, .8, 1, 0.2, '#444444'],
[-0.25,0, 0, 0.1, 1, 0.25, '#aaaaaa'],
];
Each item in the array corresponds to a coordinate. In this case the z, x, y coordinates, x width, y width and height.
In the end, my sprite list resulted in a bunch of arrays and functions that don't make a great deal of sense to the naked eye but render cute little box sprites in the game engine.
Putting it all together
With a bunch of sprites at my disposal, all that was left was to implement the game! Easy, right?
I actually took a week off specifically to work on Road Blocks, and I'm glad I did. Through the week I implemented the engine various features (some of which didn't make the final version) and tuning interactions.
Because I wanted this to be a first-class touch game, I implemented everything mobile first. This was a fantastic way to discover all the limitations of the platform at the get-go rather than having to refit a desktop game to mobile later on.
I also spent a lot of time user testing the game, be it in person or through analytics. Testing is a really important part of any gamedev process, and it was really enlightening to watch people playing my game for the first time. Many a puzzle or interaction was tuned based on feedback and watching people work out a level.
I also released my game via Twitter as a public beta to gather play statistics and weed out any errors that might crop up. I used Loggly to record a bunch of custom game stats and events, and the results were quite valuable in determining difficulty and how people were faring playing the game.
One particularly revealing fact was that most people were getting stuck on a particular level. Armed with feedback from testers and the hard facts of the analytics, I tweaked it to be not quite as difficult and pushed it from the middle of the campaign to the end to make it a sort of "final boss" level instead.
By my analytics most testers unlocked "free play" but not so many used it. Level 7 seems to be the toughest, only 4 people solved it. #js13k
— Ash Kyd (@AshKyd) September 8, 2015
As a side note, one day I got distracted and came up with a data encoding scheme for level data which helped reduce the file size in the final zip.
Conclusions
I'm really pleased with the results this year. The game clocked in at just under 13 kilobytes and made efficient use of the space.
Some notes in hindsight:
- Levels and sprites should probably use a binary data scheme to reduce file size and allow the use of Web Workers.
- For some reason HTML5 canvas makes the CPU spin up like crazy. I'd like to get to the bottom of this sometime.
- User testing is mandatory. When developing something in isolation you can get into a weird headspace and not notice the obvious stuff.
- I had initially intended to have little cars animating along the roads, but ran out of space and couldn't think of how best to do this. I need to learn more about vectors in gamedev.
Ultimately, this year's js13k was a whole heap of fun and I'm really proud of my result. There's a bunch of awesome entries that you should check out, and you should consider entering next year.
Further reading
You can play Road Blocks on the js13k website. You can also check out: