Source: map/map-tilemap-methods.js

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