yeti-404 banner image

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.

no filters

An SVG is just a set of xml tags, no different from the tags that make up a normal html page. Normally it would be in its own file and referenced in an img tag, but you can equally just include the svg directly inline in your html document, so its easy to manipulate them with javascript, and they respond to usual mouse events too. This means I didn’t need no code anything special to detect when the mouse is over something, regular mouae events work perfectly.

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.

captain blood

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

Lock-on

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.

Critters

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

tweet screenshot

https://twitter.com/KilledByAPixel/status/1299620221100097536

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.

Now, since the path definition is just a string, you can do clever stuff with it. When I build up the critter, I leave two spaces between each “pixel.” This means I can later extract this string, and use a javascript string split to get a path section per pixel. These then get cloned into their own svg element, given an update function with a random direction, and BOOM! Instant exploding particle effect. I didn’t have to code a particle system to handle these things, just create new elements, give them update functions, and push them into the update array. The items themselves manage their own lifetimes, slowly fading out their alpha channel, then marking themselves for deletion once invisible.

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

Credits

Tools used

  • 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

Stats

colourcoded minified source

  • 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:

https://js13kgames.com/entries/the-legend-of-yeti-404

(* The game does contain one mechanic that serves no real purpose, but I’ll leave that unmentioned…)