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