Elemental Entropy - My JS1k 2016 Entry
If you've previously visited my blog, you might be aware that I entered last year's js13kGames contest. Since then, I've been exploring games and application development with HTML5 canvas, so I entered this year's JS1k contest. The aim is along the same lines as js13kGames, except that technical demos are also accepted, and that submissions can not exceed 1024 bytes. And I remember complaining that 13 KB was small!
Given the theme this year is "EleMental" (yep, with that casing too!), I wrote a 2D canvas game called Elemental Entropy, in which the player rotates a shield around an oxygen particle to protect it from heat and fuel particles (because science is that fundamental, right?!). I also managed to squeeze in some very basic audio thanks to the Web Audio API's
Here's the final code that I submitted. It's 950 bytes in size:
Let's take a look at the code in project's GitHub repository. In total there are four scripts:
This is the initial source code that I wrote to represent the game. Given the small target size, I'm not doing anything vectorial or converting pixel space to world space, but I have written small, manageable methods for handling particle generation, collision, and sound. Ironically, this code ended up being cleaner, in my opinion, than my js1kGames entry; look at that
Particle constructor function!
So how big is this script? 6.98 KB. Oh dear. What next?
Turns out that by throwing software engineering best practices out the window, I was able to half the game's size. All of the functions have been replaced with a giant game loop function, the
Particle prototype was ruled out in favour of object literals, and constants have been ditched for magic values. This, for the most part, entailed my finding and replacing functions and constants in my text editor manually.
This is the
pre-min script passed to Google's Closure Compiler. I was originally using UglifyJS, but the mangling options were not flexible enough for my needs. I'm using Closure's advanced optimisations and referencing an externs script to mark the JS1k shim globals as reserved tokens. I then manually remove all instances of the
var keyword, effectively placing everything on the global object since the script doesn't run in strict mode.
Now we're down to 1.54 KB. Just another 553 bytes to go...
This is the
pre-crushed script processed with RegPack, using the online UI with these options:
- Attempt method hashing and renaming for 2D canvas context
- Assume global variable c is a 2D canvas context
- Reassign variable names to produce consecutive character blocks, except for variables a c
- Score = 1
- Gain = 0
- Length = 0
This results in the 950-byte script that I shared above.
Use Closure Compiler before RegPacking your entry, but use the advanced optimisations with caution. For example, when running it against my original source code, I experienced errors with invocation context, as a function belonging to
shieldwas subsequently disassociated with it, meaning that
thisreferred to the global object. Personally, I'd favour UglifyJS for production-quality software
When manually reducing code size, Git is your friend. Everytime a change results in a successful reduction, commit it! If you then attempt another change that increases the size, then you can easily use
git resetto undo it. You should also commit when the code actually works, as I found that manual replacement is error prone
There's always an optimisation you can make, even if it's totally wacky and unfounded. Don't get me wrong, I favour pragmatism and empiricism, but duplication of speed computation over calling a dedicated function, for example, could use fewer bytes
As a last resort, you may have to compromise on functionality. The game originally had logic to slightly randomise particle sizes and speeds, but this wasn't a core gameplay requirement. Be willing to drop anything that adds little to no value to your demo's experience
I'm now going to take a couple of months off from extra-curricular development before my brain sets on fire. Then I'm going to start working on developing games properly.