/** * @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; };