mirror of
https://github.com/liabru/matter-js.git
synced 2024-12-26 13:49:01 -05:00
replaced Matter.SAT with Matter.Collision
This commit is contained in:
parent
8adf8102fb
commit
b9e7d9dd8b
5 changed files with 408 additions and 279 deletions
|
@ -1,5 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* The `Matter.Collision` module contains methods for managing collision records.
|
* The `Matter.Collision` module contains methods for detecting collisions between a given pair of bodies.
|
||||||
|
*
|
||||||
|
* For efficient detection between a list of bodies, see `Matter.Detector` and `Matter.Query`.
|
||||||
|
*
|
||||||
|
* See `Matter.Engine` for collision events.
|
||||||
*
|
*
|
||||||
* @class Collision
|
* @class Collision
|
||||||
*/
|
*/
|
||||||
|
@ -8,13 +12,27 @@ var Collision = {};
|
||||||
|
|
||||||
module.exports = Collision;
|
module.exports = Collision;
|
||||||
|
|
||||||
|
var Vertices = require('../geometry/Vertices');
|
||||||
|
var Pair = require('./Pair');
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
var _supports = [];
|
||||||
|
|
||||||
|
var _overlapAB = {
|
||||||
|
overlap: 0,
|
||||||
|
axis: null
|
||||||
|
};
|
||||||
|
|
||||||
|
var _overlapBA = {
|
||||||
|
overlap: 0,
|
||||||
|
axis: null
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new collision record.
|
* Creates a new collision record.
|
||||||
* @method create
|
* @method create
|
||||||
* @param {body} bodyA
|
* @param {body} bodyA The first body part represented by the collision record
|
||||||
* @param {body} bodyB
|
* @param {body} bodyB The second body part represented by the collision record
|
||||||
* @return {collision} A new collision record
|
* @return {collision} A new collision record
|
||||||
*/
|
*/
|
||||||
Collision.create = function(bodyA, bodyB) {
|
Collision.create = function(bodyA, bodyB) {
|
||||||
|
@ -33,4 +51,358 @@ module.exports = Collision;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect collision between two bodies.
|
||||||
|
* @method collides
|
||||||
|
* @param {body} bodyA
|
||||||
|
* @param {body} bodyB
|
||||||
|
* @param {pairs} [pairs] Optionally reuse collision records from existing pairs.
|
||||||
|
* @return {collision|null} A collision record if detected, otherwise null
|
||||||
|
*/
|
||||||
|
Collision.collides = function(bodyA, bodyB, pairs) {
|
||||||
|
Collision._overlapAxes(_overlapAB, bodyA.vertices, bodyB.vertices, bodyA.axes);
|
||||||
|
|
||||||
|
if (_overlapAB.overlap <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Collision._overlapAxes(_overlapBA, bodyB.vertices, bodyA.vertices, bodyB.axes);
|
||||||
|
|
||||||
|
if (_overlapBA.overlap <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reuse collision records for gc efficiency
|
||||||
|
var pair = pairs && pairs.table[Pair.id(bodyA, bodyB)],
|
||||||
|
collision;
|
||||||
|
|
||||||
|
if (!pair) {
|
||||||
|
collision = Collision.create(bodyA, bodyB);
|
||||||
|
collision.collided = true;
|
||||||
|
collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;
|
||||||
|
collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;
|
||||||
|
collision.parentA = collision.bodyA.parent;
|
||||||
|
collision.parentB = collision.bodyB.parent;
|
||||||
|
} else {
|
||||||
|
collision = pair.collision;
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyA = collision.bodyA;
|
||||||
|
bodyB = collision.bodyB;
|
||||||
|
|
||||||
|
var minOverlap;
|
||||||
|
|
||||||
|
if (_overlapAB.overlap < _overlapBA.overlap) {
|
||||||
|
minOverlap = _overlapAB;
|
||||||
|
} else {
|
||||||
|
minOverlap = _overlapBA;
|
||||||
|
}
|
||||||
|
|
||||||
|
var normal = collision.normal,
|
||||||
|
supports = collision.supports,
|
||||||
|
minAxis = minOverlap.axis,
|
||||||
|
minAxisX = minAxis.x,
|
||||||
|
minAxisY = minAxis.y;
|
||||||
|
|
||||||
|
// ensure normal is facing away from bodyA
|
||||||
|
if (minAxisX * (bodyB.position.x - bodyA.position.x) + minAxisY * (bodyB.position.y - bodyA.position.y) < 0) {
|
||||||
|
normal.x = minAxisX;
|
||||||
|
normal.y = minAxisY;
|
||||||
|
} else {
|
||||||
|
normal.x = -minAxisX;
|
||||||
|
normal.y = -minAxisY;
|
||||||
|
}
|
||||||
|
|
||||||
|
collision.tangent.x = -normal.y;
|
||||||
|
collision.tangent.y = normal.x;
|
||||||
|
|
||||||
|
collision.depth = minOverlap.overlap;
|
||||||
|
|
||||||
|
collision.penetration.x = normal.x * collision.depth;
|
||||||
|
collision.penetration.y = normal.y * collision.depth;
|
||||||
|
|
||||||
|
// find support points, there is always either exactly one or two
|
||||||
|
var supportsB = Collision._findSupports(bodyA, bodyB, normal, 1),
|
||||||
|
supportCount = 0;
|
||||||
|
|
||||||
|
// find the supports from bodyB that are inside bodyA
|
||||||
|
if (Vertices.contains(bodyA.vertices, supportsB[0])) {
|
||||||
|
supports[supportCount++] = supportsB[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Vertices.contains(bodyA.vertices, supportsB[1])) {
|
||||||
|
supports[supportCount++] = supportsB[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the supports from bodyA that are inside bodyB
|
||||||
|
if (supportCount < 2) {
|
||||||
|
var supportsA = Collision._findSupports(bodyB, bodyA, normal, -1);
|
||||||
|
|
||||||
|
if (Vertices.contains(bodyB.vertices, supportsA[0])) {
|
||||||
|
supports[supportCount++] = supportsA[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportCount < 2 && Vertices.contains(bodyB.vertices, supportsA[1])) {
|
||||||
|
supports[supportCount++] = supportsA[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// account for the edge case of overlapping but no vertex containment
|
||||||
|
if (supportCount === 0) {
|
||||||
|
supports[supportCount++] = supportsB[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// update supports array size
|
||||||
|
supports.length = supportCount;
|
||||||
|
|
||||||
|
return collision;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the overlap between two sets of vertices.
|
||||||
|
* @method _overlapAxes
|
||||||
|
* @private
|
||||||
|
* @param {object} result
|
||||||
|
* @param {vertices} verticesA
|
||||||
|
* @param {vertices} verticesB
|
||||||
|
* @param {axes} axes
|
||||||
|
*/
|
||||||
|
Collision._overlapAxes = function(result, verticesA, verticesB, axes) {
|
||||||
|
var verticesALength = verticesA.length,
|
||||||
|
verticesBLength = verticesB.length,
|
||||||
|
verticesAX = verticesA[0].x,
|
||||||
|
verticesAY = verticesA[0].y,
|
||||||
|
verticesBX = verticesB[0].x,
|
||||||
|
verticesBY = verticesB[0].y,
|
||||||
|
axesLength = axes.length,
|
||||||
|
overlapMin = Number.MAX_VALUE,
|
||||||
|
overlapAxisNumber = 0,
|
||||||
|
overlap,
|
||||||
|
overlapAB,
|
||||||
|
overlapBA,
|
||||||
|
dot,
|
||||||
|
i,
|
||||||
|
j;
|
||||||
|
|
||||||
|
for (i = 0; i < axesLength; i++) {
|
||||||
|
var axis = axes[i],
|
||||||
|
axisX = axis.x,
|
||||||
|
axisY = axis.y,
|
||||||
|
minA = verticesAX * axisX + verticesAY * axisY,
|
||||||
|
minB = verticesBX * axisX + verticesBY * axisY,
|
||||||
|
maxA = minA,
|
||||||
|
maxB = minB;
|
||||||
|
|
||||||
|
for (j = 1; j < verticesALength; j += 1) {
|
||||||
|
dot = verticesA[j].x * axisX + verticesA[j].y * axisY;
|
||||||
|
|
||||||
|
if (dot > maxA) {
|
||||||
|
maxA = dot;
|
||||||
|
} else if (dot < minA) {
|
||||||
|
minA = dot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 1; j < verticesBLength; j += 1) {
|
||||||
|
dot = verticesB[j].x * axisX + verticesB[j].y * axisY;
|
||||||
|
|
||||||
|
if (dot > maxB) {
|
||||||
|
maxB = dot;
|
||||||
|
} else if (dot < minB) {
|
||||||
|
minB = dot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
overlapAB = maxA - minB;
|
||||||
|
overlapBA = maxB - minA;
|
||||||
|
overlap = overlapAB < overlapBA ? overlapAB : overlapBA;
|
||||||
|
|
||||||
|
if (overlap < overlapMin) {
|
||||||
|
overlapMin = overlap;
|
||||||
|
overlapAxisNumber = i;
|
||||||
|
|
||||||
|
if (overlap <= 0) {
|
||||||
|
// can not be intersecting
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.axis = axes[overlapAxisNumber];
|
||||||
|
result.overlap = overlapMin;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Projects vertices on an axis and returns an interval.
|
||||||
|
* @method _projectToAxis
|
||||||
|
* @private
|
||||||
|
* @param {} projection
|
||||||
|
* @param {} vertices
|
||||||
|
* @param {} axis
|
||||||
|
*/
|
||||||
|
Collision._projectToAxis = function(projection, vertices, axis) {
|
||||||
|
var min = vertices[0].x * axis.x + vertices[0].y * axis.y,
|
||||||
|
max = min;
|
||||||
|
|
||||||
|
for (var i = 1; i < vertices.length; i += 1) {
|
||||||
|
var dot = vertices[i].x * axis.x + vertices[i].y * axis.y;
|
||||||
|
|
||||||
|
if (dot > max) {
|
||||||
|
max = dot;
|
||||||
|
} else if (dot < min) {
|
||||||
|
min = dot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
projection.min = min;
|
||||||
|
projection.max = max;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds supporting vertices given two bodies along a given direction using hill-climbing.
|
||||||
|
* @method _findSupports
|
||||||
|
* @private
|
||||||
|
* @param {body} bodyA
|
||||||
|
* @param {body} bodyB
|
||||||
|
* @param {vector} normal
|
||||||
|
* @param {number} direction
|
||||||
|
* @return [vector]
|
||||||
|
*/
|
||||||
|
Collision._findSupports = function(bodyA, bodyB, normal, direction) {
|
||||||
|
var vertices = bodyB.vertices,
|
||||||
|
verticesLength = vertices.length,
|
||||||
|
bodyAPositionX = bodyA.position.x,
|
||||||
|
bodyAPositionY = bodyA.position.y,
|
||||||
|
normalX = normal.x * direction,
|
||||||
|
normalY = normal.y * direction,
|
||||||
|
nearestDistance = Number.MAX_VALUE,
|
||||||
|
vertexA,
|
||||||
|
vertexB,
|
||||||
|
vertexC,
|
||||||
|
distance,
|
||||||
|
j;
|
||||||
|
|
||||||
|
// find deepest vertex relative to the axis
|
||||||
|
for (j = 0; j < verticesLength; j += 1) {
|
||||||
|
vertexB = vertices[j];
|
||||||
|
distance = normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y);
|
||||||
|
|
||||||
|
// convex hill-climbing
|
||||||
|
if (distance < nearestDistance) {
|
||||||
|
nearestDistance = distance;
|
||||||
|
vertexA = vertexB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// measure next vertex
|
||||||
|
vertexC = vertices[(verticesLength + vertexA.index - 1) % verticesLength];
|
||||||
|
nearestDistance = normalX * (bodyAPositionX - vertexC.x) + normalY * (bodyAPositionY - vertexC.y);
|
||||||
|
|
||||||
|
// compare with previous vertex
|
||||||
|
vertexB = vertices[(vertexA.index + 1) % verticesLength];
|
||||||
|
if (normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y) < nearestDistance) {
|
||||||
|
_supports[0] = vertexA;
|
||||||
|
_supports[1] = vertexB;
|
||||||
|
|
||||||
|
return _supports;
|
||||||
|
}
|
||||||
|
|
||||||
|
_supports[0] = vertexA;
|
||||||
|
_supports[1] = vertexC;
|
||||||
|
|
||||||
|
return _supports;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Properties Documentation
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to the pair using this collision record, if there is one.
|
||||||
|
*
|
||||||
|
* @property pair
|
||||||
|
* @type {pair|null}
|
||||||
|
* @default null
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flag that indicates if the bodies were colliding when the collision was last updated.
|
||||||
|
*
|
||||||
|
* @property collided
|
||||||
|
* @type boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first body part represented by the collision (see also `collision.parentA`).
|
||||||
|
*
|
||||||
|
* @property bodyA
|
||||||
|
* @type body
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The second body part represented by the collision (see also `collision.parentB`).
|
||||||
|
*
|
||||||
|
* @property bodyB
|
||||||
|
* @type body
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first body represented by the collision (i.e. `collision.bodyA.parent`).
|
||||||
|
*
|
||||||
|
* @property parentA
|
||||||
|
* @type body
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The second body represented by the collision (i.e. `collision.bodyB.parent`).
|
||||||
|
*
|
||||||
|
* @property parentB
|
||||||
|
* @type body
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A `Number` that represents the minimum separating distance between the bodies along the collision normal.
|
||||||
|
*
|
||||||
|
* @readOnly
|
||||||
|
* @property depth
|
||||||
|
* @type number
|
||||||
|
* @default 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A normalised `Vector` that represents the direction between the bodies that provides the minimum separating distance.
|
||||||
|
*
|
||||||
|
* @property normal
|
||||||
|
* @type vector
|
||||||
|
* @default { x: 0, y: 0 }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A normalised `Vector` that is the tangent direction to the collision normal.
|
||||||
|
*
|
||||||
|
* @property tangent
|
||||||
|
* @type vector
|
||||||
|
* @default { x: 0, y: 0 }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A `Vector` that represents the direction and depth of the collision.
|
||||||
|
*
|
||||||
|
* @property penetration
|
||||||
|
* @type vector
|
||||||
|
* @default { x: 0, y: 0 }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of body vertices that represent the support points in the collision.
|
||||||
|
* These are the deepest vertices (along the collision normal) of each body that are contained by the other body's vertices.
|
||||||
|
*
|
||||||
|
* @property supports
|
||||||
|
* @type vector[]
|
||||||
|
* @default []
|
||||||
|
*/
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -11,7 +11,7 @@ var Query = {};
|
||||||
module.exports = Query;
|
module.exports = Query;
|
||||||
|
|
||||||
var Vector = require('../geometry/Vector');
|
var Vector = require('../geometry/Vector');
|
||||||
var SAT = require('./SAT');
|
var Collision = require('./Collision');
|
||||||
var Bounds = require('../geometry/Bounds');
|
var Bounds = require('../geometry/Bounds');
|
||||||
var Bodies = require('../factory/Bodies');
|
var Bodies = require('../factory/Bodies');
|
||||||
var Vertices = require('../geometry/Vertices');
|
var Vertices = require('../geometry/Vertices');
|
||||||
|
@ -23,13 +23,13 @@ var Vertices = require('../geometry/Vertices');
|
||||||
* @method collides
|
* @method collides
|
||||||
* @param {body} body
|
* @param {body} body
|
||||||
* @param {body[]} bodies
|
* @param {body[]} bodies
|
||||||
* @return {object[]} Collisions
|
* @return {collision[]} Collisions
|
||||||
*/
|
*/
|
||||||
Query.collides = function(body, bodies) {
|
Query.collides = function(body, bodies) {
|
||||||
var collisions = [],
|
var collisions = [],
|
||||||
bodiesLength = bodies.length,
|
bodiesLength = bodies.length,
|
||||||
bounds = body.bounds,
|
bounds = body.bounds,
|
||||||
collides = SAT.collides,
|
collides = Collision.collides,
|
||||||
overlaps = Bounds.overlaps;
|
overlaps = Bounds.overlaps;
|
||||||
|
|
||||||
for (var i = 0; i < bodiesLength; i++) {
|
for (var i = 0; i < bodiesLength; i++) {
|
||||||
|
@ -63,7 +63,7 @@ var Vertices = require('../geometry/Vertices');
|
||||||
* @param {vector} startPoint
|
* @param {vector} startPoint
|
||||||
* @param {vector} endPoint
|
* @param {vector} endPoint
|
||||||
* @param {number} [rayWidth]
|
* @param {number} [rayWidth]
|
||||||
* @return {object[]} Collisions
|
* @return {collision[]} Collisions
|
||||||
*/
|
*/
|
||||||
Query.ray = function(bodies, startPoint, endPoint, rayWidth) {
|
Query.ray = function(bodies, startPoint, endPoint, rayWidth) {
|
||||||
rayWidth = rayWidth || 1e-100;
|
rayWidth = rayWidth || 1e-100;
|
||||||
|
|
|
@ -1,290 +1,37 @@
|
||||||
/**
|
/**
|
||||||
|
* This module has now been replaced by `Matter.Collision`.
|
||||||
|
*
|
||||||
|
* All usage should be migrated to `Matter.Collision`.
|
||||||
|
* For back-compatibility purposes this module will remain for a short term and then later removed in a future release.
|
||||||
|
*
|
||||||
* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem.
|
* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem.
|
||||||
*
|
*
|
||||||
* @class SAT
|
* @class SAT
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var SAT = {};
|
var SAT = {};
|
||||||
|
|
||||||
module.exports = SAT;
|
module.exports = SAT;
|
||||||
|
|
||||||
var Vertices = require('../geometry/Vertices');
|
|
||||||
var Pair = require('../collision/Pair');
|
|
||||||
var Collision = require('./Collision');
|
var Collision = require('./Collision');
|
||||||
|
var Common = require('../core/Common');
|
||||||
|
var deprecated = Common.deprecated;
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
var _supports = [];
|
|
||||||
|
|
||||||
var _overlapAB = {
|
|
||||||
overlap: 0,
|
|
||||||
axis: null
|
|
||||||
};
|
|
||||||
|
|
||||||
var _overlapBA = {
|
|
||||||
overlap: 0,
|
|
||||||
axis: null
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect collision between two bodies using the Separating Axis Theorem.
|
* Detect collision between two bodies using the Separating Axis Theorem.
|
||||||
|
* @deprecated replaced by Collision.collides
|
||||||
* @method collides
|
* @method collides
|
||||||
* @param {body} bodyA
|
* @param {body} bodyA
|
||||||
* @param {body} bodyB
|
* @param {body} bodyB
|
||||||
* @param {pairs} [pairs] Optionally reuse collision objects from existing pairs.
|
* @return {collision} collision
|
||||||
* @return {collision|null} A collision object if found, otherwise null
|
|
||||||
*/
|
*/
|
||||||
SAT.collides = function(bodyA, bodyB, pairs) {
|
SAT.collides = function(bodyA, bodyB) {
|
||||||
SAT._overlapAxes(_overlapAB, bodyA.vertices, bodyB.vertices, bodyA.axes);
|
return Collision.collides(bodyA, bodyB);
|
||||||
|
|
||||||
if (_overlapAB.overlap <= 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
SAT._overlapAxes(_overlapBA, bodyB.vertices, bodyA.vertices, bodyB.axes);
|
|
||||||
|
|
||||||
if (_overlapBA.overlap <= 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reuse collision objects for gc efficiency
|
|
||||||
var pair = pairs && pairs.table[Pair.id(bodyA, bodyB)],
|
|
||||||
collision;
|
|
||||||
|
|
||||||
if (!pair) {
|
|
||||||
collision = Collision.create(bodyA, bodyB);
|
|
||||||
collision.collided = true;
|
|
||||||
collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;
|
|
||||||
collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;
|
|
||||||
collision.parentA = collision.bodyA.parent;
|
|
||||||
collision.parentB = collision.bodyB.parent;
|
|
||||||
} else {
|
|
||||||
collision = pair.collision;
|
|
||||||
}
|
|
||||||
|
|
||||||
bodyA = collision.bodyA;
|
|
||||||
bodyB = collision.bodyB;
|
|
||||||
|
|
||||||
var minOverlap;
|
|
||||||
|
|
||||||
if (_overlapAB.overlap < _overlapBA.overlap) {
|
|
||||||
minOverlap = _overlapAB;
|
|
||||||
} else {
|
|
||||||
minOverlap = _overlapBA;
|
|
||||||
}
|
|
||||||
|
|
||||||
var normal = collision.normal,
|
|
||||||
supports = collision.supports,
|
|
||||||
minAxis = minOverlap.axis,
|
|
||||||
minAxisX = minAxis.x,
|
|
||||||
minAxisY = minAxis.y;
|
|
||||||
|
|
||||||
// ensure normal is facing away from bodyA
|
|
||||||
if (minAxisX * (bodyB.position.x - bodyA.position.x) + minAxisY * (bodyB.position.y - bodyA.position.y) < 0) {
|
|
||||||
normal.x = minAxisX;
|
|
||||||
normal.y = minAxisY;
|
|
||||||
} else {
|
|
||||||
normal.x = -minAxisX;
|
|
||||||
normal.y = -minAxisY;
|
|
||||||
}
|
|
||||||
|
|
||||||
collision.tangent.x = -normal.y;
|
|
||||||
collision.tangent.y = normal.x;
|
|
||||||
|
|
||||||
collision.depth = minOverlap.overlap;
|
|
||||||
|
|
||||||
collision.penetration.x = normal.x * collision.depth;
|
|
||||||
collision.penetration.y = normal.y * collision.depth;
|
|
||||||
|
|
||||||
// find support points, there is always either exactly one or two
|
|
||||||
var supportsB = SAT._findSupports(bodyA, bodyB, normal, 1),
|
|
||||||
supportCount = 0;
|
|
||||||
|
|
||||||
// find the supports from bodyB that are inside bodyA
|
|
||||||
if (Vertices.contains(bodyA.vertices, supportsB[0])) {
|
|
||||||
supports[supportCount++] = supportsB[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Vertices.contains(bodyA.vertices, supportsB[1])) {
|
|
||||||
supports[supportCount++] = supportsB[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the supports from bodyA that are inside bodyB
|
|
||||||
if (supportCount < 2) {
|
|
||||||
var supportsA = SAT._findSupports(bodyB, bodyA, normal, -1);
|
|
||||||
|
|
||||||
if (Vertices.contains(bodyB.vertices, supportsA[0])) {
|
|
||||||
supports[supportCount++] = supportsA[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportCount < 2 && Vertices.contains(bodyB.vertices, supportsA[1])) {
|
|
||||||
supports[supportCount++] = supportsA[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// account for the edge case of overlapping but no vertex containment
|
|
||||||
if (supportCount === 0) {
|
|
||||||
supports[supportCount++] = supportsB[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// update supports array size
|
|
||||||
supports.length = supportCount;
|
|
||||||
|
|
||||||
return collision;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
deprecated(SAT, 'collides', 'SAT.collides ➤ replaced by Collision.collides');
|
||||||
* Find the overlap between two sets of vertices.
|
|
||||||
* @method _overlapAxes
|
|
||||||
* @private
|
|
||||||
* @param {object} result
|
|
||||||
* @param {vertices} verticesA
|
|
||||||
* @param {vertices} verticesB
|
|
||||||
* @param {axes} axes
|
|
||||||
*/
|
|
||||||
SAT._overlapAxes = function(result, verticesA, verticesB, axes) {
|
|
||||||
var verticesALength = verticesA.length,
|
|
||||||
verticesBLength = verticesB.length,
|
|
||||||
verticesAX = verticesA[0].x,
|
|
||||||
verticesAY = verticesA[0].y,
|
|
||||||
verticesBX = verticesB[0].x,
|
|
||||||
verticesBY = verticesB[0].y,
|
|
||||||
axesLength = axes.length,
|
|
||||||
overlapMin = Number.MAX_VALUE,
|
|
||||||
overlapAxisNumber = 0,
|
|
||||||
overlap,
|
|
||||||
overlapAB,
|
|
||||||
overlapBA,
|
|
||||||
dot,
|
|
||||||
i,
|
|
||||||
j;
|
|
||||||
|
|
||||||
for (i = 0; i < axesLength; i++) {
|
|
||||||
var axis = axes[i],
|
|
||||||
axisX = axis.x,
|
|
||||||
axisY = axis.y,
|
|
||||||
minA = verticesAX * axisX + verticesAY * axisY,
|
|
||||||
minB = verticesBX * axisX + verticesBY * axisY,
|
|
||||||
maxA = minA,
|
|
||||||
maxB = minB;
|
|
||||||
|
|
||||||
for (j = 1; j < verticesALength; j += 1) {
|
|
||||||
dot = verticesA[j].x * axisX + verticesA[j].y * axisY;
|
|
||||||
|
|
||||||
if (dot > maxA) {
|
|
||||||
maxA = dot;
|
|
||||||
} else if (dot < minA) {
|
|
||||||
minA = dot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = 1; j < verticesBLength; j += 1) {
|
|
||||||
dot = verticesB[j].x * axisX + verticesB[j].y * axisY;
|
|
||||||
|
|
||||||
if (dot > maxB) {
|
|
||||||
maxB = dot;
|
|
||||||
} else if (dot < minB) {
|
|
||||||
minB = dot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
overlapAB = maxA - minB;
|
|
||||||
overlapBA = maxB - minA;
|
|
||||||
overlap = overlapAB < overlapBA ? overlapAB : overlapBA;
|
|
||||||
|
|
||||||
if (overlap < overlapMin) {
|
|
||||||
overlapMin = overlap;
|
|
||||||
overlapAxisNumber = i;
|
|
||||||
|
|
||||||
if (overlap <= 0) {
|
|
||||||
// can not be intersecting
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.axis = axes[overlapAxisNumber];
|
|
||||||
result.overlap = overlapMin;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Projects vertices on an axis and returns an interval.
|
|
||||||
* @method _projectToAxis
|
|
||||||
* @private
|
|
||||||
* @param {} projection
|
|
||||||
* @param {} vertices
|
|
||||||
* @param {} axis
|
|
||||||
*/
|
|
||||||
SAT._projectToAxis = function(projection, vertices, axis) {
|
|
||||||
var min = vertices[0].x * axis.x + vertices[0].y * axis.y,
|
|
||||||
max = min;
|
|
||||||
|
|
||||||
for (var i = 1; i < vertices.length; i += 1) {
|
|
||||||
var dot = vertices[i].x * axis.x + vertices[i].y * axis.y;
|
|
||||||
|
|
||||||
if (dot > max) {
|
|
||||||
max = dot;
|
|
||||||
} else if (dot < min) {
|
|
||||||
min = dot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
projection.min = min;
|
|
||||||
projection.max = max;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds supporting vertices given two bodies along a given direction using hill-climbing.
|
|
||||||
* @method _findSupports
|
|
||||||
* @private
|
|
||||||
* @param {body} bodyA
|
|
||||||
* @param {body} bodyB
|
|
||||||
* @param {vector} normal
|
|
||||||
* @param {number} direction
|
|
||||||
* @return [vector]
|
|
||||||
*/
|
|
||||||
SAT._findSupports = function(bodyA, bodyB, normal, direction) {
|
|
||||||
var vertices = bodyB.vertices,
|
|
||||||
verticesLength = vertices.length,
|
|
||||||
bodyAPositionX = bodyA.position.x,
|
|
||||||
bodyAPositionY = bodyA.position.y,
|
|
||||||
normalX = normal.x * direction,
|
|
||||||
normalY = normal.y * direction,
|
|
||||||
nearestDistance = Number.MAX_VALUE,
|
|
||||||
vertexA,
|
|
||||||
vertexB,
|
|
||||||
vertexC,
|
|
||||||
distance,
|
|
||||||
j;
|
|
||||||
|
|
||||||
// find deepest vertex relative to the axis
|
|
||||||
for (j = 0; j < verticesLength; j += 1) {
|
|
||||||
vertexB = vertices[j];
|
|
||||||
distance = normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y);
|
|
||||||
|
|
||||||
// convex hill-climbing
|
|
||||||
if (distance < nearestDistance) {
|
|
||||||
nearestDistance = distance;
|
|
||||||
vertexA = vertexB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// measure next vertex
|
|
||||||
vertexC = vertices[(verticesLength + vertexA.index - 1) % verticesLength];
|
|
||||||
nearestDistance = normalX * (bodyAPositionX - vertexC.x) + normalY * (bodyAPositionY - vertexC.y);
|
|
||||||
|
|
||||||
// compare with previous vertex
|
|
||||||
vertexB = vertices[(vertexA.index + 1) % verticesLength];
|
|
||||||
if (normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y) < nearestDistance) {
|
|
||||||
_supports[0] = vertexA;
|
|
||||||
_supports[1] = vertexB;
|
|
||||||
|
|
||||||
return _supports;
|
|
||||||
}
|
|
||||||
|
|
||||||
_supports[0] = vertexA;
|
|
||||||
_supports[1] = vertexC;
|
|
||||||
|
|
||||||
return _supports;
|
|
||||||
};
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -4,6 +4,7 @@ Matter.Axes = require('../geometry/Axes');
|
||||||
Matter.Bodies = require('../factory/Bodies');
|
Matter.Bodies = require('../factory/Bodies');
|
||||||
Matter.Body = require('../body/Body');
|
Matter.Body = require('../body/Body');
|
||||||
Matter.Bounds = require('../geometry/Bounds');
|
Matter.Bounds = require('../geometry/Bounds');
|
||||||
|
Matter.Collision = require('../collision/Collision');
|
||||||
Matter.Common = require('../core/Common');
|
Matter.Common = require('../core/Common');
|
||||||
Matter.Composite = require('../body/Composite');
|
Matter.Composite = require('../body/Composite');
|
||||||
Matter.Composites = require('../factory/Composites');
|
Matter.Composites = require('../factory/Composites');
|
||||||
|
|
|
@ -79,12 +79,21 @@ const prepareMatter = (options) => {
|
||||||
Matter.Common.info = Matter.Common.warn = Matter.Common.log;
|
Matter.Common.info = Matter.Common.warn = Matter.Common.log;
|
||||||
|
|
||||||
if (options.stableSort) {
|
if (options.stableSort) {
|
||||||
const MatterSATCollides = Matter.SAT.collides;
|
if (Matter.Collision) {
|
||||||
Matter.SAT.collides = function(bodyA, bodyB, previousCollision, pairActive) {
|
const MatterCollisionCollides = Matter.Collision.collides;
|
||||||
const _bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;
|
Matter.Collision.collides = function(bodyA, bodyB, pairs) {
|
||||||
const _bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;
|
const _bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;
|
||||||
return MatterSATCollides(_bodyA, _bodyB, previousCollision, pairActive);
|
const _bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;
|
||||||
};
|
return MatterCollisionCollides(_bodyA, _bodyB, pairs);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const MatterSATCollides = Matter.SAT.collides;
|
||||||
|
Matter.SAT.collides = function(bodyA, bodyB, previousCollision, pairActive) {
|
||||||
|
const _bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;
|
||||||
|
const _bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;
|
||||||
|
return MatterSATCollides(_bodyA, _bodyB, previousCollision, pairActive);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Matter.after('Detector.collisions', function() { this.sort(collisionCompareId); });
|
Matter.after('Detector.collisions', function() { this.sort(collisionCompareId); });
|
||||||
Matter.after('Composite.allBodies', function() { sortById(this); });
|
Matter.after('Composite.allBodies', function() { sortById(this); });
|
||||||
|
|
Loading…
Reference in a new issue