Get the full commented source code of

HTML5 Suika Watermelon Game

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.