Making a game in less than 13kb part 2

In the last post we covered the basic parts of the game, and now we’ll cover more datailed parts

Camera System

Bvhydb6IYAACal5

Adding a camera really improved the game. It allowed for bigger maps and more content. This was a particular item that gave me a headache, it seemed simple but it was difficult for me to implement. After some time, it turns out to be quite simple. It may not be optimised, but it did the job.

The object representation will not change, only the drawing is affected. Based on that a new object was created to hold the camera data:

var camera = {
 x:0,
 y:0
}

Then in the update method, just update the camera (x,y) to follow the hero and always center it on the screen:

 camera.x = hero.x - Math.floor((canvas.width/tileSize)/2);
 camera.y = hero.y - Math.floor((canvas.height/tileSize)/2);

Then to draw the hero, we have to take into account the hero position:

var drawHero = function(){
     ctx.drawImage(tilesetImage, (3 * tileSize), (2 * tileSize), tileSize, tileSize, (hero.x - camera.x)*tileSize, (hero.y-camera.y)*tileSize-10, tileSize, tileSize);
}

The same for enemies:

ctx.drawImage(tilesetImage, (col * tileSize), (row * tileSize), tileSize, tileSize, (enemy.x -camera.x)*tileSize, (enemy.y-camera.y)*tileSize-10, tileSize, tileSize);

And terrain:

ctx.drawImage(tilesetImage, (tileCol * tileSize), (tileRow * tileSize), tileSize, tileSize, ((c - camera.x) * tileSize), ((r - camera.y) * tileSize), tileSize, tileSize);

And that is it! We only had to offset the drawn elements according to the camera (x,y) position. Quite simple, but also quite confusing at first. You have access to the complete code at github and you can check out the differences of how it was implemented, in particular check this commit number.

Fog of War

BwZQOb3CEAEBQqN

The fog adds a nice effect, a more dungeon feel. It also focus attention on the player which is quite nice. All the content is specified in tiles and drawn from a matrix. For this FoW we just create a new matrix to hold the alpha values, and then draw it over the current canvas.

We create an empty array:

var generateFOW = function (){
 var FOW = [];
 for (var r = 0; r < rowTileCount; r++) {
     var column = [];
     for (var c = 0; c < colTileCount; c++) {
         column.push(0);
     }
     FOW.push(column);
 }
 return FOW;
}

Then we use something called the manhattan distance, which sounds a lot more complex in the wikipedia article. basically you calculate the distance in x-axis and then in y-axis and add them both. We use several manhattan measures to create a gradient with different alphas:

 for (var r = 0; r < rowTileCount; r++) {
     for (var c = 0; c < colTileCount; c++) {
         var xDistance = Math.abs(hero.x-camera.x-c);
         var yDistance = Math.abs(hero.y-camera.y-r);
         var manhattanDistance = xDistance + yDistance;
         if (manhattanDistance < 3){
             FOW[r][c] = 0
         }
         else if (manhattanDistance < 4){
             FOW[r][c] = 0.3
         }
         else if (manhattanDistance < 5){
             FOW[r][c] = 0.5
         } else{
             FOW[r][c] = 0.7
         }
     }
 }

Finally we draw on the canvas, using the previously calculated values:

for (var r = 0; r < rowTileCount; r++) {
    for (var c = 0; c < colTileCount; c++) {
    ctx.fillStyle = "rgba(0, 0, 0,"+FOW[r][c]+")";
    ctx.fillRect(c*tileSize, r*tileSize, tileSize, tileSize);
    }
}

 

Enemies

They are a huge part of videogames, always having someone to try stop the heroe’s dream. And for that we need them to be intelligent. At first were too intelligent and they always knew where you were. Later a restriction of distance was added to avoid having a big bunch of angry  centaurs following you.

//Just follow player if near
 if (manhattanDistance >= 15) return;

Enemies only move after the player moves and we move them in the order they were pushed into an array. Each enemy with try to get into contact with the player at a manhattan distance =1 in order to attack:

 if (manhattanDistance == 1){//Attack player directly
     hero.hp -= enemy.attack;
     return;
 }

Or just move closer by one square in x-axis or y-axis:

var row = enemy.y + 1;
var column = enemy.x;

They are not too smart, but they present a threat to the player is the enemies have high attack and high health.

 

Destructible terrain

I really like destructible terrain, when I started coding at first I just spent time making my own tunnels. Having destructible terrain add more choices to the player. Dig and lose this turn movement or just take a different longer path. When followed by an enemy the choice matters.

In the 2-d array we hold the data if there is dirt or is a clear path. When the player or enemy wanted to dig we just check if the wall is destructible and if yes, we replace the value of the destructible wall with a zero:

if (isDestructibleWall(row,column)){
   topLayer[row][column] = 0;
} else{
   //Do something if required
 }
var isDestructibleWall = function(row, column){
   var tile = topLayer[row][column];
   if (tile == destructibleWallIndex){
     return true;
   }
   return false;
}

Simple, but effective.


 

For the last part of the tutorial (part 3), I will cover the music and sound effects and how the menus were drawn.

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

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