Over the last month I've been working on a game for the #js13k game competition.
The concept is fairly simple: make a game in under 13 kilobytes with no external dependencies. The idea is to see what people can come up with on a budget, and it's awesome to see some of the entries this year.
My game, Polar Defender, is a basic shoot 'em up on a polar coordinate system. It's heavily inspired by space invaders, except you have to defend various planets from all sides at once. It's heavily reliant particles and a basic polar trajectory system to provide messy, explodey space fun.
The theme of "elements: earth, air, fire, water" is optional in the contest, but I incorporated it into my level system (an earth-like planet, water planet fire and gas planet). It's a /little/ contrived, but I think it works well in terms of playability.
I wanted to include a playable level system with a playful narrative since there's only so much you can do in 13 kb and I felt it would make it a more personal experience. I feel it worked out well, with six levels (including an initial training level) on various planets and varying degrees of difficulty. After early feedback stating it's too hard to finish in one go, I adjusted the menus to make each level unlockable rather than having to start over, which really improves the gameplay in a casual sense.
Touch input is significantly more difficult than desktop input because I essentially shoehorned the same concept in where it doesn't really fit. If I had the chance to do it again I would introduce a separate tap-based firing system on mobile.
Some of the tech I used includes:
- jsfxr for sound effects, based on Jack Rugile's blog post.
- Liberal use of the native Canvas
- Regular CSS & JS for the menu system.
- Gulp, Uglify, svgo and a bunch of hand-tweaks to package and minify my codebase.
- Super rudimentary box-based collision detection.
- A basic entity/component model through which to extend base sprites.
- SVG for infinitely customisable graphics. (There's only four enemy sprites in the game, each recoloured and resized as needed.)
- Procedurally generated starfield & planets.
How to ultra-compress your JS
13 kilobytes is quite a lot in terms of raw code, but also a challenge to meet when including graphics, sound, polyfills and other boilerplate.
Minification of Polar Defender was done by hand and involved a lot of code tweaks. The ultimate deliverable needed to be compressed into 13 kilobytes of zip file, which is roughly comparable to a gzipped distribution from a web server.
Some of the things I did which aren't necessarily best practices include:
- Strip unnecessary properties and pre-compile SVG files into a JSON file to be bundled into the main JS build process. This improves compression because there's less junk and the SVG gets compressed in with the JS which presumably improves duplicate string elimination in the zip format.
- Collapse JSON structures into CSV-like strings that can be reinflated later. JSON objects are super-wasteful in terms of repeated properties, and while compression algorithms are generally pretty good with repeated content, it's still better to remove the duplicates where possible.
- Globalise commonly used functions. This isn't something I'd usually recommend
but considering the constraints what the hey. Things like aliasing
mreduces byte-level repetition. Additionally keeping everything in a local scope lets Uglify optimise away long function names.
- Loose comparison and other sneaky tricks. For instance using
1for true and
0for false saves 3 bytes per bool and works in a loose JS equality operation if you're prepared to ignore JSHint complaining a lot.
- Reuse everything. I reused a basic set of drawing functions and sprite classes for everything in-game, meaning each new feature was an iteration on an existing one rather than a completely new piece of functionality. See also entity component system on Wikipedia.
In addition to my jS13k entry, I've got a side-build available in the Chrome Web Store which you can install and carry around with you. The main benefit is that your scores are stored in the cloud and unlocked content goes wherever you do.
Overall I think it worked quite well and I'm happy with the result. There's some awesome games submitted so far and I can't wait to see how everyone goes.
The source code to Polar Defender can be found on GitHub.