/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2014 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Creates an object that is placed within a layer of a Phaser.Tilemap and can be moved around and rotated using the direction commands.
*
* @class Phaser.Plugin.TilemapWalker
* @constructor
* @param {Phaser.Game} game - Game reference to the currently running game.
* @param {Phaser.Tilemap} map - A reference to the Tilemap this TilemapWalker belongs to.
* @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to this.currentLayer.
* @param {number} x - X position of the top left of the area to copy (given in tiles, not pixels)
* @param {number} y - Y position of the top left of the area to copy (given in tiles, not pixels)
* @return {Phaser.Plugin.TilemapWalker}
*/
Phaser.Plugin.TilemapWalker = function (game, map, layer, x, y) {
/**
* @property {Phaser.Game} game - A reference to the currently running Game.
*/
this.game = game;
/**
* @property {Phaser.Tilemap} map - A reference to the Tilemap this TilemapWalker belongs to.
*/
this.map = map;
/**
* @property {number} locationLayer - The current layer of the location marker.
*/
this.locationLayer = map.getLayer(layer);
/**
* @property {Phaser.Point} location - The current marker location. You can move the marker with the movement methods.
*/
this.location = new Phaser.Point();
/**
* @property {number} facing - The direction the location marker is facing. You can rotate it using the turn and face methods.
* @default
*/
this.facing = Phaser.Tilemap.NORTH;
/**
* @property {boolean} collides - Does the TilemapWalker collide with the tiles in the map set for collision? If so it cannot move through them.
* @default
*/
this.collides = true;
/**
* @property {array} history - An array containing a history of movements through the map.
*/
this.history = [];
// TODO: History limit, History scan, record how many times walker has been on a tile before
if (typeof x !== 'undefined' && typeof y !== 'undefined')
{
this.setLocation(x, y);
}
return this;
};
Phaser.Plugin.TilemapWalker.prototype = {
/**
* Sets the location marker to the given x/y coordinates within the map.
* Once set you can move the marker around via the movement and turn methods.
*
* @method Phaser.Tilemap#setLocation
* @param {number} x - X position of the top left of the area to copy (given in tiles, not pixels)
* @param {number} y - Y position of the top left of the area to copy (given in tiles, not pixels)
* @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to this.currentLayer.
* @return {boolean} True if the location could be set, otherwise false.
*/
setLocation: function (x, y, layer) {
if (this.checkTile(x, y))
{
this.location.set(x, y);
this.history.push( { x: x, y: y });
return true;
}
return false;
},
/**
* Checks if the given x/y coordinate has a tile into which we can move.
*
* @method Phaser.Tilemap#checkTile
* @param {number} x - X position of the top left of the area to copy (given in tiles, not pixels)
* @param {number} y - Y position of the top left of the area to copy (given in tiles, not pixels)
* @return {boolean} True if the location can be moved into, false if not.
*/
checkTile: function (x, y) {
if (this.map.hasTile(x, y, this.locationLayer))
{
if (this.collides)
{
var tile = this.map.getTile(x, y, this.locationLayer);
if (tile && tile.collides)
{
return false;
}
}
return true;
}
return false;
},
updateLocation: function (x, y) {
if (this.checkTile(this.location.x + x, this.location.y + y, this.locationLayer))
{
this.location.set(this.location.x + x, this.location.y + y);
this.history.push( { x: x, y: y });
return true;
}
return false;
},
moveForward: function () {
if (this.facing === Phaser.Tilemap.NORTH)
{
return this.updateLocation(0, -1);
}
else if (this.facing === Phaser.Tilemap.EAST)
{
return this.updateLocation(1, 0);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
return this.updateLocation(0, 1);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
return this.updateLocation(-1, 0);
}
},
moveBackward: function () {
if (this.facing === Phaser.Tilemap.NORTH)
{
return this.updateLocation(0, 1);
}
else if (this.facing === Phaser.Tilemap.EAST)
{
return this.updateLocation(-1, 0);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
return this.updateLocation(0, -1);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
return this.updateLocation(1, 0);
}
},
moveLeft: function () {
if (this.facing === Phaser.Tilemap.NORTH)
{
return this.updateLocation(-1, 0);
}
else if (this.facing === Phaser.Tilemap.EAST)
{
return this.updateLocation(0, -1);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
return this.updateLocation(1, 0);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
return this.updateLocation(0, 1);
}
},
moveRight: function () {
if (this.facing === Phaser.Tilemap.NORTH)
{
return this.updateLocation(1, 0);
}
else if (this.facing === Phaser.Tilemap.EAST)
{
return this.updateLocation(0, 1);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
return this.updateLocation(-1, 0);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
return this.updateLocation(0, -1);
}
},
turnLeft: function () {
this.facing--;
if (this.facing === -1)
{
this.facing = 3;
}
},
turnRight: function () {
this.facing++;
if (this.facing === 4)
{
this.facing = 0;
}
},
putTile: function (index) {
this.map.putTile(index, this.location.x, this.location.y, this.locationLayer);
},
getTileFromLocation: function (x, y) {
return this.map.getTile(this.location.x + x, this.location.y + y, this.locationLayer, true);
},
getTile: function () {
return this.map.getTile(this.location.x, this.location.y, this.locationLayer, true);
},
getTiles: function (width, height, center) {
var startX;
var startX;
var endX;
var endY;
var incX;
var incY;
var hw = Math.floor(width / 2);
var hh = Math.floor(height / 2);
// For now we assume that center = bottom middle tile
if (center)
{
startX = this.location.x - hw;
endX = this.location.x + hw;
incX = 1;
startY = this.location.y - hh;
endY = this.location.y + hh;
incY = 1;
}
else
{
if (this.facing === Phaser.Tilemap.NORTH)
{
startX = this.location.x - hw;
endX = this.location.x + hw;
incX = 1;
// bottom middle align
startY = this.location.y - (height - 1);
endY = this.location.y;
incY = 1;
}
else if (this.facing === Phaser.Tilemap.EAST)
{
startX = this.location.x;
endX = this.location.x + (width - 1);
incX = 1;
// bottom middle align
startY = this.location.y - hh;
endY = this.location.y + hh;
incY = 1;
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
startX = this.location.x - hw;
endX = this.location.x + hw;
incX = 1;
// bottom middle align
startY = this.location.y;
endY = this.location.y + (height - 1);
incY = 1;
}
else if (this.facing === Phaser.Tilemap.WEST)
{
startX = this.location.x - (width - 1);
endX = this.location.x;
incX = 1;
// bottom middle align
startY = this.location.y - hh;
endY = this.location.y + hh;
incY = 1;
}
}
var output = [];
var row = [];
for (var y = startY; y <= endY; y += incY)
{
row = [];
for (var x = startX; x <= endX; x += incX)
{
var tile = this.map.getTile(x, y, this.locationLayer, true);
if (tile)
{
row.push(tile.index);
}
else
{
// out of bounds, so block it off
row.push(0);
}
}
output.push(row);
}
// console.log(printMatrix(output));
if (this.facing === Phaser.Tilemap.EAST)
{
output = rotateMatrix(output, 90);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
output = rotateMatrix(output, 180);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
output = rotateMatrix(output, -90);
}
// console.log('rotate');
// console.log(printMatrix(output));
return output;
},
getMiniMap: function (width, height) {
var startX;
var startX;
var endX;
var endY;
var diff = 0;
var hw = Math.floor(width / 2);
var hh = Math.floor(height / 2);
startX = this.location.x - hw;
endX = this.location.x + hw;
startY = this.location.y - hh;
endY = this.location.y + hh;
// Bounds
if (startX < 0)
{
endX += Math.abs(startX);
startX = 0;
}
if (endX > this.map.width)
{
diff = endX - this.map.width;
endX = this.map.width;
startX -= diff;
}
if (startY < 0)
{
endY += Math.abs(startY);
startY = 0;
}
if (endY > this.map.height)
{
diff = endY - this.map.height;
endY = this.map.height;
startY -= diff;
}
var output = [];
var row = [];
var walkerPosition = { x: 0, y: 0 };
for (var y = startY; y < endY; y++)
{
row = [];
for (var x = startX; x < endX; x++)
{
// Walker?
if (x === this.location.x && y === this.location.y)
{
walkerPosition.x = row.length;
walkerPosition.y = output.length;
}
var tile = this.map.getTile(x, y, this.locationLayer, true);
if (tile)
{
row.push(tile.index);
}
else
{
// out of bounds, so block it off
row.push(0);
}
}
output.push(row);
}
// console.log(printMatrix(output));
return { walker: walkerPosition, tiles: output };
},
getTileAhead: function (distance) {
if (typeof distance === 'undefined') { distance = 1; }
if (this.facing === Phaser.Tilemap.NORTH)
{
return this.getTileFromLocation(0, -distance);
}
else if (this.facing === Phaser.Tilemap.EAST)
{
return this.getTileFromLocation(distance, 0);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
return this.getTileFromLocation(0, distance);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
return this.getTileFromLocation(-distance, 0);
}
},
getTileAheadLeft: function (distance) {
if (typeof distance === 'undefined') { distance = 1; }
if (this.facing === Phaser.Tilemap.NORTH)
{
return this.getTileFromLocation(-distance, -distance);
}
else if (this.facing === Phaser.Tilemap.EAST)
{
return this.getTileFromLocation(distance, -distance);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
return this.getTileFromLocation(distance, distance);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
return this.getTileFromLocation(-distance, distance);
}
},
getTileAheadRight: function (distance) {
if (typeof distance === 'undefined') { distance = 1; }
if (this.facing === Phaser.Tilemap.NORTH)
{
return this.getTileFromLocation(distance, -distance);
}
else if (this.facing === Phaser.Tilemap.EAST)
{
return this.getTileFromLocation(distance, distance);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
return this.getTileFromLocation(-distance, distance);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
return this.getTileFromLocation(-distance, -distance);
}
},
getTileBehind: function (distance) {
if (typeof distance === 'undefined') { distance = 1; }
if (this.facing === Phaser.Tilemap.NORTH)
{
return this.getTileFromLocation(0, distance);
}
else if (this.facing === Phaser.Tilemap.EAST)
{
return this.getTileFromLocation(-distance, 0);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
return this.getTileFromLocation(0, -distance);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
return this.getTileFromLocation(distance, 0);
}
},
getTileBehindLeft: function (distance) {
if (typeof distance === 'undefined') { distance = 1; }
if (this.facing === Phaser.Tilemap.NORTH)
{
return this.getTileFromLocation(-distance, distance);
}
else if (this.facing === Phaser.Tilemap.EAST)
{
return this.getTileFromLocation(-distance, -distance);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
return this.getTileFromLocation(distance, -distance);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
return this.getTileFromLocation(distance, distance);
}
},
getTileBehindRight: function (distance) {
if (typeof distance === 'undefined') { distance = 1; }
if (this.facing === Phaser.Tilemap.NORTH)
{
return this.getTileFromLocation(distance, distance);
}
else if (this.facing === Phaser.Tilemap.EAST)
{
return this.getTileFromLocation(-distance, distance);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
return this.getTileFromLocation(-distance, -distance);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
return this.getTileFromLocation(distance, -distance);
}
},
getTileLeft: function (distance) {
if (typeof distance === 'undefined') { distance = 1; }
if (this.facing === Phaser.Tilemap.NORTH)
{
return this.getTileFromLocation(-distance, 0);
}
else if (this.facing === Phaser.Tilemap.EAST)
{
return this.getTileFromLocation(0, -distance);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
return this.getTileFromLocation(distance, 0);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
return this.getTileFromLocation(0, distance);
}
},
getTileRight: function (distance) {
if (typeof distance === 'undefined') { distance = 1; }
if (this.facing === Phaser.Tilemap.NORTH)
{
return this.getTileFromLocation(distance, 0);
}
else if (this.facing === Phaser.Tilemap.EAST)
{
return this.getTileFromLocation(0, distance);
}
else if (this.facing === Phaser.Tilemap.SOUTH)
{
return this.getTileFromLocation(-distance, 0);
}
else if (this.facing === Phaser.Tilemap.WEST)
{
return this.getTileFromLocation(0, -distance);
}
}
};
// Original from http://jsfiddle.net/MrPolywhirl/NH42z/ - tided up and de-globalised by Richard Davey
var rotateMatrix = function (matrix, direction) {
direction = ((direction % 360) + 360) % 360;
var ret = matrix;
var transpose = function (m) {
var result = new Array(m[0].length);
for (var i = 0; i < m[0].length; i++) {
result[i] = new Array(m.length - 1);
for (var j = m.length - 1; j > -1; j--) {
result[i][j] = m[j][i];
}
}
return result;
};
var reverseRows = function (m) {
return m.reverse();
};
var reverseCols = function (m) {
for (var i = 0; i < m.length; i++) {
m[i].reverse();
}
return m;
};
var rotate90Left = function (m) {
m = transpose(m);
m = reverseRows(m);
return m;
};
var rotate90Right = function (m) {
m = reverseRows(m);
m = transpose(m);
return m;
};
var rotate180 = function (m) {
m = reverseCols(m);
m = reverseRows(m);
return m;
};
if (direction == 90 || direction == -270) {
return rotate90Left(ret);
} else if (direction == -90 || direction == 270) {
return rotate90Right(ret);
} else if (Math.abs(direction) == 180) {
return rotate180(ret);
}
return matrix;
};
var pad = function (val, amt, ch) {
ch = typeof ch !== 'undefined' ? ch : ' ';
var str = val
var max = Math.abs(amt);
while (str.length < max) {
if (amt < 0) {
str += ch;
} else {
str = ch + str;
}
}
return str;
};
var printMatrix = function (matrix) {
var str = '';
for (var r = 0; r < matrix.length; r++) {
for (var c = 0; c < matrix[r].length; c++) {
var cell = matrix[r][c].toString();
if (cell != 'undefined') {
str += pad(cell, 2);
} else {
str += '?';
}
if (c < matrix[r].length - 1) {
str += ' |';
}
}
if (r < matrix.length - 1) {
str += '\n';
for (var i = 0; i < matrix[r].length; i++) {
str += '---'
if (i < matrix[r].length - 1) {
str += '+';
}
}
str += '\n';
}
}
return str;
};