mirror of
https://github.com/liabru/matter-js.git
synced 2024-12-26 13:49:01 -05:00
added broadphase to Matter.Detector
This commit is contained in:
parent
b9e7d9dd8b
commit
a6b5e7d849
2 changed files with 193 additions and 110 deletions
|
@ -1,58 +1,106 @@
|
||||||
/**
|
/**
|
||||||
* The `Matter.Detector` module contains methods for detecting collisions given a set of pairs.
|
* The `Matter.Detector` module contains methods for efficiently detecting collisions between a list of bodies using a broadphase algorithm.
|
||||||
*
|
*
|
||||||
* @class Detector
|
* @class Detector
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: speculative contacts
|
|
||||||
|
|
||||||
var Detector = {};
|
var Detector = {};
|
||||||
|
|
||||||
module.exports = Detector;
|
module.exports = Detector;
|
||||||
|
|
||||||
var SAT = require('./SAT');
|
var Common = require('../core/Common');
|
||||||
var Pair = require('./Pair');
|
var Collision = require('./Collision');
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds all collisions given a list of pairs.
|
* Creates a new collision detector.
|
||||||
* @method collisions
|
* @method create
|
||||||
* @param {pair[]} broadphasePairs
|
* @param {} options
|
||||||
* @param {engine} engine
|
* @return {detector} A new collision detector
|
||||||
* @return {array} collisions
|
|
||||||
*/
|
*/
|
||||||
Detector.collisions = function(broadphasePairs, engine) {
|
Detector.create = function(options) {
|
||||||
|
var defaults = {
|
||||||
|
bodies: [],
|
||||||
|
pairs: null
|
||||||
|
};
|
||||||
|
|
||||||
|
return Common.extend(defaults, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the list of bodies in the detector.
|
||||||
|
* @method setBodies
|
||||||
|
* @param {detector} detector
|
||||||
|
* @param {body[]} bodies
|
||||||
|
*/
|
||||||
|
Detector.setBodies = function(detector, bodies) {
|
||||||
|
detector.bodies = bodies.slice(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the detector including its list of bodies.
|
||||||
|
* @method clear
|
||||||
|
* @param {detector} detector
|
||||||
|
*/
|
||||||
|
Detector.clear = function(detector) {
|
||||||
|
detector.bodies = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Efficiently finds all collisions among all the bodies in `detector.bodies` using a broadphase algorithm.
|
||||||
|
*
|
||||||
|
* _Note:_ The specific ordering of collisions returned is not guaranteed between releases and may change for performance reasons.
|
||||||
|
* If a specific ordering is required then apply a sort to the resulting array.
|
||||||
|
* @method collisions
|
||||||
|
* @param {detector} detector
|
||||||
|
* @return {collision[]} collisions
|
||||||
|
*/
|
||||||
|
Detector.collisions = function(detector) {
|
||||||
var collisions = [],
|
var collisions = [],
|
||||||
pairs = engine.pairs,
|
pairs = detector.pairs,
|
||||||
broadphasePairsLength = broadphasePairs.length,
|
bodies = detector.bodies,
|
||||||
|
bodiesLength = bodies.length,
|
||||||
canCollide = Detector.canCollide,
|
canCollide = Detector.canCollide,
|
||||||
collides = SAT.collides,
|
collides = Collision.collides,
|
||||||
i;
|
i,
|
||||||
|
j;
|
||||||
|
|
||||||
for (i = 0; i < broadphasePairsLength; i++) {
|
bodies.sort(Detector._compareBoundsX);
|
||||||
var broadphasePair = broadphasePairs[i],
|
|
||||||
bodyA = broadphasePair[0],
|
|
||||||
bodyB = broadphasePair[1];
|
|
||||||
|
|
||||||
if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping))
|
for (i = 0; i < bodiesLength; i++) {
|
||||||
continue;
|
var bodyA = bodies[i],
|
||||||
|
boundsA = bodyA.bounds,
|
||||||
|
boundXMax = bodyA.bounds.max.x,
|
||||||
|
boundYMax = bodyA.bounds.max.y,
|
||||||
|
boundYMin = bodyA.bounds.min.y,
|
||||||
|
bodyAStatic = bodyA.isStatic || bodyA.isSleeping,
|
||||||
|
partsALength = bodyA.parts.length,
|
||||||
|
partsASingle = partsALength === 1;
|
||||||
|
|
||||||
if (!canCollide(bodyA.collisionFilter, bodyB.collisionFilter))
|
for (j = i + 1; j < bodiesLength; j++) {
|
||||||
continue;
|
var bodyB = bodies[j],
|
||||||
|
|
||||||
var boundsA = bodyA.bounds,
|
|
||||||
boundsB = bodyB.bounds;
|
boundsB = bodyB.bounds;
|
||||||
|
|
||||||
if (boundsA.min.x > boundsB.max.x || boundsA.max.x < boundsB.min.x
|
if (boundsB.min.x > boundXMax) {
|
||||||
|| boundsA.max.y < boundsB.min.y || boundsA.min.y > boundsB.max.y) {
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boundYMax < boundsB.min.y || boundYMin > boundsB.max.y) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var partsALength = bodyA.parts.length,
|
if (bodyAStatic && (bodyB.isStatic || bodyB.isSleeping)) {
|
||||||
partsBLength = bodyB.parts.length;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (partsALength === 1 && partsBLength === 1) {
|
if (!canCollide(bodyA.collisionFilter, bodyB.collisionFilter)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var partsBLength = bodyB.parts.length;
|
||||||
|
|
||||||
|
if (partsASingle && partsBLength === 1) {
|
||||||
var collision = collides(bodyA, bodyB, pairs);
|
var collision = collides(bodyA, bodyB, pairs);
|
||||||
|
|
||||||
if (collision) {
|
if (collision) {
|
||||||
|
@ -62,12 +110,12 @@ var Pair = require('./Pair');
|
||||||
var partsAStart = partsALength > 1 ? 1 : 0,
|
var partsAStart = partsALength > 1 ? 1 : 0,
|
||||||
partsBStart = partsBLength > 1 ? 1 : 0;
|
partsBStart = partsBLength > 1 ? 1 : 0;
|
||||||
|
|
||||||
for (var j = partsAStart; j < partsALength; j++) {
|
for (var k = partsAStart; k < partsALength; k++) {
|
||||||
var partA = bodyA.parts[j],
|
var partA = bodyA.parts[k],
|
||||||
boundsA = partA.bounds;
|
boundsA = partA.bounds;
|
||||||
|
|
||||||
for (var k = partsBStart; k < partsBLength; k++) {
|
for (var z = partsBStart; z < partsBLength; z++) {
|
||||||
var partB = bodyB.parts[k],
|
var partB = bodyB.parts[z],
|
||||||
boundsB = partB.bounds;
|
boundsB = partB.bounds;
|
||||||
|
|
||||||
if (boundsA.min.x > boundsB.max.x || boundsA.max.x < boundsB.min.x
|
if (boundsA.min.x > boundsB.max.x || boundsA.max.x < boundsB.min.x
|
||||||
|
@ -84,6 +132,7 @@ var Pair = require('./Pair');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return collisions;
|
return collisions;
|
||||||
};
|
};
|
||||||
|
@ -103,4 +152,39 @@ var Pair = require('./Pair');
|
||||||
return (filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0;
|
return (filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The comparison function used in the broadphase algorithm.
|
||||||
|
* Returns the signed delta of the bodies bounds on the x-axis.
|
||||||
|
* @private
|
||||||
|
* @method _sortCompare
|
||||||
|
* @param {body} bodyA
|
||||||
|
* @param {body} bodyB
|
||||||
|
* @return {number} The signed delta used for sorting
|
||||||
|
*/
|
||||||
|
Detector._compareBoundsX = function(bodyA, bodyB) {
|
||||||
|
return bodyA.bounds.min.x - bodyB.bounds.min.x;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Properties Documentation
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The array of `Matter.Body` between which the detector finds collisions.
|
||||||
|
*
|
||||||
|
* _Note:_ The order of bodies in this array _is not fixed_ and will be continually managed by the detector.
|
||||||
|
* @property bodies
|
||||||
|
* @type body[]
|
||||||
|
* @default []
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional. A `Matter.Pairs` object from which previous collision objects may be reused. Intended for internal `Matter.Engine` usage.
|
||||||
|
* @property pairs
|
||||||
|
* @type {pairs|null}
|
||||||
|
* @default null
|
||||||
|
*/
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -16,7 +16,6 @@ var Sleeping = require('./Sleeping');
|
||||||
var Resolver = require('../collision/Resolver');
|
var Resolver = require('../collision/Resolver');
|
||||||
var Detector = require('../collision/Detector');
|
var Detector = require('../collision/Detector');
|
||||||
var Pairs = require('../collision/Pairs');
|
var Pairs = require('../collision/Pairs');
|
||||||
var Grid = require('../collision/Grid');
|
|
||||||
var Events = require('./Events');
|
var Events = require('./Events');
|
||||||
var Composite = require('../body/Composite');
|
var Composite = require('../body/Composite');
|
||||||
var Constraint = require('../constraint/Constraint');
|
var Constraint = require('../constraint/Constraint');
|
||||||
|
@ -43,7 +42,6 @@ var Body = require('../body/Body');
|
||||||
enableSleeping: false,
|
enableSleeping: false,
|
||||||
events: [],
|
events: [],
|
||||||
plugin: {},
|
plugin: {},
|
||||||
grid: null,
|
|
||||||
gravity: {
|
gravity: {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 1,
|
y: 1,
|
||||||
|
@ -60,10 +58,11 @@ var Body = require('../body/Body');
|
||||||
var engine = Common.extend(defaults, options);
|
var engine = Common.extend(defaults, options);
|
||||||
|
|
||||||
engine.world = options.world || Composite.create({ label: 'World' });
|
engine.world = options.world || Composite.create({ label: 'World' });
|
||||||
engine.grid = Grid.create(options.grid || options.broadphase);
|
engine.pairs = options.pairs || Pairs.create();
|
||||||
engine.pairs = Pairs.create();
|
engine.detector = options.detector || Detector.create();
|
||||||
|
|
||||||
// temporary back compatibility
|
// for temporary back compatibility only
|
||||||
|
engine.grid = { buckets: [] };
|
||||||
engine.world.gravity = engine.gravity;
|
engine.world.gravity = engine.gravity;
|
||||||
engine.broadphase = engine.grid;
|
engine.broadphase = engine.grid;
|
||||||
engine.metrics = {};
|
engine.metrics = {};
|
||||||
|
@ -93,9 +92,10 @@ var Body = require('../body/Body');
|
||||||
correction = correction || 1;
|
correction = correction || 1;
|
||||||
|
|
||||||
var world = engine.world,
|
var world = engine.world,
|
||||||
|
detector = engine.detector,
|
||||||
|
pairs = engine.pairs,
|
||||||
timing = engine.timing,
|
timing = engine.timing,
|
||||||
grid = engine.grid,
|
timestamp = timing.timestamp,
|
||||||
gridPairs = [],
|
|
||||||
i;
|
i;
|
||||||
|
|
||||||
// increment timestamp
|
// increment timestamp
|
||||||
|
@ -109,15 +109,25 @@ var Body = require('../body/Body');
|
||||||
|
|
||||||
Events.trigger(engine, 'beforeUpdate', event);
|
Events.trigger(engine, 'beforeUpdate', event);
|
||||||
|
|
||||||
// get lists of all bodies and constraints, no matter what composites they are in
|
// get all bodies and all constraints in the world
|
||||||
var allBodies = Composite.allBodies(world),
|
var allBodies = Composite.allBodies(world),
|
||||||
allConstraints = Composite.allConstraints(world);
|
allConstraints = Composite.allConstraints(world);
|
||||||
|
|
||||||
// if sleeping enabled, call the sleeping controller
|
// update the detector bodies if they have changed
|
||||||
|
if (world.isModified) {
|
||||||
|
Detector.setBodies(detector, allBodies);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset all composite modified flags
|
||||||
|
if (world.isModified) {
|
||||||
|
Composite.setModified(world, false, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update sleeping if enabled
|
||||||
if (engine.enableSleeping)
|
if (engine.enableSleeping)
|
||||||
Sleeping.update(allBodies, timing.timeScale);
|
Sleeping.update(allBodies, timing.timeScale);
|
||||||
|
|
||||||
// applies gravity to all bodies
|
// apply gravity to all bodies
|
||||||
Engine._bodiesApplyGravity(allBodies, engine.gravity);
|
Engine._bodiesApplyGravity(allBodies, engine.gravity);
|
||||||
|
|
||||||
// update all body position and rotation by integration
|
// update all body position and rotation by integration
|
||||||
|
@ -130,27 +140,11 @@ var Body = require('../body/Body');
|
||||||
}
|
}
|
||||||
Constraint.postSolveAll(allBodies);
|
Constraint.postSolveAll(allBodies);
|
||||||
|
|
||||||
// broadphase pass: find potential collision pairs
|
// find all collisions
|
||||||
|
detector.pairs = engine.pairs;
|
||||||
// if world is dirty, we must flush the whole grid
|
var collisions = Detector.collisions(detector);
|
||||||
if (world.isModified)
|
|
||||||
Grid.clear(grid);
|
|
||||||
|
|
||||||
// update the grid buckets based on current bodies
|
|
||||||
Grid.update(grid, allBodies, engine, world.isModified);
|
|
||||||
gridPairs = grid.pairsList;
|
|
||||||
|
|
||||||
// clear all composite modified flags
|
|
||||||
if (world.isModified) {
|
|
||||||
Composite.setModified(world, false, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// narrowphase pass: find actual collisions, then create or update collision pairs
|
|
||||||
var collisions = Detector.collisions(gridPairs, engine);
|
|
||||||
|
|
||||||
// update collision pairs
|
// update collision pairs
|
||||||
var pairs = engine.pairs,
|
|
||||||
timestamp = timing.timestamp;
|
|
||||||
Pairs.update(pairs, collisions, timestamp);
|
Pairs.update(pairs, collisions, timestamp);
|
||||||
|
|
||||||
// wake up bodies involved in collisions
|
// wake up bodies involved in collisions
|
||||||
|
@ -224,17 +218,13 @@ var Body = require('../body/Body');
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the engine including the world, pairs and broadphase.
|
* Clears the engine pairs and detector.
|
||||||
* @method clear
|
* @method clear
|
||||||
* @param {engine} engine
|
* @param {engine} engine
|
||||||
*/
|
*/
|
||||||
Engine.clear = function(engine) {
|
Engine.clear = function(engine) {
|
||||||
var world = engine.world,
|
|
||||||
bodies = Composite.allBodies(world);
|
|
||||||
|
|
||||||
Pairs.clear(engine.pairs);
|
Pairs.clear(engine.pairs);
|
||||||
Grid.clear(engine.grid);
|
Detector.clear(engine.detector);
|
||||||
Grid.update(engine.grid, bodies, engine, true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -314,53 +304,53 @@ var Body = require('../body/Body');
|
||||||
* Fired just before an update
|
* Fired just before an update
|
||||||
*
|
*
|
||||||
* @event beforeUpdate
|
* @event beforeUpdate
|
||||||
* @param {} event An event object
|
* @param {object} event An event object
|
||||||
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
||||||
* @param {} event.source The source object of the event
|
* @param {engine} event.source The source object of the event
|
||||||
* @param {} event.name The name of the event
|
* @param {string} event.name The name of the event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fired after engine update and all collision events
|
* Fired after engine update and all collision events
|
||||||
*
|
*
|
||||||
* @event afterUpdate
|
* @event afterUpdate
|
||||||
* @param {} event An event object
|
* @param {object} event An event object
|
||||||
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
||||||
* @param {} event.source The source object of the event
|
* @param {engine} event.source The source object of the event
|
||||||
* @param {} event.name The name of the event
|
* @param {string} event.name The name of the event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any)
|
* Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any)
|
||||||
*
|
*
|
||||||
* @event collisionStart
|
* @event collisionStart
|
||||||
* @param {} event An event object
|
* @param {object} event An event object
|
||||||
* @param {} event.pairs List of affected pairs
|
* @param {pair[]} event.pairs List of affected pairs
|
||||||
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
||||||
* @param {} event.source The source object of the event
|
* @param {engine} event.source The source object of the event
|
||||||
* @param {} event.name The name of the event
|
* @param {string} event.name The name of the event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any)
|
* Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any)
|
||||||
*
|
*
|
||||||
* @event collisionActive
|
* @event collisionActive
|
||||||
* @param {} event An event object
|
* @param {object} event An event object
|
||||||
* @param {} event.pairs List of affected pairs
|
* @param {pair[]} event.pairs List of affected pairs
|
||||||
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
||||||
* @param {} event.source The source object of the event
|
* @param {engine} event.source The source object of the event
|
||||||
* @param {} event.name The name of the event
|
* @param {string} event.name The name of the event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any)
|
* Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any)
|
||||||
*
|
*
|
||||||
* @event collisionEnd
|
* @event collisionEnd
|
||||||
* @param {} event An event object
|
* @param {object} event An event object
|
||||||
* @param {} event.pairs List of affected pairs
|
* @param {pair[]} event.pairs List of affected pairs
|
||||||
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
* @param {number} event.timestamp The engine.timing.timestamp of the event
|
||||||
* @param {} event.source The source object of the event
|
* @param {engine} event.source The source object of the event
|
||||||
* @param {} event.name The name of the event
|
* @param {string} event.name The name of the event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -452,9 +442,18 @@ var Body = require('../body/Body');
|
||||||
* @default 0
|
* @default 0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A `Matter.Detector` instance.
|
||||||
|
*
|
||||||
|
* @property detector
|
||||||
|
* @type detector
|
||||||
|
* @default a Matter.Detector instance
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `Matter.Grid` instance.
|
* A `Matter.Grid` instance.
|
||||||
*
|
*
|
||||||
|
* @deprecated replaced by `engine.detector`
|
||||||
* @property grid
|
* @property grid
|
||||||
* @type grid
|
* @type grid
|
||||||
* @default a Matter.Grid instance
|
* @default a Matter.Grid instance
|
||||||
|
@ -463,7 +462,7 @@ var Body = require('../body/Body');
|
||||||
/**
|
/**
|
||||||
* Replaced by and now alias for `engine.grid`.
|
* Replaced by and now alias for `engine.grid`.
|
||||||
*
|
*
|
||||||
* @deprecated use `engine.grid`
|
* @deprecated replaced by `engine.detector`
|
||||||
* @property broadphase
|
* @property broadphase
|
||||||
* @type grid
|
* @type grid
|
||||||
* @default a Matter.Grid instance
|
* @default a Matter.Grid instance
|
||||||
|
|
Loading…
Reference in a new issue