js13kGames — Back to the basics

September 16, 2019

I want­ed to par­tic­i­pate in js13k for a while now, so I final­ly took the dive, sim­i­lar­ly to 7drl this year. The result­ing game is called Back­Flipped, and you can play it on either the com­pe­ti­tion site or itch! Also, you can check out the source code on Github.

I had some goals:

Here’s a lengthy post­mortem detail­ing my design deci­sions so I can refer to them lat­er, but also so oth­er peo­ple can learn! I might make a sep­a­rate post about all the opti­miza­tion tricks I used, but for now the js13k resources are very use­ful, and I tried most of the tricks list­ed there.

The Idea

I had an idea for a game where you fall into a well with plat­forms. The Left or Right arrow keys pro­pel you into that direc­tion, and if you hit a block, you score points. Then, you can kick through the block as well, to break it for more points.

For the “Back” theme, the extra lay­er I decid­ed to add was the background. When you touch a block but then move away, it moves back­wards. Once you reach the bot­tom of the well, grav­i­ty flips and you move to the back­ground your­self. The bet­ter you play, the more blocks will move to the oth­er side, increas­ing score poten­tial.

I end­ed boost­ing the speed of the game dur­ing devel­op­ment. First blocks would dis­ap­pear after leav­ing col­li­sion, now they do so on enter­ing of col­li­sion to make it clear­er you can kick through them. The Up key would not start a jump, but actu­al­ly slow your fall. If you land­ed on a block you’d lose falling speed, but now you’ll just instant­ly start anoth­er drop after falling on some­thing. The game is around five times faster than in the first ver­sion! Because this game has no tra­di­tion­al obsta­cles (such as spike blocks or ene­mies), the entire chal­lenge has to come from bat­tling the timer, which I think adds to the chaos of the game­play.

Ear­ly GIF of game­play.

Rules

My idea was to only have a set of lev­els, but I scrapped that and made it just an end­less mode. Now it has both!

While this game has lev­els, each lev­el is actu­al­ly just a ran­dom­ness seed set to a cer­tain val­ue. You can’t set a seed for ran­dom­ness in JS, but you can make your own seed­ed sys­tem. I took one from Stack­Over­flow. A down­side is that dif­fer­ent browsers gen­er­ate oth­er lev­els, but that’s not too big of an issue for this game.

At first, end­less mode would make you start at a cer­tain time, then as you’d kick blocks you’d build up a jack­pot. Hit­ting the bot­tom of the lev­el would cash out your jack­pot. But it encour­aged play­ers to con­stant­ly drop straight down and not hit all plat­forms. I revamped it with an “All Clear” mechan­ic: all plat­forms give a lit­tle bit of time, but if you hit all the plat­forms on the way down, you get a cou­ple of extra sec­onds as well. End­less mode also keeps get­ting faster and faster as you go, too, and since the lev­el keeps grow­ing and grow­ing on each flip, I think there’s a pret­ty good game bal­ance on this mode now.

Old inter­face for Jack­pot mode: The +sec counter dis­plays the jack­pot val­ue, which gets claimed when you flip around.

Interface

I don’t think many js13k par­tic­i­pants have “mak­ing a title screen” as their top pri­or­i­ty. For me it’s rather impor­tant, because it’s the first impres­sion the play­er will get from your game. I was quite hap­py to be able to make a sim­ple but cool title screen using css col­ors and trans­forms.

I did­n’t want to make sep­a­rate texts for desk­top & mobile, so the game shows “Press Space or Tap Screen” on both plat­forms.

The game runs like nor­mal in the back­ground, except with the play­er, trail, and col­li­sions dis­abled. Also, the title screen gets recy­cled as a game over screen by replac­ing the text. This makes the game seem more live­ly since it’s a screen­saver when you’re not play­ing!

In oth­er parts of the game the UI is min­i­mal­ist:  there’s a timer, a level/score indi­ca­tor, and a progress bar. A text box shows game help on the title screen and oth­er info when need­ed, for exam­ple upon game saves.

I want­ed a screen-fill­ing respon­sive game, so I use Zdog’s zoom prop­er­ty to make the game fit to small­er screens, with @media rules in CSS doing the UI.

Mobile

I did not plan to enter in the Mobile cat­e­go­ry, but some­one want­ed me to sub­mit a sim­ple mobile web game as part a test, so I decid­ed to add it to Back­Flipped.

I set­tled on using swipe direc­tions to input the same direc­tion arrow key, using a GitHub gist as base. It works a bit finicky (espe­cial­ly with short swipes) but it’s good enough to play with one fin­ger. You do have to swipe a lot when the game starts get­ting faster! I also used these con­trols as an excuse to add input buffer­ing: so if the game can’t han­dle play­er input in the cur­rent step, it’ll repeat it for a cou­ple more frames in case the play­er timed just a bit too ear­ly.

The ver­sion I orig­i­nal­ly sub­mit­ted for js13k had bro­ken swipe con­trols. Luck­i­ly, a short email to the js13k team with a new ver­sion of the game was enough to get the jam ver­sion updat­ed!

This is pret­ty much how the game looks like on my old­er smart­phone… The text isn’t very big, but at least it fits!

Faking it with Zdog

In Zdog, the 3D effect is only real­ly vis­i­ble when the cam­era rotates. My game did­n’t require a lot of rotat­ing though, but I decid­ed to make the cam­era a lit­tle bit skewed to con­vey depth a bit bet­ter.

