0
0
Fork 0
mirror of https://github.com/liabru/matter-js.git synced 2025-01-12 16:08:50 -05:00

initial work on compound bodies

This commit is contained in:
liabru 2015-01-29 23:25:58 +00:00
parent b3921fb72e
commit 243fce47c9
9 changed files with 245 additions and 40 deletions

View file

@ -30,6 +30,7 @@
<div class="controls-container">
<select id="demo-select">
<option value="mixed">Mixed Shapes</option>
<option value="concave">Concave Shapes</option>
<option value="mixedSolid">Solid Rendering</option>
<option value="newtonsCradle">Newton's Cradle</option>
<option value="wreckingBall">Wrecking Ball</option>

View file

@ -117,6 +117,54 @@
var renderOptions = _engine.render.options;
};
Demo.concave = function() {
var _world = _engine.world;
Demo.reset();
var s = 50;
//var vertices = [{ x: 0, y: 0 }, { x: 0, y: 2 * s },
// { x: 1 * s, y: 2 * s }, { x: 1 * s, y: 1 * s },
// { x: 2 * s, y: 1 * s }, { x: 2 * s, y: 0 }];
//var vertices = Matter.Vertices.fromPath('-5 78,70 126,57 195,114 139,191 201,161 136,217 83,151 83,122 -1,82 85');
var partA = Bodies.rectangle(200, 200, 200, 20);
var partB = Bodies.rectangle(200, 200, 20, 200);
var middle = Bodies.rectangle(200, 200, 20, 20);
//var parent = Bodies.rectangle(200, 200, 200, 200);
var vertices = Matter.Vertices.create(partA.vertices.concat(partB.vertices.concat(middle.vertices)), true);
Matter.Vertices.clockwiseSort(vertices);
//debugger;
var hull = Matter.Vertices.hull(vertices);
console.log(vertices);
console.log(hull);
var parent = Body.create({
position: { x: 200, y: 200 },
vertices: hull
});
//debugger;
partA.parent = parent;
partB.parent = parent;
parent.parts = [parent, partA, partB];
World.add(_world, parent);
_world.gravity.y = 0;
var renderOptions = _engine.render.options;
renderOptions.showCollisions = true;
renderOptions.showBounds = true;
};
Demo.slingshot = function() {
var _world = _engine.world;

View file

@ -116,7 +116,8 @@ var Body = {};
anglePrev: body.anglePrev || body.angle,
vertices: body.vertices,
isStatic: body.isStatic,
isSleeping: body.isSleeping
isSleeping: body.isSleeping,
parts: body.parts || [body]
});
Vertices.rotate(body.vertices, body.angle, body.position);
@ -313,6 +314,8 @@ var Body = {};
Vertices.translate(body.vertices, delta);
Bounds.update(body.bounds, body.vertices, body.velocity);
//Common.each(body.children, Body.setPosition, position);
};
/**
@ -330,6 +333,8 @@ var Body = {};
Vertices.rotate(body.vertices, delta, body.position);
Axes.rotate(body.axes, delta);
Bounds.update(body.bounds, body.vertices, body.velocity);
//Common.each(body.children, Body.setAngle, angle);
};
/**
@ -439,12 +444,15 @@ var Body = {};
body.angularSpeed = Math.abs(body.angularVelocity);
// transform the body geometry
Vertices.translate(body.vertices, body.velocity);
if (body.angularVelocity !== 0) {
Vertices.rotate(body.vertices, body.angularVelocity, body.position);
Axes.rotate(body.axes, body.angularVelocity);
for (var i = 0; i < body.parts.length; i++) {
var part = body.parts[i];
Vertices.translate(part.vertices, body.velocity);
if (body.angularVelocity !== 0) {
Vertices.rotate(part.vertices, body.angularVelocity, body.position);
Axes.rotate(part.axes, body.angularVelocity);
}
Bounds.update(part.bounds, body.vertices, body.velocity);
}
Bounds.update(body.bounds, body.vertices, body.velocity);
};
/**

View file

@ -41,33 +41,43 @@ var Detector = {};
// mid phase
if (Bounds.overlaps(bodyA.bounds, bodyB.bounds)) {
/*for (var j = 1; j < bodyA.parts.length; j++) {
var partA = bodyA.parts[j];
// find a previous collision we could reuse
var pairId = Pair.id(bodyA, bodyB),
pair = pairsTable[pairId],
previousCollision;
for (var k = 1; k < bodyB.parts.length; k++) {
var partB = bodyB.parts[k];
if (pair && pair.isActive) {
previousCollision = pair.collision;
} else {
previousCollision = null;
}
if (Bounds.overlaps(partA.bounds, partB.bounds)) {*/
// narrow phase
var collision = SAT.collides(bodyA, bodyB, previousCollision);
// find a previous collision we could reuse
var pairId = Pair.id(bodyA, bodyB),
pair = pairsTable[pairId],
previousCollision;
// @if DEBUG
metrics.narrowphaseTests += 1;
if (collision.reused)
metrics.narrowReuseCount += 1;
// @endif
if (pair && pair.isActive) {
previousCollision = pair.collision;
} else {
previousCollision = null;
}
if (collision.collided) {
collisions.push(collision);
// @if DEBUG
metrics.narrowDetections += 1;
// @endif
}
// narrow phase
var collision = SAT.collides(bodyA, bodyB, previousCollision);
// @if DEBUG
metrics.narrowphaseTests += 1;
if (collision.reused)
metrics.narrowReuseCount += 1;
// @endif
if (collision.collided) {
collisions.push(collision);
// @if DEBUG
metrics.narrowDetections += 1;
// @endif
}
//}
//}
//}
}
}

View file

