How to create an HTML5 swap and match-3 game engine like the one used in Spellfall iOS game using Phaser
Talking about Spellfall game, Game development, HTML5, Javascript and Phaser.
You already know there is an universe full of match-3 games out there, and each one has its way to combine and match symbols in order to do something the game requires.
Normally, at each move – no matter how you actually move – you should do at least a match.
Moreover, behind that “no matter how you actually move”, there always is a rule swap tiles.
This is not the case of Spellfall from Backflip Studios where you can swap any tile you want with any other tile you want, no matter where they are, and no matter if you make a match.
Definitively the simplest way to approach a match-3 game although the game has a lot of other features which make it quite difficult.
So, what I did today was writing a quick Phaser HTML5 demo of this kind of swapping tiles just like in the original game.
This is what you are going to create, also playable from this link:
Just drag a tile onto another tile to swap them.
There isn’t that much to say about the code, as it is even simpler than the HTML5 Drag and Match engine made with Phaser I published last month.
Here I am just using tweens and group swapping to keep some tiles always in front of the stage.
The fully commented source code is here:
<!doctype html>
<html>
<head>
<script src="phaser.min.js"></script>
<style>
body{margin:0}
</style>
<script type="text/javascript">
window.onload = function() {
var game = new Phaser.Game(300,300,Phaser.CANVAS,"",{preload:onPreload, create:onCreate, update:onUpdate});
// you can change these values to customize the game
var tileSize = 50; // tile size, in pixels
var fieldSize = 6; // number of tiles per row/column
var tileTypes = 6; // different kind of tiles allowed
var pickedZoom = 1.1; // zoom ratio to highlight picked tile
// variables used by game engine
var dragging = false; // are we dragging?
var movingRow; // row of the moving tile
var movingCol; // col of the moving tile
var tileArray = []; // array with all game tiles
var tileGroup; // group containing all tiles
var movingTileGroup; // group containing the moving tile
// when preloading, load the spritesheet with all tiles
function onPreload() {
game.load.spritesheet("tiles","tiles.png",tileSize,tileSize);
}
// the game has been created
function onCreate() {
// show the game in full screen
game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
game.scale.setScreenSize();
// add groups. movingTileGroup needs to be above tileGroup so moving tiles
// will always have an higher z index and will always stay on top of the game
tileGroup = game.add.group();
movingTileGroup = game.add.group();
// game field generation, all tiles initially added to "tileGroup" tile
for(i=0;i<fieldSize;i++){
tileArray[i]=[];
for(j=0;j<fieldSize;j++){
var randomTile = Math.floor(Math.random()*tileTypes)
theTile=game.add.sprite(j*tileSize+tileSize/2,i*tileSize+tileSize/2,"tiles");
theTile.frame = randomTile;
theTile.anchor.setTo(0.5,0.5);
tileArray[i][j]=theTile;
tileGroup.add(theTile);
}
}
// listener for input down
game.input.onDown.add(pickTile, this);
}
// a tile has been picked
function pickTile(){
// save input coordinates
startX = game.input.worldX;
startY = game.input.worldY;
// retrieve picked row and column
movingRow = Math.floor(startY/tileSize);
movingCol = Math.floor(startX/tileSize);
// move the tile to the upper group, so it will surely be at top of the stage
movingTileGroup.add(tileArray[movingRow][movingCol]);
// zoom the tile
tileArray[movingRow][movingCol].width=tileSize*pickedZoom;
tileArray[movingRow][movingCol].height=tileSize*pickedZoom;
// now dragging is allowed
dragging = true
// update listeners
game.input.onDown.remove(pickTile, this);
game.input.onUp.add(releaseTile, this);
}
// a tile has been released
function releaseTile(){
// remove the listener
game.input.onUp.remove(releaseTile, this);
// return the tile to its originary group
tileGroup.add(tileArray[movingRow][movingCol]);
// determine landing row and column
var landingRow = Math.floor(tileArray[movingRow][movingCol].y/tileSize);
var landingCol = Math.floor(tileArray[movingRow][movingCol].x/tileSize);
// reset the moving tile to its original size
tileArray[movingRow][movingCol].width = tileSize;
tileArray[movingRow][movingCol].height = tileSize;
// swap tiles, both visually and in tileArray array...
tileArray[movingRow][movingCol].x=landingCol*tileSize+tileSize/2;
tileArray[movingRow][movingCol].y=landingRow*tileSize+tileSize/2;
// ...but only if there moving and landing tiles are different!!
if(movingRow!=landingRow || movingCol!=landingCol){
// place the tile to move on the upper group
movingTileGroup.add(tileArray[landingRow][landingCol]);
// destination tile will move to start tile with a tween
var tileTween = game.add.tween(tileArray[landingRow][landingCol]);
tileTween.to({
x:movingCol*tileSize+tileSize/2,
y:movingRow*tileSize+tileSize/2
},800,Phaser.Easing.Cubic.Out,true); // <- this "true" means "start immediatly"
tileTween.onComplete.add(function(){
tileGroup.add(tileArray[landingRow][landingCol]);
// once the tween is completed update tileArray array
game.input.onDown.add(pickTile, this);
var temp = tileArray[landingRow][landingCol];
tileArray[landingRow][landingCol] = tileArray[movingRow][movingCol];
tileArray[movingRow][movingCol] = temp;
});
}
else {
// otherwise just let the player be able to swap another tile
game.input.onDown.add(pickTile, this);
}
// we aren't dragging anymore
dragging = false;
}
// the game is being updated
function onUpdate() {
// if we are dragging a tile
if(dragging){
// check x and y distance from starting to current input location
distX = game.input.worldX-startX;
distY = game.input.worldY-startY;
// move the tile
tileArray[movingRow][movingCol].x=movingCol*tileSize+tileSize/2+distX;
tileArray[movingRow][movingCol].y=movingRow*tileSize+tileSize/2+distY;
}
}
};
</script>
</head>
<body>
</body>
</html>
And obviously you can download the entire project.
I will add some gameplay to this prototype this week, stay tuned.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.
