HTML5 prototype of iOS “o:anquan” puzzle game powered with Phaser – finished prototype with flood fill implementation
Talking about o:anquan game, Game development, HTML5, Javascript and Phaser.
Learn cross platform HTML5 game development
Check my Gumroad page for commented source code, games and books.
indexOf
method using pointInArray
function because indexOf
standard javascript method does not work with Phaser Point class.
Now the concept is:
1 – Place three random numbers (explained in the first part)
2 – Make a move (same as above)
3 – Remove matching number using flood fill
4 – Back to point 1
I highlighted the new lines of code, still no comments because I did not have the time, but I am sure you will appreciate it.
var game;
var gameOptions = {
gameWidth: 800,
gameHeight: 1400,
tileSize: 120,
fieldSize: {
rows: 6,
cols: 6
},
fallSpeed: 250,
diagonal: false,
colors: [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff]
}
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 = 0x222222;
game.load.spritesheet("tiles", "assets/sprites/tiles.png", gameOptions.tileSize, gameOptions.tileSize);
},
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.tileGroup = game.add.group();
this.tileGroup.x = (game.width - gameOptions.tileSize * gameOptions.fieldSize.cols) / 2;
this.tileGroup.y = (game.height - gameOptions.tileSize * gameOptions.fieldSize.rows) / 2;
for(var i = 0; i < gameOptions.fieldSize.rows; i++){
this.tilesArray[i] = [];
for(var j = 0; j < gameOptions.fieldSize.cols; j++){
this.addTile(i, j);
}
}
this.placeNumbers();
},
placeNumbers: function(){
var emptySpots = [];
for(var i = 0; i < gameOptions.fieldSize.rows; i++){
for(var j = 0; j < gameOptions.fieldSize.cols; j++){
if(this.tilesArray[i][j].value == 0){
emptySpots.push(this.tilesArray[i][j].coordinate);
}
}
}
for(i = 0; i < 3; i++){
var item = Phaser.ArrayUtils.removeRandomItem(emptySpots);
if(item){
var randomValue = game.rnd.integerInRange(2, 9);
this.tilesArray[item.y][item.x].value = randomValue;
this.tilesArray[item.y][item.x].frame = randomValue;
}
}
},
addTile: function(row, col){
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.value = 0;
theTile.picked = false;
theTile.coordinate = new Phaser.Point(col, row);
this.tilesArray[row][col] = theTile;
this.tileGroup.add(theTile);
},
pickTile: function(e){
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);
if(this.tilesArray[row][col].value > 0){
this.tilesArray[row][col].alpha = 0.5;
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){
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);
if(row != this.visitedTiles[this.visitedTiles.length - 1].y || col != this.visitedTiles[this.visitedTiles.length - 1].x){
var distance = new Phaser.Point(e.position.x - this.tileGroup.x, e.position.y - this.tileGroup.y).distance(this.tilesArray[row][col]);
if(distance < gameOptions.tileSize * 0.4){
var previousTileValue = this.tilesArray[this.visitedTiles[this.visitedTiles.length - 1].y][this.visitedTiles[this.visitedTiles.length - 1].x].value;
if(!this.tilesArray[row][col].picked && this.checkAdjacent(new Phaser.Point(col, row), this.visitedTiles[this.visitedTiles.length - 1]) && previousTileValue > 1 && this.tilesArray[row][col].value == 0){
this.tilesArray[row][col].picked = true;
this.tilesArray[row][col].alpha = 0.5;
this.tilesArray[row][col].value = previousTileValue - 1;
this.tilesArray[row][col].frame = previousTileValue - 1;
this.tilesArray[this.visitedTiles[this.visitedTiles.length - 1].y][this.visitedTiles[this.visitedTiles.length - 1].x].value = 1;
this.tilesArray[this.visitedTiles[this.visitedTiles.length - 1].y][this.visitedTiles[this.visitedTiles.length - 1].x].frame = 1;
this.visitedTiles.push(this.tilesArray[row][col].coordinate);
}
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].value = 0;
this.tilesArray[this.visitedTiles[this.visitedTiles.length - 1].y][this.visitedTiles[this.visitedTiles.length - 1].x].frame = 0;
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.tilesArray[this.visitedTiles[this.visitedTiles.length - 1].y][this.visitedTiles[this.visitedTiles.length - 1].x].value = previousTileValue + 1;
this.tilesArray[this.visitedTiles[this.visitedTiles.length - 1].y][this.visitedTiles[this.visitedTiles.length - 1].x].frame = previousTileValue + 1;
}
}
}
}
}
},
releaseTile: function(){
game.input.onUp.remove(this.releaseTile, this);
game.input.deleteMoveCallback(this.moveTile, this);
game.input.onDown.add(this.pickTile, this);
for(var i = 0; i < this.visitedTiles.length; i++){
this.tilesArray[this.visitedTiles[i].y][this.visitedTiles[i].x].picked = false;
this.tilesArray[this.visitedTiles[i].y][this.visitedTiles[i].x].alpha = 1;
}
if(this.visitedTiles.length > 1){
for(i = 0; i < this.visitedTiles.length; i++){
this.filled = [];
this.filled.length = 0;
this.floodFill(this.visitedTiles[i], this.tilesArray[this.visitedTiles[i].y][this.visitedTiles[i].x].value);
if(this.filled.length > 1){
for(var j = 0; j < this.filled.length; j++){
this.tilesArray[this.filled[j].y][this.filled[j].x].value = 0;
this.tilesArray[this.filled[j].y][this.filled[j].x].frame = 0;
}
}
}
this.placeNumbers();
}
},
checkAdjacent: function(p1, p2){
if(gameOptions.diagonal){
return (Math.abs(p1.x - p2.x) <= 1) && (Math.abs(p1.y - p2.y) <= 1);
}
else{
return (Math.abs(p1.x - p2.x) == 1 && p1.y - p2.y == 0) || (Math.abs(p1.y - p2.y) == 1 && p1.x - p2.x == 0);
}
},
floodFill: function(p, n){
if(p.x < 0 || p.y < 0 || p.x >= gameOptions.fieldSize.cols || p.y >= gameOptions.fieldSize.rows){
return;
}
if(this.tilesArray[p.y][p.x].value == n && !this.pointInArray(p)){
this.filled.push(p);
this.floodFill(new Phaser.Point(p.x + 1, p.y), n);
this.floodFill(new Phaser.Point(p.x - 1, p.y), n);
this.floodFill(new Phaser.Point(p.x, p.y + 1), n);
this.floodFill(new Phaser.Point(p.x, p.y - 1), n);
}
},
pointInArray: function(p){
for(var i = 0; i < this.filled.length; i++){
if(this.filled[i].x == p.x && this.filled[i].y == p.y){
return true;
}
}
return false;
}
}
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.