Runjumpers Post-mortem

I made a game for GBJAM 5 called Runjumpers. It’s an action jumping game with a 4 color palette for the graphics. Here’s a few interesting things I learned while making it.

Game designy stuff

Music is important

I knew it would eat up a lot of my limited time, since I’d never done it before, so I decided in advance to not add any music. But half of all the feedback I’ve gotten so far has mentioned that it would be nice if the game had music.

So I’ve been looking into how to make music. I don’t ever expect to make a masterpiece, but being able to create some passable catchy tunes will come in handy for future game jams.

I’m planning on a post-jam update for the game with some music. So far, I’ve only got this track for the title screen. Making something suitable for the running part has proven trickier. I’m gonna keep trying though.


Small gameplay changes can make a big difference

When I first started making the game it only had one jump key, and you could only jump one height. I thought about having a variable height jump based on how long you pushed the key, but first I tried just adding a hop key for small jumps. The game instantly became much more interesting and challenging.

I played around and started building levels based on choosing between hop and jump. As I tested them I would get frustrated and think things like, “Oh come on! I almost had it… Just one more try and I’ll get past that part!” I was having fun. This was working.

So this change only increased the available player choices at any given moment from 2 (jump / don’t jump) to 3. Sure that’s still a 50% increase in complexity, but it’s also the smallest change possible. Sometimes that’s all you need.

Technical JavaScripty stuff

JavaScript at 60 Frames Per Second is tricky

I was getting some lag when testing my game in Firefox on a different computer. After some investigation I found one interesting place for optimization.

I don’t usually worry about the details of garbage collection when writing JavaScript. It’s just something that happens automatically. But when you only have 16.6ms to update each frame, any garbage collection step that takes longer than that means dropped frames and choppy animation. Now, modern browsers are actually pretty good at scheduling garbage collection between frames, but it can still add up quickly and slower or busier machines can still fall behind.

How do we reduce garbage collection? Just reduce the amount of garbage we create. What is garbage exactly? In this case we mean creating objects that are never used again. The browser has to do some computation to free up that memory.

Here’s a great stackoverflow answer with a list of things that cause browsers to allocate memory.

So for example:

update() {
  //...
  player.pos = { x: newX, y: newY };
  //...
}

Whoops we just created a new throwaway object every time our update code runs.

update() {
  //...
  player.pos.x = newX;
  player.pos.y = newY;
  //...
}

Much better.

In general, instead of creating new objects during the game loop, create your objects at init time and make changes to those.

Here’s a profile of 6 seconds of gameplay in Chrome from before I refactored to avoid this.

Screenshot of a graph of JavaScript heap allocation showing dozens of jaggy sawtooths spread over 6 seconds

And here’s after.

Screenshot of a graph of JavaScript heap allocation showing only two smooth increases and sharp drops spread over 6 seconds

Check out those heap allocation graphs. Also notice ‘Minor GC’ drops from 17.3ms to 0.4ms. And this is just a simple running game with no enemies or items. In a game with bullets and enemies flying around the difference would even be more dramatic.

KeyboardEvent.key is cool

Modern KeyboardEvents are great.

Instead of something like this:

window.addEventListener('keydown', function(event) {
  if (event.keyCode === 38) { // Up
    player.jump();
  }
});


we can write this:

window.addEventListener('keydown', function(event) {
  if (event.key === 'UpArrow') {
    player.jump();
  }
});

Unfortunately this isn’t currently supported by Safari, but that can be fixed with a polyfill.

One more issue is that Edge uses some non-standard key names (still not fixed since IE9!), so you will actually have to write:

window.addEventListener('keydown', function(event) {
  if (event.key === 'UpArrow' || event.key === 'Up') {
    player.jump();
  }
});

Check the footnotes here for more details on those.

Even with these drawbacks, it’s still a lot nicer than littering your code with arcane keyCode numbers.

Don’t forget to play the game

https://walsh9.itch.io/runjumpers

Runjumpers

I made a little running and jumping game for GBJAM 5 last week.

Runjumpers Screenshot

It’s a finite-runner with 5 levels and a character creator.

[z] to jump. [x] to hop.

You can play here or here.

My #js13kgames Faves