The screen flips around once you reach the bot­tom. I can only make the Zdog illus­tra­tion rotate around its mid­dle, which caused issues when the play­er was fur­ther away. The fix was mak­ing the play­er jump back to the ori­gin when the cam­era starts flip­ping, then mov­ing all oth­er objects to the same posi­tion, rel­a­tive to the play­er before the jump. Now the tran­si­tion is super smooth!

A lot of the things that look like they’re exact­ly behind the play­er, are actu­al­ly placed diag­o­nal­ly of that in 3D space. I did this to com­bat Z‑fighting, when the ren­der­er changes in which order over­lap­ping shapes are drawn. Now what looks neat­ly when watch­ing from the game cam­era, is actu­al­ly not placed behind each oth­er:

You’ll notice the trail and the play­er are in dif­fer­ent places, but from where the cam­era usu­al­ly is it seems like they’re in the same place.

But it works won­der­ful­ly when watched from the game cam­era. And that was good enough.

Colors!

If you have a game with only flat col­ors, it’s a missed oppor­tu­ni­ty if you don’t add mul­ti­ple palettes. I tried it in my game Mobil­i­ty!, but I only end­ed up chang­ing the back­ground col­or, not the entire palette.

Back­flipped defines six dif­fer­ent col­ors: fore­ground and back­ground, blocks on the fore- and back­ground, char­ac­ter body/dots and eye/trail col­or. The back­ground col­ors are most impor­tant, because every­thing else needs to have a decent con­trast col­or with it.

The block col­ors also need good back­ground con­trast when you’re on their lay­er, but need to fade away into the back­ground when they’re not: a tricky bal­ance. So I used a palette cre­ator designed to test the con­trast of col­ors, and end­ed up mak­ing a few palettes that use the flip­ping mechan­ic of the game metaphor­i­cal­ly: for exam­ple, Dawn­break switch­es between dusk and dawn.

Coil sub­scribers get two extra col­or palettes that are unlocked from the start. I think this is a good cos­met­ic good­ie to offer to sub­scribers since it does­n’t influ­ence game­play too much, but does look very fan­cy and pre­mi­um. Over­all, I’m very hap­py with the vari­a­tion among these sev­en col­or palettes!

The default col­ors.
Straw­ber­ry Patch
Blue­ber­ry Juice
Bright & Light
Styl­ish Mono­chrome
Beau Blue­print, one of the exclu­sive palettes…
And Dawn­break, the oth­er exclu­sive palette.

Finishing

I kept a close eye on my mini­fied file size at the start, man­u­al­ly mini­fy­ing code and com­bin­ing assets in a sin­gle file. Lat­er on, I found it eas­i­er to focus on get­ting the game done and wor­ry about file size lat­er. I found it risky to start opti­miz­ing too soon, as it might make my code messier than it already is, but this bench­mark gave me an idea about how big I could make the game in a month.

I zipped the game at mul­ti­ple times dur­ing devel­op­ment, with wide­ly fluc­tu­at­ing file sizes. Screen­shot from WinDir­Stat.

As the end kept crawl­ing clos­er, I tried auto­mat­ed lint­ing solu­tions, but I could­n’t get them to work. I end­ed up writ­ing a man­u­al lin­ter in Javascript & HTML. It allows you to paste HTML, CSS, and JS, assign file­names, and hit a but­ton to get a sin­gle out­put HTML with the con­tents of the oth­er files embed­ded. I actu­al­ly end­ed up learn­ing a bit about how RegEx works to min­i­mize the code a lit­tle bit (adapt­ing xem’s Min­i­Mini­fi­er), and I might expand it to be more user friend­ly.

Screen­shot from my lin­ter: clean files come in, messy com­bined file comes out. Com­bined with mini­fi­ca­tion, this saves around 1/3th of char­ac­ters!

The main way I lost file size was by remov­ing unused Zdog func­tion­al­i­ty, like shapes I was­n’t using. After­wards, the removals got more spe­cif­ic, result­ing in a very messy but small ver­sion of Zdog.

I checked the game with the entry bot which helped me spot some last minute issues. Although I for­got to sub­mit the game with the bot, man­u­al­ly fill­ing the form instead. Ah well!

The full source code (except fav­i­con) for Back­Flipped. Screen­shot from Visu­al Stu­dio Code.

Take-away

My main real­iza­tion was that, no mat­ter how much fun it is to opti­mize the file size of your game, you should­n’t for­get to make the game fun to play as well. Bal­anc­ing the tech­ni­cal and game­play relat­ed issues was very hard, and it almost went awry, destroy­ing my moti­va­tion for the project. Luck­i­ly, after iter­at­ing some more and hav­ing a few more testers, I did man­age to make the game fun.

Fin­ish­ing it was also pret­ty hard: thir­ty days for a 13kb game sounds real­ly gen­er­ous, but know­ing when you should stop adding new stuff to focus on mini­fy­ing and pol­ish­ing what’s there was also pret­ty dif­fi­cult. I ran into a cou­ple of annoy­ing last-minute bugs, but luck­i­ly I was able to get it into a ship­pable con­di­tion in time!

You can play Back­Flipped on itch and on the js13k com­pe­ti­tion site. Also, check out any of the 244 oth­er sub­mis­sions for the jam— some real­ly inter­est­ing games to find there, and you could fit them all on two or three flop­py disks!