Elias Schütt
Web developer

Hello, I'm Elias Schütt, a young web developer from Germany.

I am currently attending high school. When finished I will study Japanese and Computer science.

In my spare time I prepare for my japanese studies and occasionally work on web related projects.

View all entries

A little insight in the development of my latest cross-platform HTML5 game

Published on October 8th, 2013

This blog post is oriented towards my soon to be released game called Pathfinder (temporary name). It is a puzzle/memorization game with several difficulties, achievements, funky music and an editor to create your own levels. You can try it right here: http://elias-schuett.de/indev/pathfinder/. I plan to publish it on the google play and chrome market sometime this week.

Responsive design

Let's start by explaining how to make the app/game adjust itself to all the different devices. I myself have never done anything like this before but I knew about css media queries, so I simply chose a few min-width's and corrected the width and font-size accordingly in percentages.

@media only screen and (orientation : portrait) and (min-width : 0px)   { /* ... */ }
@media only screen and (orientation : portrait) and (min-width : 321px) { /* ... */ }
@media only screen and (orientation : portrait) and (min-width : 800px) { /* ... */ }

This means of course that we have to use em or % for all other properties like padding, margin etc.

Once I got the CSS setup I had to adjust the game itself aswell. The tile size for example is calculated like this:

Level.tileSize = Math.min(
    $(window).width() / Level.fieldSize.x,
    $(window).height() / Level.fieldSize.y
) - Level.tileMargin | 0;

fieldSize defines the number of tiles in each direction. The | 0 at the end simpy floors the result (gotta love bit-wise operators).
Now we can determine the canvas size like follows.

ctx.canvas.width = Level.fieldSize.x * (Level.tileSize + Level.tileMargin);
ctx.canvas.height = Level.fieldSize.y * (Level.tileSize + Level.tileMargin);

Javascript libraries

But enough code, let's take a look at what libraries I used to make this game possible:

  • RequireJS

  • jQuery

    • When it comes to complex UI's and animation jQuery is always the way to go.
  • Prefix free

    • I had to use a bunch of gradients and special CSS3 properties like box-sizing where prefixfree really comes in handy.
  • Underscore.js

    • Not too essential in my particular game, but it turned out pretty useful here and there.
  • fastclick

    • A life saver. I struggled so long with removing that stupid 300ms click lag on touch devices. It always produced weird bugs where the event would fire on elements that are inserted at runtime behind the clicked element. Fastclick eliminated those bugs for me.
  • canvg

    • The browser on some older android devices doesn't support SVG, so I had to use this javascript SVG parser as a fallback.
  • cordova

    • The cordova.js library which is part of the phonegap package. It is used to access some internal hardware features like orientation, the camera, etc. I only used it for playing audio with cordova's new Media(), HTML5's new Audio doesn't work here unfortunately.

And last but not least: G5.js my own little javascript game engine I began developing 8 months ago. It handles the entire game-loop mechanic for you, has a neat animation class and other useful constructors for vector math, spritesheets and all that stuff.

Caching user data

The user data (settings, image cache, achievements) is saved inside the browsers localstorage. What I don't like about the native localStorage API is that you can only save strings inside it. So I wrote this little wrapper function, which enables me to save and retrieve simple javascript objects. I might even add a base64 encryption in the future:

Utils.localStorage = function(key, value) {
    if (key !== undefined && value !== undefined) {
        window.localStorage.setItem(key, JSON.stringify(value));
    } else if (key !== undefined) {
        return JSON.parse(window.localStorage.getItem(key));
    }
};

Easy isn't it? Now we can simply do:

var settings = Utils.localStorage("settings");
settings.music = true;
Utils.localStorage("settings", settings);

What I had to cache in my game was the level previews and the individual tile patterns in svg format. I calculated the optimal resolution by dividing the smaller screen size by the average level size:

OTR: Math.min(
    window.screen.width,
    window.screen.height
) / 7

This ensures that we only use the resolution necessary in our canvas game. What you could also do is pre-scale all the svg's into different png sizes but I like have everything a little dynamic.

That's it for now, I will revise this post once the game is fully published.

loading repositories...
loading