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:
parent
b3921fb72e
commit
243fce47c9
9 changed files with 245 additions and 40 deletions
|
@ -30,6 +30,7 @@
|
||||||
<div class="controls-container">
|
<div class="controls-container">
|
||||||
<select id="demo-select">
|
<select id="demo-select">
|
||||||
<option value="mixed">Mixed Shapes</option>
|
<option value="mixed">Mixed Shapes</option>
|
||||||
|
<option value="concave">Concave Shapes</option>
|
||||||
<option value="mixedSolid">Solid Rendering</option>
|
<option value="mixedSolid">Solid Rendering</option>
|
||||||
<option value="newtonsCradle">Newton's Cradle</option>
|
<option value="newtonsCradle">Newton's Cradle</option>
|
||||||
<option value="wreckingBall">Wrecking Ball</option>
|
<option value="wreckingBall">Wrecking Ball</option>
|
||||||
|
|
|
@ -114,7 +114,55 @@
|
||||||
|
|
||||||
World.add(_world, stack);
|
World.add(_world, stack);
|
||||||
|
|
||||||
var renderOptions = _engine.render.options;
|
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() {
|
Demo.slingshot = function() {
|
||||||
|
|
|
@ -116,7 +116,8 @@ var Body = {};
|
||||||
anglePrev: body.anglePrev || body.angle,
|
anglePrev: body.anglePrev || body.angle,
|
||||||
vertices: body.vertices,
|
vertices: body.vertices,
|
||||||
isStatic: body.isStatic,
|
isStatic: body.isStatic,
|
||||||
isSleeping: body.isSleeping
|
isSleeping: body.isSleeping,
|
||||||
|
parts: body.parts || [body]
|
||||||
});
|
});
|
||||||
|
|
||||||
Vertices.rotate(body.vertices, body.angle, body.position);
|
Vertices.rotate(body.vertices, body.angle, body.position);
|
||||||
|
@ -313,6 +314,8 @@ var Body = {};
|
||||||
|
|
||||||
Vertices.translate(body.vertices, delta);
|
Vertices.translate(body.vertices, delta);
|
||||||
Bounds.update(body.bounds, body.vertices, body.velocity);
|
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);
|
Vertices.rotate(body.vertices, delta, body.position);
|
||||||
Axes.rotate(body.axes, delta);
|
Axes.rotate(body.axes, delta);
|
||||||
Bounds.update(body.bounds, body.vertices, body.velocity);
|
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);
|
body.angularSpeed = Math.abs(body.angularVelocity);
|
||||||
|
|
||||||
// transform the body geometry
|
// transform the body geometry
|
||||||
Vertices.translate(body.vertices, body.velocity);
|
for (var i = 0; i < body.parts.length; i++) {
|
||||||
if (body.angularVelocity !== 0) {
|
var part = body.parts[i];
|
||||||
Vertices.rotate(body.vertices, body.angularVelocity, body.position);
|
Vertices.translate(part.vertices, body.velocity);
|
||||||
Axes.rotate(body.axes, body.angularVelocity);
|
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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -41,33 +41,43 @@ var Detector = {};
|
||||||
|
|
||||||
// mid phase
|
// mid phase
|
||||||
if (Bounds.overlaps(bodyA.bounds, bodyB.bounds)) {
|
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
|
for (var k = 1; k < bodyB.parts.length; k++) {
|
||||||
var pairId = Pair.id(bodyA, bodyB),
|
var partB = bodyB.parts[k];
|
||||||
pair = pairsTable[pairId],
|
|
||||||
previousCollision;
|
|
||||||
|
|
||||||
if (pair && pair.isActive) {
|
if (Bounds.overlaps(partA.bounds, partB.bounds)) {*/
|
||||||
previousCollision = pair.collision;
|
|
||||||
} else {
|
|
||||||
previousCollision = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// narrow phase
|
// find a previous collision we could reuse
|
||||||
var collision = SAT.collides(bodyA, bodyB, previousCollision);
|
var pairId = Pair.id(bodyA, bodyB),
|
||||||
|
pair = pairsTable[pairId],
|
||||||
|
previousCollision;
|
||||||
|
|
||||||
// @if DEBUG
|
if (pair && pair.isActive) {
|
||||||
metrics.narrowphaseTests += 1;
|
previousCollision = pair.collision;
|
||||||
if (collision.reused)
|
} else {
|
||||||
metrics.narrowReuseCount += 1;
|
previousCollision = null;
|
||||||
// @endif
|
}
|
||||||
|
|
||||||
if (collision.collided) {
|
// narrow phase
|
||||||
collisions.push(collision);
|
var collision = SAT.collides(bodyA, bodyB, previousCollision);
|
||||||
// @if DEBUG
|
|
||||||
metrics.narrowDetections += 1;
|
// @if DEBUG
|
||||||
// @endif
|
metrics.narrowphaseTests += 1;
|
||||||
}
|
if (collision.reused)
|
||||||
|
metrics.narrowReuseCount += 1;
|
||||||
|
// @endif
|
||||||
|
|
||||||
|
if (collision.collided) {
|
||||||
|
collisions.push(collision);
|
||||||
|
// @if DEBUG
|
||||||
|
metrics.narrowDetections += 1;
|
||||||
|
// @endif
|
||||||
|
}
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,8 +98,11 @@ var Resolver = {};
|
||||||
body.positionPrev.y += body.positionImpulse.y;
|
body.positionPrev.y += body.positionImpulse.y;
|
||||||
|
|
||||||
// update body geometry
|
// update body geometry
|
||||||
Vertices.translate(body.vertices, body.positionImpulse);
|
for (var j = 0; j < body.parts.length; j++) {
|
||||||
Bounds.update(body.bounds, body.vertices, body.velocity);
|
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
|
// dampen accumulator to warm the next step
|
||||||
body.positionImpulse.x *= _positionWarming;
|
body.positionImpulse.x *= _positionWarming;
|
||||||
|
|
|
@ -249,16 +249,19 @@ var Constraint = {};
|
||||||
impulse = body.constraintImpulse;
|
impulse = body.constraintImpulse;
|
||||||
|
|
||||||
// update geometry and reset
|
// 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) {
|
if (impulse.angle !== 0) {
|
||||||
Vertices.rotate(body.vertices, impulse.angle, body.position);
|
Vertices.rotate(part.vertices, impulse.angle, body.position);
|
||||||
Axes.rotate(body.axes, impulse.angle);
|
Axes.rotate(part.axes, impulse.angle);
|
||||||
impulse.angle = 0;
|
impulse.angle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bounds.update(part.bounds, body.vertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bounds.update(body.bounds, body.vertices);
|
|
||||||
|
|
||||||
impulse.x = 0;
|
impulse.x = 0;
|
||||||
impulse.y = 0;
|
impulse.y = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,6 +122,18 @@ var Vector = {};
|
||||||
return (vectorA.x * vectorB.y) - (vectorA.y * vectorB.x);
|
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.
|
* Adds the two vectors.
|
||||||
* @method add
|
* @method add
|
||||||
|
|
|
@ -89,6 +89,23 @@ var Vertices = {};
|
||||||
return Vector.div(centre, 6 * area);
|
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.
|
* Returns the area of the set of vertices.
|
||||||
* @method area
|
* @method area
|
||||||
|
@ -306,4 +323,73 @@ var Vertices = {};
|
||||||
return newVertices;
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -448,14 +448,15 @@ var Render = {};
|
||||||
Render.bodyWireframes = function(engine, bodies, context) {
|
Render.bodyWireframes = function(engine, bodies, context) {
|
||||||
var c = context,
|
var c = context,
|
||||||
i,
|
i,
|
||||||
j;
|
j,
|
||||||
|
k;
|
||||||
|
|
||||||
c.beginPath();
|
c.beginPath();
|
||||||
|
|
||||||
for (i = 0; i < bodies.length; i++) {
|
for (i = 0; i < bodies.length; i++) {
|
||||||
var body = bodies[i];
|
var body = bodies[i];
|
||||||
|
|
||||||
if (!body.render.visible)
|
if (!body.render.visible || body.parts.length === 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
c.moveTo(body.vertices[0].x, body.vertices[0].y);
|
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.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.lineWidth = 1;
|
||||||
c.strokeStyle = '#bbb';
|
c.strokeStyle = '#bbb';
|
||||||
c.stroke();
|
c.stroke();
|
||||||
|
|
Loading…
Reference in a new issue