I finally played through 100+ js13kgames entries. It was hard to narrow it down but here are some of my favorites.

  • Bubble Trap - A clever puzzle game about editing levels to control the paths of bubbles. I had to stop playing when telling colors apart got more important, but what I played was really well done.
  • Evil Glitch - Really polished arena shooter. Maybe just me but I’m feeling kind of a 2D Devil Daggers vibe.
  • Fix the Glitch - Go into the computer zone and solve an assortment of neat computer themed puzzle minigames.
  • Glitch Blob - Addictive fish tank simulator. Amazing use of CSS for the graphics.
  • Glitch in outer space - Top down puzzle adventure game just full of atmosphere. I got stuck but I want to come back to this one.
  • Glitchformer - I won’t spoil it but the glitch mechanic in this game is so great. Would love to see it expanded upon.
  • Phosphorous Dating - Match up 90s couples based on their profiles. Strangely immersive. Super-polished retro-Windows UI.
  • Super Chrono Portal Maker - A puzzle platformer that has it all.
  • Theo’s Escape - Great looking one-button platformer. Don’t give up at the cogs! There’s more to see!
  • GLITCHICKEN - Fantastic use of the theme. Abuse glitches in collision code and more to make your escape.
  • Tonder - A really clever take on Guess Who where the game gives you the answers and have to figure out the question. All wrapped up in a super-slick dating app UI.

yoctoPets Post-mortem

I recently made a weird virtual pet simulation called yoctoPets for the js13kgames competition. The theme this year was ‘Glitch’. Hera are a few things I learned while making this game.

Naive simulation can have surprisingly good results.

When I wanted to add a dot-matrix style printer effect, I did some quick Googling to check out how exactly did they work, and particularly what flaws gave dot-matrix printouts their distinctive look. Well, as the name ‘dot-matrix’ suggests, they print everything out as a grid of dots. One thing that really stuck out was the fact that the alignment of dots from row to row was subject to analog imperfections.

So to simulate this I took a very straightforward approach and just drew each square yoctoPet pixel as a 4x4 grid of round dots, offsetting the horizontal position of each dot by a tiny random amount to create imperfections. I originally assumed I might have to do more work and this would be a first step, but when I saw the result it just looked great.Okay, I did do a little more work to make the realtime printing effect, but again that was simply drawing the dots row by row and moving the paper just like a real printer would do. And making the ink run out was just a matter of increasing transparency by a tiny amount for each dot printed. Basically I just tried what was obvious instead of looking for clever tricks.

screenshot of printer results

In the game, a small melody plays when your pet dies. I guess it shouldn’t be surprising, but I was quite pleased that all I had to do was copy the frequencies and durations of the notes off some sheet music and beep them out over the Web Audio API and it sounded like music.

sheet music for 'shave and a haircut'

=>

var C4 = 263;
var B3 = 247;
var A3 = 220;
var G3 = 196;
var REST = 0;
var SHAVE_AND_A_HAIRCUT = [
  {frequency: C4, duration: 1/4},
  {frequency: G3, duration: 1/8},
  {frequency: G3, duration: 1/8},
  {frequency: A3, duration: 1/4},
  {frequency: G3, duration: 1/4},
  {frequency: REST, duration: 1/4},
  {frequency: B3, duration: 1/4},
  {frequency: C4, duration: 1/4},
];

=>

See the Pen shave and a haircut by Matt Walsh (@walsh9) on CodePen.

Bitmap fonts are easy

Had to do a tiny font for the pixel screen and displaying it wasn’t much more work than drawing any other tile. Just have to map pixel positions in the graphic to an array of letters instead of using tile indices or tile names.

yoctopets pixel font

=>

screenshot of font in action

Google Closure Compiler really is a compiler

I always just thought of it as a fancy minifier. But when you turn on those advanced optimization features it starts to get really particular about your code really fast. I didn’t have a lot of time and was never that close to the 13k limit, so I didn’t get into it too much, just doing the minimal amount of source code annotation to keep Closure Compiler happy. But it did get me thinking about the possibilities of using it in other projects. Seems good when you want sanity checks on your code beyond what a linter can provide.

As always, CSS gradients and shadows are fantastic

Just look at those buttons. Look at that paper.

screenshot showing off shiny case and crisp paper

There’s more but I don’t want to reveal all of the mysteries. Please check out the game and adopt your own yoctoPet today.