/*Map methods for tilemaps*/
/**
* Get array of mapped tilemap's vertices used as rays targets.
*
* @method Raycaster.Map#tilemap.getPoints
* @memberof Raycaster.Map
* @instance
* @private
* @since 0.7.3
*
* @param {Raycaster.Ray} [ray] - {Raycaster.Ray} object used in some some types of maps.
*
* @return {Phaser.Geom.Point[]} - Array of mapped object's vertices.
*/
export function getPoints(ray = false) {
if(!this.active)
return [];
if(!ray || ray && (ray.detectionRange == 0 || ray.detectionRange >= Phaser.Math.MAX_SAFE_INTEGER))
return this._points;
let points = [];
for(let point of this._points) {
if(Phaser.Math.Distance.Between(ray.origin.x, ray.origin.y, point.x, point.y) <= ray.detectionRange)
points.push(point);
}
//get intersections between tilemap's segments and ray's detection range edge
let segments = this.getSegments(ray);
for(let segment of segments) {
if(Phaser.Math.Distance.Between(ray.origin.x, ray.origin.y, segment.x1, segment.y1) > ray.detectionRange)
points.push(new Phaser.Geom.Point(segment.x1, segment.y1));
if(Phaser.Math.Distance.Between(ray.origin.x, ray.origin.y, segment.x2, segment.y2) > ray.detectionRange)
points.push(new Phaser.Geom.Point(segment.x2, segment.y2));
}
return points;
};
/**
* Get array of mapped tilemap's segments used to test object's intersection with ray.
*
* @method Raycaster.Map#tilemap.getSegments
* @memberof Raycaster.Map
* @instance
* @private
* @since 0.7.3
*
* @param {Raycaster.Ray} [ray] - {Raycaster.Ray} object used in some some types of maps.
*
* @return {Phaser.Geom.Line[]} - Array of mapped object's segments.
*/
export function getSegments(ray = false) {
if(!this.active)
return [];
if(!ray || (ray && (ray.detectionRange == 0 || ray.detectionRange >= Phaser.Math.MAX_SAFE_INTEGER)))
return this._segments;
let segments = [];
for(let segment of this._segments) {
if(Phaser.Geom.Intersects.LineToCircle(segment, ray.detectionRangeCircle)) {
segments.push(segment);
}
}
return segments;
};
/**
* Update tilemap's map of points and segments.
*
* @method Raycaster.Map#tilemap.updateMap
* @memberof Raycaster.Map
* @instance
* @private
* @since 0.7.3
*
* @return {Raycaster.Map} {@link Raycaster.Map Raycaster.Map} instance
*/
export function updateMap() {
if(!this.active)
return this;
let points = [],
segments = [],
columns = Array(this.object.layer.data[0].length + 1);
for(let i = 0, iLength = columns.length; i < iLength; i++) {
columns[i] = [];
}
//calculate offset based on object position and origin point
let offset = new Phaser.Geom.Point(this.object.x, this.object.y);
let row = this.object.layer.data[0],
tileWidth = this.object.layer.tileWidth * this.object.scaleX,
tileHeight = this.object.layer.tileHeight * this.object.scaleY,
startPoint,
endPoint;
//set top horizontal lines
if(this.collisionTiles.includes(row[0].index)) {
startPoint = new Phaser.Geom.Point(offset.x, offset.y);
endPoint = new Phaser.Geom.Point(tileWidth + offset.x, offset.y);
columns[0].push(startPoint);
}
for(let i = 1, iLength = row.length; i < iLength; i++) {
let tile = row[i];
if(!this.collisionTiles.includes(tile.index)) {
if(startPoint) {
startPoint.neighbours = [endPoint];
endPoint.neighbours = [startPoint];
points.push(startPoint, endPoint);
segments.push(new Phaser.Geom.Line(startPoint.x, startPoint.y, endPoint.x, endPoint.y));
columns[i].push(endPoint);
startPoint = false;
endPoint = false;
}
continue;
}
let x = i * tileWidth + offset.x,
y = offset.y;
if(!startPoint) {
startPoint = new Phaser.Geom.Point(x, y);
columns[i].push(startPoint);
}
if(!endPoint) {
endPoint = new Phaser.Geom.Point(x + tileWidth, y);
}
else {
endPoint.x = x + tileWidth;
}
}
if(startPoint) {
startPoint.neighbours = [endPoint];
endPoint.neighbours = [startPoint];
points.push(startPoint, endPoint);
segments.push(new Phaser.Geom.Line(startPoint.x, startPoint.y, endPoint.x, endPoint.y));
columns[row.length].push(endPoint);
}
startPoint = false;
endPoint = false;
for(let i = 1, iLength = this.object.layer.data.length; i < iLength; i++) {
row = this.object.layer.data[i];
let higherRow = this.object.layer.data[i - 1];
if(this.collisionTiles.includes(row[0].index) != this.collisionTiles.includes(higherRow[0].index)) {
startPoint = new Phaser.Geom.Point(offset.x, i * tileHeight + offset.y);
endPoint = new Phaser.Geom.Point(tileWidth + offset.x, i * tileHeight + offset.y);
columns[0].push(startPoint);
}
for(let j = 1, jLength = row.length; j < jLength; j++) {
let tile = row[j],
isCollisionTile = this.collisionTiles.includes(tile.index),
isCollisionHigherTile = this.collisionTiles.includes(higherRow[j].index);
if(isCollisionTile == isCollisionHigherTile) {
if(startPoint) {
startPoint.neighbours = [endPoint];
endPoint.neighbours = [startPoint];
points.push(startPoint, endPoint);
segments.push(new Phaser.Geom.Line(startPoint.x, startPoint.y, endPoint.x, endPoint.y));
columns[j].push(endPoint);
startPoint = false;
endPoint = false;
}
continue;
}
let x = j * tileWidth + offset.x,
y = i * tileHeight + offset.y;
if(!startPoint) {
startPoint = new Phaser.Geom.Point(x, y);
columns[j].push(startPoint);
}
if(!endPoint) {
endPoint = new Phaser.Geom.Point(x + tileWidth, y);
}
else {
endPoint.x = x + tileWidth;
}
}
if(startPoint) {
startPoint.neighbours = [endPoint];
endPoint.neighbours = [startPoint];
points.push(startPoint, endPoint);
segments.push(new Phaser.Geom.Line(startPoint.x, startPoint.y, endPoint.x, endPoint.y));
columns[row.length].push(endPoint);
}
startPoint = false;
endPoint = false;
}
//set bottom horizontal lines
row = this.object.layer.data.slice(-1)[0];
let y = this.object.layer.data.length * tileHeight + offset.y;
if(this.collisionTiles.includes(row[0].index)) {
startPoint = new Phaser.Geom.Point(offset.x, y);
endPoint = new Phaser.Geom.Point(tileWidth + offset.x, y);
columns[0].push(startPoint);
}
for(let i = 1, iLength = row.length; i < iLength; i++) {
let tile = row[i];
if(!this.collisionTiles.includes(tile.index)) {
if(startPoint) {
startPoint.neighbours = [endPoint];
endPoint.neighbours = [startPoint];
points.push(startPoint, endPoint);
segments.push(new Phaser.Geom.Line(startPoint.x, startPoint.y, endPoint.x, endPoint.y));
columns[i].push(endPoint);
startPoint = false;
endPoint = false;
}
continue;
}
let x = i * tileWidth + offset.x;
if(!startPoint) {
startPoint = new Phaser.Geom.Point(x, y);
columns[i].push(startPoint);
}
if(!endPoint) {
endPoint = new Phaser.Geom.Point(x + tileWidth, y);
}
else {
endPoint.x = x + tileWidth;
}
}
if(startPoint) {
startPoint.neighbours = [endPoint];
endPoint.neighbours = [startPoint];
points.push(startPoint, endPoint);
segments.push(new Phaser.Geom.Line(startPoint.x, startPoint.y, endPoint.x, endPoint.y));
columns[row.length].push(endPoint);
}
//set vertical lines
for(let i = 0, iLength = columns.length; i < iLength; i++) {
const column = columns[i];
for(let j = 0, jLength = column.length - 1; j < jLength; j++) {
segments.push(new Phaser.Geom.Line(column[j].x, column[j].y, column[j+1].x, column[j+1].y));
column[j].neighbours.push(column[j+1]);
column[j+1].neighbours.push(column[j]);
j++;
}
}
this._points = points;
this._segments = segments;
return this;
};
/**
* Set tile types which should be mapped (for Phaser.Tilemaps.StaticTilemapLayer and Phaser.Tilemaps.DynamicTilemapLayer maps only).
*
* @method Raycaster.Map#setCollisionTiles
* @memberof Raycaster.Map
* @instance
* @since 0.7.3
*
* @param {array} [tiles = []] - Set of tile's indexes to map.
*
* @return {Raycaster.Map} {@link Raycaster.Map Raycaster.Map} instance
*/
export function setCollisionTiles(tiles = []) {
this.collisionTiles = tiles;
return this;
}