Making a game in less than 13kb part 1

Making a game is quite a challenge, making it in less than 13kb is insane. Here are all the details on my game Shield Maiden and how it was made. My first idea of game was a rogue-like and since I had never made one before I decided to go for it.

Game loop

Since April I have been developing in JavaScript, using Phaser as engine. This time, not even Phaser could be used for the engine.  A game loop was one of the minimal requirements, at least the update and render states.

Did a little research and found information about how to implement it in an article.

1. Use canvas as the drawing surface and attach the logic in the game.js script

<!DOCTYPE html>
<html>
<head lang="en">
   <title>A JS game in under 13kb</title>
</head>
<body>
   <canvas id=myCanvas width="704" height="480"></canvas>
   <script src="game.js"></script>
</body>
</html>

This is a minimal index.html with just the canvas and the game.js script

2. Request animation frame(In the game.js script):

var main = function () {
    var now = Date.now();
    var delta = now - then;
    update(delta / 1000);
    render();
    then = now;
    requestAnimationFrame(main);
};
var reset = function () {
    //Setup of the game world, initialize variables, etc...
};
var update = function (delta) {
    //Update of the game world
};
var render = function () {
    //Here is where we draw to canvas
};
var w = window;
requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;
var then = Date.now();
reset();
main();

Those are the most basic parts. The delta allows for ajustments, but since the game here is tile based and the actions are triggered by user input, I could just ignore it. In the requestAnimationFrame, there are several logic OR (||) for cross-browser support.

Capture Keyboard Input

After getting to work the game loop the next step was to capture the arrow keys.

1. Adding listeners for keyup/keydown and track of press status

var playerHasMoved = false;
var canPressKey = true;
var keysDown = {};
addEventListener("keydown", function (e) {
    if (canPressKey){
        playerHasMoved = false;
        keysDown[e.keyCode] = true;
        canPressKey = false;
    }
}, false);
addEventListener("keyup", function (e) {
    delete keysDown[e.keyCode];
    canPressKey = true;
}, false);

Shield Maiden requires 5 keys to be captured, the ARROWS plus the X key. Also a requirement was to only make an action after a full key down to key up. An action will only occur when pressing a key, and to trigger it again the key would have to be pressed again. This is accomplished with the canPressKey flag.

2. Update game according to keys

var KEY_UP = 38;
var KEY_DOWN = 40;
var KEY_LEFT = 37;
var KEY_RIGHT = 39;
var KEY_X = 88;
var update = function (delta){
    if (KEY_X in keysDown){
        //Do something when X is pressed
    }
 }

Inside the update function we can keep track of the key presses and do actions according to them, like move left when the user pressed the left arrow.

World Representation

To store the world map a 2-d arrays are used:

var topLayer = [[]];
var groundLayer = [];

The groundLayer was used to draw the background images and the topLayer is where all the game elements are placed: Destructible rocks, enemies, player and items.

A small example of a generated layer:

var layer = [
 [0,0,0,0,0],
 [1,0,0,0,1],
 [1,0,0,0,1]];

Then by assigning special meaning to each number we can draw each of the tiles. Then in the render method draw according to the index of the array.

Specifying the game size in variables helps to always use the same values and be able to change them fast if you require.

var tileSize = 32;
var rowTileCount = 48;
var colTileCount = 48;

Originally the game width/height was fixed and assigned the size by using canvas.height/tileSize and having a canvas size multiple of the tileSize.

Drawing in Canvas

To draw in the canvas we use the drawImage function, the regular function is:

context.drawImage(img,x,y);

This will draw the entire img in the x,y position, but for our purposes we use a tile map with several images(to save space):

js13k

We use a different drawImage function:

context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);

This allows us to specify the image and just a portion of the image we want to draw, then draw it in the x,y position. Read more in wc3school. It is important to clear the canvas if you are not completely redrawing it using:

context.clearRect(0,0,canvas.width, canvas.height);

It is quite an expensive task, but for the purpose of this game it seemed fine, so no optimization was done.

Using the drawImage function we can now draw the background without problem:

var imageNumTiles = 4;//Tiles per row
for (var r = 0; r < rowTileCount; r++) {
    for (var c = 0; c < colTileCount; c++) {
        var tile = groundLayer[ r ][ c ];
        var tileRow = (tile / imageNumTiles) | 0; 
        var tileCol = (tile % imageNumTiles) | 0;
        ctx.drawImage(tilesetImage, (tileCol * tileSize), (tileRow * tileSize), tileSize, tileSize, (c * tileSize), (r  * tileSize), tileSize, tileSize);
    }
}

Having our map in the 2-d array, we hace rows and columns so we iterate over all the values and according to the value stored in the array we pick the correct portion of the image to draw.

Each of the values represent the tile number.

js13

Using the example:

var layer = [
 [0,0,0,0,0],
 [1,0,0,0,1],
 [1,0,0,0,1]];

We would be drawing only the clear tile and the floor tile. By adding more layers, we can draw the enemies and items. We can also move them by changing the content of the layer. For example, the Blue Centaur is number 7 and is placed at the top left:

var layer = [
 [7,0,0,0,0],
 [0,0,0,0,0],
 [0,0,0,0,0]];

To change the position is just a matter of updating the 7 position in the array:

var layer = [
 [0,0,0,0,7],
 [0,0,0,0,0],
 [,0,0,0,0]];

Now the Blue Centaur is in the top right.


 

That was quite a lot of information, but it covers the basis for the game, the rest of the features are just improvements over the existing game logic that would be addressed in part 2 of this post.

Remember you can access the complete code in my github. And take a look at the game in the js13kgames site.

One thought on “Making a game in less than 13kb part 1

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s