HTML5 Drag and Match engine updated to Phaser 2.6.2 update – adding tweens
Talking about Drag and Match game, Game development, HTML5, Javascript and Phaser.
Do you like my tutorials?
Then consider supporting me on Ko-fi.
handleStop
method:
// the game itself
var game;
// global game options
var gameOptions = {
// width of the game, in pixels
gameWidth: 400,
// height of the game, in pixels
gameHeight: 400,
// size of the sprite sheet, in pixels
spritesheetSize: 50,
// size of each tile, in pixels
tileSize: 50,
// size of the field, in tiles
fieldSize: 6,
// different tile types
tileTypes: 6,
// distance from the left of the screen to the left of the board, in pixels
offsetX: 50,
// distance from the top of the screen to the top of the board, in pixels
offsetY: 50,
// duration of the tween to adjust tiles, in milliseconds
tweenSpeed: 100
}
// some constants to be used in the game
// I am not dragging
var NO_DRAG = 0;
// I am dragging horizontally
var HORIZONTAL_DRAG = 1;
// I am dragging vertically
var VERTICAL_DRAG = 2;
// The game state is "doing nothing"
var GAME_STATE_IDLE = 0;
// When the player is dragging a row/column
var GAME_STATE_DRAG = 1;
// When the player stops dragging
var GAME_STATE_STOP = 2;
// when the window has been fully loaded
window.onload = function() {
// creation of a Game instance
game = new Phaser.Game(gameOptions.gameWidth, gameOptions.gameHeight);
// adding "PlayGame" state
game.state.add("PlayGame", playGame)
// starting "PlayGame" state
game.state.start("PlayGame");
}
var playGame = function(game){}
playGame.prototype = {
// when the state preloads
preload: function(){
// loading the spritesheet with all tile images
game.load.spritesheet("tiles", "tiles.png", gameOptions.spritesheetSize, gameOptions.spritesheetSize);
// setting the game on maximum scale mode to cover the entire screen
game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
game.scale.pageAlignHorizontally = true;
game.scale.pageAlignVertically = true;
},
// once the state has been created
create: function(){
// tileArray is the array which will contain all tiles
this.tileArray = [];
// creation of the group which will contain all tiles
this.tileGroup = game.add.group();
// adjusting group position according to offset
this.tileGroup.x = gameOptions.offsetX;
this.tileGroup.y = gameOptions.offsetY;
// creation of a mask with the same size of the board to be placed in the same position of the group
// this way we are hiding everything is outside the board
this.tileMask = game.add.graphics(this.tileGroup.x, this.tileGroup.y);
this.tileMask.beginFill(0xffffff);
this.tileMask.drawRect(0, 0, gameOptions.fieldSize * gameOptions.tileSize, gameOptions.fieldSize * gameOptions.tileSize);
this.tileGroup.mask = this.tileMask;
this.tileMask.visible = true;
// filling the board with tiles thanks to "addTile" method
for(var i = 0; i < gameOptions.fieldSize; i++){
this.tileArray[i] = [];
for(j = 0; j < gameOptions.fieldSize; j++){
this.addTile(i, j);
}
}
// adding the temporary tile thanks to addTempTile method
this.addTempTile();
// waiting for player input to call pickTile method
game.input.onDown.add(this.pickTile, this);
// the game has just been created, so we are doing nothing
this.gameState = GAME_STATE_IDLE;
},
// function to add a tile at a given row and column
addTile: function(row, col){
// choosing a random tile
var randomTile = game.rnd.integerInRange(0, gameOptions.tileTypes - 1);
// creation of the sprite in the proper position
var theTile = game.add.sprite(col * gameOptions.tileSize, row * gameOptions.tileSize, "tiles");
// setting tile width and height
theTile.width = gameOptions.tileSize;
theTile.height = gameOptions.tileSize;
// showing the frame according to tile value
theTile.frame = randomTile;
// saving the value inside a custom property
theTile.value = randomTile;
// inserting the tile in tileArray array
this.tileArray[row][col] = theTile;
// adding the sprite to tileGroup group
this.tileGroup.add(theTile);
},
// function to add the temporary tile
addTempTile: function(){
// creation of the sprite, no matter the position, we won't show it at the moment
this.tempTile = game.add.sprite(0, 0, "tiles");
// setting its width and height
this.tempTile.width = gameOptions.tileSize;
this.tempTile.height = gameOptions.tileSize;
// setting the sprite to non visible
this.tempTile.visible = false;
// adding the sprite to tileGroup group
this.tileGroup.add(this.tempTile);
},
// function to triggered when the player touches/clicks on the canvas
pickTile: function(e){
// determining row and column according to input position, tile size and offset
this.movingRow = Math.floor((e.position.y - gameOptions.offsetY) / gameOptions.tileSize);
this.movingCol = Math.floor((e.position.x - gameOptions.offsetX) / gameOptions.tileSize);
// if row and column are actually inside game field...
if(this.movingRow >= 0 && this.movingCol >= 0 && this.movingRow < gameOptions.fieldSize && this.movingCol < gameOptions.fieldSize){
// at the moment we aren't dragging
this.dragDirection = NO_DRAG;
// removing the listener which waits for the input to begin
game.input.onDown.remove(this.pickTile, this);
// adding a listener which waits for the input to end then call releaseTile method
game.input.onUp.add(this.releaseTile, this);
// adding a listener which waits for the input to move then call moveTile method
game.input.addMoveCallback(this.moveTile, this);
}
},
// function to be executed at each frame
update:function(){
// checking game state to see what to do
switch(this.gameState){
// we are dragging
case GAME_STATE_DRAG:
// call handleDrag method
this.handleDrag();
break;
// we just stopped dragging
case GAME_STATE_STOP:
// call handleStop method
this.handleStop();
break;
}
// at the end of the function, we set gameState again to idle
this.gameState = GAME_STATE_IDLE;
},
// function to handle - and draw on the canvas - the game when the player drags a row/column
handleDrag:function(){
// two different things to do according to drag direction
switch(this.dragDirection){
// horizontal drag
case HORIZONTAL_DRAG:
// hiding temporary tile
this.tempTile.visible = false;
// placing the temporary tile in the proper row
this.tempTile.y = this.movingRow * gameOptions.tileSize;
// deltaX is the amount of tiles we are moving
var deltaX = (Math.floor(this.distX / gameOptions.tileSize) % gameOptions.fieldSize);
// deltaX >= 0 means we are moving to the right (or not moving)
if (deltaX >= 0) {
// temporary tile frame is now the same as the rightmost visible tile
this.tempTile.frame = this.tileArray[this.movingRow][gameOptions.fieldSize - 1 - deltaX].value;
}
// we are moving to the left
else{
// temporary tile frame is now the same as the leftmost visible tile
deltaX = deltaX * -1 - 1;
this.tempTile.frame = this.tileArray[this.movingRow][deltaX].value;
}
// looping through all the moving row
for(var i = 0; i < gameOptions.fieldSize; i++){
// adjusting each tile horizontal position
this.tileArray[this.movingRow][i].x = (i * gameOptions.tileSize + this.distX) % (gameOptions.tileSize * gameOptions.fieldSize);
// if tile position is less than zero...
if (this.tileArray[this.movingRow][i].x < 0) {
// ... place it on the opposite side of the game field
this.tileArray[this.movingRow][i].x += gameOptions.tileSize * gameOptions.fieldSize;
}
}
// tileX is the amount of pixels we are moving, capped to gameOptions.tileSize
var tileX = this.distX % gameOptions.tileSize;
// if the amount is greater than zero (moving to the right)
if(tileX > 0){
// placing temporary tile before the leftmost tile
this.tempTile.x = tileX - gameOptions.tileSize;
// showing temportary tile
this.tempTile.visible = true;
}
// if the amount is less than zero (moving to the left)
if(tileX < 0){
// placing temporary tile before the leftmost tile
this.tempTile.x = tileX;
// showing temportary tile
this.tempTile.visible = true;
}
break;
// vertical drag, same concept seen in horizontal drag, just applied to Y axis
case VERTICAL_DRAG:
this.tempTile.visible = false;
this.tempTile.x = this.movingCol * gameOptions.tileSize;
var deltaY = (Math.floor(this.distY / gameOptions.tileSize) % gameOptions.fieldSize);
if (deltaY >= 0) {
this.tempTile.frame = this.tileArray[gameOptions.fieldSize - 1 - deltaY][this.movingCol].value;
}
else{
deltaY = deltaY * -1 - 1;
this.tempTile.frame = this.tileArray[deltaY][this.movingCol].value;
}
for(var i = 0; i < gameOptions.fieldSize; i++){
this.tileArray[i][this.movingCol].y = (i * gameOptions.tileSize + this.distY) % (gameOptions.tileSize * gameOptions.fieldSize);
if (this.tileArray[i][this.movingCol].y < 0) {
this.tileArray[i][this.movingCol].y += gameOptions.tileSize * gameOptions.fieldSize;
}
}
var tileY = this.distY % gameOptions.tileSize;
if(tileY > 0){
this.tempTile.y = tileY - gameOptions.tileSize;
this.tempTile.visible = true;
}
if(tileY < 0){
this.tempTile.y = tileY;
this.tempTile.visible = true;
}
break;
}
},
// function to handle - and draw on the canvas - the game when the player stops dragging a row/column
handleStop:function(){
// two different things to do according to drag direction
switch(this.dragDirection){
// horizontal drag
case HORIZONTAL_DRAG:
// we have to find how many "half tiles" we dragged
var shiftAmount = Math.floor(this.distX / (gameOptions.tileSize / 2));
// and now let's see how many tiles we dragged, with a modulo operation because the max amount is fieldSize - 1
shiftAmount = Math.ceil(shiftAmount / 2) % gameOptions.fieldSize;
// creation of a temporary array
var tempArray = [];
// now the idea is to insert in tempArray array the tileArray items in the order they are at the end of the drag
// when shiftAmount is greater than 0, we dragged to the right
if(shiftAmount > 0){
for(var i = 0; i < gameOptions.fieldSize; i++){
tempArray[(shiftAmount + i) % gameOptions.fieldSize] = this.tileArray[this.movingRow][i].value;
}
}
// when shiftAmount is less than zero, we dragged to the left
else{
shiftAmount *= -1;
for(var i = 0; i < gameOptions.fieldSize; i++){
tempArray[i] = this.tileArray[this.movingRow][(shiftAmount + i) % gameOptions.fieldSize].value;
}
}
// the offset is the amount of pixels we dragged, with tileSize as maximum
var offset = this.distX % gameOptions.tileSize;
// if we dragged for more than half a tile...
if(Math.abs(offset) > gameOptions.tileSize / 2){
// adjusting the offset according we dragged to the left (less than zero) or to the right
if(offset < 0){
offset = offset + gameOptions.tileSize;
}
else{
offset = offset - gameOptions.tileSize;
}
}
// copying content from tempArray to tileArray and adjust tile position
for(i = 0; i < gameOptions.fieldSize; i++){
this.tileArray[this.movingRow][i].value = tempArray[i];
this.tileArray[this.movingRow][i].frame = tempArray[i];
this.tileArray[this.movingRow][i].x = i * gameOptions.tileSize + offset;
// tween to adjust tile position
game.add.tween(this.tileArray[this.movingRow][i]).to({
x: i * gameOptions.tileSize
}, gameOptions.tweenSpeed, Phaser.Easing.Cubic.Out, true);
}
// tempdestination is the destination of the temporary tile, outside to the left
var tempDestination = -gameOptions.tileSize
// if the offset is less than zero, then move temporary tile on the opposite side of the board
if(offset < 0){
this.tempTile.x += gameOptions.tileSize * gameOptions.fieldSize;
// also set temporary tile destinatiokn outside to the right
tempDestination = gameOptions.fieldSize * gameOptions.tileSize;
}
// then adjusting temporary tile position with a tween
var tween = game.add.tween(this.tempTile).to({
x: tempDestination
}, gameOptions.tweenSpeed, Phaser.Easing.Cubic.Out, true);
// we add the listener for a new input only when the tween is completed
tween.onComplete.add(function(){
game.input.onDown.add(this.pickTile, this);
}, this)
break;
// vertical drag follows the same concepts seen in horizontal drag
case VERTICAL_DRAG:
var shiftAmount = Math.floor(this.distY / (gameOptions.tileSize / 2));
shiftAmount = Math.ceil(shiftAmount / 2) % gameOptions.fieldSize;
var tempArray = [];
if(shiftAmount > 0){
for(var i = 0; i < gameOptions.fieldSize; i++){
tempArray[(shiftAmount + i) % gameOptions.fieldSize] = this.tileArray[i][this.movingCol].value;
}
}
else{
shiftAmount *= -1;
for(var i = 0; i < gameOptions.fieldSize; i++){
tempArray[i] = this.tileArray[(shiftAmount + i) % gameOptions.fieldSize][this.movingCol].value;
}
}
var offset = this.distY % gameOptions.tileSize;
if(Math.abs(offset) > gameOptions.tileSize / 2){
if(offset < 0){
offset = offset + gameOptions.tileSize;
}
else{
offset = offset - gameOptions.tileSize;
}
}
for(var i = 0; i < gameOptions.fieldSize; i++){
this.tileArray[i][this.movingCol].value = tempArray[i];
this.tileArray[i][this.movingCol].frame = tempArray[i];
this.tileArray[i][this.movingCol].y = i * gameOptions.tileSize + offset;
game.add.tween(this.tileArray[i][this.movingCol]).to({
y: i * gameOptions.tileSize
}, gameOptions.tweenSpeed, Phaser.Easing.Cubic.Out, true);
}
var tempDestination = -gameOptions.tileSize
if(offset < 0){
this.tempTile.y += gameOptions.tileSize * gameOptions.fieldSize;
tempDestination = gameOptions.fieldSize * gameOptions.tileSize;
}
var tween = game.add.tween(this.tempTile).to({
y: tempDestination
}, gameOptions.tweenSpeed, Phaser.Easing.Cubic.Out, true);
tween.onComplete.add(function(){
game.input.onDown.add(this.pickTile, this);
}, this)
break;
}
// we aren't dragging anymore
this.dragDirection = NO_DRAG;
},
// function to be triggered when the player moves the mouse/finger
moveTile: function(e){
// we are dragging
this.gameState = GAME_STATE_DRAG;
// determining horizontal and vertical distance between start and current input position
this.distX = e.position.x - e.positionDown.x;
this.distY = e.position.y - e.positionDown.y;
// if we aren't dragging yet...
if(this.dragDirection == NO_DRAG){
// how many pixels are we travelling with our finger/mouse?
var distance = e.position.distance(e.positionDown);
// more than 5 pixels? ok, that's enough to determine the direction
if(distance > 5) {
// trigonometry to know drag angle
var dragAngle = Math.abs(Math.atan2(this.distY, this.distX));
// if drag angle is between PI/4 and 3PI/4...
if((dragAngle > Math.PI / 4 && dragAngle < 3 * Math.PI / 4)) {
// ... we can say it's a vertical drag
this.dragDirection = VERTICAL_DRAG;
}
else {
// else it's an horizontal drag
this.dragDirection = HORIZONTAL_DRAG;
}
}
}
},
// function to be triggered when the player releases the mouse/finger
releaseTile: function(){
// we stopped dragging
this.gameState = GAME_STATE_STOP;
// removing listeners
game.input.onUp.remove(this.releaseTile, this);
game.input.deleteMoveCallback(this.moveTile, this);
}
}
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.