Talking about Roguelike game, Game development, HTML5, Javascript and Phaser.
We are getting closer to the final algorithm to calculate dynamic light and shadow in tile based roguelike games, and we are going to cover another important feature: drawing circles in a tile based environment. While in previous step I showed you the Bresenhams line algorithm although you probably still do not know why, this time it’s quite easy to understand how we are going to use circles in a tile based environment: to simulate the radius of a point light, which could be a torch on the wall or the light halo around your character. A web page which clearly explains how to create any kind of line, circle, ellipse and Bézier curve is The Beauty of Bresenham’s Algorithm and that’s the code I translated from C to JavaScript to draw circles in a tile based environment. Look at the example: Drag the white tiles to move both the grey line and the red circles. We are now very close to the solution of our problem and soon we will be able to create light and shadows in a tile map environment. Here is the code I used, you can save for future usedrawBresenham
and drawCircle
functions, the other lines have just been written to make the demo work.
var game;
var gridWidth = 40;
var gridHeight = 40;
var tileSize = 16;
var sightRadius = 7;
window.onload = function() {
game = new Phaser.Game(640, 640, Phaser.AUTO, "");
game.state.add("PlayGame", playGame);
game.state.start("PlayGame");
}
var playGame = function(game){};
playGame.prototype = {
preload: function(){
game.load.image("tile", "tile.png");
},
create: function(){
var startCol = game.rnd.between(0, gridWidth - 1);
var startRow = game.rnd.between(0, gridHeight - 1);
this.startPoint = game.add.sprite(startCol * tileSize, startRow * tileSize, "tile");
this.startPoint.inputEnabled = true;
this.startPoint.input.enableDrag();
this.startPoint.input.boundsRect = new Phaser.Rectangle(0, 0, game.width, game.height);
this.startPoint.input.enableSnap(tileSize, tileSize, true, true);
do{
var endCol = game.rnd.between(0, gridWidth - 1);
var endRow = game.rnd.between(0, gridHeight - 1);
} while (startRow == endRow && startCol == endCol);
this.endPoint = game.add.sprite(endCol * tileSize, endRow * tileSize, "tile");
this.endPoint.inputEnabled = true;
this.endPoint.input.enableDrag();
this.endPoint.input.boundsRect = new Phaser.Rectangle(0, 0, game.width, game.height);
this.endPoint.input.enableSnap(tileSize, tileSize, true, true);
this.lineGroup = game.add.group();
},
update: function(){
this.lineGroup.removeAll(true);
this.drawBresenham(this.startPoint.x / tileSize, this.startPoint.y / tileSize, this.endPoint.x / tileSize, this.endPoint.y / tileSize);
this.drawCircle(this.startPoint.x / tileSize, this.startPoint.y / tileSize, sightRadius);
this.drawCircle(this.endPoint.x / tileSize, this.endPoint.y / tileSize, sightRadius);
},
drawBresenham: function(x0, y0, x1, y1){
var dx = Math.abs(x1 - x0);
var sx = -1;
if(x0 < x1){
var sx = 1
}
var dy = Math.abs(y1 - y0);
var sy = -1;
if(y0 < y1){
var sy = 1;
}
var err = -dy / 2;
if(dx > dy){
err = dx / 2;
}
do{
var tile = game.add.sprite(x0 * tileSize, y0 * tileSize, "tile");
tile.alpha = 0.5;
this.lineGroup.add(tile);
var e2 = err;
if(e2 > -dx){
err -= dy;
x0 += sx;
}
if(e2 < dy){
err += dx;
y0 += sy;
}
} while(x0 != x1 || y0 != y1)
},
drawCircle: function(x0, y0, radius){
var x = -radius
var y = 0;
var err = 2 - 2 * radius;
do {
console.log((x0 - x) * tileSize);
this.placeTile((x0 - x) * tileSize, (y0 + y) * tileSize, 0.5, 0xff0000);
this.placeTile((x0 - y) * tileSize, (y0 - x) * tileSize, 0.5, 0xff0000);
this.placeTile((x0 + x) * tileSize, (y0 - y) * tileSize, 0.5, 0xff0000);
this.placeTile((x0 + y) * tileSize, (y0 + x) * tileSize, 0.5, 0xff0000);
radius = err;
if (radius <= y){
y++;
err += y * 2 + 1;
}
if (radius > x || err > y){
x++;
err += x * 2 + 1;
}
} while (x < 0);
},
placeTile: function(x, y, alpha, tint){
var tile = game.add.sprite(x, y, "tile");
tile.tint = tint;
tile.alpha = alpha;
this.lineGroup.add(tile);
}
}
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.