diff --git a/src/body/Body.js b/src/body/Body.js index 14ec51f..f6173b2 100644 --- a/src/body/Body.js +++ b/src/body/Body.js @@ -117,6 +117,7 @@ var Body = {}; vertices: body.vertices, isStatic: body.isStatic, isSleeping: body.isSleeping, + parent: body.parent || body, parts: body.parts || [body] }); @@ -194,6 +195,9 @@ var Body = {}; case 'angularVelocity': Body.setAngularVelocity(body, value); break; + case 'parts': + Body.setParts(body, value); + break; default: body[property] = value; @@ -298,6 +302,78 @@ var Body = {}; Bounds.update(body.bounds, body.vertices, body.velocity); }; + /** + * Sets the parts of the `body` and updates mass, inertia and centroid. + * Each part will have its parent set to `body`. + * By default the convex hull will be automatically computed and set on `body`, unless `autoHull` is set to `false.` + * Note that this method will ensure that the first part in `body.parts` will always be the `body`. + * @method setParts + * @param {body} body + * @param [body] parts + * @param {bool} [autoHull=true] + */ + Body.setParts = function(body, parts, autoHull) { + autoHull = typeof autoHull !== 'undefined' ? autoHull : true; + + // ensure the body is always at index 0 + var index = Common.indexOf(parts, body); + if (index > -1) { + parts.splice(index, 1); + } + + parts.unshift(body); + body.parts = parts; + + if (parts.length === 1) + return; + + var i; + + // find the convex hull of all parts to set on the parent body + if (autoHull) { + var vertices = []; + for (i = 1; i < parts.length; i++) { + vertices = vertices.concat(parts[i].vertices); + } + + Vertices.clockwiseSort(vertices); + + var hull = Vertices.hull(vertices), + hullCentre = Vertices.centre(hull); + + Body.setVertices(body, hull); + Body.setPosition(body, hullCentre); + } + + // find the combined properties of all parts to set on the parent body + var mass = 0, + area = 0, + inertia = 0, + centroid = { x: 0, y: 0 }; + + for (i = 1; i < parts.length; i++) { + var part = parts[i]; + part.parent = body; + mass += part.mass; + area += part.area; + inertia += part.inertia; + Vector.add(centroid, part.position, centroid); + } + + centroid = Vector.div(centroid, parts.length - 1); + + body.area = area; + body.parent = body; + body.position.x = centroid.x; + body.position.y = centroid.y; + body.positionPrev.x = centroid.x; + body.positionPrev.y = centroid.y; + + Body.setMass(body, mass); + Body.setInertia(body, inertia); + Body.setPosition(body, centroid); + }; + /** * Sets the position of the body instantly. Velocity, angle, force etc. are unchanged. * @method setPosition @@ -314,8 +390,6 @@ var Body = {}; Vertices.translate(body.vertices, delta); Bounds.update(body.bounds, body.vertices, body.velocity); - - //Common.each(body.children, Body.setPosition, position); }; /** @@ -333,8 +407,6 @@ 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); }; /** @@ -452,6 +524,10 @@ var Body = {}; Axes.rotate(part.axes, body.angularVelocity); } Bounds.update(part.bounds, body.vertices, body.velocity); + if (i > 0) { + part.position.x += body.velocity.x; + part.position.y += body.velocity.y; + } } }; diff --git a/src/collision/Detector.js b/src/collision/Detector.js index 701aec8..ef1150d 100644 --- a/src/collision/Detector.js +++ b/src/collision/Detector.js @@ -41,16 +41,15 @@ var Detector = {}; // mid phase if (Bounds.overlaps(bodyA.bounds, bodyB.bounds)) { - /*for (var j = 1; j < bodyA.parts.length; j++) { + for (var j = bodyA.parts.length > 1 ? 1 : 0; j < bodyA.parts.length; j++) { var partA = bodyA.parts[j]; - for (var k = 1; k < bodyB.parts.length; k++) { + for (var k = bodyB.parts.length > 1 ? 1 : 0; k < bodyB.parts.length; k++) { var partB = bodyB.parts[k]; - if (Bounds.overlaps(partA.bounds, partB.bounds)) {*/ - + if ((partA === bodyA && partB === bodyB) || Bounds.overlaps(partA.bounds, partB.bounds)) { // find a previous collision we could reuse - var pairId = Pair.id(bodyA, bodyB), + var pairId = Pair.id(partA, partB), pair = pairsTable[pairId], previousCollision; @@ -61,7 +60,7 @@ var Detector = {}; } // narrow phase - var collision = SAT.collides(bodyA, bodyB, previousCollision); + var collision = SAT.collides(partA, partB, previousCollision); // @if DEBUG metrics.narrowphaseTests += 1; @@ -75,9 +74,9 @@ var Detector = {}; metrics.narrowDetections += 1; // @endif } - //} - //} - //} + } + } + } } } diff --git a/src/collision/Resolver.js b/src/collision/Resolver.js index 9be4543..beb0e73 100644 --- a/src/collision/Resolver.js +++ b/src/collision/Resolver.js @@ -40,8 +40,8 @@ var Resolver = {}; continue; collision = pair.collision; - bodyA = collision.bodyA; - bodyB = collision.bodyB; + bodyA = collision.parentA; + bodyB = collision.parentB; vertex = collision.supports[0]; vertexCorrected = collision.supportCorrected; normal = collision.normal; @@ -61,8 +61,8 @@ var Resolver = {}; continue; collision = pair.collision; - bodyA = collision.bodyA; - bodyB = collision.bodyB; + bodyA = collision.parentA; + bodyB = collision.parentB; normal = collision.normal; positionImpulse = ((pair.separation * _positionDampen) - pair.slop) * timeScale; @@ -102,6 +102,10 @@ var Resolver = {}; var part = body.parts[j]; Vertices.translate(part.vertices, body.positionImpulse); Bounds.update(part.bounds, body.vertices, body.velocity); + if (j > 0) { + part.position.x += body.positionImpulse.x; + part.position.y += body.positionImpulse.y; + } } // dampen accumulator to warm the next step @@ -142,8 +146,8 @@ var Resolver = {}; contacts = pair.activeContacts; collision = pair.collision; - bodyA = collision.bodyA; - bodyB = collision.bodyB; + bodyA = collision.parentA; + bodyB = collision.parentB; normal = collision.normal; tangent = collision.tangent; @@ -197,8 +201,8 @@ var Resolver = {}; continue; var collision = pair.collision, - bodyA = collision.bodyA, - bodyB = collision.bodyB, + bodyA = collision.parentA, + bodyB = collision.parentB, normal = collision.normal, tangent = collision.tangent, contacts = pair.activeContacts, diff --git a/src/collision/SAT.js b/src/collision/SAT.js index ff39422..c660412 100644 --- a/src/collision/SAT.js +++ b/src/collision/SAT.js @@ -87,6 +87,8 @@ var SAT = {}; collision.collided = true; collision.normal = minOverlap.axis; collision.depth = minOverlap.overlap; + collision.parentA = collision.bodyA.parent; + collision.parentB = collision.bodyB.parent; bodyA = collision.bodyA; bodyB = collision.bodyB; diff --git a/src/constraint/Constraint.js b/src/constraint/Constraint.js index 3a8371e..4ca596d 100644 --- a/src/constraint/Constraint.js +++ b/src/constraint/Constraint.js @@ -260,6 +260,11 @@ var Constraint = {}; } Bounds.update(part.bounds, body.vertices); + + if (j > 0) { + part.position.x += impulse.x; + part.position.y += impulse.y; + } } impulse.x = 0; diff --git a/src/geometry/Vertices.js b/src/geometry/Vertices.js index ff84fd3..bfa7cf5 100644 --- a/src/geometry/Vertices.js +++ b/src/geometry/Vertices.js @@ -337,7 +337,7 @@ var Vertices = {}; }); return vertices; - } + }; /** * Returns the convex hull of the input vertices as a new array of points.