mirror of
https://github.com/liabru/matter-js.git
synced 2024-11-27 09:50:52 -05:00
fixed compound body stability, improved position resolver
This commit is contained in:
parent
3ed80343e1
commit
e01dd229a9
5 changed files with 68 additions and 42 deletions
|
@ -40,6 +40,7 @@ var Body = {};
|
||||||
torque: 0,
|
torque: 0,
|
||||||
positionImpulse: { x: 0, y: 0 },
|
positionImpulse: { x: 0, y: 0 },
|
||||||
constraintImpulse: { x: 0, y: 0, angle: 0 },
|
constraintImpulse: { x: 0, y: 0, angle: 0 },
|
||||||
|
totalContacts: 0,
|
||||||
speed: 0,
|
speed: 0,
|
||||||
angularSpeed: 0,
|
angularSpeed: 0,
|
||||||
velocity: { x: 0, y: 0 },
|
velocity: { x: 0, y: 0 },
|
||||||
|
|
|
@ -8,9 +8,32 @@ var Resolver = {};
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
var _restingThresh = 4,
|
Resolver._restingThresh = 4;
|
||||||
_positionDampen = 0.2,
|
Resolver._positionDampen = 0.9;
|
||||||
_positionWarming = 0.6;
|
Resolver._positionWarming = 0.8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
* @method preSolvePosition
|
||||||
|
* @param {pair[]} pairs
|
||||||
|
*/
|
||||||
|
Resolver.preSolvePosition = function(pairs) {
|
||||||
|
var i,
|
||||||
|
pair,
|
||||||
|
activeCount;
|
||||||
|
|
||||||
|
// find total contacts on each body
|
||||||
|
for (i = 0; i < pairs.length; i++) {
|
||||||
|
pair = pairs[i];
|
||||||
|
|
||||||
|
if (!pair.isActive)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
activeCount = pair.activeContacts.length;
|
||||||
|
pair.collision.parentA.totalContacts += activeCount;
|
||||||
|
pair.collision.parentB.totalContacts += activeCount;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description
|
* Description
|
||||||
|
@ -26,6 +49,8 @@ var Resolver = {};
|
||||||
bodyB,
|
bodyB,
|
||||||
normal,
|
normal,
|
||||||
bodyBtoA,
|
bodyBtoA,
|
||||||
|
contactShare,
|
||||||
|
contactCount = {},
|
||||||
tempA = Vector._temp[0],
|
tempA = Vector._temp[0],
|
||||||
tempB = Vector._temp[1],
|
tempB = Vector._temp[1],
|
||||||
tempC = Vector._temp[2],
|
tempC = Vector._temp[2],
|
||||||
|
@ -53,27 +78,29 @@ var Resolver = {};
|
||||||
|
|
||||||
for (i = 0; i < pairs.length; i++) {
|
for (i = 0; i < pairs.length; i++) {
|
||||||
pair = pairs[i];
|
pair = pairs[i];
|
||||||
|
|
||||||
if (!pair.isActive)
|
if (!pair.isActive || pair.separation < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
collision = pair.collision;
|
collision = pair.collision;
|
||||||
bodyA = collision.parentA;
|
bodyA = collision.parentA;
|
||||||
bodyB = collision.parentB;
|
bodyB = collision.parentB;
|
||||||
normal = collision.normal;
|
normal = collision.normal;
|
||||||
positionImpulse = ((pair.separation * _positionDampen) - pair.slop) * timeScale;
|
positionImpulse = (pair.separation - pair.slop) * timeScale;
|
||||||
|
|
||||||
if (bodyA.isStatic || bodyB.isStatic)
|
if (bodyA.isStatic || bodyB.isStatic)
|
||||||
positionImpulse *= 2;
|
positionImpulse *= 2;
|
||||||
|
|
||||||
if (!(bodyA.isStatic || bodyA.isSleeping)) {
|
if (!(bodyA.isStatic || bodyA.isSleeping)) {
|
||||||
bodyA.positionImpulse.x += normal.x * positionImpulse;
|
contactShare = Resolver._positionDampen / bodyA.totalContacts;
|
||||||
bodyA.positionImpulse.y += normal.y * positionImpulse;
|
bodyA.positionImpulse.x += normal.x * positionImpulse * contactShare;
|
||||||
|
bodyA.positionImpulse.y += normal.y * positionImpulse * contactShare;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(bodyB.isStatic || bodyB.isSleeping)) {
|
if (!(bodyB.isStatic || bodyB.isSleeping)) {
|
||||||
bodyB.positionImpulse.x -= normal.x * positionImpulse;
|
contactShare = Resolver._positionDampen / bodyB.totalContacts;
|
||||||
bodyB.positionImpulse.y -= normal.y * positionImpulse;
|
bodyB.positionImpulse.x -= normal.x * positionImpulse * contactShare;
|
||||||
|
bodyB.positionImpulse.y -= normal.y * positionImpulse * contactShare;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -87,6 +114,9 @@ var Resolver = {};
|
||||||
for (var i = 0; i < bodies.length; i++) {
|
for (var i = 0; i < bodies.length; i++) {
|
||||||
var body = bodies[i];
|
var body = bodies[i];
|
||||||
|
|
||||||
|
// reset contact count
|
||||||
|
body.totalContacts = 0;
|
||||||
|
|
||||||
if (body.positionImpulse.x !== 0 || body.positionImpulse.y !== 0) {
|
if (body.positionImpulse.x !== 0 || body.positionImpulse.y !== 0) {
|
||||||
// update body geometry
|
// update body geometry
|
||||||
for (var j = 0; j < body.parts.length; j++) {
|
for (var j = 0; j < body.parts.length; j++) {
|
||||||
|
@ -100,10 +130,16 @@ var Resolver = {};
|
||||||
// move the body without changing velocity
|
// move the body without changing velocity
|
||||||
body.positionPrev.x += body.positionImpulse.x;
|
body.positionPrev.x += body.positionImpulse.x;
|
||||||
body.positionPrev.y += body.positionImpulse.y;
|
body.positionPrev.y += body.positionImpulse.y;
|
||||||
|
|
||||||
// dampen accumulator to warm the next step
|
if (Vector.dot(body.positionImpulse, body.velocity) < 0) {
|
||||||
body.positionImpulse.x *= _positionWarming;
|
// reset cached impulse if the body has velocity along it
|
||||||
body.positionImpulse.y *= _positionWarming;
|
body.positionImpulse.x = 0;
|
||||||
|
body.positionImpulse.y = 0;
|
||||||
|
} else {
|
||||||
|
// warm the next iteration
|
||||||
|
body.positionImpulse.x *= Resolver._positionWarming;
|
||||||
|
body.positionImpulse.y *= Resolver._positionWarming;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -241,7 +277,7 @@ var Resolver = {};
|
||||||
tangentImpulse *= share;
|
tangentImpulse *= share;
|
||||||
|
|
||||||
// handle high velocity and resting collisions separately
|
// handle high velocity and resting collisions separately
|
||||||
if (normalVelocity < 0 && normalVelocity * normalVelocity > _restingThresh * timeScaleSquared) {
|
if (normalVelocity < 0 && normalVelocity * normalVelocity > Resolver._restingThresh * timeScaleSquared) {
|
||||||
// high velocity so clear cached contact impulse
|
// high velocity so clear cached contact impulse
|
||||||
contact.normalImpulse = 0;
|
contact.normalImpulse = 0;
|
||||||
contact.tangentImpulse = 0;
|
contact.tangentImpulse = 0;
|
||||||
|
|
|
@ -117,7 +117,7 @@ var SAT = {};
|
||||||
if (Vertices.contains(bodyA.vertices, verticesB[0]))
|
if (Vertices.contains(bodyA.vertices, verticesB[0]))
|
||||||
supports.push(verticesB[0]);
|
supports.push(verticesB[0]);
|
||||||
|
|
||||||
if (verticesB.length > 1 && Vertices.contains(bodyA.vertices, verticesB[1]))
|
if (Vertices.contains(bodyA.vertices, verticesB[1]))
|
||||||
supports.push(verticesB[1]);
|
supports.push(verticesB[1]);
|
||||||
|
|
||||||
// find the supports from bodyA that are inside bodyB
|
// find the supports from bodyA that are inside bodyB
|
||||||
|
@ -127,7 +127,7 @@ var SAT = {};
|
||||||
if (Vertices.contains(bodyB.vertices, verticesA[0]))
|
if (Vertices.contains(bodyB.vertices, verticesA[0]))
|
||||||
supports.push(verticesA[0]);
|
supports.push(verticesA[0]);
|
||||||
|
|
||||||
if (verticesA.length > 1 && supports.length < 2 && Vertices.contains(bodyB.vertices, verticesA[1]))
|
if (supports.length < 2 && Vertices.contains(bodyB.vertices, verticesA[1]))
|
||||||
supports.push(verticesA[1]);
|
supports.push(verticesA[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,21 +245,15 @@ var SAT = {};
|
||||||
nearestDistance = -Vector.dot(normal, vertexToBody);
|
nearestDistance = -Vector.dot(normal, vertexToBody);
|
||||||
vertexB = vertex;
|
vertexB = vertex;
|
||||||
|
|
||||||
// if the closest vertex is internal, we can't use the next connected vertex
|
var nextIndex = (vertexA.index + 1) % vertices.length;
|
||||||
if (!vertexA.isInternal) {
|
vertex = vertices[nextIndex];
|
||||||
var nextIndex = (vertexA.index + 1) % vertices.length;
|
vertexToBody.x = vertex.x - bodyAPosition.x;
|
||||||
vertex = vertices[nextIndex];
|
vertexToBody.y = vertex.y - bodyAPosition.y;
|
||||||
vertexToBody.x = vertex.x - bodyAPosition.x;
|
distance = -Vector.dot(normal, vertexToBody);
|
||||||
vertexToBody.y = vertex.y - bodyAPosition.y;
|
if (distance < nearestDistance) {
|
||||||
distance = -Vector.dot(normal, vertexToBody);
|
vertexB = vertex;
|
||||||
if (distance < nearestDistance) {
|
|
||||||
vertexB = vertex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vertexB)
|
|
||||||
return [vertexA];
|
|
||||||
|
|
||||||
return [vertexA, vertexB];
|
return [vertexA, vertexB];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -160,17 +160,18 @@ var Engine = {};
|
||||||
if (pairs.collisionStart.length > 0)
|
if (pairs.collisionStart.length > 0)
|
||||||
Events.trigger(engine, 'collisionStart', { pairs: pairs.collisionStart });
|
Events.trigger(engine, 'collisionStart', { pairs: pairs.collisionStart });
|
||||||
|
|
||||||
|
// iteratively resolve position between collisions
|
||||||
|
Resolver.preSolvePosition(pairs.list);
|
||||||
|
for (i = 0; i < engine.positionIterations; i++) {
|
||||||
|
Resolver.solvePosition(pairs.list, timing.timeScale);
|
||||||
|
}
|
||||||
|
Resolver.postSolvePosition(allBodies);
|
||||||
|
|
||||||
// iteratively resolve velocity between collisions
|
// iteratively resolve velocity between collisions
|
||||||
Resolver.preSolveVelocity(pairs.list);
|
Resolver.preSolveVelocity(pairs.list);
|
||||||
for (i = 0; i < engine.velocityIterations; i++) {
|
for (i = 0; i < engine.velocityIterations; i++) {
|
||||||
Resolver.solveVelocity(pairs.list, timing.timeScale);
|
Resolver.solveVelocity(pairs.list, timing.timeScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
// iteratively resolve position between collisions
|
|
||||||
for (i = 0; i < engine.positionIterations; i++) {
|
|
||||||
Resolver.solvePosition(pairs.list, timing.timeScale);
|
|
||||||
}
|
|
||||||
Resolver.postSolvePosition(allBodies);
|
|
||||||
|
|
||||||
// trigger collision events
|
// trigger collision events
|
||||||
if (pairs.collisionActive.length > 0)
|
if (pairs.collisionActive.length > 0)
|
||||||
|
|
|
@ -19,11 +19,6 @@ var Axes = {};
|
||||||
|
|
||||||
// find the unique axes, using edge normal gradients
|
// find the unique axes, using edge normal gradients
|
||||||
for (var i = 0; i < vertices.length; i++) {
|
for (var i = 0; i < vertices.length; i++) {
|
||||||
// skip internal edges
|
|
||||||
if (vertices[i].isInternal) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var j = (i + 1) % vertices.length,
|
var j = (i + 1) % vertices.length,
|
||||||
normal = Vector.normalise({
|
normal = Vector.normalise({
|
||||||
x: vertices[j].y - vertices[i].y,
|
x: vertices[j].y - vertices[i].y,
|
||||||
|
@ -33,7 +28,6 @@ var Axes = {};
|
||||||
|
|
||||||
// limit precision
|
// limit precision
|
||||||
gradient = gradient.toFixed(3).toString();
|
gradient = gradient.toFixed(3).toString();
|
||||||
|
|
||||||
axes[gradient] = normal;
|
axes[gradient] = normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue