Talking about Dungeon Raid game, Game development, HTML5, Javascript and Phaser.
With the new match-three games like Bejeweled Stars starting to conquer the mobile market once again, it’s time to port some of my old match-three tutorials to HTML5 and Phaser, as well as to start writing new ones. I am going to start with a basic prototype of Dungeon Raid engine. I wrote a lot about this game as you can see, and with its engine I made Globez game which is also available as a full commented HTML5 source code but for those of you which just want to see the basics, here is an HTML5 prototype:
var game;
var gameOptions = {
gameWidth: 750,
gameHeight: 750,
tileSize: 140,
fieldSize: 5
}
window.onload = function() {
game = new Phaser.Game(gameOptions.gameWidth, gameOptions.gameHeight);
game.state.add("TheGame", TheGame);
game.state.start("TheGame");
}
var TheGame = function(){};
TheGame.prototype = {
preload: function(){
game.stage.backgroundColor = 0x444444;
game.load.image("tiles", "assets/sprites/tiles.png");
game.load.spritesheet("arrows", "assets/sprites/arrows.png", 420, 420);
},
create: function(){
game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
game.scale.pageAlignHorizontally = true;
game.scale.pageAlignVertically = true;
this.createLevel();
game.input.onDown.add(this.pickTile, this);
},
createLevel: function(){
this.tilesArray = [];
this.arrowsArray = [];
// group creation and placement to stay in the center of the canvas
this.tileGroup = game.add.group();
this.arrowsGroup = game.add.group();
var groupSize = gameOptions.tileSize * gameOptions.fieldSize;
this.tileGroup.x = (game.width - groupSize) / 2;
this.tileGroup.y = (game.height - groupSize) / 2;
this.arrowsGroup.x = (game.width - groupSize) / 2;
this.arrowsGroup.y = (game.height - groupSize) / 2;
// tile creation
for(var i = 0; i < gameOptions.fieldSize; i++){
this.tilesArray[i] = [];
for(var j = 0; j < gameOptions.fieldSize; j++){
this.addTile(i, j);
}
}
},
addTile: function(row, col){
// adding a new tile
var tileXPos = col * gameOptions.tileSize + gameOptions.tileSize / 2;
var tileYPos = row * gameOptions.tileSize + gameOptions.tileSize / 2;
var theTile = game.add.sprite(tileXPos, tileYPos, "tiles");
theTile.anchor.set(0.5);
theTile.picked = false;
theTile.coordinate = new Phaser.Point(col, row);
this.tilesArray[row][col] = theTile;
this.tileGroup.add(theTile);
},
pickTile: function(e){
// picking the first tile
this.visitedTiles = [];
this.visitedTiles.length = 0;
if(this.tileGroup.getBounds().contains(e.position.x, e.position.y)){
var col = Math.floor((e.position.x - this.tileGroup.x) / gameOptions.tileSize);
var row = Math.floor((e.position.y - this.tileGroup.y) / gameOptions.tileSize);
this.tilesArray[row][col].alpha = 0.5;
this.tilesArray[row][col].picked = true;
game.input.onDown.remove(this.pickTile, this);
game.input.onUp.add(this.releaseTile, this);
game.input.addMoveCallback(this.moveTile, this);
this.visitedTiles.push(this.tilesArray[row][col].coordinate);
}
},
moveTile: function(e){
// we are over a tile
if(this.tileGroup.getBounds().contains(e.position.x, e.position.y)){
var col = Math.floor((e.position.x - this.tileGroup.x) / gameOptions.tileSize);
var row = Math.floor((e.position.y - this.tileGroup.y) / gameOptions.tileSize);
var distance = new Phaser.Point(e.position.x - this.tileGroup.x, e.position.y - this.tileGroup.y).distance(this.tilesArray[row][col]);
// we are inside enough a tile
if(distance < gameOptions.tileSize * 0.4){
// a new, adjacent tile
if(!this.tilesArray[row][col].picked && this.checkAdjacent(new Phaser.Point(col, row), this.visitedTiles[this.visitedTiles.length - 1])){
this.tilesArray[row][col].picked = true;
this.tilesArray[row][col].alpha = 0.5;
this.visitedTiles.push(this.tilesArray[row][col].coordinate);
this.addArrow();
}
// backtrack
else{
if(this.visitedTiles.length > 1 && row == this.visitedTiles[this.visitedTiles.length - 2].y && col == this.visitedTiles[this.visitedTiles.length - 2].x){
this.tilesArray[this.visitedTiles[this.visitedTiles.length - 1].y][this.visitedTiles[this.visitedTiles.length - 1].x].picked = false;
this.tilesArray[this.visitedTiles[this.visitedTiles.length - 1].y][this.visitedTiles[this.visitedTiles.length - 1].x].alpha = 1;
this.visitedTiles.pop();
this.arrowsArray[this.arrowsArray.length - 1].destroy();
this.arrowsArray.pop();
}
}
}
}
},
releaseTile: function(){
// clear the path
this.arrowsGroup.removeAll(true);
for(var i = 0; i < gameOptions.fieldSize; i++){
for(var j = 0; j < gameOptions.fieldSize; j++){
this.tilesArray[i][j].alpha = 1;
this.tilesArray[i][j].picked = false;
}
}
game.input.onUp.remove(this.releaseTile, this);
game.input.deleteMoveCallback(this.moveTile, this);
game.input.onDown.add(this.pickTile, this);
},
checkAdjacent: function(p1, p2){
return (Math.abs(p1.x - p2.x) <= 1) && (Math.abs(p1.y - p2.y) <= 1);
},
addArrow: function(){
// adding the arrows
var fromTile = this.visitedTiles[this.visitedTiles.length - 2];
var arrow = game.add.sprite(this.tilesArray[fromTile.y][fromTile.x].x, this.tilesArray[fromTile.y][fromTile.x].y, "arrows");
this.arrowsGroup.add(arrow);
arrow.anchor.set(0.5);
// this routine handles arrow frame and angle according to its direction
var tileDiff = new Phaser.Point(this.visitedTiles[this.visitedTiles.length - 1].x, this.visitedTiles[this.visitedTiles.length - 1].y)
tileDiff.subtract(this.visitedTiles[this.visitedTiles.length - 2].x, this.visitedTiles[this.visitedTiles.length - 2].y);
if(tileDiff.x == 0){
arrow.angle = -90 * tileDiff.y;
}
else{
arrow.angle = 90 * (tileDiff.x + 1);
if(tileDiff.y != 0){
arrow.frame = 1;
if(tileDiff.y + tileDiff.x == 0){
arrow.angle -= 90;
}
}
}
this.arrowsArray.push(arrow);
}
}
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.