> Build and publish an HTML5 game for iPad – Part 3

A bit late on the roadmap due to an hard disk failure, here comes the third episode of the saga. This time I’m going to show you a quick screencast and you’ll finally discover what the game will be about.

Backup, backup a lot, backup often

Last week, following to an unfortunate series of events, I lost both the development version and the backup files of the graphics for the game.

The code itself is safe, I have multiple copies on multiple repositories spread all over the globe. I keep files bigger than a couple of gigas on “just” two locations instead… one of them being a RAID1 NAS. But life has a vivid sense of humor and there’s nothing worst than a false sense of safety regarding backup copies of your work.

To make a long story short: don’t trust your external hard drive. Time Machine is as fail safe as your HD (ie: not safe at all). The same goes for DropBox and most cloud services.

My suggestion is to start from a RAID1 NAS, and make multiple copies of the same file too. Then search an online backup service that supports geographic redundancy (my weapon of choice is rsync.net).

Anyway I had to start the design from scratch and not so surprisingly it came up much better than the first version. If you have time, when you find the design you like, close it and redo it from blank page, the new version will be noticeably better.

The game

Sorry for the rant. Here below the long awaited sneak preview of the game in all its alpha stage glory. Please remember that it’s all CSS/JS, no canvas has been harmed!

The goal is to compose words tapping adjacent tiles. Of course you’ll also have bonus tiles granting you more points and “special abilities” just to spice up the gameplay. To add some variety every 3 levels you’ll end up in a bonus stage, a mini-game where you’ll be asked to find the more words possible given a set of 8 letters (kinda Scrabblish).

That’s it. Nothing more, nothing less. Hope you’ll like it.

The scoreboard

If you like the scoreboard you’ll be happy to know that I’m giving it away for free. It’s a very simple dependency-free javascript library called jsOdometer. You find it on github and you can see a live demo here (works on Chrome too).

If you need it bigger you’ll probably have to change the translateZ() value in the odometer.js file at line 21.

Admittedly it is in beta stage and some more work is needed to make it rock solid, but still better than programming it from scratch.

iPad Display

It seems that the iPad display is a bit over-saturated, especially in the red-orange spectrum. That nice wooden texture you see in the demo turns into a distracting red background on the real device. Remember to desaturate by 8-10% your reds before deploying to iPad.

Sound

Working with sound and music is a mess for so many reasons.

First of all, the iPad speaker sucks. It is especially bad at sound effects. Always choose clear, simple, short and with few basses effects. I’ve tried dozens files before finding the ones that don’t sound like a drunk squirrel.

Secondly, the native code to WebView wrapper is slow. It takes 100-200ms before the sound is actually played, an infinitely long time for a game. Not only that, the interface lags during this timeframe. PhoneGap provides the great Media API but to reduce (but not completely remove) the lag you have to be smart.

I noticed that the play > stop > play sequence is too much to handle for the device. It works for background music, but not for sound effects that need to be played multiple times per minute. The solution is to never stop the audio file.

Build an “audio sprite” file. Merge together all your sound effects into a single file and add one second of silence at the end of each effect and at the beginning of the file.

At startup play the sound file and immediately pause it (it’s not a stop! Just a pause). When you need a sound you have to position the audio “head” at the beginning of the needed sound with seekTo(ms) first, then when the sound is played you pause it again. The audio file is basically never stopped.

The following is a quick and dirty example of how your sound function might look like:

var sound = (function () {
	var hasSound = false,
		
		fx,
		fxTimer;
	
	function init () {
		hasSound = 'Media' in window;

		fx = new Media('audio/fx.m4a');

		seekPlay(0,100);
	}

	function seekPlay (from, to) {
		if (!hasSound) return;

		clearTimeout(fxTimer);
	
		to = to || 500;
		
		fx.pause();
		fx.seekTo(from);
		fx.play();
		
		fxTimer = setTimeout(function () {
			fx.pause();
		}, to);
	}
	
	function boom () {
		seekPlay(1000);
	}
	
	function clank () {
		seekPlay(2205);
	}
	
	function kapow () {
		seekPlay(3380)
	}

	return {
		init: init,
		boom: boom,
		clank: clank,
		kapow: kapow,
	};
})();

At this point you can call sound.boom() and your code should take care of everything.

The interface is still plagued by a small lag each time you play an effect. The solution this time is to defer the call to the sound function.

setTimeout(function() { sound.boom(); }, 0);

Forcing the browser repaint with the element.offsetHeight trick also seems to work. I’m not completely satisfied by the audio performance on the original iPad (iPad2 is good enough) and I will surely spend more time on this topic later when the game logic will be completed.

Music

If like me you can’t say the difference between a piano and a cello you are pretty much forced to look for a soundtrack on one of the many royalty free music sites around. Read the license agreement carefully, there are many limitations in score usage.

Very good resources are Premiumbeat, Neosounds and Soundrangers.

Remember that you have to take the KB count as low as possible, so try to pick a short loopable track.

/Share the joy

/Reactions

    • Author: Loan Myers
    • Posted on: 2011/12/05
    • At: 23:34

    Really Sleek! Did you design that as well?

    • Author: ayorosmage
    • Posted on: 2011/12/06
    • At: 09:44

    Hi and congratulation for your tutorial.
    I have a question. Does the design adapt for any devices ( means works also on android tablets) or it is just ok for iPad ??

    • first version will be ipad only, iphone and android are coming up next

        • Author: ayorosmage
        • Posted on: 2011/12/06
        • At: 11:16

        Ok thanks.
        By the way, do you plan to share the javascript code on this blog once the app has been posted on App Store ? I think it could be very interesting !

      • reasonable

    • Author: Edoardo
    • Posted on: 2011/12/06
    • At: 13:42

    Great, thanks for sharing.

    I love the sleek music/pause performance workaround!

  • The sound improvement is what I need. Thank you!
    Here is a Japanese translation.
    http://d.hatena.ne.jp/nextliteracy/20111207/1323226720

  • Great, thanks for sharing.

    • Author: Ghigo
    • Posted on: 2012/01/05
    • At: 11:10

    Great article. Thanks!

    • Author: Mark
    • Posted on: 2012/01/19
    • At: 23:12

    Thanks for sharing. What is the reason for putting the sounds in a single file (‘sound sprite’)? Would it not be sufficient to just pause any sound you play just before it finishes, and then seekTo/play next time you need to play it?

    • yes, it should work with multiple files as well. The good of sound sprites is that they can be reused in web apps (not phonegap’d) as the iOS browser supports just one audio stream at a time.

        • Author: Mark
        • Posted on: 2012/01/20
        • At: 09:22

        Ah, thanks, very good point.

    • Author: Rares
    • Posted on: 2012/01/26
    • At: 13:13

    After reading about the sound problems I’ve got this idea: Why not use a web worker (thread) to play audio? Two minutes later I found there is no Audio inside a web worker. Which is really lame IMHO.

    Does anybody knows why we cannot do that? I mean is there a good reason to not allow access to Audio in a web worker?