mirror of
https://github.com/liabru/matter-js.git
synced 2025-01-11 16:00:48 -05:00
optimised SAT.collides
This commit is contained in:
parent
2096961846
commit
0af144c78b
2 changed files with 89 additions and 63 deletions
|
@ -55,11 +55,9 @@ var Bounds = require('../geometry/Bounds');
|
||||||
var partB = bodyB.parts[k];
|
var partB = bodyB.parts[k];
|
||||||
|
|
||||||
if ((partA === bodyA && partB === bodyB) || overlaps(partA.bounds, partB.bounds)) {
|
if ((partA === bodyA && partB === bodyB) || overlaps(partA.bounds, partB.bounds)) {
|
||||||
// find a previous collision we could reuse
|
|
||||||
var pair = pairsTable[pairId(partA, partB)];
|
|
||||||
|
|
||||||
// narrow phase
|
// narrow phase
|
||||||
var collision = collides(partA, partB, pair && pair.isActive ? pair.collision : null);
|
var pair = pairsTable[pairId(partA, partB)];
|
||||||
|
var collision = collides(partA, partB, pair && pair.collision, pair && pair.isActive);
|
||||||
|
|
||||||
if (collision.collided) {
|
if (collision.collided) {
|
||||||
collisions.push(collision);
|
collisions.push(collision);
|
||||||
|
|
|
@ -27,20 +27,47 @@ var Vector = require('../geometry/Vector');
|
||||||
axisNumber: 0
|
axisNumber: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new collision record.
|
||||||
|
* @private
|
||||||
|
* @method create
|
||||||
|
* @param {body} bodyA
|
||||||
|
* @param {body} bodyB
|
||||||
|
* @return {collision} A new collision
|
||||||
|
*/
|
||||||
|
SAT.create = function(bodyA, bodyB) {
|
||||||
|
return {
|
||||||
|
collided: false,
|
||||||
|
bodyA: bodyA,
|
||||||
|
bodyB: bodyB,
|
||||||
|
parentA: bodyA.parent,
|
||||||
|
parentB: bodyB.parent,
|
||||||
|
axisBodyA: bodyA,
|
||||||
|
axisBodyB: bodyB,
|
||||||
|
axisNumber: 0,
|
||||||
|
depth: 0,
|
||||||
|
normal: { x: 0, y: 0 },
|
||||||
|
tangent: { x: 0, y: 0 },
|
||||||
|
penetration: { x: 0, y: 0 },
|
||||||
|
supports: []
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect collision between two bodies using the Separating Axis Theorem.
|
* Detect collision between two bodies using the Separating Axis Theorem.
|
||||||
* @method collides
|
* @method collides
|
||||||
* @param {body} bodyA
|
* @param {body} bodyA
|
||||||
* @param {body} bodyB
|
* @param {body} bodyB
|
||||||
* @param {collision} previousCollision
|
* @param {?collision} previousCollision
|
||||||
|
* @param {?boolean} [previousPairActive=false]
|
||||||
* @return {collision} collision
|
* @return {collision} collision
|
||||||
*/
|
*/
|
||||||
SAT.collides = function(bodyA, bodyB, previousCollision) {
|
SAT.collides = function(bodyA, bodyB, previousCollision, pairActive) {
|
||||||
var minOverlap,
|
var minOverlap,
|
||||||
collision,
|
collision = previousCollision || SAT.create(bodyA, bodyB),
|
||||||
canReusePrevCol = false;
|
canReusePrevCol;
|
||||||
|
|
||||||
if (previousCollision) {
|
if (pairActive && previousCollision.collided) {
|
||||||
// estimate total motion
|
// estimate total motion
|
||||||
var parentA = bodyA.parent,
|
var parentA = bodyA.parent,
|
||||||
parentB = bodyB.parent,
|
parentB = bodyB.parent,
|
||||||
|
@ -49,24 +76,18 @@ var Vector = require('../geometry/Vector');
|
||||||
|
|
||||||
// we may be able to (partially) reuse collision result
|
// we may be able to (partially) reuse collision result
|
||||||
// but only safe if collision was resting
|
// but only safe if collision was resting
|
||||||
canReusePrevCol = previousCollision && previousCollision.collided && motion < 0.2;
|
canReusePrevCol = motion < 0.2;
|
||||||
|
|
||||||
// reuse collision object
|
|
||||||
collision = previousCollision;
|
|
||||||
} else {
|
|
||||||
collision = { collided: false, bodyA: bodyA, bodyB: bodyB };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previousCollision && canReusePrevCol) {
|
if (canReusePrevCol) {
|
||||||
// if we can reuse the collision result
|
// if we can reuse the collision result
|
||||||
// we only need to test the previously found axis
|
// we only need to test the previously found axis
|
||||||
var axisBodyA = collision.axisBody,
|
var axisBodyA = previousCollision.axisBodyA,
|
||||||
axisBodyB = axisBodyA === bodyA ? bodyB : bodyA,
|
axisBodyB = previousCollision.axisBodyB,
|
||||||
axes = [axisBodyA.axes[previousCollision.axisNumber]];
|
axes = [axisBodyA.axes[previousCollision.axisNumber]];
|
||||||
|
|
||||||
SAT._overlapAxes(_overlapAB, axisBodyA.vertices, axisBodyB.vertices, axes);
|
SAT._overlapAxes(_overlapAB, axisBodyA.vertices, axisBodyB.vertices, axes);
|
||||||
collision.reused = true;
|
|
||||||
|
|
||||||
if (_overlapAB.overlap <= 0) {
|
if (_overlapAB.overlap <= 0) {
|
||||||
collision.collided = false;
|
collision.collided = false;
|
||||||
return collision;
|
return collision;
|
||||||
|
@ -92,10 +113,12 @@ var Vector = require('../geometry/Vector');
|
||||||
|
|
||||||
if (_overlapAB.overlap < _overlapBA.overlap) {
|
if (_overlapAB.overlap < _overlapBA.overlap) {
|
||||||
minOverlap = _overlapAB;
|
minOverlap = _overlapAB;
|
||||||
collision.axisBody = bodyA;
|
collision.axisBodyA = bodyA;
|
||||||
|
collision.axisBodyB = bodyB;
|
||||||
} else {
|
} else {
|
||||||
minOverlap = _overlapBA;
|
minOverlap = _overlapBA;
|
||||||
collision.axisBody = bodyB;
|
collision.axisBodyA = bodyB;
|
||||||
|
collision.axisBodyB = bodyA;
|
||||||
}
|
}
|
||||||
|
|
||||||
// important for reuse later
|
// important for reuse later
|
||||||
|
@ -112,52 +135,51 @@ var Vector = require('../geometry/Vector');
|
||||||
bodyA = collision.bodyA;
|
bodyA = collision.bodyA;
|
||||||
bodyB = collision.bodyB;
|
bodyB = collision.bodyB;
|
||||||
|
|
||||||
|
var normal = collision.normal,
|
||||||
|
supports = collision.supports;
|
||||||
|
|
||||||
// ensure normal is facing away from bodyA
|
// ensure normal is facing away from bodyA
|
||||||
if (Vector.dot(minOverlap.axis, Vector.sub(bodyB.position, bodyA.position)) < 0) {
|
if (Vector.dot(minOverlap.axis, Vector.sub(bodyB.position, bodyA.position)) < 0) {
|
||||||
collision.normal = {
|
normal.x = minOverlap.axis.x;
|
||||||
x: minOverlap.axis.x,
|
normal.y = minOverlap.axis.y;
|
||||||
y: minOverlap.axis.y
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
collision.normal = {
|
normal.x = -minOverlap.axis.x;
|
||||||
x: -minOverlap.axis.x,
|
normal.y = -minOverlap.axis.y;
|
||||||
y: -minOverlap.axis.y
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
collision.tangent = Vector.perp(collision.normal);
|
collision.tangent.x = -normal.y;
|
||||||
|
collision.tangent.y = normal.x;
|
||||||
|
|
||||||
collision.penetration = collision.penetration || {};
|
collision.penetration.x = normal.x * collision.depth;
|
||||||
collision.penetration.x = collision.normal.x * collision.depth;
|
collision.penetration.y = normal.y * collision.depth;
|
||||||
collision.penetration.y = collision.normal.y * collision.depth;
|
|
||||||
|
|
||||||
// find support points, there is always either exactly one or two
|
// find support points, there is always either exactly one or two
|
||||||
var verticesB = SAT._findSupports(bodyA, bodyB, collision.normal, 1),
|
var supportsB = SAT._findSupports(bodyA, bodyB, collision.normal, 1);
|
||||||
supports = [];
|
|
||||||
|
// clear supports
|
||||||
|
supports.length = 0;
|
||||||
|
|
||||||
// find the supports from bodyB that are inside bodyA
|
// find the supports from bodyB that are inside bodyA
|
||||||
if (Vertices.contains(bodyA.vertices, verticesB[0]))
|
if (Vertices.contains(bodyA.vertices, supportsB[0]))
|
||||||
supports.push(verticesB[0]);
|
supports.push(supportsB[0]);
|
||||||
|
|
||||||
if (Vertices.contains(bodyA.vertices, verticesB[1]))
|
if (Vertices.contains(bodyA.vertices, supportsB[1]))
|
||||||
supports.push(verticesB[1]);
|
supports.push(supportsB[1]);
|
||||||
|
|
||||||
// find the supports from bodyA that are inside bodyB
|
// find the supports from bodyA that are inside bodyB
|
||||||
if (supports.length < 2) {
|
if (supports.length < 2) {
|
||||||
var verticesA = SAT._findSupports(bodyB, bodyA, collision.normal, -1);
|
var supportsA = SAT._findSupports(bodyB, bodyA, collision.normal, -1);
|
||||||
|
|
||||||
if (Vertices.contains(bodyB.vertices, verticesA[0]))
|
if (Vertices.contains(bodyB.vertices, supportsA[0]))
|
||||||
supports.push(verticesA[0]);
|
supports.push(supportsA[0]);
|
||||||
|
|
||||||
if (supports.length < 2 && Vertices.contains(bodyB.vertices, verticesA[1]))
|
if (supports.length < 2 && Vertices.contains(bodyB.vertices, supportsA[1]))
|
||||||
supports.push(verticesA[1]);
|
supports.push(supportsA[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// account for the edge case of overlapping but no vertex containment
|
// account for the edge case of overlapping but no vertex containment
|
||||||
if (supports.length < 1)
|
if (supports.length === 0)
|
||||||
supports = [verticesB[0]];
|
supports.push(supportsB[0]);
|
||||||
|
|
||||||
collision.supports = supports;
|
|
||||||
|
|
||||||
return collision;
|
return collision;
|
||||||
};
|
};
|
||||||
|
@ -174,22 +196,26 @@ var Vector = require('../geometry/Vector');
|
||||||
SAT._overlapAxes = function(result, verticesA, verticesB, axes) {
|
SAT._overlapAxes = function(result, verticesA, verticesB, axes) {
|
||||||
var verticesALength = verticesA.length,
|
var verticesALength = verticesA.length,
|
||||||
verticesBLength = verticesB.length,
|
verticesBLength = verticesB.length,
|
||||||
|
verticesAX = verticesA[0].x,
|
||||||
|
verticesAY = verticesA[0].y,
|
||||||
|
verticesBX = verticesB[0].x,
|
||||||
|
verticesBY = verticesB[0].y,
|
||||||
axesLength = axes.length,
|
axesLength = axes.length,
|
||||||
dot,
|
overlapMin = Number.MAX_VALUE,
|
||||||
|
overlapAxisNumber = 0,
|
||||||
overlap,
|
overlap,
|
||||||
overlapAB,
|
overlapAB,
|
||||||
overlapBA,
|
overlapBA,
|
||||||
|
dot,
|
||||||
i,
|
i,
|
||||||
j;
|
j;
|
||||||
|
|
||||||
result.overlap = Number.MAX_VALUE;
|
|
||||||
|
|
||||||
for (i = 0; i < axesLength; i++) {
|
for (i = 0; i < axesLength; i++) {
|
||||||
var axis = axes[i],
|
var axis = axes[i],
|
||||||
axisX = axis.x,
|
axisX = axis.x,
|
||||||
axisY = axis.y,
|
axisY = axis.y,
|
||||||
minA = verticesA[0].x * axisX + verticesA[0].y * axisY,
|
minA = verticesAX * axisX + verticesAY * axisY,
|
||||||
minB = verticesB[0].x * axisX + verticesB[0].y * axisY,
|
minB = verticesBX * axisX + verticesBY * axisY,
|
||||||
maxA = minA,
|
maxA = minA,
|
||||||
maxB = minB;
|
maxB = minB;
|
||||||
|
|
||||||
|
@ -217,18 +243,20 @@ var Vector = require('../geometry/Vector');
|
||||||
overlapBA = maxB - minA;
|
overlapBA = maxB - minA;
|
||||||
overlap = overlapAB < overlapBA ? overlapAB : overlapBA;
|
overlap = overlapAB < overlapBA ? overlapAB : overlapBA;
|
||||||
|
|
||||||
if (overlap <= 0) {
|
if (overlap < overlapMin) {
|
||||||
result.overlap = overlap;
|
overlapMin = overlap;
|
||||||
result.axisNumber = i;
|
overlapAxisNumber = i;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overlap < result.overlap) {
|
if (overlap <= 0) {
|
||||||
result.overlap = overlap;
|
// can not be intersecting
|
||||||
result.axis = axis;
|
break;
|
||||||
result.axisNumber = i;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.axis = axes[overlapAxisNumber];
|
||||||
|
result.axisNumber = overlapAxisNumber;
|
||||||
|
result.overlap = overlapMin;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue