Developing an old-school 2D mobile-friendly loop-based platform game using canvas and touch API (PART 1)

Back in my youth I used to write my own games. They weren’t very good games, but they were just about playable and thought me many concepts about coding. For this article I originally wanted to target the game to 3 platforms: Computers with keyboards, Smartphones and tablets, and The Sony PS4, but after doing some checking it seems the PS4’s gamepad isn’t accessible from Javascript (thanks Sony), so I’ll concentrate on the first two.

I want to write something that closely represents Super Mario Brothers, without infringing on copyright. This was originally released on the Nintendo NES way back in 85. The NES came with a control pad with two buttons: A and B. and a 4-button D-pad, giving a total of 6 buttons. If you were rich, you could buy the 2-controller pack, which meant 2 people could play the game by taking turns but they needed different controllers. (Yes, it makes no sense now either)… maybe they were more worried about germs back in the 80s..who knows.

I’m going to go slowly with this tutorial cause I want to develop the framework first before we delve into the game proper. That means handling various screen resolutions, checking for support of APIs, and abstracting this stuff away as much as possible from our game code. (Trust me it will be better in the long run). Also, you may want to be aware that I’m a fullscreen kind of guy and I’ll be coding this game such that the game takes up as much of the screen as possible. This is essential on smartphones where the display is small but also  essential on web browsers where the user’s attention could otherwise be stolen by ads and other such distractions.

I’ll begin with the template I’m using nowadays for most of my web work, plus a few extra bits.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
</head>
<body></body>
</html>

Nothing too complex there, you may not be familiar with the “viewport” meta tag. This is a mobile-specific tag that needs to be added to stop the user from zooming in/out the webpage and also allows the developer to hard-code a width (in pixels) so mobile browsers with different resolutions will automagically scale the content up/down so the page appears with the same proportions no matter what screen resolution their device has. We’re not going to use this feature so we’ve set it to “device-width”. (my reason is because I suspect this will add an extra layer of processing on the device which will put more pressure on the CPU and give less cycles to our game which we want to run as smoothly as possible).

Abstracting the gamepads

We intend our platform game to run on touchscreen devices as well as “traditional” computers, but there’s a third type of device we’d like to support and that’s computers with gamepads attached. There’s a relatively young API that modern browsers are starting to support and that’s the Gamepad API. It allows gamepad events to be heard by javascript thus allowing a HTML-based game to be controlled using a gamepad. I’ll get on to that later.

For now let’s forget about how we’re going to read the physical hardware or even what kind of hardware it is (if it is hardware), and write some simple javascript which will define our 2 Nintendo NES joypads (gamepads):

var gamepads=[
   {up:false,down:false,left:false,right:false,A:false,B:false}, // Player 1
   {up:false,down:false,left:false,right:false,A:false,B:false} // Player 2
];

We can think of this structure as the ‘middle man’ between our (messy) API code and our (nice) game code. The game programmer will never ‘see past’ this structure and will simply read the boolean values to see whether a particular button is or isn’t pressed.

What did I mean by loop-based?

Most web programming these days is event-based, but all the cartridge-based games back in the 80s were loop-based. The game centered around a “main loop” which would run 25 times a second (or 50) typically doing the following tasks:

while (alive){
   updatePlayer();
   updateBaddies();
   detectCollisions();
   drawBackground();
   drawSprites();
   waitVSync();
   flipBuffers();
}

Needless to say this is a very rough description. updatePlayer() would update the player’s sprite (let’s call him Mario), by reading the gamepad’s buttons and reading some other variables related to the player such as current X/Y coordinates, X/Y velocity, whether he was big mario or small mario / whether he was “dying”… and based on these it would arrive at the correct X/Y coordinates and the correct mario sprite to render. updateBaddies() would do something similar for all the baddies on the screen. detectCollisions() would check if Mario has come into contact with any baddies, drawBackground() and drawSprites() would draw the background/ sprites in their correct places and waitVSync() would wait until the TV’s beam had reached the bottom of the screen and returned back to the top of the screen ready to begin the next frame. This ensured a steady frame rate as long as all of the work was done before that beam got to the bottom of the screen. If a game missed that deadline, it would have to wait for the next VSync thus causing that frame to stay onscreen for twice as long as it should have.

There was also another colsely-related concept called double buffering that all games needed to implement in order to look “good”. I have a suspicion that we shouldn’t need it for our canvas-based game. I wrote one a few years ago when canvas had just been invented and I did need to implement a double buffer, which meant 2 canvases (canvii?) stacked on top of each other and while one was being drawn on the other was on display to the viewer, then once the first one is fully drawn it’s put on display and the other one is flipped. This involved changing the z-Index values and some messy css positioning code. I suspect this problem has been sorted out in newer browsers and the programmers have devised some clever way of rendering things to the canvas in “bunches” then displaying it all in an instant, overwriting what was previously there. This would make sense since it ensures less resources to be consumed by the browser and makes coding easier for the developer (us). I am just speculating here though and I could be wrong.

Our main loop

Without further ado, here’s our main loop:

var mainLoop=setInterval(function(){
// Loop code goes here
},20);

