In the beginning
Having done the traditional “canvas + sprites” rendering last year, this time around I decided to try something different. Again I decided to go with a “80s arcade” feel, this time going for old vector based games like the classic Tempest.
I decided I wanted to learn more about how SVGs work, and after a little research, I had a basic glow effect and some animated boxes moving around
The glow itself is just a few gaussian blur filters stacked on top if each other with varing strengths, but it makes all the difference for the feel of the game - with the blurs turned off the game looks very flat in comparison.
Also, there is no need for any sort of rendering code, so unlike a usual canvas based game where you’d have a loop that performed
- check inputs
- update game element’s
- draw everything on screen
my game loop is purely concerned with updating everything. Mouse events handle the inputs, and the browser automatically renders the svg for me when the js updates it.
I also went with an entity system, so every updating object has its own data blob and an update function - this means anything to be animated just needs to be added to the main objects array, and the game loop handles the rest, so for example, the player’s ship just interpolates its position towards the mouse position each frame, and updates the ship’s svg element with a new path describing what to draw.
Turtles all the way down
SVG paths are more like a little programming language than a graphic format. Put simply it contains a path, with a list of instructions telling the renderer what to draw.
- Move to 0,0
- Draw a horizontal line for 50 pixels
- Draw a line 20 pixels left, and 10 down
- and so on
So to draw the player ship, it basically draws the diamond at the back, then an inverted V shape, with the tip of that V skewed depending on the ship’s position to give a feeling of depth. The game contains absolutely no 3d code at all, it just moves things around and makes them smaller.
Let’s dance to Joy Division
One of the influences for this game was the deeply weird French game Captain Blood, which involved the player, searching the galaxy for accidental clones of themselves, so they could boil them down and recover vital life essences. The main gameplay involved visiting planets, flying a drone down to the surface, having weird disjointed conversations with confused aliens, who you often ended up abducting.
Anyway, the whole alien conversations bit seemed way beyond what I could achieve in a month, within 13k, but I felt the galactic search and planetary landing bits could work, so I set off to make a Joy Division simulator.
Initially I planned to generate full planetary landscapes which you’d have to fly around and search for points of interest, but eventually this was simplified right down. A Perlin noise generator is used to generate heights which are plotted into the wavy terrain cross section lines. The sampled X position is moved left or right depending on the ship’s position, the Y position just keeps rolling. Again, there’s no real 3d here, it just scales the lines as it draws them from top to bottom, sampling a narrower and narrower slice for each subsequent line.
The warp effect is exactly the same as the ground lines, it just gets plotted into a circle (using simple sin/cos calls)
Battle of the planets
A galaxy needs lots of planets to search, and a bit if randomness. The galaxy’s sectors are split between three factions (or four if you count the “unclaimed” sectors too.) I made some effort to pick three colours that should be distinctive for colour blind players as I initially planned the different factions to play a much bigger role.
The map is randomly built using a sort if drunkard’s walk which creates a nice mess of alignments in something that looks fairly organic. The game then rolls some random stats for each sector which get combined with the faction’s stats to decide the economy for the sector’s single planet.
A place type is also chosen, using a sort of pseudo weighted randomness - there are arrays in the game for settlement type and the items you discover at them, sorted into a list based on how common they are - the game picks a random number and walks through the list until it finds an item with a weight higher than its random number, and that’s the element it picks. It made tuning the game quite easy as I just heeded to tweak the weightings to change how likely something is to appear.
Each planet also gets a bunch of random numbers used to draw the backgrounds in orbit and on the planet
It causes me much confusion and pain when I realise that another of the game’s more modern influences, Rez, is itself twenty years old now, so is definitely retro by today’s standards. I basically ripped off the lock on targeting from there, as its a mechanic that always felt immensely satisfying. As previously mentioned the game doesn’t have a traditional input phase, just each targetable thing has onmouseover events which handle when the mouse pointer is dragged across.
Again, I originally planned for the different planets to have different attitudes and friendliness ratings towards the player, that would change as you played, so each planet would put up a different level of defence. This got stripped right back to “one of the planet’s random stats decides how many waves of space invader things appear.”
With the critters themselves I really lucked out seeing this tweet in my timeline at the right moment
I tracked back to the original monochrome version and hacked that code down until it drew just a single random sprite at a time, then translated that to generate little squares in an svg pathm instead of pixels plotted on a canvas.
X marks the spot
For ages I had the “search and trade” element of the game working, but no real aim or objective. I toyed with the idea of just gradually ramping up the difficulty, and hoping nobody noticed it was impossible to complete (*), but eventually I figured how to shoehorn in this year’s 404 theme - hunting for something lost, and so quickly wrote a bit of bad sci-fi back story about a fleet of ancient colony ships that escaped a doomed planet. I also made it topical (an alien pandemic) which also explains why nobody seems overly bothered by you flying around blasting everything out of the skies - thanks for clearing out those critters, here, please buy my random mcguffins.
And talking of mcguffins, that helped finish off the objective - there are a number of ancient transponders scattered around the map, and if the player finds three, it will triangulate the position, and give the player a last bit of bad sci-fi exposition, and, in the tradition of this sort of game, let the player just carry on regardless
- Music by Mattia Fortunati - Thanks so much! It really wouldn’t have been the same with some random generic music!
- Uses ZzFX and ZzFXM by Frank Force and Keith Clark for sound effects and music, which is, quite frankly [no pun intended) an absolute technical marvel, and total game changer when it comes to good sounding audio for tiny web projects.
- Perlin noise generator adapted from https://gist.github.com/banksean/304522 by Sean McCullough
- Random alien sprite generator adapted from this snippet https://www.dwitter.net/d/3078 by FireFly
- Logic for generating the arc path [for the lock-on cooldown counter) adapted from https://stackoverflow.com/a/18473154 by Oliver Searle-Barnes
- VSCode for most of the code editing [running on Windows, and inside an Ubuntu chroot on my Samsung tablet)
- advzip for crunching down the zips as much possible
- filepp to allow c style #define macros to customise my minification process
- minify to actually minify the preprocessed html+js
- github to run CI builds and auto publish the WIP builds
- Method Draw for online SVG editing
- SVG optimiser to crunch down and optimise SVGs
- Full source file: 70946 bytes - this contains all code and svg data
- Preprocessed and minified, this shrinks down to 41261 bytes
Zip crunches this down to 13310 bytes, which is just inside our budget!
SVG data accounts for 2.7k of the final archive
Library code accounts for 1.5k
Sound effects and music definitions: 680 bytes [did I mention what a technical marvel ZzFX and ZzFXM are?)
Everything else is js code, and the tiniest amount of html to hold it all together
If you haven’t played it yet, the game itself can be found here:
(* The game does contain one mechanic that serves no real purpose, but I’ll leave that unmentioned…)