Skip to content

Commit a6b5e7d

Browse files
committed
added broadphase to Matter.Detector
1 parent b9e7d9d commit a6b5e7d

2 files changed

Lines changed: 195 additions & 112 deletions

File tree

src/collision/Detector.js

Lines changed: 142 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,133 @@
11
/**
2-
* The `Matter.Detector` module contains methods for detecting collisions given a set of pairs.
2+
* The `Matter.Detector` module contains methods for efficiently detecting collisions between a list of bodies using a broadphase algorithm.
33
*
44
* @class Detector
55
*/
66

7-
// TODO: speculative contacts
8-
97
var Detector = {};
108

119
module.exports = Detector;
1210

13-
var SAT = require('./SAT');
14-
var Pair = require('./Pair');
11+
var Common = require('../core/Common');
12+
var Collision = require('./Collision');
1513

1614
(function() {
1715

1816
/**
19-
* Finds all collisions given a list of pairs.
17+
* Creates a new collision detector.
18+
* @method create
19+
* @param {} options
20+
* @return {detector} A new collision detector
21+
*/
22+
Detector.create = function(options) {
23+
var defaults = {
24+
bodies: [],
25+
pairs: null
26+
};
27+
28+
return Common.extend(defaults, options);
29+
};
30+
31+
/**
32+
* Sets the list of bodies in the detector.
33+
* @method setBodies
34+
* @param {detector} detector
35+
* @param {body[]} bodies
36+
*/
37+
Detector.setBodies = function(detector, bodies) {
38+
detector.bodies = bodies.slice(0);
39+
};
40+
41+
/**
42+
* Clears the detector including its list of bodies.
43+
* @method clear
44+
* @param {detector} detector
45+
*/
46+
Detector.clear = function(detector) {
47+
detector.bodies = [];
48+
};
49+
50+
/**
51+
* Efficiently finds all collisions among all the bodies in `detector.bodies` using a broadphase algorithm.
52+
*
53+
* _Note:_ The specific ordering of collisions returned is not guaranteed between releases and may change for performance reasons.
54+
* If a specific ordering is required then apply a sort to the resulting array.
2055
* @method collisions
21-
* @param {pair[]} broadphasePairs
22-
* @param {engine} engine
23-
* @return {array} collisions
56+
* @param {detector} detector
57+
* @return {collision[]} collisions
2458
*/
25-
Detector.collisions = function(broadphasePairs, engine) {
59+
Detector.collisions = function(detector) {
2660
var collisions = [],
27-
pairs = engine.pairs,
28-
broadphasePairsLength = broadphasePairs.length,
61+
pairs = detector.pairs,
62+
bodies = detector.bodies,
63+
bodiesLength = bodies.length,
2964
canCollide = Detector.canCollide,
30-
collides = SAT.collides,
31-
i;
32-
33-
for (i = 0; i < broadphasePairsLength; i++) {
34-
var broadphasePair = broadphasePairs[i],
35-
bodyA = broadphasePair[0],
36-
bodyB = broadphasePair[1];
37-
38-
if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping))
39-
continue;
40-
41-
if (!canCollide(bodyA.collisionFilter, bodyB.collisionFilter))
42-
continue;
43-
44-
var boundsA = bodyA.bounds,
45-
boundsB = bodyB.bounds;
46-
47-
if (boundsA.min.x > boundsB.max.x || boundsA.max.x < boundsB.min.x
48-
|| boundsA.max.y < boundsB.min.y || boundsA.min.y > boundsB.max.y) {
49-
continue;
50-
}
65+
collides = Collision.collides,
66+
i,
67+
j;
68+
69+
bodies.sort(Detector._compareBoundsX);
70+
71+
for (i = 0; i < bodiesLength; i++) {
72+
var bodyA = bodies[i],
73+
boundsA = bodyA.bounds,
74+
boundXMax = bodyA.bounds.max.x,
75+
boundYMax = bodyA.bounds.max.y,
76+
boundYMin = bodyA.bounds.min.y,
77+
bodyAStatic = bodyA.isStatic || bodyA.isSleeping,
78+
partsALength = bodyA.parts.length,
79+
partsASingle = partsALength === 1;
80+
81+
for (j = i + 1; j < bodiesLength; j++) {
82+
var bodyB = bodies[j],
83+
boundsB = bodyB.bounds;
84+
85+
if (boundsB.min.x > boundXMax) {
86+
break;
87+
}
5188

52-
var partsALength = bodyA.parts.length,
53-
partsBLength = bodyB.parts.length;
89+
if (boundYMax < boundsB.min.y || boundYMin > boundsB.max.y) {
90+
continue;
91+
}
5492

55-
if (partsALength === 1 && partsBLength === 1) {
56-
var collision = collides(bodyA, bodyB, pairs);
93+
if (bodyAStatic && (bodyB.isStatic || bodyB.isSleeping)) {
94+
continue;
95+
}
5796

58-
if (collision) {
59-
collisions.push(collision);
97+
if (!canCollide(bodyA.collisionFilter, bodyB.collisionFilter)) {
98+
continue;
6099
}
61-
} else {
62-
var partsAStart = partsALength > 1 ? 1 : 0,
63-
partsBStart = partsBLength > 1 ? 1 : 0;
64-
65-
for (var j = partsAStart; j < partsALength; j++) {
66-
var partA = bodyA.parts[j],
67-
boundsA = partA.bounds;
68-
69-
for (var k = partsBStart; k < partsBLength; k++) {
70-
var partB = bodyB.parts[k],
71-
boundsB = partB.bounds;
72-
73-
if (boundsA.min.x > boundsB.max.x || boundsA.max.x < boundsB.min.x
74-
|| boundsA.max.y < boundsB.min.y || boundsA.min.y > boundsB.max.y) {
75-
continue;
76-
}
77100

78-
var collision = collides(partA, partB, pairs);
101+
var partsBLength = bodyB.parts.length;
102+
103+
if (partsASingle && partsBLength === 1) {
104+
var collision = collides(bodyA, bodyB, pairs);
79105

80-
if (collision) {
81-
collisions.push(collision);
106+
if (collision) {
107+
collisions.push(collision);
108+
}
109+
} else {
110+
var partsAStart = partsALength > 1 ? 1 : 0,
111+
partsBStart = partsBLength > 1 ? 1 : 0;
112+
113+
for (var k = partsAStart; k < partsALength; k++) {
114+
var partA = bodyA.parts[k],
115+
boundsA = partA.bounds;
116+
117+
for (var z = partsBStart; z < partsBLength; z++) {
118+
var partB = bodyB.parts[z],
119+
boundsB = partB.bounds;
120+
121+
if (boundsA.min.x > boundsB.max.x || boundsA.max.x < boundsB.min.x
122+
|| boundsA.max.y < boundsB.min.y || boundsA.min.y > boundsB.max.y) {
123+
continue;
124+
}
125+
126+
var collision = collides(partA, partB, pairs);
127+
128+
if (collision) {
129+
collisions.push(collision);
130+
}
82131
}
83132
}
84133
}
@@ -103,4 +152,39 @@ var Pair = require('./Pair');
103152
return (filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0;
104153
};
105154

155+
/**
156+
* The comparison function used in the broadphase algorithm.
157+
* Returns the signed delta of the bodies bounds on the x-axis.
158+
* @private
159+
* @method _sortCompare
160+
* @param {body} bodyA
161+
* @param {body} bodyB
162+
* @return {number} The signed delta used for sorting
163+
*/
164+
Detector._compareBoundsX = function(bodyA, bodyB) {
165+
return bodyA.bounds.min.x - bodyB.bounds.min.x;
166+
};
167+
168+
/*
169+
*
170+
* Properties Documentation
171+
*
172+
*/
173+
174+
/**
175+
* The array of `Matter.Body` between which the detector finds collisions.
176+
*
177+
* _Note:_ The order of bodies in this array _is not fixed_ and will be continually managed by the detector.
178+
* @property bodies
179+
* @type body[]
180+
* @default []
181+
*/
182+
183+
/**
184+
* Optional. A `Matter.Pairs` object from which previous collision objects may be reused. Intended for internal `Matter.Engine` usage.
185+
* @property pairs
186+
* @type {pairs|null}
187+
* @default null
188+
*/
189+
106190
})();

0 commit comments

Comments
 (0)