This function will run every 20ms , or every .02 of a second, giving, (1/.02)=50 loops per second. or 50Hz. It would be nice to have it run at 100Hz but this might put too much strain on mobile devices. It may not be smooth enough for the young gamers of today who demand ultra high frame rates. So if they want 100Hz they are welcome to modify the javascript and play at 2X the speed.

Getting the canvas out of the way

I hate CSS. I’d like to keep the CSS to an absolute minimum for this tutorial so let’s try and nail the canvas code and get it positioned properly before we move on to the good stuff.

game.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<script type="text/javascript" src="game.js"></script>
<style>
body{
        margin:0px;
        padding:0px;
        overflow:hidden;
}
#theCanvas{
        margin:0px;
        padding:0px;
        border:0px;
        width:100%;
        height:100%;
}
</style>
</head>
<body onload="game.init()" onresize="game.resizeCanvas()">
<canvas id="theCanvas"></canvas>
</body>
</html>

game.js:

var game=(function(){
	var cvs; // reference to the canvas itself
	var ctx; // canvas's 2D drawing context
	var frame=0; // counts the number of frames in our game
	
	var gamepads=[
		{up:false,down:false,left:false,right:false,A:false,B:false}, // Player 1
		{up:false,down:false,left:false,right:false,A:false,B:false} // Player 2
	];

	var resizeCanvas=function(){
		cvs.style.width=window.innerWidth+"px";
		cvs.style.height=window.innerHeight+"px";	
	};

	var init=function(){
		cvs=document.getElementById("theCanvas");

		// Set width and height of our game raster
		// (in pixels). These will never change
		cvs.width=900;
		cvs.height=500;

		resizeCanvas();

		ctx=cvs.getContext("2d");
		ctx.font="20px Bold Arial";
		ctx.textAlign="center";
		ctx.textBaseline="middle";


		var mainLoop=setInterval(function(){
			// Loop code goes here
			//
			frame++;

			ctx.fillStyle="#0f0";
			ctx.fillRect(0,0,cvs.width,cvs.height);
			ctx.fillStyle="#000";
			ctx.fillText("Frame "+frame,cvs.width/2,cvs.height/2);

		},20);
	};

	// Public properties
	return{
		resizeCanvas:resizeCanvas,
		init:init
	};	

})();

So that’s the most basic HTML and JS code. If you run it on your browser (computer or phone) it should show a green background with the words Frame XXX in the middle with XXX increasing rather fast. The good news is the HTML code is done!. That’s it! same with the CSS! after this all we’ll be working with is Javascript and the only element we’ll be working on is the canvas.

In part 2 we’ll “plug in” our gamepads and get them live and responding to keypresses/touch events. Stay tuned!

Advertisement

Writing your own shell in perl

I’m getting back into Perl programming because I think it’s a great language, and with Perl 6 coming soon I think we’ll see a big Perl revival soon. It’s also the only interpreted language I know so from a purely functional perspective, My choices are either Perl, C, or to learn a new language. Python springs to mind, I’ve never learned Python and don’t intend to unless I’m put in a situation where I need to learn it.

Anyway if you’re a Python programmer you can probably translate my Perl code into Python fairly easily, I’ll keep it as un-Perlish as possible. So this is a tutorial about writing a shell. What is a shell? You’ll probably say “a command line”, and you’re pretty-much right. A shell is simply a program that runs other programs for the user, usually in a loop, until it gets some special command (usually ‘exit’).

Incidentally, you should never name your program `exit’, because if you store it in ~/bin or /usr/bin it will be impossible to call from a shell, as the shell interpreter will always just exit when it gets this command. I was curious about this myself and actually wrote a program called `exit’ which I stored in ~/bin and couldn’t execute it. Anyway, here’s our perl shell code, in all it’s glory:

#!/usr/bin/perl
# psh.pl
# (c) computersciencealgorithms.com
use strict;
use warnings;
 
while (<STDIN>){
 
system($_);
 
}

Believe it or not, this actually works! And you can in fact use pipes (|) and redirections () although this is kind of cheating. You see the system() command checks the string it gets and if it finds any shell metacharacters it passes the command to the systems default shell (/bin/sh -c on unix) for execution, so effectively whenever our shell gets a string more complex than a simple (command+args) it gives the job to the system shell which does it for us and passes us back the output.

So if we wanted to create our own fully-fledged shell interpreter we could examine the string and dissect it into separate commands and set up pipelines and input/output files etc but that’s all a little too complex for the purposes of this article, so for now we’ll just let bash take care of all that hairy stuff.

How can we improve our shell?

