A Tourist In Paris: a JS13KGAMES 2017 postmortem

The tiny blinking square is a tourist, and the big blinking square a monument…

Game ideation

Art direction

Just imagine a pixelated tourist running around with a camera and no map!
Camera? Check! Map? Check! Helpless running around? Check!

Technical choices

6-year-old me managed it, so how hard could it be?
Yup, Paris can be sneaky with the Tourist :(

What went right

  • The game goals are explained on a dedicated screen displayed just before the game starts.
Fun fact: the background color is different everytime.
  • I used a pixelart font (courtesy of Peters and Flo- who created it for their JS13KGAMES 2016 game Glitch Hunter). A 1px black outline helps the text stand out regardless of the background colors, which was useful since mine were unpredictable by design.
  • The score is the number of monuments the player has been able to visit before his tour bus left, and the player can tweet this number when the game ends (many thanks to Ryan Malm who gave me permission to use the Twitter code from his JS13KGAMES 2016 game Super Glitch Box)
The tweet generated by the game for a player to share his score.
  • I finally figured out a collision response algorithm for diagonal motions against a obstacle. It’s far from physically accurate, but it does the trick: I am not trying to find the exact collision point (“rewind” or “backtrack”) and move the player along the wall by the right amount from that point (“slide”). Instead I merely push the player back outside the wall (“pushback”). The frame rate is fast enough that the player doesn’t have time to go very far into the wall. After correction, he ends up pretty close to where he should have been, so it’s still convincing enough.
Accurate response on the left, approximate response on the right.
  • I implemented mobile controls (they’re far from perfect, but it’s a first step). On top of allowing me to enter the less crowded Mobile category of the jam (53 submissions versus 222 for the Desktop category), it was close to my heart that A Tourist In Paris could be played on a smartphone or tablet: I often read about new indie games on my mobile device during my commute, and I’m always frustrated when I can’t get past their title screen because they only support keyboard & mouse. I seldom have time to go back to these games once I’ve arrived at home (or work), and it’s a just wasted opportunity for both the game developers and the potential player.

Lessons learned

#1 — Have your boilerplate code ready before the jam begins

#2 — Have a few game ideas ahead of the jam.

Since last JS13k, I’ve listed a dozen game concepts on paper (mostly puzzle or reflection games, because that’s the genre I like the most), and waited for this year’s theme to see which idea would suit it the most…

#3 — Join the JS13KGAMES Slack channel

#4 — Know your code obfuscator

// src/game.js
var atlas = { hero: new Image('hero.png') };
function render() {
var posX = 0,
posY = 0;
drawImage(atlas.hero, posX, posY);
}
render();~$ uglifyjs src/game.js -o dist/game.js --mangle// dist/game.js (indented for clarity)
var atlas = { hero: new Image('hero.png') };
function render() {
var a = 0, // only local variables get renamed
b = 0;
drawImage(atlas.hero, a, b);
}
render();
// src/game.js
(function() { // IIFE
var atlas = { hero: new Image('hero.png') };
function render() {
var posX = 0,
posY = 0;
drawImage(atlas.hero, posX, posY);
}
render();
})()
~$ uglifyjs src/game.js -o dist/game.js --mangle// dist/game.js (indented for clarity)
(function() {
var a = { hero: new Image('hero.png') };
function b() { // variables local to IIFE gets renamed
var c = 0,
d = 0;
drawImage(a.hero, c, d);
}
b();
})()
// src/game.js
var atlas = { hero: new Image('hero.png') };
function render() {
var posX = 0,
posY = 0;
drawImage(atlas.hero, posX, posY);
}
render();~$ uglifyjs src/game.js -o dist/game.js --mangle --toplevel// dist/game.js (indented for clarity)
var a = { hero: new Image('hero.png') };
function b() { // renamed even though global
var c = 0,
d = 0;
drawImage(a.hero, c, d);
}
b();
// src/game.js
var atlas = { hero: new Image('hero.png') };
var entityType = 'hero';
function render() {
drawImage(atlas.hero, 0, 0); // dot notation
drawImage(atlas['hero'], 10, 10); // square brackets with strings
drawImage(atlas[enemyType], 20, 20); // square brackers with var
}
~$ uglifyjs src/game.js -o dist/game.js --mangle --mangle-props --toplevel// dist/game.js (indented for clarity)
var a = { a: new Image('hero.png') };
var b = 'hero'; // value does not get renamed to 'a'
function c() {
drawImage(a.a, 0, 0); // ok
drawImage(a['a'], 10, 10); // ok
drawImage(a[b], 20, 20); // KABOOM! a.hero no longer exists
}
// src/game.js
var indexHero = 0,
indexEnemy = 1;
var atlas = [ new Image('hero.png'), new Image('enemy.png') ];function render() {
drawImage(atlas[indexHero], 0, 0);
}
~$ uglifyjs src/game.js -o dist/game.js --mangle --toplevel// dist/game.js (indented for clarity)
var a = 0,
b = 1;
var c = [ new Image('hero.png'), new Image('enemy.png') ];function d() {
drawImage(c[a], 0, 0); // index renamed like other variables
}

In conclusion (or “so… I made a maze game”)

--

--

--

Software engineer turned manager and father of four, I create pixel art, video games and visual experiments on the Web.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Angular10 Dashboard With firebase

//platform.twitter.com/widgets.js from Twitter https://twitter.com/runner_click

Angular 9 Material Base Module

CRUD Operations:

Introduction to DOM Manipulation

A Flexible Way of Building

Designing a Scalable API Rate Limiter in Node.js Application — Cloudnweb

Depth Series #3: Getting started with the Braintree Sandbox

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Jerome Lecomte

Jerome Lecomte

Software engineer turned manager and father of four, I create pixel art, video games and visual experiments on the Web.

More from Medium

JavaScript Simplified — A Beginner’s Guide

RV’n B

Using useState the right way .

Mini Interview with Terri Vellmann