@ -98,8 +98,11 @@ var Resolver = {};
body.positionPrev.y += body.positionImpulse.y;
// update body geometry
Vertices.translate(body.vertices, body.positionImpulse);
Bounds.update(body.bounds, body.vertices, body.velocity);
for (var j = 0; j < body.parts.length; j++) {
var part = body.parts[j];
Vertices.translate(part.vertices, body.positionImpulse);
Bounds.update(part.bounds, body.vertices, body.velocity);
}
// dampen accumulator to warm the next step
body.positionImpulse.x *= _positionWarming;

View file

@ -249,16 +249,19 @@ var Constraint = {};
impulse = body.constraintImpulse;
// update geometry and reset
Vertices.translate(body.vertices, impulse);
for (var j = 0; j < body.parts.length; j++) {
var part = body.parts[j];
Vertices.translate(part.vertices, impulse);
if (impulse.angle !== 0) {
Vertices.rotate(body.vertices, impulse.angle, body.position);
Axes.rotate(body.axes, impulse.angle);
impulse.angle = 0;
if (impulse.angle !== 0) {
Vertices.rotate(part.vertices, impulse.angle, body.position);
Axes.rotate(part.axes, impulse.angle);
impulse.angle = 0;
}
Bounds.update(part.bounds, body.vertices);
}
Bounds.update(body.bounds, body.vertices);
impulse.x = 0;
impulse.y = 0;
}

View file

@ -122,6 +122,18 @@ var Vector = {};
return (vectorA.x * vectorB.y) - (vectorA.y * vectorB.x);
};
/**
* Returns the cross-product of three vectors.
* @method cross3
* @param {vector} vectorA
* @param {vector} vectorB
* @param {vector} vectorC
* @return {number} The cross product of the three vectors
*/
Vector.cross3 = function(vectorA, vectorB, vectorC) {
return (vectorB.x - vectorA.x) * (vectorC.y - vectorA.y) - (vectorB.y - vectorA.y) * (vectorC.x - vectorA.x);
};
/**
* Adds the two vectors.
* @method add

View file

@ -89,6 +89,23 @@ var Vertices = {};
return Vector.div(centre, 6 * area);
};
/**
* Returns the average (mean) of the set of vertices.
* @method mean
* @param {vertices} vertices
* @return {vector} The average point
*/
Vertices.mean = function(vertices) {
var average = { x: 0, y: 0 };
for (var i = 0; i < vertices.length; i++) {
average.x += vertices[i].x;
average.y += vertices[i].y;
}
return Vector.div(average, vertices.length);
};
/**
* Returns the area of the set of vertices.
* @method area
@ -306,4 +323,73 @@ var Vertices = {};
return newVertices;
};
/**
* Sorts the input vertices into clockwise order in place.
* @method clockwiseSort
* @param {vertices} vertices
* @return {vertices} vertices
*/
Vertices.clockwiseSort = function(vertices) {
var mean = Vertices.mean(vertices);
vertices.sort(function(vertexA, vertexB) {
return Vector.angle(mean, vertexA) - Vector.angle(mean, vertexB);
});
return vertices;
}
/**
* Returns the convex hull of the input vertices as a new array of points.
* @method hull
* @param {vertices} vertices
* @return [vertex] vertices
*/
Vertices.hull = function(vertices) {
// http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
var upper = [],
lower = [],
vertex,
i;
// sort vertices on x-axis (y-axis for ties)
vertices = vertices.slice(0);
vertices.sort(function(vertexA, vertexB) {
var dx = vertexA.x - vertexB.x;
return dx !== 0 ? dx : vertexA.y - vertexB.y;
});
// build lower hull
for (i = 0; i < vertices.length; i++) {
vertex = vertices[i];
while (lower.length >= 2
&& Vector.cross3(lower[lower.length - 2], lower[lower.length - 1], vertex) <= 0) {
lower.pop();
}
lower.push(vertex);
}
// build upper hull
for (i = vertices.length - 1; i >= 0; i--) {
vertex = vertices[i];
while (upper.length >= 2
&& Vector.cross3(upper[upper.length - 2], upper[upper.length - 1], vertex) <= 0) {
upper.pop();
}
upper.push(vertex);
}
// concatenation of the lower and upper hulls gives the convex hull
// omit last points because they are repeated at the beginning of the other list
upper.pop();
lower.pop();
return upper.concat(lower);
};
})();

View file

@ -448,14 +448,15 @@ var Render = {};
Render.bodyWireframes = function(engine, bodies, context) {
var c = context,
i,
j;
j,
k;
c.beginPath();
for (i = 0; i < bodies.length; i++) {
var body = bodies[i];
if (!body.render.visible)
if (!body.render.visible || body.parts.length === 1)
continue;
c.moveTo(body.vertices[0].x, body.vertices[0].y);
@ -467,6 +468,39 @@ var Render = {};
c.lineTo(body.vertices[0].x, body.vertices[0].y);
}
c.lineWidth = 1;
c.strokeStyle = '#9E9277';
c.stroke();
for (i = 0; i < bodies.length; i++) {
var body = bodies[i];
for (j = 0; j < body.vertices.length; j++) {
c.fillStyle = 'yellow';
c.fillText(j, body.vertices[j].x, body.vertices[j].y + 10);
}
}
c.beginPath();
for (i = 0; i < bodies.length; i++) {
var body = bodies[i];
if (!body.render.visible)
continue;
for (k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) {
var part = body.parts[k];
c.moveTo(part.vertices[0].x, part.vertices[0].y);
for (j = 1; j < part.vertices.length; j++) {
c.lineTo(part.vertices[j].x, part.vertices[j].y);
}
c.lineTo(part.vertices[0].x, part.vertices[0].y);
}
}
c.lineWidth = 1;
c.strokeStyle = '#bbb';
c.stroke();