Let’s make our shell more useful. If you play around with the shell from the listing above, the only way to exit from it is by pressing Ctrl-C. This is functional enough, and if you invoke another process from it, such as `top’ and press Ctrl-C, it returns control to the caller (our shell), which is nice, but what if we’re running a program and press Ctrl-C but the program exits just before we press it? That’s why most shells just display ^C when Ctrl-C is pressed, and is exited by the user typing “exit”. Let’s do that.

#!/usr/bin/perl
#
# psh.pl
#
# (c) computersciencealgorithms.com
#
use strict;
use warnings;

# set up interrupt handler
sub interrupt{
    # control gets here when user presses Ctrl-C
    print "\n";
}
$SIG{INT} = \&interrupt;

while (<STDIN>){
    # get rid of the trailing \n
    chop $_;
    
    # exit?
    exit 0 if $_ eq "exit";
    
    # run the command
    system($_);
}

This shell behaves slightly more like bash, Whenever the user presses Ctrl-C, the operating system (Linux) sends the SIGINT signal to the process. Under normal circumstances this will cause the program to exit, unless we’ve set up a handler, which we have. This is useful for closing files/network connections, and doing any “cleanup” operations to ensure data integrity/security etc. But in this case, we simply print a “\n”, as the shell that called our shell (bash) also received that SIGINT and printed it’s own “^C”. Again, we could override this behavior… but why should we, when this accomplishes what we need?

The next essential ingredient in our shell is a “cd” or “chdir” command. At the moment our poor little shell is locked in the directory where he was born, and there he will die! Let’s give him the gift of directory traversal.

#!/usr/bin/perl
#
# psh.pl
#
# (c) computersciencealgorithms.com
#
use strict;
use warnings;

# set up interrupt handler
sub interrupt{
    # control gets here when user presses Ctrl-C
    print "\n";
}
$SIG{INT} = \&interrupt;

while (<STDIN>){
    # get rid of the trailing \n
    chop $_;
    
    # exit?
    exit 0 if $_ eq "exit";
    
    # cd?
    if ($_ =~ /^cd\s*[^\s]*/){
        $_ =~ s/(^cd\s*|")//g;
        (length && chdir $_) or print "Can't cd into $_ :(\n";
        
    }else{
        # run the command
        system($_);
    }
}

Isn’t it nice the way you can choose whether to use “&&” or “and” in perl and you can put in brackets in function calls, or not, depending on the mood you’re in?

Here, again, I’ve intercepted any command string that starts with “cd”, used a regex replacement to strip out any whitespace after the cd, leaving only the directory name (or a zero-length string, which is checked by simply using the command “length”.. how cool is that?), if the length is >1 the chdir() command is invoked and the shell’s working directory is changed. Incidentally, you may have figured out that “cd”, along with “exit” are not actual UNIX commands (type ‘man cd’).. nor does it make sense to implement them as commands, because although they would do what they’re supposed to do and do it very well, they would only be doing it in the context of themselves. For instance if I wrote a program called “exit”:

#!/usr/bin/perl
#
# exit.pl
#
# (c) computersciencealgorithms.com
#
use strict;
use warnings;

$#ARGV+1 and exit $ARGV[0] or exit;

This is a fairly comprehensive `exit’ program that takes an optional exit code argument, and does the job of exiting (from itself) very well indeed, Likewise with `cd’:

#!/usr/bin/perl
#
# cd.pl
#
# (c) computersciencealgorithms.com
#
use strict;
use warnings;

$#ARGV+1 and -d $ARGV[0] and chdir $ARGV[0] or exit 1;

This cd program checks for an argument, checks for the existance of a directory and if it’s there, changes into it, otherwise exits with failure (1). But again, completely useless because it inherits it’s working directory from the calling process, chdir()’s into an absolute or relative path, then dies, but the calling process is still stuck in the same directory it was in in the first place… two utterly useless commands!

Making it look more bash-ish

At the moment our shell lacks a prompt, so it would be nice to know what user we are (if you like to su this is pretty important), and of course it’s also nice to know what directory we’re in. So let’s do that.

#!/usr/bin/perl
#
# psh.pl
#
# (c) computersciencealgorithms.com
#
use Cwd;
use Sys::Hostname;
use strict;
use warnings;

# returns our prompt string
sub prompt{
	my $uid=$<; # gets the user's id (0 is root)
	my $username=getpwuid($uid);
	my $hostname=hostname;
	my $dir=getcwd;
	my $sym='$';
	$sym='#' unless $uid;
	$username."@".$hostname.":".$dir.$sym." ";
}

# set up interrupt handler
sub interrupt{
    # control gets here when user presses Ctrl-C
    print "\n";
}
$SIG{INT} = \&interrupt;

print prompt;

while (<STDIN>){
	# get rid of the trailing \n
	chop $_;
	
	# exit?
	exit 0 if $_ eq "exit";
	
	# cd?
	if ($_ =~ /^cd\s*[^\s]*/){
		$_ =~ s/(^cd\s*|")//g;
		(length && chdir $_) or print "Can't cd into $_ :(\n";
		
	}else{
		# run the command
		system($_);
	}
	
	print prompt;
}

So there we go! A working shell in exactly 50 lines of perl code. The prompt string mimics the bash shell enough that I got confused when running it. It’s still missing some key features. Namely tab completion and the home (~) shortcut. It’s also not very colorful and everything is printed in grey. Still it’s a functional shell and you can use it to do real work and add your own custom features.

Next week I’ll begin my series on Perl TCP/IP programming which will culminate in the creation of a Telnet server so we can use our shell from anywhere in the world. Stay tuned

Oh and remember when I said I’d keep the code as un-perlish as possible? I lied.