Source: ray/overlap.js

/**
 * Get game objects overlaping field of view.
 *
 * @method Raycaster.Ray#overlap
 * @memberof Raycaster.Ray
 * @instance
 * @since 0.8.0
 *
 * @param {object|object[]} [objects] - Game object / array off game objects to test.
 *
 * @return {object[]} Array of game objects that overlaps with field of view.
 */
export function overlap(objects) {
    let targets = [];
    let overlapCircle = new Phaser.Geom.Circle(this.origin.x, this.origin.y, this.collisionRange);

    //matter physics
    if(this.bodyType === 'matter') {
        let isCollisionInfo = false;
        if(objects === undefined) {
            objects = this._raycaster.scene.matter.query.collides(this.body, this._raycaster.scene.matter.getMatterBodies());

            for(let object of objects) {   
                let body = object.bodyA === this.body ? object.bodyB : object.bodyA;

                if(this.testMatterOverlap(body))
                    targets.push(body);
            }
        }
        //get object's body
        else {
            if(!Array.isArray(objects))
                objects = [objects];
            
            for(let object of objects) {
                if(object === this.body)
                    continue;
    
                if(this.testMatterOverlap(object))
                    targets.push(object);
            }
        }
    }
    //arcade physics
    else {
        let bodies = false;
        //get bodies in range
        if(objects === undefined) {
            objects = this._raycaster.scene.physics.overlapCirc(this.origin.x, this.origin.y, this.collisionRange, true, true);
            bodies = true;
        }
        //get object's body
        else if(!Array.isArray(objects)) {
            objects = [objects];
        }
        //if objects are bodies
        if(bodies) {
            for(let body of objects) {
                if(body === this.body)
                    continue;
            
                let hitbox;
                //get physics body hitbox
                if(body.isCircle) {
                    hitbox = new Phaser.Geom.Circle(body.position.x + body.halfWidth, body.position.y + body.halfWidth, body.halfWidth);
                }
                else {
                    hitbox = new Phaser.Geom.Rectangle(body.x, body.y, body.width, body.height);
                }

                if(this.testArcadeOverlap(hitbox))
                    targets.push(body.gameObject);
            }
        }
        //if objects are game objects
        else {
            for(let object of objects) {
                if(object.body === undefined)
                    continue;

                let hitbox;
                //get physics body hitbox
                if(object.body.isCircle) {
                    hitbox = new Phaser.Geom.Circle(object.body.position.x + object.body.halfWidth, object.body.position.y + object.body.halfWidth, object.body.halfWidth);
                    if(!Phaser.Geom.Intersects.CircleToCircle(overlapCircle, hitbox))
                        continue;
                }
                else {
                    hitbox = new Phaser.Geom.Rectangle(object.body.x, object.body.y, object.body.width, object.body.height);
                    if(!Phaser.Geom.Intersects.CircleToRectangle(overlapCircle, hitbox))
                        continue;
                }

                if(this.testArcadeOverlap(hitbox))
                    targets.push(object);
            }
        }
    }

    return targets;
}

/**
 * Process callback for physics collider / overlap.
 *
 * @method Raycaster.Ray#processOverlap
 * @memberof Raycaster.Ray
 * @instance
 * @since 0.8.0
 *
 * @param {object} object1 - Game object or matter body passed by collider / overlap or matter CollisionInfo object.
 * @param {object} object2 - Game object or matter body passed by collider / overlap. Ignored if matter CollisionInfo object was passed as first argument.
 *
 * @return {boolean} Return true if game object is overlapping ray's field of view.
 */
export function processOverlap(object1, object2) {
    let obj1, obj2, target;
    //check if it's matter collisionInfo object
    if(object1.bodyA !== undefined && object1.bodyB !== undefined) {
        obj1 = object1.bodyA;
        obj2 = object1.bodyB;
    }
    else {
        obj1 = object1;
        obj2 = object2;
    }

    if(obj1._ray !== undefined && obj1._ray === this)
        target = obj2;
    else if(obj2._ray !== undefined && obj2._ray === this)
        target = obj1;
    else
        return false;

    return (this.overlap(target).length > 0);
}   

/**
 * Test if hitbox overlaps with field of view. Method used in {@link Raycaster.Ray#overlap Ray.overlap}.
 *
 * @method Raycaster.Ray#testArcadeOverlap
 * @memberof Raycaster.Ray
 * @instance
 * @private
 * @since 0.8.0
 *
 * @param {object} hitbox - Game object's hitbox generated inside {@link Raycaster.Ray#overlap Ray.overlap}.
 *
 * @return {boolean} True if hitbox overlaps with {@link Raycaster.Ray Raycaster.Ray} field of view.
 */
export function testArcadeOverlap(hitbox) {
    let overlap = false;

    //iterate through field of view slices to check collisions with target
    for(let slice of this.slicedIntersections) {
        //if hitbox is a circle
        if(hitbox.type == 0) {
            overlap = Phaser.Geom.Intersects.TriangleToCircle(slice, hitbox);
        }
        //if hitbox is a rectangle
        else {
            overlap = Phaser.Geom.Intersects.RectangleToTriangle(hitbox, slice);
        }

        if(overlap) {
            return true;
        }
    }

    return false;
}

/**
 * Test if matter body overlaps with field of view. Method used in {@link Raycaster.Ray#overlap Ray.overlap}.
 *
 * @method Raycaster.Ray#testMatterOverlap
 * @memberof Raycaster.Ray
 * @instance
 * @private
 * @since 0.9.0
 *
 * @param {object} body - Matter body.
 *
 * @return {boolean} True if body overlaps with {@link Raycaster.Ray Raycaster.Ray} field of view.
 */
export function testMatterOverlap(object) {
    let body;

    if(object.type === 'body')
        body = object;
    else if(object.body !== undefined)
        body = object.body;
    else
        return false;

    //if body is concave, ignore convex body
    let parts = body.parts.length > 1 ? body.parts.splice(1) : body.parts;
    //iterate through bodies
    for(let part of parts) {
        let pointA = part.vertices[0];

        for(let i = 1, length = part.vertices.length; i < length; i++) {
            let pointB = part.vertices[i];
            let segment = new Phaser.Geom.Line(pointA.x, pointA.y, pointB.x, pointB.y);

            //iterate through field of view slices to check collisions with target
            for(let slice of this.slicedIntersections) {
                let overlap = Phaser.Geom.Intersects.TriangleToLine(slice, segment);
                //additional checking if slice contain segment's points due to TriangleToLine bug.
                if(!overlap)
                    overlap = Phaser.Geom.Triangle.ContainsPoint(slice, segment.getPointA());
                if(!overlap)
                    overlap = Phaser.Geom.Triangle.ContainsPoint(slice, segment.getPointB());

                if(overlap) {
                    return true;
                }
            }
            pointA = pointB;
        }

        //closing segment
        let segment = new Phaser.Geom.Line(part.vertices[part.vertices.length - 1].x, part.vertices[part.vertices.length - 1].y, part.vertices[0].x, part.vertices[0].y);
         //iterate through field of view slices to check collisions with target
        for(let slice of this.slicedIntersections) {
            let overlap = Phaser.Geom.Intersects.TriangleToLine(slice, segment);

            if(overlap) {
                return true;
            }
        }
    }

    return false;
}