From 59d62be8995b143f2d847368ee3614701c4ba2d1 Mon Sep 17 00:00:00 2001 From: liabru Date: Tue, 25 Apr 2017 23:43:29 +0100 Subject: [PATCH 01/31] added optional output argument to Vector.rotate --- src/geometry/Vector.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/geometry/Vector.js b/src/geometry/Vector.js index 0eaacdf..bfc512d 100644 --- a/src/geometry/Vector.js +++ b/src/geometry/Vector.js @@ -62,14 +62,16 @@ module.exports = Vector; * @method rotate * @param {vector} vector * @param {number} angle - * @return {vector} A new vector rotated about (0, 0) + * @param {vector} [output] + * @return {vector} The vector rotated about (0, 0) */ - Vector.rotate = function(vector, angle) { + Vector.rotate = function(vector, angle, output) { var cos = Math.cos(angle), sin = Math.sin(angle); - return { - x: vector.x * cos - vector.y * sin, - y: vector.x * sin + vector.y * cos - }; + if (!output) output = {}; + var x = vector.x * cos - vector.y * sin; + output.y = vector.x * sin + vector.y * cos; + output.x = x; + return output; }; /** From 26a60e4dcf50c12f758f65ba84574f31065c1f44 Mon Sep 17 00:00:00 2001 From: liabru Date: Tue, 25 Apr 2017 23:47:49 +0100 Subject: [PATCH 02/31] fixed various problems with constraints --- src/constraint/Constraint.js | 150 +++++++++++++++-------------------- 1 file changed, 62 insertions(+), 88 deletions(-) diff --git a/src/constraint/Constraint.js b/src/constraint/Constraint.js index 5ba2717..730e2f0 100644 --- a/src/constraint/Constraint.js +++ b/src/constraint/Constraint.js @@ -8,14 +8,6 @@ * @class Constraint */ -// TODO: fix instability issues with torque -// TODO: linked constraints -// TODO: breakable constraints -// TODO: collision constraints -// TODO: allow constrained bodies to sleep -// TODO: handle 0 length constraints properly -// TODO: impulse caching and warming - var Constraint = {}; module.exports = Constraint; @@ -29,8 +21,10 @@ var Common = require('../core/Common'); (function() { - var _minLength = 0.000001, - _minDifference = 0.001; + var _zeroVector = { x: 0, y: 0 }; + + Constraint._warming = 0.4; + Constraint._minLength = 0.000001; /** * Creates a new constraint. @@ -54,7 +48,7 @@ var Common = require('../core/Common'); initialPointB = constraint.bodyB ? Vector.add(constraint.bodyB.position, constraint.pointB) : constraint.pointB, length = Vector.magnitude(Vector.sub(initialPointA, initialPointB)); - constraint.length = constraint.length || length || _minLength; + constraint.length = typeof constraint.length !== 'undefined' ? constraint.length : length; // render var render = { @@ -106,13 +100,13 @@ var Common = require('../core/Common'); // update reference angle if (bodyA && !bodyA.isStatic) { - constraint.pointA = Vector.rotate(pointA, bodyA.angle - constraint.angleA); + Vector.rotate(pointA, bodyA.angle - constraint.angleA, pointA); constraint.angleA = bodyA.angle; } // update reference angle if (bodyB && !bodyB.isStatic) { - constraint.pointB = Vector.rotate(pointB, bodyB.angle - constraint.angleB); + Vector.rotate(pointB, bodyB.angle - constraint.angleB, pointB); constraint.angleB = bodyB.angle; } @@ -125,111 +119,91 @@ var Common = require('../core/Common'); if (!pointAWorld || !pointBWorld) return; - var delta = Vector.sub(pointAWorld, pointBWorld), - currentLength = Vector.magnitude(delta); - - // prevent singularity - if (currentLength === 0) - currentLength = _minLength; - - // solve distance constraint with Gauss-Siedel method - var difference = (currentLength - constraint.length) / currentLength, - normal = Vector.div(delta, currentLength), - force = Vector.mult(delta, difference * 0.5 * constraint.stiffness * timeScale * timeScale); - - // if difference is very small, we can skip - if (Math.abs(1 - (currentLength / constraint.length)) < _minDifference * timeScale) - return; - - var velocityPointA, - velocityPointB, - offsetA, - offsetB, - oAn, - oBn, - bodyADenom, - bodyBDenom; + var velocityPointA = _zeroVector, + velocityPointB = _zeroVector; if (bodyA && !bodyA.isStatic) { - // point body offset - offsetA = { - x: pointAWorld.x - bodyA.position.x + force.x, - y: pointAWorld.y - bodyA.position.y + force.y - }; - // update velocity bodyA.velocity.x = bodyA.position.x - bodyA.positionPrev.x; bodyA.velocity.y = bodyA.position.y - bodyA.positionPrev.y; bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev; // find point velocity and body mass - velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(offsetA), bodyA.angularVelocity)); - oAn = Vector.dot(offsetA, normal); - bodyADenom = bodyA.inverseMass + bodyA.inverseInertia * oAn * oAn; - } else { - velocityPointA = { x: 0, y: 0 }; - bodyADenom = bodyA ? bodyA.inverseMass : 0; + velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(pointA), bodyA.angularVelocity)); } if (bodyB && !bodyB.isStatic) { - // point body offset - offsetB = { - x: pointBWorld.x - bodyB.position.x - force.x, - y: pointBWorld.y - bodyB.position.y - force.y - }; - // update velocity bodyB.velocity.x = bodyB.position.x - bodyB.positionPrev.x; bodyB.velocity.y = bodyB.position.y - bodyB.positionPrev.y; bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev; // find point velocity and body mass - velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(offsetB), bodyB.angularVelocity)); - oBn = Vector.dot(offsetB, normal); - bodyBDenom = bodyB.inverseMass + bodyB.inverseInertia * oBn * oBn; - } else { - velocityPointB = { x: 0, y: 0 }; - bodyBDenom = bodyB ? bodyB.inverseMass : 0; + velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(pointB), bodyB.angularVelocity)); + } + + var delta = Vector.sub(pointAWorld, pointBWorld), + currentLength = Vector.magnitude(delta); + + // prevent singularity + if (currentLength === 0) { + currentLength = Constraint._minLength; + delta.x = Constraint._minLength; + } + + // solve distance constraint with Gauss-Siedel method + var difference = (currentLength - constraint.length) / currentLength, + normal = Vector.div(delta, currentLength), + force = Vector.mult(delta, difference * constraint.stiffness * timeScale * timeScale), + relativeVelocity = Vector.sub(velocityPointB, velocityPointA), + massTotal = (bodyA ? bodyA.inverseMass : 0) + (bodyB ? bodyB.inverseMass : 0), + inertiaTotal = (bodyA ? bodyA.inverseInertia : 0) + (bodyB ? bodyB.inverseInertia : 0), + normalImpulse = Vector.dot(normal, relativeVelocity) / (massTotal + inertiaTotal), + normalVelocity, + torque, + share; + + if (normalImpulse < 0) { + normalVelocity = { + x: normal.x * normalImpulse, + y: normal.y * normalImpulse + }; } - - var relativeVelocity = Vector.sub(velocityPointB, velocityPointA), - normalImpulse = Vector.dot(normal, relativeVelocity) / (bodyADenom + bodyBDenom); - - if (normalImpulse > 0) normalImpulse = 0; - - var normalVelocity = { - x: normal.x * normalImpulse, - y: normal.y * normalImpulse - }; - var torque; - if (bodyA && !bodyA.isStatic) { - torque = Vector.cross(offsetA, normalVelocity) * bodyA.inverseInertia * (1 - constraint.angularStiffness); + share = bodyA.inverseMass / massTotal; // keep track of applied impulses for post solving - bodyA.constraintImpulse.x -= force.x; - bodyA.constraintImpulse.y -= force.y; - bodyA.constraintImpulse.angle += torque; + bodyA.constraintImpulse.x -= force.x * share; + bodyA.constraintImpulse.y -= force.y * share; // apply forces - bodyA.position.x -= force.x; - bodyA.position.y -= force.y; - bodyA.angle += torque; + bodyA.position.x -= force.x * share; + bodyA.position.y -= force.y * share; + + if (normalVelocity) { + torque = Vector.cross(pointA, normalVelocity) * bodyA.inverseInertia * (1 - constraint.angularStiffness); + bodyA.constraintImpulse.angle += torque; + bodyA.angle += torque; + } } if (bodyB && !bodyB.isStatic) { - torque = Vector.cross(offsetB, normalVelocity) * bodyB.inverseInertia * (1 - constraint.angularStiffness); + share = bodyB.inverseMass / massTotal; // keep track of applied impulses for post solving - bodyB.constraintImpulse.x += force.x; - bodyB.constraintImpulse.y += force.y; - bodyB.constraintImpulse.angle -= torque; + bodyB.constraintImpulse.x += force.x * share; + bodyB.constraintImpulse.y += force.y * share; // apply forces - bodyB.position.x += force.x; - bodyB.position.y += force.y; - bodyB.angle -= torque; + bodyB.position.x += force.x * share; + bodyB.position.y += force.y * share; + + if (normalVelocity) { + torque = Vector.cross(pointB, normalVelocity) * bodyB.inverseInertia * (1 - constraint.angularStiffness); + bodyB.constraintImpulse.angle -= torque; + bodyB.angle -= torque; + } } }; @@ -245,7 +219,7 @@ var Common = require('../core/Common'); var body = bodies[i], impulse = body.constraintImpulse; - if (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0) { + if (body.isStatic || (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0)) { continue; } From daf26af006ee0de5a5597dc91e3d81d196e5dde5 Mon Sep 17 00:00:00 2001 From: liabru Date: Tue, 25 Apr 2017 23:48:37 +0100 Subject: [PATCH 03/31] implemented constraint warming --- src/constraint/Constraint.js | 28 +++++++++++++++++++++++++--- src/core/Engine.js | 1 + 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/constraint/Constraint.js b/src/constraint/Constraint.js index 730e2f0..627353a 100644 --- a/src/constraint/Constraint.js +++ b/src/constraint/Constraint.js @@ -72,6 +72,27 @@ var Common = require('../core/Common'); return constraint; }; + /** + * Prepares for solving by constraint warming. + * @private + * @method preSolveAll + * @param {body[]} bodies + */ + Constraint.preSolveAll = function(bodies) { + for (var i = 0; i < bodies.length; i += 1) { + var body = bodies[i], + impulse = body.constraintImpulse; + + if (body.isStatic || (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0)) { + continue; + } + + body.position.x += impulse.x; + body.position.y += impulse.y; + body.angle += impulse.angle; + } + }; + /** * Solves all constraints in a list of collisions. * @private @@ -247,9 +268,10 @@ var Common = require('../core/Common'); Bounds.update(part.bounds, part.vertices, body.velocity); } - impulse.angle = 0; - impulse.x = 0; - impulse.y = 0; + // dampen the cached impulse for warming next step + impulse.angle *= Constraint._warming; + impulse.x *= Constraint._warming; + impulse.y *= Constraint._warming; } }; diff --git a/src/core/Engine.js b/src/core/Engine.js index 33885e9..42c9de1 100644 --- a/src/core/Engine.js +++ b/src/core/Engine.js @@ -150,6 +150,7 @@ var Body = require('../body/Body'); _bodiesUpdate(allBodies, delta, timing.timeScale, correction, world.bounds); // update all constraints + Constraint.preSolveAll(allBodies); for (i = 0; i < engine.constraintIterations; i++) { Constraint.solveAll(allConstraints, timing.timeScale); } From 068fdc0f2ac15e0139288d820e99aa8a2ae7f750 Mon Sep 17 00:00:00 2001 From: liabru Date: Sat, 29 Apr 2017 21:17:09 +0100 Subject: [PATCH 04/31] fixed constraint torque calculation --- src/constraint/Constraint.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/constraint/Constraint.js b/src/constraint/Constraint.js index 627353a..369250b 100644 --- a/src/constraint/Constraint.js +++ b/src/constraint/Constraint.js @@ -29,6 +29,7 @@ var Common = require('../core/Common'); /** * Creates a new constraint. * All properties have default values, and many are pre-calculated automatically based on other properties. + * To simulate a revolute constraint (or pin joint) set `length: 0` and `stiffness: 1`. * See the properties section below for detailed information on what you can pass via the `options` object. * @method create * @param {} options @@ -179,12 +180,13 @@ var Common = require('../core/Common'); relativeVelocity = Vector.sub(velocityPointB, velocityPointA), massTotal = (bodyA ? bodyA.inverseMass : 0) + (bodyB ? bodyB.inverseMass : 0), inertiaTotal = (bodyA ? bodyA.inverseInertia : 0) + (bodyB ? bodyB.inverseInertia : 0), - normalImpulse = Vector.dot(normal, relativeVelocity) / (massTotal + inertiaTotal), + resistanceTotal = massTotal + inertiaTotal, + normalImpulse = Vector.dot(normal, relativeVelocity) / resistanceTotal, normalVelocity, torque, share; - if (normalImpulse < 0) { + if (normalImpulse < 0 && constraint.angularStiffness < 1) { normalVelocity = { x: normal.x * normalImpulse, y: normal.y * normalImpulse @@ -203,7 +205,8 @@ var Common = require('../core/Common'); bodyA.position.y -= force.y * share; if (normalVelocity) { - torque = Vector.cross(pointA, normalVelocity) * bodyA.inverseInertia * (1 - constraint.angularStiffness); + share = (bodyA.inverseInertia + bodyA.inverseMass) / resistanceTotal; + torque = Vector.cross(pointA, normalVelocity) * share * bodyA.inverseInertia * constraint.stiffness * (1 - constraint.angularStiffness); bodyA.constraintImpulse.angle += torque; bodyA.angle += torque; } @@ -221,7 +224,8 @@ var Common = require('../core/Common'); bodyB.position.y += force.y * share; if (normalVelocity) { - torque = Vector.cross(pointB, normalVelocity) * bodyB.inverseInertia * (1 - constraint.angularStiffness); + share = (bodyB.inverseInertia + bodyB.inverseMass) / resistanceTotal; + torque = Vector.cross(pointB, normalVelocity) * share * bodyB.inverseInertia * constraint.stiffness * (1 - constraint.angularStiffness); bodyB.constraintImpulse.angle -= torque; bodyB.angle -= torque; } From b6e597378e62bb7ac44e25de708cf3cd694cda0a Mon Sep 17 00:00:00 2001 From: liabru Date: Sat, 29 Apr 2017 23:23:14 +0100 Subject: [PATCH 05/31] improved Examples.bridge --- examples/bridge.js | 52 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/examples/bridge.js b/examples/bridge.js index 62ae03f..e62ac85 100644 --- a/examples/bridge.js +++ b/examples/bridge.js @@ -37,23 +37,53 @@ Example.bridge = function() { // add bodies var group = Body.nextGroup(true); - var bridge = Composites.stack(150, 300, 9, 1, 10, 10, function(x, y) { - return Bodies.rectangle(x, y, 50, 20, { collisionFilter: { group: group } }); + var bridge = Composites.stack(160, 290, 15, 1, 0, 0, function(x, y) { + return Bodies.rectangle(x - 20, y, 53, 20, { + collisionFilter: { group: group }, + chamfer: 5, + render: { + fillStyle: '#575375' + } + }); }); - Composites.chain(bridge, 0.5, 0, -0.5, 0, { stiffness: 0.9 }); + Composites.chain(bridge, 0.3, 0, -0.3, 0, { + stiffness: 1.2, + length: 0, + render: { + visible: false + } + }); - var stack = Composites.stack(200, 40, 6, 3, 0, 0, function(x, y) { - return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 40)); + var stack = Composites.stack(250, 50, 4, 3, 0, 0, function(x, y) { + return Bodies.polygon(x, y, 1, Common.random(20, 40)); }); World.add(world, [ bridge, - Bodies.rectangle(80, 440, 120, 280, { isStatic: true }), - Bodies.rectangle(720, 440, 120, 280, { isStatic: true }), - Constraint.create({ pointA: { x: 140, y: 300 }, bodyB: bridge.bodies[0], pointB: { x: -25, y: 0 } }), - Constraint.create({ pointA: { x: 660, y: 300 }, bodyB: bridge.bodies[8], pointB: { x: 25, y: 0 } }), - stack + stack, + Bodies.rectangle(30, 490, 220, 380, { + isStatic: true, + chamfer: { radius: 20 } + }), + Bodies.rectangle(770, 490, 220, 380, { + isStatic: true, + chamfer: { radius: 20 } + }), + Constraint.create({ + pointA: { x: 140, y: 300 }, + bodyB: bridge.bodies[0], + pointB: { x: -25, y: 0 }, + length: 2, + stiffness: 0.5 + }), + Constraint.create({ + pointA: { x: 660, y: 300 }, + bodyB: bridge.bodies[14], + pointB: { x: 25, y: 0 }, + length: 2, + stiffness: 0.5 + }) ]); // add mouse control @@ -61,7 +91,7 @@ Example.bridge = function() { mouseConstraint = MouseConstraint.create(engine, { mouse: mouse, constraint: { - stiffness: 0.2, + stiffness: 0.1, render: { visible: false } From a8d19501486d89e7ec5aeba2956fac4325a3cfe0 Mon Sep 17 00:00:00 2001 From: liabru Date: Tue, 2 May 2017 23:50:01 +0100 Subject: [PATCH 06/31] fixed constraint torque calculation --- src/constraint/Constraint.js | 64 +++++++++--------------------------- 1 file changed, 15 insertions(+), 49 deletions(-) diff --git a/src/constraint/Constraint.js b/src/constraint/Constraint.js index 369250b..68d75ae 100644 --- a/src/constraint/Constraint.js +++ b/src/constraint/Constraint.js @@ -24,6 +24,7 @@ var Common = require('../core/Common'); var _zeroVector = { x: 0, y: 0 }; Constraint._warming = 0.4; + Constraint._torqueDampen = 0.8; Constraint._minLength = 0.000001; /** @@ -120,6 +121,9 @@ var Common = require('../core/Common'); pointA = constraint.pointA, pointB = constraint.pointB; + if (!bodyA && !bodyB) + return; + // update reference angle if (bodyA && !bodyA.isStatic) { Vector.rotate(pointA, bodyA.angle - constraint.angleA, pointA); @@ -141,58 +145,24 @@ var Common = require('../core/Common'); if (!pointAWorld || !pointBWorld) return; - var velocityPointA = _zeroVector, - velocityPointB = _zeroVector; - - if (bodyA && !bodyA.isStatic) { - // update velocity - bodyA.velocity.x = bodyA.position.x - bodyA.positionPrev.x; - bodyA.velocity.y = bodyA.position.y - bodyA.positionPrev.y; - bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev; - - // find point velocity and body mass - velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(pointA), bodyA.angularVelocity)); - } - - if (bodyB && !bodyB.isStatic) { - // update velocity - bodyB.velocity.x = bodyB.position.x - bodyB.positionPrev.x; - bodyB.velocity.y = bodyB.position.y - bodyB.positionPrev.y; - bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev; - - // find point velocity and body mass - velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(pointB), bodyB.angularVelocity)); - } - var delta = Vector.sub(pointAWorld, pointBWorld), currentLength = Vector.magnitude(delta); // prevent singularity - if (currentLength === 0) { + if (currentLength < Constraint._minLength) { currentLength = Constraint._minLength; - delta.x = Constraint._minLength; } // solve distance constraint with Gauss-Siedel method var difference = (currentLength - constraint.length) / currentLength, - normal = Vector.div(delta, currentLength), - force = Vector.mult(delta, difference * constraint.stiffness * timeScale * timeScale), - relativeVelocity = Vector.sub(velocityPointB, velocityPointA), + stiffness = constraint.stiffness < 1 ? constraint.stiffness * timeScale : constraint.stiffness, + force = Vector.mult(delta, difference * stiffness), massTotal = (bodyA ? bodyA.inverseMass : 0) + (bodyB ? bodyB.inverseMass : 0), inertiaTotal = (bodyA ? bodyA.inverseInertia : 0) + (bodyB ? bodyB.inverseInertia : 0), resistanceTotal = massTotal + inertiaTotal, - normalImpulse = Vector.dot(normal, relativeVelocity) / resistanceTotal, - normalVelocity, torque, share; - if (normalImpulse < 0 && constraint.angularStiffness < 1) { - normalVelocity = { - x: normal.x * normalImpulse, - y: normal.y * normalImpulse - }; - } - if (bodyA && !bodyA.isStatic) { share = bodyA.inverseMass / massTotal; @@ -204,12 +174,10 @@ var Common = require('../core/Common'); bodyA.position.x -= force.x * share; bodyA.position.y -= force.y * share; - if (normalVelocity) { - share = (bodyA.inverseInertia + bodyA.inverseMass) / resistanceTotal; - torque = Vector.cross(pointA, normalVelocity) * share * bodyA.inverseInertia * constraint.stiffness * (1 - constraint.angularStiffness); - bodyA.constraintImpulse.angle += torque; - bodyA.angle += torque; - } + // apply torque + torque = (Vector.cross(pointA, force) / resistanceTotal) * Constraint._torqueDampen * bodyA.inverseInertia; + bodyA.constraintImpulse.angle -= torque; + bodyA.angle -= torque; } if (bodyB && !bodyB.isStatic) { @@ -223,12 +191,10 @@ var Common = require('../core/Common'); bodyB.position.x += force.x * share; bodyB.position.y += force.y * share; - if (normalVelocity) { - share = (bodyB.inverseInertia + bodyB.inverseMass) / resistanceTotal; - torque = Vector.cross(pointB, normalVelocity) * share * bodyB.inverseInertia * constraint.stiffness * (1 - constraint.angularStiffness); - bodyB.constraintImpulse.angle -= torque; - bodyB.angle -= torque; - } + // apply torque + torque = (Vector.cross(pointB, force) / resistanceTotal) * Constraint._torqueDampen * bodyB.inverseInertia; + bodyB.constraintImpulse.angle += torque; + bodyB.angle += torque; } }; From a5bd6b2d558645b0f070a626b6a8566e37749e30 Mon Sep 17 00:00:00 2001 From: liabru Date: Wed, 3 May 2017 21:10:14 +0100 Subject: [PATCH 07/31] change constraint solve order --- src/constraint/Constraint.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/constraint/Constraint.js b/src/constraint/Constraint.js index 68d75ae..61de118 100644 --- a/src/constraint/Constraint.js +++ b/src/constraint/Constraint.js @@ -103,9 +103,27 @@ var Common = require('../core/Common'); * @param {number} timeScale */ Constraint.solveAll = function(constraints, timeScale) { - for (var i = 0; i < constraints.length; i++) { + // Solve fixed constraints first. + for (var i = 0; i < constraints.length; i += 1) { + var constraint = constraints[i], + fixedA = !constraint.bodyA || (constraint.bodyA && constraint.bodyA.isStatic), + fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic); + + if (fixedA || fixedB) { + Constraint.solve(constraints[i], timeScale); + } + } + + // Solve free constraints last. + for (i = 0; i < constraints.length; i += 1) { + constraint = constraints[i]; + fixedA = !constraint.bodyA || (constraint.bodyA && constraint.bodyA.isStatic); + fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic); + + if (!fixedA && !fixedB) { Constraint.solve(constraints[i], timeScale); } + } }; /** From f49d053e1f0602b30d13e2d93b70d7068e0333d2 Mon Sep 17 00:00:00 2001 From: liabru Date: Wed, 3 May 2017 21:13:29 +0100 Subject: [PATCH 08/31] added second pass for constraint solving --- src/constraint/Constraint.js | 8 +++----- src/core/Engine.js | 11 ++++++++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/constraint/Constraint.js b/src/constraint/Constraint.js index 61de118..07509c7 100644 --- a/src/constraint/Constraint.js +++ b/src/constraint/Constraint.js @@ -21,10 +21,8 @@ var Common = require('../core/Common'); (function() { - var _zeroVector = { x: 0, y: 0 }; - Constraint._warming = 0.4; - Constraint._torqueDampen = 0.8; + Constraint._torqueDampen = 1; Constraint._minLength = 0.000001; /** @@ -121,8 +119,8 @@ var Common = require('../core/Common'); fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic); if (!fixedA && !fixedB) { - Constraint.solve(constraints[i], timeScale); - } + Constraint.solve(constraints[i], timeScale); + } } }; diff --git a/src/core/Engine.js b/src/core/Engine.js index 42c9de1..2466fde 100644 --- a/src/core/Engine.js +++ b/src/core/Engine.js @@ -149,7 +149,7 @@ var Body = require('../body/Body'); // update all body position and rotation by integration _bodiesUpdate(allBodies, delta, timing.timeScale, correction, world.bounds); - // update all constraints + // update all constraints (first pass) Constraint.preSolveAll(allBodies); for (i = 0; i < engine.constraintIterations; i++) { Constraint.solveAll(allConstraints, timing.timeScale); @@ -158,7 +158,6 @@ var Body = require('../body/Body'); // broadphase pass: find potential collision pairs if (broadphase.controller) { - // if world is dirty, we must flush the whole grid if (world.isModified) broadphase.controller.clear(broadphase); @@ -167,7 +166,6 @@ var Body = require('../body/Body'); broadphase.controller.update(broadphase, allBodies, engine, world.isModified); broadphasePairs = broadphase.pairsList; } else { - // if no broadphase set, we just pass all bodies broadphasePairs = allBodies; } @@ -201,6 +199,13 @@ var Body = require('../body/Body'); } Resolver.postSolvePosition(allBodies); + // update all constraints (second pass) + Constraint.preSolveAll(allBodies); + for (i = 0; i < engine.constraintIterations; i++) { + Constraint.solveAll(allConstraints, timing.timeScale); + } + Constraint.postSolveAll(allBodies); + // iteratively resolve velocity between collisions Resolver.preSolveVelocity(pairs.list); for (i = 0; i < engine.velocityIterations; i++) { From b277b3994060c0cacf7ea8fd0d0472666c3765bc Mon Sep 17 00:00:00 2001 From: liabru Date: Wed, 3 May 2017 21:21:48 +0100 Subject: [PATCH 09/31] improved Examples.bridge --- examples/bridge.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/bridge.js b/examples/bridge.js index e62ac85..a8ff806 100644 --- a/examples/bridge.js +++ b/examples/bridge.js @@ -41,6 +41,8 @@ Example.bridge = function() { return Bodies.rectangle(x - 20, y, 53, 20, { collisionFilter: { group: group }, chamfer: 5, + density: 0.005, + frictionAir: 0.05, render: { fillStyle: '#575375' } @@ -48,15 +50,15 @@ Example.bridge = function() { }); Composites.chain(bridge, 0.3, 0, -0.3, 0, { - stiffness: 1.2, + stiffness: 1, length: 0, render: { visible: false } }); - var stack = Composites.stack(250, 50, 4, 3, 0, 0, function(x, y) { - return Bodies.polygon(x, y, 1, Common.random(20, 40)); + var stack = Composites.stack(250, 50, 6, 3, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 50, 50, Common.random(20, 40)); }); World.add(world, [ @@ -75,14 +77,14 @@ Example.bridge = function() { bodyB: bridge.bodies[0], pointB: { x: -25, y: 0 }, length: 2, - stiffness: 0.5 + stiffness: 0.9 }), Constraint.create({ pointA: { x: 660, y: 300 }, - bodyB: bridge.bodies[14], + bodyB: bridge.bodies[bridge.bodies.length - 1], pointB: { x: 25, y: 0 }, length: 2, - stiffness: 0.5 + stiffness: 0.9 }) ]); From 130e6b3f5647b7fa0d9ee251066e3c700d8a7236 Mon Sep 17 00:00:00 2001 From: liabru Date: Wed, 3 May 2017 21:26:40 +0100 Subject: [PATCH 10/31] improved Example.car using pin constraint --- examples/car.js | 4 ++-- src/factory/Composites.js | 34 +++++++++++++++++----------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/examples/car.js b/examples/car.js index 3d9a0de..897b5e9 100644 --- a/examples/car.js +++ b/examples/car.js @@ -42,10 +42,10 @@ Example.car = function() { ]); var scale = 0.9; - World.add(world, Composites.car(150, 100, 100 * scale, 40 * scale, 30 * scale)); + World.add(world, Composites.car(150, 100, 150 * scale, 30 * scale, 30 * scale)); scale = 0.8; - World.add(world, Composites.car(350, 300, 100 * scale, 40 * scale, 30 * scale)); + World.add(world, Composites.car(350, 300, 150 * scale, 30 * scale, 30 * scale)); World.add(world, [ Bodies.rectangle(200, 150, 400, 20, { isStatic: true, angle: Math.PI * 0.06 }), diff --git a/src/factory/Composites.js b/src/factory/Composites.js index 1f63cca..c6c75c7 100644 --- a/src/factory/Composites.js +++ b/src/factory/Composites.js @@ -239,53 +239,53 @@ var Bodies = require('./Bodies'); */ Composites.car = function(xx, yy, width, height, wheelSize) { var group = Body.nextGroup(true), - wheelBase = -20, + wheelBase = 20, wheelAOffset = -width * 0.5 + wheelBase, wheelBOffset = width * 0.5 - wheelBase, wheelYOffset = 0; var car = Composite.create({ label: 'Car' }), - body = Bodies.trapezoid(xx, yy, width, height, 0.3, { + body = Bodies.rectangle(xx, yy, width, height, { collisionFilter: { group: group }, - friction: 0.01, chamfer: { - radius: 10 - } + radius: height * 0.5 + }, + density: 0.0002 }); var wheelA = Bodies.circle(xx + wheelAOffset, yy + wheelYOffset, wheelSize, { collisionFilter: { group: group }, - friction: 0.8, - density: 0.01 + friction: 0.8 }); var wheelB = Bodies.circle(xx + wheelBOffset, yy + wheelYOffset, wheelSize, { collisionFilter: { group: group }, - friction: 0.8, - density: 0.01 + friction: 0.8 }); var axelA = Constraint.create({ - bodyA: body, - pointA: { x: wheelAOffset, y: wheelYOffset }, - bodyB: wheelA, - stiffness: 0.2, + bodyB: body, + pointB: { x: wheelAOffset, y: wheelYOffset }, + bodyA: wheelA, + stiffness: 1, + length: 0, render: { lineWidth: 0 } }); var axelB = Constraint.create({ - bodyA: body, - pointA: { x: wheelBOffset, y: wheelYOffset }, - bodyB: wheelB, - stiffness: 0.2, + bodyB: body, + pointB: { x: wheelBOffset, y: wheelYOffset }, + bodyA: wheelB, + stiffness: 1, + length: 0, render: { lineWidth: 0 } From 0e1509947917e11a18416eba2a51e90e4a315b7c Mon Sep 17 00:00:00 2001 From: liabru Date: Wed, 3 May 2017 21:28:39 +0100 Subject: [PATCH 11/31] improved Example.catapult using pin constraint --- examples/catapult.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/catapult.js b/examples/catapult.js index 64c4965..7fa0809 100644 --- a/examples/catapult.js +++ b/examples/catapult.js @@ -9,7 +9,9 @@ Example.catapult = function() { MouseConstraint = Matter.MouseConstraint, Mouse = Matter.Mouse, World = Matter.World, - Bodies = Matter.Bodies; + Bodies = Matter.Bodies, + Body = Matter.Body, + Vector = Matter.Vector; // create engine var engine = Engine.create(), @@ -35,20 +37,27 @@ Example.catapult = function() { Runner.run(runner, engine); // add bodies + var group = Body.nextGroup(true); + var stack = Composites.stack(250, 255, 1, 6, 0, 0, function(x, y) { return Bodies.rectangle(x, y, 30, 30); }); - var catapult = Bodies.rectangle(400, 520, 320, 20); + var catapult = Bodies.rectangle(400, 520, 320, 20, { collisionFilter: { group: group } }); World.add(world, [ stack, catapult, Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), Bodies.rectangle(250, 555, 20, 50, { isStatic: true }), + Bodies.rectangle(400, 535, 20, 80, { isStatic: true, collisionFilter: { group: group } }), Bodies.circle(560, 100, 50, { density: 0.005 }), - Constraint.create({ bodyA: catapult, pointB: { x: 390, y: 580 } }), - Constraint.create({ bodyA: catapult, pointB: { x: 410, y: 580 } }) + Constraint.create({ + bodyA: catapult, + pointB: Vector.clone(catapult.position), + stiffness: 1, + length: 0 + }) ]); // add mouse control From 9d2f0ffb5b3d8747bc69109190908507a5b14fc0 Mon Sep 17 00:00:00 2001 From: liabru Date: Wed, 3 May 2017 21:31:29 +0100 Subject: [PATCH 12/31] improved Example.chains using pin constraint --- examples/chains.js | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/examples/chains.js b/examples/chains.js index 11f7f87..c019b9d 100644 --- a/examples/chains.js +++ b/examples/chains.js @@ -39,7 +39,7 @@ Example.chains = function() { // add bodies var group = Body.nextGroup(true); - var ropeA = Composites.stack(200, 100, 4, 2, 10, 10, function(x, y) { + var ropeA = Composites.stack(100, 50, 8, 1, 10, 10, function(x, y) { return Bodies.rectangle(x, y, 50, 20, { collisionFilter: { group: group } }); }); @@ -47,15 +47,13 @@ Example.chains = function() { Composite.add(ropeA, Constraint.create({ bodyB: ropeA.bodies[0], pointB: { x: -25, y: 0 }, - pointA: { x: 200, y: 100 }, + pointA: { x: ropeA.bodies[0].position.x, y: ropeA.bodies[0].position.y }, stiffness: 0.5 })); - World.add(world, ropeA); - group = Body.nextGroup(true); - var ropeB = Composites.stack(500, 100, 5, 2, 10, 10, function(x, y) { + var ropeB = Composites.stack(350, 50, 10, 1, 10, 10, function(x, y) { return Bodies.circle(x, y, 20, { collisionFilter: { group: group } }); }); @@ -63,11 +61,30 @@ Example.chains = function() { Composite.add(ropeB, Constraint.create({ bodyB: ropeB.bodies[0], pointB: { x: -20, y: 0 }, - pointA: { x: 500, y: 100 }, + pointA: { x: ropeB.bodies[0].position.x, y: ropeB.bodies[0].position.y }, stiffness: 0.5 })); - World.add(world, ropeB); + group = Body.nextGroup(true); + + var ropeC = Composites.stack(600, 50, 13, 1, 10, 10, function(x, y) { + return Bodies.rectangle(x - 20, y, 50, 20, { collisionFilter: { group: group }, chamfer: 5 }); + }); + + Composites.chain(ropeC, 0.3, 0, -0.3, 0, { stiffness: 1, length: 0 }); + Composite.add(ropeC, Constraint.create({ + bodyB: ropeC.bodies[0], + pointB: { x: -20, y: 0 }, + pointA: { x: ropeC.bodies[0].position.x, y: ropeC.bodies[0].position.y }, + stiffness: 0.5 + })); + + World.add(world, [ + ropeA, + ropeB, + ropeC, + Bodies.rectangle(400, 600, 1200, 50.5, { isStatic: true }) + ]); // add mouse control var mouse = Mouse.create(render.canvas), From e6babf04a8b11bdf76c617c4a9e75bc97c3843ea Mon Sep 17 00:00:00 2001 From: liabru Date: Wed, 3 May 2017 21:34:03 +0100 Subject: [PATCH 13/31] fixed Examples.compound constraint offset --- examples/compound.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/compound.js b/examples/compound.js index b72aeed..6d2488a 100644 --- a/examples/compound.js +++ b/examples/compound.js @@ -23,7 +23,6 @@ Example.compound = function() { width: Math.min(document.documentElement.clientWidth, 800), height: Math.min(document.documentElement.clientHeight, 600), showAxes: true, - showPositions: true, showConvexHulls: true } }); @@ -61,7 +60,7 @@ Example.compound = function() { var constraint = Constraint.create({ pointA: { x: 400, y: 100 }, bodyB: compoundBodyB, - pointB: { x: 0, y: -50 } + pointB: { x: 0, y: 0 } }); World.add(world, [ From 1bae2dee459b1f542ef2c0e24f3cb3aae98bc571 Mon Sep 17 00:00:00 2001 From: liabru Date: Wed, 3 May 2017 21:42:41 +0100 Subject: [PATCH 14/31] fix soft body stiffness --- examples/cloth.js | 3 ++- src/factory/Composites.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/cloth.js b/examples/cloth.js index 7586cf0..001fca7 100644 --- a/examples/cloth.js +++ b/examples/cloth.js @@ -34,7 +34,8 @@ Example.cloth = function() { // add bodies var group = Body.nextGroup(true), particleOptions = { friction: 0.00001, collisionFilter: { group: group }, render: { visible: false }}, - cloth = Composites.softBody(200, 200, 20, 12, 5, 5, false, 8, particleOptions); + constraintOptions = { stiffness: 0.06 }, + cloth = Composites.softBody(200, 200, 20, 12, 5, 5, false, 8, particleOptions, constraintOptions); for (var i = 0; i < 20; i++) { cloth.bodies[i].isStatic = true; diff --git a/src/factory/Composites.js b/src/factory/Composites.js index c6c75c7..7ef9f3f 100644 --- a/src/factory/Composites.js +++ b/src/factory/Composites.js @@ -317,7 +317,7 @@ var Bodies = require('./Bodies'); */ Composites.softBody = function(xx, yy, columns, rows, columnGap, rowGap, crossBrace, particleRadius, particleOptions, constraintOptions) { particleOptions = Common.extend({ inertia: Infinity }, particleOptions); - constraintOptions = Common.extend({ stiffness: 0.4 }, constraintOptions); + constraintOptions = Common.extend({ stiffness: 0.2 }, constraintOptions); var softBody = Composites.stack(xx, yy, columns, rows, columnGap, rowGap, function(x, y) { return Bodies.circle(x, y, particleRadius, particleOptions); From ab0283b5b39908bd3306625fec6bac6685b6732b Mon Sep 17 00:00:00 2001 From: liabru Date: Wed, 3 May 2017 22:05:38 +0100 Subject: [PATCH 15/31] fix constraint.angularStiffness --- src/constraint/Constraint.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/constraint/Constraint.js b/src/constraint/Constraint.js index 07509c7..61ebd13 100644 --- a/src/constraint/Constraint.js +++ b/src/constraint/Constraint.js @@ -191,7 +191,7 @@ var Common = require('../core/Common'); bodyA.position.y -= force.y * share; // apply torque - torque = (Vector.cross(pointA, force) / resistanceTotal) * Constraint._torqueDampen * bodyA.inverseInertia; + torque = (Vector.cross(pointA, force) / resistanceTotal) * Constraint._torqueDampen * bodyA.inverseInertia * (1 - constraint.angularStiffness); bodyA.constraintImpulse.angle -= torque; bodyA.angle -= torque; } @@ -208,7 +208,7 @@ var Common = require('../core/Common'); bodyB.position.y += force.y * share; // apply torque - torque = (Vector.cross(pointB, force) / resistanceTotal) * Constraint._torqueDampen * bodyB.inverseInertia; + torque = (Vector.cross(pointB, force) / resistanceTotal) * Constraint._torqueDampen * bodyB.inverseInertia * (1 - constraint.angularStiffness); bodyB.constraintImpulse.angle += torque; bodyB.angle += torque; } From 749ed5066e009dc2b4668820394884a7a1dc0578 Mon Sep 17 00:00:00 2001 From: liabru Date: Thu, 4 May 2017 00:31:56 +0100 Subject: [PATCH 16/31] added rotation point parameter to Body.rotate, closes #410 --- src/body/Body.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/body/Body.js b/src/body/Body.js index fb0e0dd..cc1857c 100644 --- a/src/body/Body.js +++ b/src/body/Body.js @@ -492,9 +492,24 @@ var Axes = require('../geometry/Axes'); * @method rotate * @param {body} body * @param {number} rotation + * @param {vector} [point] */ - Body.rotate = function(body, rotation) { - Body.setAngle(body, body.angle + rotation); + Body.rotate = function(body, rotation, point) { + if (!point) { + Body.setAngle(body, body.angle + rotation); + } else { + var cos = Math.cos(rotation), + sin = Math.sin(rotation), + dx = body.position.x - point.x, + dy = body.position.y - point.y; + + Body.setPosition(body, { + x: point.x + (dx * cos - dy * sin), + y: point.y + (dx * sin + dy * cos) + }); + + Body.setAngle(body, body.angle + rotation); + } }; /** From a7aa47d3e7b3e54e0a9647f076741b97c46de353 Mon Sep 17 00:00:00 2001 From: liabru Date: Thu, 4 May 2017 00:33:21 +0100 Subject: [PATCH 17/31] added Example.doublePendulum --- demo/index.html | 1 + demo/js/Demo.js | 6 ++ examples/doublePendulum.js | 151 +++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 examples/doublePendulum.js diff --git a/demo/index.html b/demo/index.html index 880edac..e248179 100644 --- a/demo/index.html +++ b/demo/index.html @@ -44,6 +44,7 @@ + diff --git a/demo/js/Demo.js b/demo/js/Demo.js index 014bb6e..4a7a498 100644 --- a/demo/js/Demo.js +++ b/demo/js/Demo.js @@ -118,6 +118,12 @@ init: Example.concave, sourceLink: sourceLinkRoot + '/concave.js' }, + { + name: 'Double Pendulum', + id: 'doublePendulum', + init: Example.doublePendulum, + sourceLink: sourceLinkRoot + '/doublePendulum.js' + }, { name: 'Events', id: 'events', diff --git a/examples/doublePendulum.js b/examples/doublePendulum.js new file mode 100644 index 0000000..bef6958 --- /dev/null +++ b/examples/doublePendulum.js @@ -0,0 +1,151 @@ +var Example = Example || {}; + +Example.doublePendulum = function() { + var Engine = Matter.Engine, + Events = Matter.Events, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composite = Matter.Composite, + Composites = Matter.Composites, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies, + Vector = Matter.Vector; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.documentElement.clientWidth, 800), + height: Math.min(document.documentElement.clientHeight, 600), + wireframes: false, + background: '#0f0f13' + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var group = Body.nextGroup(true), + length = 200, + width = 25; + + var pendulum = Composites.stack(350, 160, 2, 1, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, length, width, { + collisionFilter: { group: group }, + frictionAir: 0, + chamfer: 5, + render: { + fillStyle: 'transparent', + lineWidth: 1 + } + }); + }); + + pendulum.bodies[0].render.strokeStyle = '#4a485b'; + pendulum.bodies[1].render.strokeStyle = '#4a485b'; + + Composites.chain(pendulum, 0.5, 0, -0.5, 0, { + stiffness: 1, + length: 0, + angularStiffness: 0.7, + render: { + lineWidth: 0 + } + }); + + Composite.add(pendulum, Constraint.create({ + bodyB: pendulum.bodies[0], + pointB: { x: -length * 0.5, y: 0 }, + pointA: { x: pendulum.bodies[0].position.x - length * 0.5, y: pendulum.bodies[0].position.y }, + stiffness: 1, + length: 0, + render: { + lineWidth: 0 + } + })); + + var lowerArm = pendulum.bodies[1]; + + Body.rotate(lowerArm, -Math.PI * 0.3, { + x: lowerArm.position.x - 100, + y: lowerArm.position.y + }); + + World.add(world, pendulum); + + var trail = []; + + Events.on(render, 'afterRender', function() { + trail.unshift({ + position: Vector.clone(lowerArm.position), + speed: lowerArm.speed + }); + + Render.startViewTransform(render); + render.context.globalAlpha = 0.7; + + for (var i = 0; i < trail.length; i += 1) { + var point = trail[i].position, + speed = trail[i].speed; + + var hue = 250 + Math.round((1 - Math.min(1, speed / 10)) * 170); + render.context.fillStyle = 'hsl(' + hue + ', 100%, 55%)'; + render.context.fillRect(point.x, point.y, 2, 2); + } + + render.context.globalAlpha = 1; + Render.endViewTransform(render); + + if (trail.length > 2000) { + trail.pop(); + } + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 700, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file From d1fbe95f7ac4cb681d716b8016f46a96e7d9c3c9 Mon Sep 17 00:00:00 2001 From: liabru Date: Thu, 4 May 2017 00:38:45 +0100 Subject: [PATCH 18/31] changed lint rules --- .eslintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc b/.eslintrc index 63e3be3..e67f987 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,6 +3,7 @@ "no-fallthrough": 2, "no-console": 0, "no-unused-vars": 0, + "no-redeclare": 0, "indent": [ 2, 4 From fe9b05d520e5428d70a5886582e7de8f295679f9 Mon Sep 17 00:00:00 2001 From: liabru Date: Thu, 4 May 2017 00:40:04 +0100 Subject: [PATCH 19/31] update alpha build --- build/matter.js | 275 ++++++++++++++++++++++---------------------- build/matter.min.js | 157 ++++++++++++------------- 2 files changed, 219 insertions(+), 213 deletions(-) diff --git a/build/matter.js b/build/matter.js index c4fbaee..c605fbe 100644 --- a/build/matter.js +++ b/build/matter.js @@ -1,5 +1,5 @@ /** -* matter-js 0.12.0 by @liabru 2017-02-02 +* matter-js 0.12.0-alpha by @liabru 2017-05-03 * http://brm.io/matter-js/ * License MIT */ @@ -523,9 +523,24 @@ var Axes = _dereq_('../geometry/Axes'); * @method rotate * @param {body} body * @param {number} rotation + * @param {vector} [point] */ - Body.rotate = function(body, rotation) { - Body.setAngle(body, body.angle + rotation); + Body.rotate = function(body, rotation, point) { + if (!point) { + Body.setAngle(body, body.angle + rotation); + } else { + var cos = Math.cos(rotation), + sin = Math.sin(rotation), + dx = body.position.x - point.x, + dy = body.position.y - point.y; + + Body.setPosition(body, { + x: point.x + (dx * cos - dy * sin), + y: point.y + (dx * sin + dy * cos) + }); + + Body.setAngle(body, body.angle + rotation); + } }; /** @@ -3468,14 +3483,6 @@ var Vector = _dereq_('../geometry/Vector'); * @class Constraint */ -// TODO: fix instability issues with torque -// TODO: linked constraints -// TODO: breakable constraints -// TODO: collision constraints -// TODO: allow constrained bodies to sleep -// TODO: handle 0 length constraints properly -// TODO: impulse caching and warming - var Constraint = {}; module.exports = Constraint; @@ -3489,12 +3496,14 @@ var Common = _dereq_('../core/Common'); (function() { - var _minLength = 0.000001, - _minDifference = 0.001; + Constraint._warming = 0.4; + Constraint._torqueDampen = 1; + Constraint._minLength = 0.000001; /** * Creates a new constraint. * All properties have default values, and many are pre-calculated automatically based on other properties. + * To simulate a revolute constraint (or pin joint) set `length: 0` and `stiffness: 1`. * See the properties section below for detailed information on what you can pass via the `options` object. * @method create * @param {} options @@ -3514,7 +3523,7 @@ var Common = _dereq_('../core/Common'); initialPointB = constraint.bodyB ? Vector.add(constraint.bodyB.position, constraint.pointB) : constraint.pointB, length = Vector.magnitude(Vector.sub(initialPointA, initialPointB)); - constraint.length = constraint.length || length || _minLength; + constraint.length = typeof constraint.length !== 'undefined' ? constraint.length : length; // render var render = { @@ -3538,6 +3547,27 @@ var Common = _dereq_('../core/Common'); return constraint; }; + /** + * Prepares for solving by constraint warming. + * @private + * @method preSolveAll + * @param {body[]} bodies + */ + Constraint.preSolveAll = function(bodies) { + for (var i = 0; i < bodies.length; i += 1) { + var body = bodies[i], + impulse = body.constraintImpulse; + + if (body.isStatic || (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0)) { + continue; + } + + body.position.x += impulse.x; + body.position.y += impulse.y; + body.angle += impulse.angle; + } + }; + /** * Solves all constraints in a list of collisions. * @private @@ -3546,8 +3576,26 @@ var Common = _dereq_('../core/Common'); * @param {number} timeScale */ Constraint.solveAll = function(constraints, timeScale) { - for (var i = 0; i < constraints.length; i++) { - Constraint.solve(constraints[i], timeScale); + // Solve fixed constraints first. + for (var i = 0; i < constraints.length; i += 1) { + var constraint = constraints[i], + fixedA = !constraint.bodyA || (constraint.bodyA && constraint.bodyA.isStatic), + fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic); + + if (fixedA || fixedB) { + Constraint.solve(constraints[i], timeScale); + } + } + + // Solve free constraints last. + for (i = 0; i < constraints.length; i += 1) { + constraint = constraints[i]; + fixedA = !constraint.bodyA || (constraint.bodyA && constraint.bodyA.isStatic); + fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic); + + if (!fixedA && !fixedB) { + Constraint.solve(constraints[i], timeScale); + } } }; @@ -3564,15 +3612,18 @@ var Common = _dereq_('../core/Common'); pointA = constraint.pointA, pointB = constraint.pointB; + if (!bodyA && !bodyB) + return; + // update reference angle if (bodyA && !bodyA.isStatic) { - constraint.pointA = Vector.rotate(pointA, bodyA.angle - constraint.angleA); + Vector.rotate(pointA, bodyA.angle - constraint.angleA, pointA); constraint.angleA = bodyA.angle; } // update reference angle if (bodyB && !bodyB.isStatic) { - constraint.pointB = Vector.rotate(pointB, bodyB.angle - constraint.angleB); + Vector.rotate(pointB, bodyB.angle - constraint.angleB, pointB); constraint.angleB = bodyB.angle; } @@ -3589,107 +3640,52 @@ var Common = _dereq_('../core/Common'); currentLength = Vector.magnitude(delta); // prevent singularity - if (currentLength === 0) - currentLength = _minLength; + if (currentLength < Constraint._minLength) { + currentLength = Constraint._minLength; + } // solve distance constraint with Gauss-Siedel method var difference = (currentLength - constraint.length) / currentLength, - normal = Vector.div(delta, currentLength), - force = Vector.mult(delta, difference * 0.5 * constraint.stiffness * timeScale * timeScale); - - // if difference is very small, we can skip - if (Math.abs(1 - (currentLength / constraint.length)) < _minDifference * timeScale) - return; + stiffness = constraint.stiffness < 1 ? constraint.stiffness * timeScale : constraint.stiffness, + force = Vector.mult(delta, difference * stiffness), + massTotal = (bodyA ? bodyA.inverseMass : 0) + (bodyB ? bodyB.inverseMass : 0), + inertiaTotal = (bodyA ? bodyA.inverseInertia : 0) + (bodyB ? bodyB.inverseInertia : 0), + resistanceTotal = massTotal + inertiaTotal, + torque, + share; - var velocityPointA, - velocityPointB, - offsetA, - offsetB, - oAn, - oBn, - bodyADenom, - bodyBDenom; - if (bodyA && !bodyA.isStatic) { - // point body offset - offsetA = { - x: pointAWorld.x - bodyA.position.x + force.x, - y: pointAWorld.y - bodyA.position.y + force.y - }; - - // update velocity - bodyA.velocity.x = bodyA.position.x - bodyA.positionPrev.x; - bodyA.velocity.y = bodyA.position.y - bodyA.positionPrev.y; - bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev; - - // find point velocity and body mass - velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(offsetA), bodyA.angularVelocity)); - oAn = Vector.dot(offsetA, normal); - bodyADenom = bodyA.inverseMass + bodyA.inverseInertia * oAn * oAn; - } else { - velocityPointA = { x: 0, y: 0 }; - bodyADenom = bodyA ? bodyA.inverseMass : 0; - } - - if (bodyB && !bodyB.isStatic) { - // point body offset - offsetB = { - x: pointBWorld.x - bodyB.position.x - force.x, - y: pointBWorld.y - bodyB.position.y - force.y - }; - - // update velocity - bodyB.velocity.x = bodyB.position.x - bodyB.positionPrev.x; - bodyB.velocity.y = bodyB.position.y - bodyB.positionPrev.y; - bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev; - - // find point velocity and body mass - velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(offsetB), bodyB.angularVelocity)); - oBn = Vector.dot(offsetB, normal); - bodyBDenom = bodyB.inverseMass + bodyB.inverseInertia * oBn * oBn; - } else { - velocityPointB = { x: 0, y: 0 }; - bodyBDenom = bodyB ? bodyB.inverseMass : 0; - } - - var relativeVelocity = Vector.sub(velocityPointB, velocityPointA), - normalImpulse = Vector.dot(normal, relativeVelocity) / (bodyADenom + bodyBDenom); - - if (normalImpulse > 0) normalImpulse = 0; - - var normalVelocity = { - x: normal.x * normalImpulse, - y: normal.y * normalImpulse - }; - - var torque; - - if (bodyA && !bodyA.isStatic) { - torque = Vector.cross(offsetA, normalVelocity) * bodyA.inverseInertia * (1 - constraint.angularStiffness); + share = bodyA.inverseMass / massTotal; // keep track of applied impulses for post solving - bodyA.constraintImpulse.x -= force.x; - bodyA.constraintImpulse.y -= force.y; - bodyA.constraintImpulse.angle += torque; + bodyA.constraintImpulse.x -= force.x * share; + bodyA.constraintImpulse.y -= force.y * share; // apply forces - bodyA.position.x -= force.x; - bodyA.position.y -= force.y; - bodyA.angle += torque; + bodyA.position.x -= force.x * share; + bodyA.position.y -= force.y * share; + + // apply torque + torque = (Vector.cross(pointA, force) / resistanceTotal) * Constraint._torqueDampen * bodyA.inverseInertia * (1 - constraint.angularStiffness); + bodyA.constraintImpulse.angle -= torque; + bodyA.angle -= torque; } if (bodyB && !bodyB.isStatic) { - torque = Vector.cross(offsetB, normalVelocity) * bodyB.inverseInertia * (1 - constraint.angularStiffness); + share = bodyB.inverseMass / massTotal; // keep track of applied impulses for post solving - bodyB.constraintImpulse.x += force.x; - bodyB.constraintImpulse.y += force.y; - bodyB.constraintImpulse.angle -= torque; + bodyB.constraintImpulse.x += force.x * share; + bodyB.constraintImpulse.y += force.y * share; // apply forces - bodyB.position.x += force.x; - bodyB.position.y += force.y; - bodyB.angle -= torque; + bodyB.position.x += force.x * share; + bodyB.position.y += force.y * share; + + // apply torque + torque = (Vector.cross(pointB, force) / resistanceTotal) * Constraint._torqueDampen * bodyB.inverseInertia * (1 - constraint.angularStiffness); + bodyB.constraintImpulse.angle += torque; + bodyB.angle += torque; } }; @@ -3705,7 +3701,7 @@ var Common = _dereq_('../core/Common'); var body = bodies[i], impulse = body.constraintImpulse; - if (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0) { + if (body.isStatic || (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0)) { continue; } @@ -3733,9 +3729,10 @@ var Common = _dereq_('../core/Common'); Bounds.update(part.bounds, part.vertices, body.velocity); } - impulse.angle = 0; - impulse.x = 0; - impulse.y = 0; + // dampen the cached impulse for warming next step + impulse.angle *= Constraint._warming; + impulse.x *= Constraint._warming; + impulse.y *= Constraint._warming; } }; @@ -4835,7 +4832,8 @@ var Body = _dereq_('../body/Body'); // update all body position and rotation by integration _bodiesUpdate(allBodies, delta, timing.timeScale, correction, world.bounds); - // update all constraints + // update all constraints (first pass) + Constraint.preSolveAll(allBodies); for (i = 0; i < engine.constraintIterations; i++) { Constraint.solveAll(allConstraints, timing.timeScale); } @@ -4843,7 +4841,6 @@ var Body = _dereq_('../body/Body'); // broadphase pass: find potential collision pairs if (broadphase.controller) { - // if world is dirty, we must flush the whole grid if (world.isModified) broadphase.controller.clear(broadphase); @@ -4852,7 +4849,6 @@ var Body = _dereq_('../body/Body'); broadphase.controller.update(broadphase, allBodies, engine, world.isModified); broadphasePairs = broadphase.pairsList; } else { - // if no broadphase set, we just pass all bodies broadphasePairs = allBodies; } @@ -4886,6 +4882,13 @@ var Body = _dereq_('../body/Body'); } Resolver.postSolvePosition(allBodies); + // update all constraints (second pass) + Constraint.preSolveAll(allBodies); + for (i = 0; i < engine.constraintIterations; i++) { + Constraint.solveAll(allConstraints, timing.timeScale); + } + Constraint.postSolveAll(allBodies); + // iteratively resolve velocity between collisions Resolver.preSolveVelocity(pairs.list); for (i = 0; i < engine.velocityIterations; i++) { @@ -5325,7 +5328,7 @@ var Common = _dereq_('./Common'); * @readOnly * @type {String} */ - Matter.version = '0.12.0'; + Matter.version = '0.12.0-alpha'; /** * A list of plugin dependencies to be installed. These are normally set and installed through `Matter.use`. @@ -6974,53 +6977,53 @@ var Bodies = _dereq_('./Bodies'); */ Composites.car = function(xx, yy, width, height, wheelSize) { var group = Body.nextGroup(true), - wheelBase = -20, + wheelBase = 20, wheelAOffset = -width * 0.5 + wheelBase, wheelBOffset = width * 0.5 - wheelBase, wheelYOffset = 0; var car = Composite.create({ label: 'Car' }), - body = Bodies.trapezoid(xx, yy, width, height, 0.3, { + body = Bodies.rectangle(xx, yy, width, height, { collisionFilter: { group: group }, - friction: 0.01, chamfer: { - radius: 10 - } + radius: height * 0.5 + }, + density: 0.0002 }); var wheelA = Bodies.circle(xx + wheelAOffset, yy + wheelYOffset, wheelSize, { collisionFilter: { group: group }, - friction: 0.8, - density: 0.01 + friction: 0.8 }); var wheelB = Bodies.circle(xx + wheelBOffset, yy + wheelYOffset, wheelSize, { collisionFilter: { group: group }, - friction: 0.8, - density: 0.01 + friction: 0.8 }); var axelA = Constraint.create({ - bodyA: body, - pointA: { x: wheelAOffset, y: wheelYOffset }, - bodyB: wheelA, - stiffness: 0.2, + bodyB: body, + pointB: { x: wheelAOffset, y: wheelYOffset }, + bodyA: wheelA, + stiffness: 1, + length: 0, render: { lineWidth: 0 } }); var axelB = Constraint.create({ - bodyA: body, - pointA: { x: wheelBOffset, y: wheelYOffset }, - bodyB: wheelB, - stiffness: 0.2, + bodyB: body, + pointB: { x: wheelBOffset, y: wheelYOffset }, + bodyA: wheelB, + stiffness: 1, + length: 0, render: { lineWidth: 0 } @@ -7052,7 +7055,7 @@ var Bodies = _dereq_('./Bodies'); */ Composites.softBody = function(xx, yy, columns, rows, columnGap, rowGap, crossBrace, particleRadius, particleOptions, constraintOptions) { particleOptions = Common.extend({ inertia: Infinity }, particleOptions); - constraintOptions = Common.extend({ stiffness: 0.4 }, constraintOptions); + constraintOptions = Common.extend({ stiffness: 0.2 }, constraintOptions); var softBody = Composites.stack(xx, yy, columns, rows, columnGap, rowGap, function(x, y) { return Bodies.circle(x, y, particleRadius, particleOptions); @@ -7538,14 +7541,16 @@ module.exports = Vector; * @method rotate * @param {vector} vector * @param {number} angle - * @return {vector} A new vector rotated about (0, 0) + * @param {vector} [output] + * @return {vector} The vector rotated about (0, 0) */ - Vector.rotate = function(vector, angle) { + Vector.rotate = function(vector, angle, output) { var cos = Math.cos(angle), sin = Math.sin(angle); - return { - x: vector.x * cos - vector.y * sin, - y: vector.x * sin + vector.y * cos - }; + if (!output) output = {}; + var x = vector.x * cos - vector.y * sin; + output.y = vector.x * sin + vector.y * cos; + output.x = x; + return output; }; /** diff --git a/build/matter.min.js b/build/matter.min.js index 46eafe8..f68314c 100644 --- a/build/matter.min.js +++ b/build/matter.min.js @@ -1,89 +1,90 @@ /** -* matter-js 0.12.0 by @liabru 2017-02-02 +* matter-js 0.12.0-alpha by @liabru 2017-05-03 * http://brm.io/matter-js/ * License MIT */ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Matter=e()}}(function(){return function e(t,n,o){function i(s,a){if(!n[s]){if(!t[s]){var l="function"==typeof require&&require;if(!a&&l)return l(s,!0);if(r)return r(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var u=n[s]={exports:{}};t[s][0].call(u.exports,function(e){var n=t[s][1][e];return i(n?n:e)},u,u.exports,e,t,n,o)}return n[s].exports}for(var r="function"==typeof require&&require,s=0;s0&&r.rotateAbout(s.position,n,e.position,s.position)}},o.setVelocity=function(e,t){e.positionPrev.x=e.position.x-t.x,e.positionPrev.y=e.position.y-t.y,e.velocity.x=t.x,e.velocity.y=t.y,e.speed=r.magnitude(e.velocity)},o.setAngularVelocity=function(e,t){e.anglePrev=e.angle-t,e.angularVelocity=t,e.angularSpeed=Math.abs(e.angularVelocity)},o.translate=function(e,t){ -o.setPosition(e,r.add(e.position,t))},o.rotate=function(e,t){o.setAngle(e,e.angle+t)},o.scale=function(e,n,r,s){for(var a=0;a0&&(f.position.x+=e.velocity.x,f.position.y+=e.velocity.y),0!==e.angularVelocity&&(i.rotate(f.vertices,e.angularVelocity,e.position),c.rotate(f.axes,e.angularVelocity),p>0&&r.rotateAbout(f.position,e.angularVelocity,e.position,f.position)),l.update(f.bounds,f.vertices,e.velocity)}},o.applyForce=function(e,t,n){e.force.x+=n.x,e.force.y+=n.y;var o={x:t.x-e.position.x,y:t.y-e.position.y};e.torque+=o.x*n.y-o.y*n.x};var t=function(e){for(var t={mass:0,area:0,inertia:0,centre:{x:0,y:0}},n=1===e.parts.length?0:1;n1?1:0;d1?1:0;f0:0!==(e.mask&t.category)&&0!==(t.mask&e.category)}}()},{"../geometry/Bounds":26,"./Pair":7,"./SAT":11}],6:[function(e,t,n){var o={};t.exports=o;var i=e("./Pair"),r=e("./Detector"),s=e("../core/Common");!function(){o.create=function(e){var t={controller:o,detector:r.collisions,buckets:{},pairs:{},pairsList:[],bucketWidth:48,bucketHeight:48};return s.extend(t,e)},o.update=function(n,o,i,r){var s,p,f,m,v,y=i.world,g=n.buckets,x=!1; -for(s=0;sy.bounds.max.x||h.bounds.max.yy.bounds.max.y)){var b=t(n,h);if(!h.region||b.id!==h.region.id||r){h.region&&!r||(h.region=b);var w=e(b,h.region);for(p=w.startCol;p<=w.endCol;p++)for(f=w.startRow;f<=w.endRow;f++){v=a(p,f),m=g[v];var S=p>=b.startCol&&p<=b.endCol&&f>=b.startRow&&f<=b.endRow,C=p>=h.region.startCol&&p<=h.region.endCol&&f>=h.region.startRow&&f<=h.region.endRow;!S&&C&&C&&m&&u(n,m,h),(h.region===b||S&&!C||r)&&(m||(m=l(g,v)),c(n,m,h))}h.region=b,x=!0}}}x&&(n.pairsList=d(n))},o.clear=function(e){e.buckets={},e.pairs={},e.pairsList=[]};var e=function(e,t){var o=Math.min(e.startCol,t.startCol),i=Math.max(e.endCol,t.endCol),r=Math.min(e.startRow,t.startRow),s=Math.max(e.endRow,t.endRow);return n(o,i,r,s)},t=function(e,t){var o=t.bounds,i=Math.floor(o.min.x/e.bucketWidth),r=Math.floor(o.max.x/e.bucketWidth),s=Math.floor(o.min.y/e.bucketHeight),a=Math.floor(o.max.y/e.bucketHeight); -return n(i,r,s,a)},n=function(e,t,n,o){return{id:e+","+t+","+n+","+o,startCol:e,endCol:t,startRow:n,endRow:o}},a=function(e,t){return"C"+e+"R"+t},l=function(e,t){var n=e[t]=[];return n},c=function(e,t,n){for(var o=0;o0?o.push(n):delete e.pairs[t[i]];return o}}()},{"../core/Common":14,"./Detector":5,"./Pair":7}],7:[function(e,t,n){var o={};t.exports=o;var i=e("./Contact");!function(){o.create=function(e,t){var n=e.bodyA,i=e.bodyB,r=e.parentA,s=e.parentB,a={id:o.id(n,i),bodyA:n,bodyB:i,contacts:{},activeContacts:[],separation:0,isActive:!0,isSensor:n.isSensor||i.isSensor,timeCreated:t,timeUpdated:t,inverseMass:r.inverseMass+s.inverseMass,friction:Math.min(r.friction,s.friction), -frictionStatic:Math.max(r.frictionStatic,s.frictionStatic),restitution:Math.max(r.restitution,s.restitution),slop:Math.max(r.slop,s.slop)};return o.update(a,e,t),a},o.update=function(e,t,n){var r=e.contacts,s=t.supports,a=e.activeContacts,l=t.parentA,c=t.parentB;if(e.collision=t,e.inverseMass=l.inverseMass+c.inverseMass,e.friction=Math.min(l.friction,c.friction),e.frictionStatic=Math.max(l.frictionStatic,c.frictionStatic),e.restitution=Math.max(l.restitution,c.restitution),e.slop=Math.max(l.slop,c.slop),a.length=0,t.collided){for(var u=0;ue&&c.push(s);for(s=0;sf.friction*f.frictionStatic*E*n&&(O=V,F=s.clamp(f.friction*R*n,-O,O));var L=r.cross(A,g),W=r.cross(P,g),q=b/(v.inverseMass+y.inverseMass+v.inverseInertia*L*L+y.inverseInertia*W*W);if(_*=q,F*=q,I<0&&I*I>o._restingThresh*n)S.normalImpulse=0;else{var N=S.normalImpulse;S.normalImpulse=Math.min(S.normalImpulse+_,0),_=S.normalImpulse-N}if(T*T>o._restingThreshTangent*n)S.tangentImpulse=0;else{var D=S.tangentImpulse;S.tangentImpulse=s.clamp(S.tangentImpulse+F,-O,O),F=S.tangentImpulse-D}i.x=g.x*_+x.x*F,i.y=g.y*_+x.y*F,v.isStatic||v.isSleeping||(v.positionPrev.x+=i.x*v.inverseMass,v.positionPrev.y+=i.y*v.inverseMass, -v.anglePrev+=r.cross(A,i)*v.inverseInertia),y.isStatic||y.isSleeping||(y.positionPrev.x-=i.x*y.inverseMass,y.positionPrev.y-=i.y*y.inverseMass,y.anglePrev-=r.cross(P,i)*y.inverseInertia)}}}}}()},{"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],11:[function(e,t,n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../geometry/Vector");!function(){o.collides=function(t,o,s){var a,l,c,u,d=!1;if(s){var p=t.parent,f=o.parent,m=p.speed*p.speed+p.angularSpeed*p.angularSpeed+f.speed*f.speed+f.angularSpeed*f.angularSpeed;d=s&&s.collided&&m<.2,u=s}else u={collided:!1,bodyA:t,bodyB:o};if(s&&d){var v=u.axisBody,y=v===t?o:t,g=[v.axes[s.axisNumber]];if(c=e(v.vertices,y.vertices,g),u.reused=!0,c.overlap<=0)return u.collided=!1,u}else{if(a=e(t.vertices,o.vertices,t.axes),a.overlap<=0)return u.collided=!1,u;if(l=e(o.vertices,t.vertices,o.axes),l.overlap<=0)return u.collided=!1,u;a.overlapi?i=a:a=0?s.index-1:u.length-1;i=u[f],c.x=i.x-d.x,c.y=i.y-d.y,l=-r.dot(n,c),a=i;var m=(s.index+1)%u.length;return i=u[m],c.x=i.x-d.x,c.y=i.y-d.y,o=-r.dot(n,c),o0&&(P=0);var B,M={x:m.x*P,y:m.y*P};i&&!i.isStatic&&(B=r.cross(x,M)*i.inverseInertia*(1-n.angularStiffness),i.constraintImpulse.x-=v.x,i.constraintImpulse.y-=v.y,i.constraintImpulse.angle+=B,i.position.x-=v.x,i.position.y-=v.y,i.angle+=B),s&&!s.isStatic&&(B=r.cross(h,M)*s.inverseInertia*(1-n.angularStiffness),s.constraintImpulse.x+=v.x,s.constraintImpulse.y+=v.y,s.constraintImpulse.angle-=B,s.position.x+=v.x,s.position.y+=v.y,s.angle-=B)}}},o.postSolveAll=function(e){for(var t=0;t0&&(u.position.x+=o.x,u.position.y+=o.y),0!==o.angle&&(i.rotate(u.vertices,o.angle,n.position),l.rotate(u.axes,o.angle),c>0&&r.rotateAbout(u.position,o.angle,n.position,u.position)),a.update(u.bounds,u.vertices,n.velocity)}o.angle=0,o.x=0,o.y=0}}}}()},{"../core/Common":14,"../core/Sleeping":22,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],13:[function(e,t,n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../core/Sleeping"),s=e("../core/Mouse"),a=e("../core/Events"),l=e("../collision/Detector"),c=e("./Constraint"),u=e("../body/Composite"),d=e("../core/Common"),p=e("../geometry/Bounds");!function(){o.create=function(t,n){var i=(t?t.mouse:null)||(n?n.mouse:null);i||(t&&t.render&&t.render.canvas?i=s.create(t.render.canvas):n&&n.element?i=s.create(n.element):(i=s.create(),d.warn("MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected"))); -var r=c.create({label:"Mouse Constraint",pointA:i.position,pointB:{x:0,y:0},length:.01,stiffness:.1,angularStiffness:1,render:{strokeStyle:"#90EE90",lineWidth:3}}),l={type:"mouseConstraint",mouse:i,element:null,body:null,constraint:r,collisionFilter:{category:1,mask:4294967295,group:0}},p=d.extend(l,n);return a.on(t,"beforeUpdate",function(){var n=u.allBodies(t.world);o.update(p,n),e(p)}),p},o.update=function(e,t){var n=e.mouse,o=e.constraint,s=e.body;if(0===n.button){if(o.bodyB)r.set(o.bodyB,!1),o.pointA=n.position;else for(var c=0;c1?1:0;u0&&r.rotateAbout(s.position,n,e.position,s.position)}},o.setVelocity=function(e,t){e.positionPrev.x=e.position.x-t.x,e.positionPrev.y=e.position.y-t.y,e.velocity.x=t.x,e.velocity.y=t.y,e.speed=r.magnitude(e.velocity)},o.setAngularVelocity=function(e,t){e.anglePrev=e.angle-t,e.angularVelocity=t,e.angularSpeed=Math.abs(e.angularVelocity)},o.translate=function(e,t){ +o.setPosition(e,r.add(e.position,t))},o.rotate=function(e,t,n){if(n){var i=Math.cos(t),r=Math.sin(t),s=e.position.x-n.x,a=e.position.y-n.y;o.setPosition(e,{x:n.x+(s*i-a*r),y:n.y+(s*r+a*i)}),o.setAngle(e,e.angle+t)}else o.setAngle(e,e.angle+t)},o.scale=function(e,n,r,s){for(var a=0;a0&&(f.position.x+=e.velocity.x,f.position.y+=e.velocity.y),0!==e.angularVelocity&&(i.rotate(f.vertices,e.angularVelocity,e.position),c.rotate(f.axes,e.angularVelocity),p>0&&r.rotateAbout(f.position,e.angularVelocity,e.position,f.position)),l.update(f.bounds,f.vertices,e.velocity)}},o.applyForce=function(e,t,n){e.force.x+=n.x,e.force.y+=n.y;var o={x:t.x-e.position.x,y:t.y-e.position.y};e.torque+=o.x*n.y-o.y*n.x};var t=function(e){for(var t={mass:0,area:0,inertia:0,centre:{x:0,y:0}},n=1===e.parts.length?0:1;n1?1:0;u1?1:0;f0:0!==(e.mask&t.category)&&0!==(t.mask&e.category)}}()},{"../geometry/Bounds":26,"./Pair":7,"./SAT":11}],6:[function(e,t,n){var o={};t.exports=o;var i=e("./Pair"),r=e("./Detector"),s=e("../core/Common"); +!function(){o.create=function(e){var t={controller:o,detector:r.collisions,buckets:{},pairs:{},pairsList:[],bucketWidth:48,bucketHeight:48};return s.extend(t,e)},o.update=function(n,o,i,r){var s,p,f,m,v,y=i.world,g=n.buckets,x=!1;for(s=0;sy.bounds.max.x||h.bounds.max.yy.bounds.max.y)){var b=t(n,h);if(!h.region||b.id!==h.region.id||r){h.region&&!r||(h.region=b);var w=e(b,h.region);for(p=w.startCol;p<=w.endCol;p++)for(f=w.startRow;f<=w.endRow;f++){v=a(p,f),m=g[v];var S=p>=b.startCol&&p<=b.endCol&&f>=b.startRow&&f<=b.endRow,C=p>=h.region.startCol&&p<=h.region.endCol&&f>=h.region.startRow&&f<=h.region.endRow;!S&&C&&C&&m&&d(n,m,h),(h.region===b||S&&!C||r)&&(m||(m=l(g,v)),c(n,m,h))}h.region=b,x=!0}}}x&&(n.pairsList=u(n))},o.clear=function(e){e.buckets={},e.pairs={},e.pairsList=[]};var e=function(e,t){var o=Math.min(e.startCol,t.startCol),i=Math.max(e.endCol,t.endCol),r=Math.min(e.startRow,t.startRow),s=Math.max(e.endRow,t.endRow); +return n(o,i,r,s)},t=function(e,t){var o=t.bounds,i=Math.floor(o.min.x/e.bucketWidth),r=Math.floor(o.max.x/e.bucketWidth),s=Math.floor(o.min.y/e.bucketHeight),a=Math.floor(o.max.y/e.bucketHeight);return n(i,r,s,a)},n=function(e,t,n,o){return{id:e+","+t+","+n+","+o,startCol:e,endCol:t,startRow:n,endRow:o}},a=function(e,t){return"C"+e+"R"+t},l=function(e,t){var n=e[t]=[];return n},c=function(e,t,n){for(var o=0;o0?o.push(n):delete e.pairs[t[i]];return o}}()},{"../core/Common":14,"./Detector":5,"./Pair":7}],7:[function(e,t,n){var o={};t.exports=o;var i=e("./Contact");!function(){o.create=function(e,t){var n=e.bodyA,i=e.bodyB,r=e.parentA,s=e.parentB,a={ +id:o.id(n,i),bodyA:n,bodyB:i,contacts:{},activeContacts:[],separation:0,isActive:!0,isSensor:n.isSensor||i.isSensor,timeCreated:t,timeUpdated:t,inverseMass:r.inverseMass+s.inverseMass,friction:Math.min(r.friction,s.friction),frictionStatic:Math.max(r.frictionStatic,s.frictionStatic),restitution:Math.max(r.restitution,s.restitution),slop:Math.max(r.slop,s.slop)};return o.update(a,e,t),a},o.update=function(e,t,n){var r=e.contacts,s=t.supports,a=e.activeContacts,l=t.parentA,c=t.parentB;if(e.collision=t,e.inverseMass=l.inverseMass+c.inverseMass,e.friction=Math.min(l.friction,c.friction),e.frictionStatic=Math.max(l.frictionStatic,c.frictionStatic),e.restitution=Math.max(l.restitution,c.restitution),e.slop=Math.max(l.slop,c.slop),a.length=0,t.collided){for(var d=0;de&&c.push(s);for(s=0;sf.friction*f.frictionStatic*E*n&&(F=V,L=s.clamp(f.friction*R*n,-F,F));var O=r.cross(A,g),W=r.cross(P,g),q=b/(v.inverseMass+y.inverseMass+v.inverseInertia*O*O+y.inverseInertia*W*W);if(_*=q,L*=q,I<0&&I*I>o._restingThresh*n)S.normalImpulse=0;else{var D=S.normalImpulse;S.normalImpulse=Math.min(S.normalImpulse+_,0),_=S.normalImpulse-D}if(T*T>o._restingThreshTangent*n)S.tangentImpulse=0;else{var N=S.tangentImpulse;S.tangentImpulse=s.clamp(S.tangentImpulse+L,-F,F), +L=S.tangentImpulse-N}i.x=g.x*_+x.x*L,i.y=g.y*_+x.y*L,v.isStatic||v.isSleeping||(v.positionPrev.x+=i.x*v.inverseMass,v.positionPrev.y+=i.y*v.inverseMass,v.anglePrev+=r.cross(A,i)*v.inverseInertia),y.isStatic||y.isSleeping||(y.positionPrev.x-=i.x*y.inverseMass,y.positionPrev.y-=i.y*y.inverseMass,y.anglePrev-=r.cross(P,i)*y.inverseInertia)}}}}}()},{"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],11:[function(e,t,n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../geometry/Vector");!function(){o.collides=function(t,o,s){var a,l,c,d,u=!1;if(s){var p=t.parent,f=o.parent,m=p.speed*p.speed+p.angularSpeed*p.angularSpeed+f.speed*f.speed+f.angularSpeed*f.angularSpeed;u=s&&s.collided&&m<.2,d=s}else d={collided:!1,bodyA:t,bodyB:o};if(s&&u){var v=d.axisBody,y=v===t?o:t,g=[v.axes[s.axisNumber]];if(c=e(v.vertices,y.vertices,g),d.reused=!0,c.overlap<=0)return d.collided=!1,d}else{if(a=e(t.vertices,o.vertices,t.axes),a.overlap<=0)return d.collided=!1, +d;if(l=e(o.vertices,t.vertices,o.axes),l.overlap<=0)return d.collided=!1,d;a.overlapi?i=a:a=0?s.index-1:d.length-1;i=d[f],c.x=i.x-u.x,c.y=i.y-u.y,l=-r.dot(n,c),a=i;var m=(s.index+1)%d.length;return i=d[m],c.x=i.x-u.x,c.y=i.y-u.y,o=-r.dot(n,c),o0&&(u.position.x+=c.x,u.position.y+=c.y),0!==c.angle&&(i.rotate(u.vertices,c.angle,n.position),l.rotate(u.axes,c.angle),d>0&&r.rotateAbout(u.position,c.angle,n.position,u.position)),a.update(u.bounds,u.vertices,n.velocity)}c.angle*=o._warming,c.x*=o._warming,c.y*=o._warming}}}}()},{"../core/Common":14,"../core/Sleeping":22,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],13:[function(e,t,n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../core/Sleeping"),s=e("../core/Mouse"),a=e("../core/Events"),l=e("../collision/Detector"),c=e("./Constraint"),d=e("../body/Composite"),u=e("../core/Common"),p=e("../geometry/Bounds");!function(){o.create=function(t,n){var i=(t?t.mouse:null)||(n?n.mouse:null);i||(t&&t.render&&t.render.canvas?i=s.create(t.render.canvas):n&&n.element?i=s.create(n.element):(i=s.create(),u.warn("MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected"))); +var r=c.create({label:"Mouse Constraint",pointA:i.position,pointB:{x:0,y:0},length:.01,stiffness:.1,angularStiffness:1,render:{strokeStyle:"#90EE90",lineWidth:3}}),l={type:"mouseConstraint",mouse:i,element:null,body:null,constraint:r,collisionFilter:{category:1,mask:4294967295,group:0}},p=u.extend(l,n);return a.on(t,"beforeUpdate",function(){var n=d.allBodies(t.world);o.update(p,n),e(p)}),p},o.update=function(e,t){var n=e.mouse,o=e.constraint,s=e.body;if(0===n.button){if(o.bodyB)r.set(o.bodyB,!1),o.pointA=n.position;else for(var c=0;c1?1:0;d>16)+o,r=(n>>8&255)+o,s=(255&n)+o;return"#"+(16777216+65536*(i<255?i<1?0:i:255)+256*(r<255?r<1?0:r:255)+(s<255?s<1?0:s:255)).toString(16).slice(1)},o.shuffle=function(e){for(var t=e.length-1;t>0;t--){var n=Math.floor(o.random()*(t+1)),i=e[t];e[t]=e[n],e[n]=i}return e},o.choose=function(e){return e[Math.floor(o.random()*e.length)]},o.isElement=function(e){try{return e instanceof HTMLElement}catch(t){return"object"==typeof e&&1===e.nodeType&&"object"==typeof e.style&&"object"==typeof e.ownerDocument}},o.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)},o.isFunction=function(e){return"function"==typeof e},o.isPlainObject=function(e){return"object"==typeof e&&e.constructor===Object; },o.isString=function(e){return"[object String]"===toString.call(e)},o.clamp=function(e,t,n){return en?n:e},o.sign=function(e){return e<0?-1:1},o.now=function(){var e=window.performance||{};return e.now=function(){return e.now||e.webkitNow||e.msNow||e.oNow||e.mozNow||function(){return+new Date}}(),e.now()},o.random=function(t,n){return t="undefined"!=typeof t?t:0,n="undefined"!=typeof n?n:1,t+e()*(n-t)};var e=function(){return o._seed=(9301*o._seed+49297)%233280,o._seed/233280};o.colorToNumber=function(e){return e=e.replace("#",""),3==e.length&&(e=e.charAt(0)+e.charAt(0)+e.charAt(1)+e.charAt(1)+e.charAt(2)+e.charAt(2)),parseInt(e,16)},o.logLevel=1,o.log=function(){console&&o.logLevel>0&&o.logLevel<=3&&console.log.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},o.info=function(){console&&o.logLevel>0&&o.logLevel<=2&&console.info.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},o.warn=function(){console&&o.logLevel>0&&o.logLevel<=3&&console.warn.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments))); },o.nextId=function(){return o._nextId++},o.indexOf=function(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0;n0&&u.trigger(o,"collisionStart",{pairs:w.collisionStart}),s.preSolvePosition(w.list),c=0;c0&&u.trigger(o,"collisionActive",{ -pairs:w.collisionActive}),w.collisionEnd.length>0&&u.trigger(o,"collisionEnd",{pairs:w.collisionEnd}),e(x),u.trigger(o,"afterUpdate",g),o},o.merge=function(e,t){if(f.extend(e,t),t.world){e.world=t.world,o.clear(e);for(var n=d.allBodies(e.world),i=0;ir?(i.warn("Plugin.register:",o.toString(t),"was upgraded to",o.toString(e)),o._registry[e.name]=e):n-1},o.isFor=function(e,t){var n=e.for&&o.dependencyParse(e.for);return!e.for||t.name===n.name&&o.versionSatisfies(t.version,n.range)},o.use=function(e,t){if(e.uses=(e.uses||[]).concat(t||[]),0===e.uses.length)return void i.warn("Plugin.use:",o.toString(e),"does not specify any dependencies to install.");for(var n=o.dependencies(e),r=i.topologicalSort(n),s=[],a=0;a0&&i.info(s.join(" "))},o.dependencies=function(e,t){var n=o.dependencyParse(e),r=n.name;if(t=t||{},!(r in t)){e=o.resolve(e)||e,t[r]=i.map(e.uses||[],function(t){ -o.isPlugin(t)&&o.register(t);var r=o.dependencyParse(t),s=o.resolve(t);return s&&!o.versionSatisfies(s.version,r.range)?(i.warn("Plugin.dependencies:",o.toString(s),"does not satisfy",o.toString(r),"used by",o.toString(n)+"."),s._warned=!0,e._warned=!0):s||(i.warn("Plugin.dependencies:",o.toString(t),"used by",o.toString(n),"could not be resolved."),e._warned=!0),r.name});for(var s=0;s=i[2];if("^"===n.operator)return i[0]>0?s[0]===i[0]&&r.number>=n.number:i[1]>0?s[1]===i[1]&&s[2]>=i[2]:s[2]===i[2]}return e===t||"*"===e}}()},{"./Common":14}],21:[function(e,t,n){var o={};t.exports=o;var i=e("./Events"),r=e("./Engine"),s=e("./Common");!function(){var e,t;if("undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame,t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),!e){var n;e=function(e){n=setTimeout(function(){e(s.now())},1e3/60)},t=function(){clearTimeout(n)}}o.create=function(e){ -var t={fps:60,correction:1,deltaSampleSize:60,counterTimestamp:0,frameCounter:0,deltaHistory:[],timePrev:null,timeScalePrev:1,frameRequestId:null,isFixed:!1,enabled:!0},n=s.extend(t,e);return n.delta=n.delta||1e3/n.fps,n.deltaMin=n.deltaMin||1e3/n.fps,n.deltaMax=n.deltaMax||1e3/(.5*n.fps),n.fps=1e3/n.delta,n},o.run=function(t,n){return"undefined"!=typeof t.positionIterations&&(n=t,t=o.create()),function i(r){t.frameRequestId=e(i),r&&t.enabled&&o.tick(t,n,r)}(),t},o.tick=function(e,t,n){var o,s=t.timing,a=1,l={timestamp:s.timestamp};i.trigger(e,"beforeTick",l),i.trigger(t,"beforeTick",l),e.isFixed?o=e.delta:(o=n-e.timePrev||e.delta,e.timePrev=n,e.deltaHistory.push(o),e.deltaHistory=e.deltaHistory.slice(-e.deltaSampleSize),o=Math.min.apply(null,e.deltaHistory),o=oe.deltaMax?e.deltaMax:o,a=o/e.delta,e.delta=o),0!==e.timeScalePrev&&(a*=s.timeScale/e.timeScalePrev),0===s.timeScale&&(a=0),e.timeScalePrev=s.timeScale,e.correction=a,e.frameCounter+=1,n-e.counterTimestamp>=1e3&&(e.fps=e.frameCounter*((n-e.counterTimestamp)/1e3), -e.counterTimestamp=n,e.frameCounter=0),i.trigger(e,"tick",l),i.trigger(t,"tick",l),t.world.isModified&&t.render&&t.render.controller&&t.render.controller.clear&&t.render.controller.clear(t.render),i.trigger(e,"beforeUpdate",l),r.update(t,o,a),i.trigger(e,"afterUpdate",l),t.render&&t.render.controller&&(i.trigger(e,"beforeRender",l),i.trigger(t,"beforeRender",l),t.render.controller.world(t.render),i.trigger(e,"afterRender",l),i.trigger(t,"afterRender",l)),i.trigger(e,"afterTick",l),i.trigger(t,"afterTick",l)},o.stop=function(e){t(e.frameRequestId)},o.start=function(e,t){o.run(e,t)}}()},{"./Common":14,"./Engine":15,"./Events":16}],22:[function(e,t,n){var o={};t.exports=o;var i=e("./Events");!function(){o._motionWakeThreshold=.18,o._motionSleepThreshold=.08,o._minBias=.9,o.update=function(e,t){for(var n=t*t*t,i=0;i0&&r.motion=r.sleepThreshold&&o.set(r,!0)):r.sleepCounter>0&&(r.sleepCounter-=1)}else o.set(r,!1)}},o.afterCollisions=function(e,t){for(var n=t*t*t,i=0;io._motionWakeThreshold*n&&o.set(c,!1)}}}},o.set=function(e,t){var n=e.isSleeping;t?(e.isSleeping=!0,e.sleepCounter=e.sleepThreshold,e.positionImpulse.x=0,e.positionImpulse.y=0,e.positionPrev.x=e.position.x,e.positionPrev.y=e.position.y,e.anglePrev=e.angle,e.speed=0,e.angularSpeed=0,e.motion=0,n||i.trigger(e,"sleepStart")):(e.isSleeping=!1,e.sleepCounter=0,n&&i.trigger(e,"sleepEnd"))}}()},{"./Events":16}],23:[function(e,t,n){(function(n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../core/Common"),s=e("../body/Body"),a=e("../geometry/Bounds"),l=e("../geometry/Vector"),c="undefined"!=typeof window?window.decomp:"undefined"!=typeof n?n.decomp:null; -!function(){o.rectangle=function(e,t,n,o,a){a=a||{};var l={label:"Rectangle Body",position:{x:e,y:t},vertices:i.fromPath("L 0 0 L "+n+" 0 L "+n+" "+o+" L 0 "+o)};if(a.chamfer){var c=a.chamfer;l.vertices=i.chamfer(l.vertices,c.radius,c.quality,c.qualityMin,c.qualityMax),delete a.chamfer}return s.create(r.extend({},l,a))},o.trapezoid=function(e,t,n,o,a,l){l=l||{},a*=.5;var c,u=(1-2*a)*n,d=n*a,p=d+u,f=p+d;c=a<.5?"L 0 0 L "+d+" "+-o+" L "+p+" "+-o+" L "+f+" 0":"L 0 0 L "+p+" "+-o+" L "+f+" 0";var m={label:"Trapezoid Body",position:{x:e,y:t},vertices:i.fromPath(c)};if(l.chamfer){var v=l.chamfer;m.vertices=i.chamfer(m.vertices,v.radius,v.quality,v.qualityMin,v.qualityMax),delete l.chamfer}return s.create(r.extend({},m,l))},o.circle=function(e,t,n,i,s){i=i||{};var a={label:"Circle Body",circleRadius:n};s=s||25;var l=Math.ceil(Math.max(10,Math.min(s,n)));return l%2===1&&(l+=1),o.polygon(e,t,l,n,r.extend({},a,i))},o.polygon=function(e,t,n,a,l){if(l=l||{},n<3)return o.circle(e,t,a,l);for(var c=2*Math.PI/n,u="",d=.5*c,p=0;p0&&i.area(P)1?(f=s.create(r.extend({parts:m.slice(0)},o)),s.setPosition(f,{x:e,y:t}),f):m[0]}}()}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../body/Body":1,"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],24:[function(e,t,n){var o={};t.exports=o;var i=e("../body/Composite"),r=e("../constraint/Constraint"),s=e("../core/Common"),a=e("../body/Body"),l=e("./Bodies");!function(){o.stack=function(e,t,n,o,r,s,l){for(var c,u=i.create({label:"Stack" -}),d=e,p=t,f=0,m=0;mv&&(v=x),a.translate(g,{x:.5*h,y:.5*x}),d=g.bounds.max.x+r,i.addBody(u,g),c=g,f+=1}else d+=r}p+=v+s,d=e}return u},o.chain=function(e,t,n,o,a,l){for(var c=e.bodies,u=1;u0)for(c=0;c0&&(p=f[c-1+(l-1)*t],i.addConstraint(e,r.create(s.extend({bodyA:p,bodyB:d},a)))),o&&cp)){c=p-c;var m=c,v=n-1-c;if(!(sv)){1===d&&a.translate(u,{x:(s+(n%2===1?1:-1))*f,y:0});var y=u?s*f:0;return l(e+y+s*r,o,s,c,u,d)}}})},o.newtonsCradle=function(e,t,n,o,s){for(var a=i.create({label:"Newtons Cradle"}),c=0;ce.max.x&&(e.max.x=i.x),i.xe.max.y&&(e.max.y=i.y),i.y0?e.max.x+=n.x:e.min.x+=n.x,n.y>0?e.max.y+=n.y:e.min.y+=n.y)},o.contains=function(e,t){return t.x>=e.min.x&&t.x<=e.max.x&&t.y>=e.min.y&&t.y<=e.max.y},o.overlaps=function(e,t){return e.min.x<=t.max.x&&e.max.x>=t.min.x&&e.max.y>=t.min.y&&e.min.y<=t.max.y},o.translate=function(e,t){e.min.x+=t.x,e.max.x+=t.x,e.min.y+=t.y,e.max.y+=t.y},o.shift=function(e,t){var n=e.max.x-e.min.x,o=e.max.y-e.min.y;e.min.x=t.x,e.max.x=t.x+n,e.min.y=t.y,e.max.y=t.y+o}}()},{}],27:[function(e,t,n){var o={};t.exports=o;e("../geometry/Bounds");!function(){o.pathToVertices=function(t,n){ -var o,i,r,s,a,l,c,u,d,p,f,m,v=[],y=0,g=0,x=0;n=n||15;var h=function(e,t,n){var o=n%2===1&&n>1;if(!d||e!=d.x||t!=d.y){d&&o?(f=d.x,m=d.y):(f=0,m=0);var i={x:f+e,y:m+t};!o&&d||(d=i),v.push(i),g=f+e,x=m+t}},b=function(e){var t=e.pathSegTypeAsLetter.toUpperCase();if("Z"!==t){switch(t){case"M":case"L":case"T":case"C":case"S":case"Q":g=e.x,x=e.y;break;case"H":g=e.x;break;case"V":x=e.y}h(g,x,e.pathSegType)}};for(e(t),r=t.getTotalLength(),l=[],o=0;o0)return!1}return!0},o.scale=function(e,t,n,r){if(1===t&&1===n)return e;r=r||o.centre(e);for(var s,a,l=0;l=0?l-1:e.length-1],u=e[l],d=e[(l+1)%e.length],p=t[l0&&(r|=2),3===r)return!1;return 0!==r||null},o.hull=function(e){var t,n,o=[],r=[];for(e=e.slice(0),e.sort(function(e,t){var n=e.x-t.x;return 0!==n?n:e.y-t.y}),n=0;n=2&&i.cross3(r[r.length-2],r[r.length-1],t)<=0;)r.pop();r.push(t)}for(n=e.length-1;n>=0;n--){for(t=e[n];o.length>=2&&i.cross3(o[o.length-2],o[o.length-1],t)<=0;)o.pop();o.push(t)}return o.pop(),r.pop(), -o.concat(r)}}()},{"../core/Common":14,"../geometry/Vector":28}],30:[function(e,t,n){var o=t.exports=e("../core/Matter");o.Body=e("../body/Body"),o.Composite=e("../body/Composite"),o.World=e("../body/World"),o.Contact=e("../collision/Contact"),o.Detector=e("../collision/Detector"),o.Grid=e("../collision/Grid"),o.Pairs=e("../collision/Pairs"),o.Pair=e("../collision/Pair"),o.Query=e("../collision/Query"),o.Resolver=e("../collision/Resolver"),o.SAT=e("../collision/SAT"),o.Constraint=e("../constraint/Constraint"),o.MouseConstraint=e("../constraint/MouseConstraint"),o.Common=e("../core/Common"),o.Engine=e("../core/Engine"),o.Events=e("../core/Events"),o.Mouse=e("../core/Mouse"),o.Runner=e("../core/Runner"),o.Sleeping=e("../core/Sleeping"),o.Plugin=e("../core/Plugin"),o.Bodies=e("../factory/Bodies"),o.Composites=e("../factory/Composites"),o.Axes=e("../geometry/Axes"),o.Bounds=e("../geometry/Bounds"),o.Svg=e("../geometry/Svg"),o.Vector=e("../geometry/Vector"),o.Vertices=e("../geometry/Vertices"), -o.Render=e("../render/Render"),o.RenderPixi=e("../render/RenderPixi"),o.World.add=o.Composite.add,o.World.remove=o.Composite.remove,o.World.addComposite=o.Composite.addComposite,o.World.addBody=o.Composite.addBody,o.World.addConstraint=o.Composite.addConstraint,o.World.clear=o.Composite.clear,o.Engine.run=o.Runner.run},{"../body/Body":1,"../body/Composite":2,"../body/World":3,"../collision/Contact":4,"../collision/Detector":5,"../collision/Grid":6,"../collision/Pair":7,"../collision/Pairs":8,"../collision/Query":9,"../collision/Resolver":10,"../collision/SAT":11,"../constraint/Constraint":12,"../constraint/MouseConstraint":13,"../core/Common":14,"../core/Engine":15,"../core/Events":16,"../core/Matter":17,"../core/Metrics":18,"../core/Mouse":19,"../core/Plugin":20,"../core/Runner":21,"../core/Sleeping":22,"../factory/Bodies":23,"../factory/Composites":24,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Svg":27,"../geometry/Vector":28,"../geometry/Vertices":29,"../render/Render":31, -"../render/RenderPixi":32}],31:[function(e,t,n){var o={};t.exports=o;var i=e("../core/Common"),r=e("../body/Composite"),s=e("../geometry/Bounds"),a=e("../core/Events"),l=e("../collision/Grid"),c=e("../geometry/Vector"),u=e("../core/Mouse");!function(){var e,t;"undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout(function(){e(i.now())},1e3/60)},t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),o.create=function(e){var t={controller:o,engine:null,element:null,canvas:null,mouse:null,frameRequestId:null,options:{width:800,height:600,pixelRatio:1,background:"#18181d",wireframeBackground:"#0f0f13",hasBounds:!!e.bounds,enabled:!0,wireframes:!0,showSleeping:!0,showDebug:!1,showBroadphase:!1,showBounds:!1,showVelocity:!1,showCollisions:!1,showSeparations:!1,showAxes:!1,showPositions:!1, -showAngleIndicator:!1,showIds:!1,showShadows:!1,showVertexNumbers:!1,showConvexHulls:!1,showInternalEdges:!1,showMousePosition:!1}},r=i.extend(t,e);return r.canvas&&(r.canvas.width=r.options.width||r.canvas.width,r.canvas.height=r.options.height||r.canvas.height),r.mouse=e.mouse,r.engine=e.engine,r.canvas=r.canvas||n(r.options.width,r.options.height),r.context=r.canvas.getContext("2d"),r.textures={},r.bounds=r.bounds||{min:{x:0,y:0},max:{x:r.canvas.width,y:r.canvas.height}},1!==r.options.pixelRatio&&o.setPixelRatio(r,r.options.pixelRatio),i.isElement(r.element)?r.element.appendChild(r.canvas):i.log("Render.create: options.element was undefined, render.canvas was created but not appended","warn"),r},o.run=function(t){!function n(i){t.frameRequestId=e(n),o.world(t)}()},o.stop=function(e){t(e.frameRequestId)},o.setPixelRatio=function(e,t){var n=e.options,o=e.canvas;"auto"===t&&(t=d(o)),n.pixelRatio=t,o.setAttribute("data-pixel-ratio",t),o.width=n.width*t,o.height=n.height*t,o.style.width=n.width+"px", -o.style.height=n.height+"px",e.context.scale(t,t)},o.lookAt=function(e,t,n,o){o="undefined"==typeof o||o,t=i.isArray(t)?t:[t],n=n||{x:0,y:0};for(var r={min:{x:1/0,y:1/0},max:{x:-(1/0),y:-(1/0)}},s=0;sr.max.x&&(r.max.x=c.x),l.yr.max.y&&(r.max.y=c.y))}var d=r.max.x-r.min.x+2*n.x,p=r.max.y-r.min.y+2*n.y,f=e.canvas.height,m=e.canvas.width,v=m/f,y=d/p,g=1,x=1;y>v?x=y/v:g=v/y,e.options.hasBounds=!0,e.bounds.min.x=r.min.x,e.bounds.max.x=r.min.x+d*g,e.bounds.min.y=r.min.y,e.bounds.max.y=r.min.y+p*x,o&&(e.bounds.min.x+=.5*d-d*g*.5,e.bounds.max.x+=.5*d-d*g*.5,e.bounds.min.y+=.5*p-p*x*.5,e.bounds.max.y+=.5*p-p*x*.5),e.bounds.min.x-=n.x,e.bounds.max.x-=n.x,e.bounds.min.y-=n.y,e.bounds.max.y-=n.y,e.mouse&&(u.setScale(e.mouse,{x:(e.bounds.max.x-e.bounds.min.x)/e.canvas.width,y:(e.bounds.max.y-e.bounds.min.y)/e.canvas.height -}),u.setOffset(e.mouse,e.bounds.min))},o.startViewTransform=function(e){var t=e.bounds.max.x-e.bounds.min.x,n=e.bounds.max.y-e.bounds.min.y,o=t/e.options.width,i=n/e.options.height;e.context.scale(1/o,1/i),e.context.translate(-e.bounds.min.x,-e.bounds.min.y)},o.endViewTransform=function(e){e.context.setTransform(e.options.pixelRatio,0,0,e.options.pixelRatio,0,0)},o.world=function(e){var t,n=e.engine,i=n.world,d=e.canvas,p=e.context,m=e.options,v=r.allBodies(i),y=r.allConstraints(i),g=m.wireframes?m.wireframeBackground:m.background,x=[],h=[],b={timestamp:n.timing.timestamp};if(a.trigger(e,"beforeRender",b),e.currentBackground!==g&&f(e,g),p.globalCompositeOperation="source-in",p.fillStyle="transparent",p.fillRect(0,0,d.width,d.height),p.globalCompositeOperation="source-over",m.hasBounds){for(t=0;t=500){var c="";s.timing&&(c+="fps: "+Math.round(s.timing.fps)+l),e.debugString=c,e.debugTimestamp=o.timing.timestamp}if(e.debugString){n.font="12px Arial",a.wireframes?n.fillStyle="rgba(255,255,255,0.5)":n.fillStyle="rgba(0,0,0,0.5)";for(var u=e.debugString.split("\n"),d=0;d1?1:0;s1?1:0;a1?1:0;r1?1:0;l1?1:0;r1?1:0;r1?1:0;i0)){var d=o.activeContacts[0].vertex.x,p=o.activeContacts[0].vertex.y;2===o.activeContacts.length&&(d=(o.activeContacts[0].vertex.x+o.activeContacts[1].vertex.x)/2,p=(o.activeContacts[0].vertex.y+o.activeContacts[1].vertex.y)/2),i.bodyB===i.supports[0].body||i.bodyA.isStatic===!0?a.moveTo(d-8*i.normal.x,p-8*i.normal.y):a.moveTo(d+8*i.normal.x,p+8*i.normal.y), -a.lineTo(d,p)}l.wireframes?a.strokeStyle="rgba(255,165,0,0.7)":a.strokeStyle="orange",a.lineWidth=1,a.stroke()},o.separations=function(e,t,n){var o,i,r,s,a,l=n,c=e.options;for(l.beginPath(),a=0;a1?1:0;p0&&d.trigger(o,"collisionStart",{pairs:w.collisionStart}),s.preSolvePosition(w.list),c=0;c0&&d.trigger(o,"collisionActive",{pairs:w.collisionActive}),w.collisionEnd.length>0&&d.trigger(o,"collisionEnd",{pairs:w.collisionEnd}),e(x),d.trigger(o,"afterUpdate",g),o},o.merge=function(e,t){if(f.extend(e,t),t.world){e.world=t.world,o.clear(e);for(var n=u.allBodies(e.world),i=0;ir?(i.warn("Plugin.register:",o.toString(t),"was upgraded to",o.toString(e)),o._registry[e.name]=e):n-1},o.isFor=function(e,t){var n=e.for&&o.dependencyParse(e.for);return!e.for||t.name===n.name&&o.versionSatisfies(t.version,n.range)},o.use=function(e,t){if(e.uses=(e.uses||[]).concat(t||[]),0===e.uses.length)return void i.warn("Plugin.use:",o.toString(e),"does not specify any dependencies to install.");for(var n=o.dependencies(e),r=i.topologicalSort(n),s=[],a=0;a0&&i.info(s.join(" "))},o.dependencies=function(e,t){var n=o.dependencyParse(e),r=n.name; +if(t=t||{},!(r in t)){e=o.resolve(e)||e,t[r]=i.map(e.uses||[],function(t){o.isPlugin(t)&&o.register(t);var r=o.dependencyParse(t),s=o.resolve(t);return s&&!o.versionSatisfies(s.version,r.range)?(i.warn("Plugin.dependencies:",o.toString(s),"does not satisfy",o.toString(r),"used by",o.toString(n)+"."),s._warned=!0,e._warned=!0):s||(i.warn("Plugin.dependencies:",o.toString(t),"used by",o.toString(n),"could not be resolved."),e._warned=!0),r.name});for(var s=0;s=i[2];if("^"===n.operator)return i[0]>0?s[0]===i[0]&&r.number>=n.number:i[1]>0?s[1]===i[1]&&s[2]>=i[2]:s[2]===i[2]}return e===t||"*"===e}}()},{"./Common":14}],21:[function(e,t,n){var o={};t.exports=o;var i=e("./Events"),r=e("./Engine"),s=e("./Common");!function(){var e,t;if("undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame,t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),!e){var n;e=function(e){n=setTimeout(function(){e(s.now())},1e3/60)},t=function(){clearTimeout(n); +}}o.create=function(e){var t={fps:60,correction:1,deltaSampleSize:60,counterTimestamp:0,frameCounter:0,deltaHistory:[],timePrev:null,timeScalePrev:1,frameRequestId:null,isFixed:!1,enabled:!0},n=s.extend(t,e);return n.delta=n.delta||1e3/n.fps,n.deltaMin=n.deltaMin||1e3/n.fps,n.deltaMax=n.deltaMax||1e3/(.5*n.fps),n.fps=1e3/n.delta,n},o.run=function(t,n){return"undefined"!=typeof t.positionIterations&&(n=t,t=o.create()),function i(r){t.frameRequestId=e(i),r&&t.enabled&&o.tick(t,n,r)}(),t},o.tick=function(e,t,n){var o,s=t.timing,a=1,l={timestamp:s.timestamp};i.trigger(e,"beforeTick",l),i.trigger(t,"beforeTick",l),e.isFixed?o=e.delta:(o=n-e.timePrev||e.delta,e.timePrev=n,e.deltaHistory.push(o),e.deltaHistory=e.deltaHistory.slice(-e.deltaSampleSize),o=Math.min.apply(null,e.deltaHistory),o=oe.deltaMax?e.deltaMax:o,a=o/e.delta,e.delta=o),0!==e.timeScalePrev&&(a*=s.timeScale/e.timeScalePrev),0===s.timeScale&&(a=0),e.timeScalePrev=s.timeScale,e.correction=a,e.frameCounter+=1, +n-e.counterTimestamp>=1e3&&(e.fps=e.frameCounter*((n-e.counterTimestamp)/1e3),e.counterTimestamp=n,e.frameCounter=0),i.trigger(e,"tick",l),i.trigger(t,"tick",l),t.world.isModified&&t.render&&t.render.controller&&t.render.controller.clear&&t.render.controller.clear(t.render),i.trigger(e,"beforeUpdate",l),r.update(t,o,a),i.trigger(e,"afterUpdate",l),t.render&&t.render.controller&&(i.trigger(e,"beforeRender",l),i.trigger(t,"beforeRender",l),t.render.controller.world(t.render),i.trigger(e,"afterRender",l),i.trigger(t,"afterRender",l)),i.trigger(e,"afterTick",l),i.trigger(t,"afterTick",l)},o.stop=function(e){t(e.frameRequestId)},o.start=function(e,t){o.run(e,t)}}()},{"./Common":14,"./Engine":15,"./Events":16}],22:[function(e,t,n){var o={};t.exports=o;var i=e("./Events");!function(){o._motionWakeThreshold=.18,o._motionSleepThreshold=.08,o._minBias=.9,o.update=function(e,t){for(var n=t*t*t,i=0;i0&&r.motion=r.sleepThreshold&&o.set(r,!0)):r.sleepCounter>0&&(r.sleepCounter-=1)}else o.set(r,!1)}},o.afterCollisions=function(e,t){for(var n=t*t*t,i=0;io._motionWakeThreshold*n&&o.set(c,!1)}}}},o.set=function(e,t){var n=e.isSleeping;t?(e.isSleeping=!0,e.sleepCounter=e.sleepThreshold,e.positionImpulse.x=0,e.positionImpulse.y=0,e.positionPrev.x=e.position.x,e.positionPrev.y=e.position.y,e.anglePrev=e.angle,e.speed=0,e.angularSpeed=0,e.motion=0,n||i.trigger(e,"sleepStart")):(e.isSleeping=!1,e.sleepCounter=0,n&&i.trigger(e,"sleepEnd"))}}()},{"./Events":16}],23:[function(e,t,n){(function(n){ +var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../core/Common"),s=e("../body/Body"),a=e("../geometry/Bounds"),l=e("../geometry/Vector"),c="undefined"!=typeof window?window.decomp:"undefined"!=typeof n?n.decomp:null;!function(){o.rectangle=function(e,t,n,o,a){a=a||{};var l={label:"Rectangle Body",position:{x:e,y:t},vertices:i.fromPath("L 0 0 L "+n+" 0 L "+n+" "+o+" L 0 "+o)};if(a.chamfer){var c=a.chamfer;l.vertices=i.chamfer(l.vertices,c.radius,c.quality,c.qualityMin,c.qualityMax),delete a.chamfer}return s.create(r.extend({},l,a))},o.trapezoid=function(e,t,n,o,a,l){l=l||{},a*=.5;var c,d=(1-2*a)*n,u=n*a,p=u+d,f=p+u;c=a<.5?"L 0 0 L "+u+" "+-o+" L "+p+" "+-o+" L "+f+" 0":"L 0 0 L "+p+" "+-o+" L "+f+" 0";var m={label:"Trapezoid Body",position:{x:e,y:t},vertices:i.fromPath(c)};if(l.chamfer){var v=l.chamfer;m.vertices=i.chamfer(m.vertices,v.radius,v.quality,v.qualityMin,v.qualityMax),delete l.chamfer}return s.create(r.extend({},m,l))},o.circle=function(e,t,n,i,s){i=i||{};var a={label:"Circle Body", +circleRadius:n};s=s||25;var l=Math.ceil(Math.max(10,Math.min(s,n)));return l%2===1&&(l+=1),o.polygon(e,t,l,n,r.extend({},a,i))},o.polygon=function(e,t,n,a,l){if(l=l||{},n<3)return o.circle(e,t,a,l);for(var c=2*Math.PI/n,d="",u=.5*c,p=0;p0&&i.area(P)1?(f=s.create(r.extend({parts:m.slice(0)},o)),s.setPosition(f,{x:e,y:t}),f):m[0]}}()}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../body/Body":1,"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],24:[function(e,t,n){ +var o={};t.exports=o;var i=e("../body/Composite"),r=e("../constraint/Constraint"),s=e("../core/Common"),a=e("../body/Body"),l=e("./Bodies");!function(){o.stack=function(e,t,n,o,r,s,l){for(var c,d=i.create({label:"Stack"}),u=e,p=t,f=0,m=0;mv&&(v=x),a.translate(g,{x:.5*h,y:.5*x}),u=g.bounds.max.x+r,i.addBody(d,g),c=g,f+=1}else u+=r}p+=v+s,u=e}return d},o.chain=function(e,t,n,o,a,l){for(var c=e.bodies,d=1;d0)for(c=0;c0&&(p=f[c-1+(l-1)*t],i.addConstraint(e,r.create(s.extend({bodyA:p,bodyB:u},a)))),o&&cp)){c=p-c;var m=c,v=n-1-c;if(!(sv)){1===u&&a.translate(d,{x:(s+(n%2===1?1:-1))*f,y:0});var y=d?s*f:0;return l(e+y+s*r,o,s,c,d,u)}}})},o.newtonsCradle=function(e,t,n,o,s){for(var a=i.create({label:"Newtons Cradle"}),c=0;ce.max.x&&(e.max.x=i.x),i.xe.max.y&&(e.max.y=i.y),i.y0?e.max.x+=n.x:e.min.x+=n.x,n.y>0?e.max.y+=n.y:e.min.y+=n.y)},o.contains=function(e,t){return t.x>=e.min.x&&t.x<=e.max.x&&t.y>=e.min.y&&t.y<=e.max.y},o.overlaps=function(e,t){return e.min.x<=t.max.x&&e.max.x>=t.min.x&&e.max.y>=t.min.y&&e.min.y<=t.max.y},o.translate=function(e,t){e.min.x+=t.x,e.max.x+=t.x,e.min.y+=t.y,e.max.y+=t.y},o.shift=function(e,t){ +var n=e.max.x-e.min.x,o=e.max.y-e.min.y;e.min.x=t.x,e.max.x=t.x+n,e.min.y=t.y,e.max.y=t.y+o}}()},{}],27:[function(e,t,n){var o={};t.exports=o;e("../geometry/Bounds");!function(){o.pathToVertices=function(t,n){var o,i,r,s,a,l,c,d,u,p,f,m,v=[],y=0,g=0,x=0;n=n||15;var h=function(e,t,n){var o=n%2===1&&n>1;if(!u||e!=u.x||t!=u.y){u&&o?(f=u.x,m=u.y):(f=0,m=0);var i={x:f+e,y:m+t};!o&&u||(u=i),v.push(i),g=f+e,x=m+t}},b=function(e){var t=e.pathSegTypeAsLetter.toUpperCase();if("Z"!==t){switch(t){case"M":case"L":case"T":case"C":case"S":case"Q":g=e.x,x=e.y;break;case"H":g=e.x;break;case"V":x=e.y}h(g,x,e.pathSegType)}};for(e(t),r=t.getTotalLength(),l=[],o=0;o0)return!1}return!0},o.scale=function(e,t,n,r){if(1===t&&1===n)return e;r=r||o.centre(e);for(var s,a,l=0;l=0?l-1:e.length-1],d=e[l],u=e[(l+1)%e.length],p=t[l0&&(r|=2),3===r)return!1;return 0!==r||null},o.hull=function(e){var t,n,o=[],r=[];for(e=e.slice(0),e.sort(function(e,t){var n=e.x-t.x;return 0!==n?n:e.y-t.y; +}),n=0;n=2&&i.cross3(r[r.length-2],r[r.length-1],t)<=0;)r.pop();r.push(t)}for(n=e.length-1;n>=0;n--){for(t=e[n];o.length>=2&&i.cross3(o[o.length-2],o[o.length-1],t)<=0;)o.pop();o.push(t)}return o.pop(),r.pop(),o.concat(r)}}()},{"../core/Common":14,"../geometry/Vector":28}],30:[function(e,t,n){var o=t.exports=e("../core/Matter");o.Body=e("../body/Body"),o.Composite=e("../body/Composite"),o.World=e("../body/World"),o.Contact=e("../collision/Contact"),o.Detector=e("../collision/Detector"),o.Grid=e("../collision/Grid"),o.Pairs=e("../collision/Pairs"),o.Pair=e("../collision/Pair"),o.Query=e("../collision/Query"),o.Resolver=e("../collision/Resolver"),o.SAT=e("../collision/SAT"),o.Constraint=e("../constraint/Constraint"),o.MouseConstraint=e("../constraint/MouseConstraint"),o.Common=e("../core/Common"),o.Engine=e("../core/Engine"),o.Events=e("../core/Events"),o.Mouse=e("../core/Mouse"),o.Runner=e("../core/Runner"),o.Sleeping=e("../core/Sleeping"),o.Plugin=e("../core/Plugin"), +o.Bodies=e("../factory/Bodies"),o.Composites=e("../factory/Composites"),o.Axes=e("../geometry/Axes"),o.Bounds=e("../geometry/Bounds"),o.Svg=e("../geometry/Svg"),o.Vector=e("../geometry/Vector"),o.Vertices=e("../geometry/Vertices"),o.Render=e("../render/Render"),o.RenderPixi=e("../render/RenderPixi"),o.World.add=o.Composite.add,o.World.remove=o.Composite.remove,o.World.addComposite=o.Composite.addComposite,o.World.addBody=o.Composite.addBody,o.World.addConstraint=o.Composite.addConstraint,o.World.clear=o.Composite.clear,o.Engine.run=o.Runner.run},{"../body/Body":1,"../body/Composite":2,"../body/World":3,"../collision/Contact":4,"../collision/Detector":5,"../collision/Grid":6,"../collision/Pair":7,"../collision/Pairs":8,"../collision/Query":9,"../collision/Resolver":10,"../collision/SAT":11,"../constraint/Constraint":12,"../constraint/MouseConstraint":13,"../core/Common":14,"../core/Engine":15,"../core/Events":16,"../core/Matter":17,"../core/Metrics":18,"../core/Mouse":19,"../core/Plugin":20, +"../core/Runner":21,"../core/Sleeping":22,"../factory/Bodies":23,"../factory/Composites":24,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Svg":27,"../geometry/Vector":28,"../geometry/Vertices":29,"../render/Render":31,"../render/RenderPixi":32}],31:[function(e,t,n){var o={};t.exports=o;var i=e("../core/Common"),r=e("../body/Composite"),s=e("../geometry/Bounds"),a=e("../core/Events"),l=e("../collision/Grid"),c=e("../geometry/Vector"),d=e("../core/Mouse");!function(){var e,t;"undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout(function(){e(i.now())},1e3/60)},t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),o.create=function(e){var t={controller:o,engine:null,element:null,canvas:null,mouse:null,frameRequestId:null,options:{width:800,height:600,pixelRatio:1,background:"#18181d", +wireframeBackground:"#0f0f13",hasBounds:!!e.bounds,enabled:!0,wireframes:!0,showSleeping:!0,showDebug:!1,showBroadphase:!1,showBounds:!1,showVelocity:!1,showCollisions:!1,showSeparations:!1,showAxes:!1,showPositions:!1,showAngleIndicator:!1,showIds:!1,showShadows:!1,showVertexNumbers:!1,showConvexHulls:!1,showInternalEdges:!1,showMousePosition:!1}},r=i.extend(t,e);return r.canvas&&(r.canvas.width=r.options.width||r.canvas.width,r.canvas.height=r.options.height||r.canvas.height),r.mouse=e.mouse,r.engine=e.engine,r.canvas=r.canvas||n(r.options.width,r.options.height),r.context=r.canvas.getContext("2d"),r.textures={},r.bounds=r.bounds||{min:{x:0,y:0},max:{x:r.canvas.width,y:r.canvas.height}},1!==r.options.pixelRatio&&o.setPixelRatio(r,r.options.pixelRatio),i.isElement(r.element)?r.element.appendChild(r.canvas):i.log("Render.create: options.element was undefined, render.canvas was created but not appended","warn"),r},o.run=function(t){!function n(i){t.frameRequestId=e(n),o.world(t)}()},o.stop=function(e){ +t(e.frameRequestId)},o.setPixelRatio=function(e,t){var n=e.options,o=e.canvas;"auto"===t&&(t=u(o)),n.pixelRatio=t,o.setAttribute("data-pixel-ratio",t),o.width=n.width*t,o.height=n.height*t,o.style.width=n.width+"px",o.style.height=n.height+"px",e.context.scale(t,t)},o.lookAt=function(e,t,n,o){o="undefined"==typeof o||o,t=i.isArray(t)?t:[t],n=n||{x:0,y:0};for(var r={min:{x:1/0,y:1/0},max:{x:-(1/0),y:-(1/0)}},s=0;sr.max.x&&(r.max.x=c.x),l.yr.max.y&&(r.max.y=c.y))}var u=r.max.x-r.min.x+2*n.x,p=r.max.y-r.min.y+2*n.y,f=e.canvas.height,m=e.canvas.width,v=m/f,y=u/p,g=1,x=1;y>v?x=y/v:g=v/y,e.options.hasBounds=!0,e.bounds.min.x=r.min.x,e.bounds.max.x=r.min.x+u*g,e.bounds.min.y=r.min.y,e.bounds.max.y=r.min.y+p*x,o&&(e.bounds.min.x+=.5*u-u*g*.5,e.bounds.max.x+=.5*u-u*g*.5,e.bounds.min.y+=.5*p-p*x*.5,e.bounds.max.y+=.5*p-p*x*.5), +e.bounds.min.x-=n.x,e.bounds.max.x-=n.x,e.bounds.min.y-=n.y,e.bounds.max.y-=n.y,e.mouse&&(d.setScale(e.mouse,{x:(e.bounds.max.x-e.bounds.min.x)/e.canvas.width,y:(e.bounds.max.y-e.bounds.min.y)/e.canvas.height}),d.setOffset(e.mouse,e.bounds.min))},o.startViewTransform=function(e){var t=e.bounds.max.x-e.bounds.min.x,n=e.bounds.max.y-e.bounds.min.y,o=t/e.options.width,i=n/e.options.height;e.context.scale(1/o,1/i),e.context.translate(-e.bounds.min.x,-e.bounds.min.y)},o.endViewTransform=function(e){e.context.setTransform(e.options.pixelRatio,0,0,e.options.pixelRatio,0,0)},o.world=function(e){var t,n=e.engine,i=n.world,u=e.canvas,p=e.context,m=e.options,v=r.allBodies(i),y=r.allConstraints(i),g=m.wireframes?m.wireframeBackground:m.background,x=[],h=[],b={timestamp:n.timing.timestamp};if(a.trigger(e,"beforeRender",b),e.currentBackground!==g&&f(e,g),p.globalCompositeOperation="source-in",p.fillStyle="transparent",p.fillRect(0,0,u.width,u.height),p.globalCompositeOperation="source-over",m.hasBounds){ +for(t=0;t=500){var c="";s.timing&&(c+="fps: "+Math.round(s.timing.fps)+l),e.debugString=c,e.debugTimestamp=o.timing.timestamp}if(e.debugString){n.font="12px Arial",a.wireframes?n.fillStyle="rgba(255,255,255,0.5)":n.fillStyle="rgba(0,0,0,0.5)";for(var d=e.debugString.split("\n"),u=0;u1?1:0;s1?1:0;a1?1:0;r1?1:0;l1?1:0;r1?1:0;r1?1:0;i0)){var u=o.activeContacts[0].vertex.x,p=o.activeContacts[0].vertex.y;2===o.activeContacts.length&&(u=(o.activeContacts[0].vertex.x+o.activeContacts[1].vertex.x)/2,p=(o.activeContacts[0].vertex.y+o.activeContacts[1].vertex.y)/2),i.bodyB===i.supports[0].body||i.bodyA.isStatic===!0?a.moveTo(u-8*i.normal.x,p-8*i.normal.y):a.moveTo(u+8*i.normal.x,p+8*i.normal.y),a.lineTo(u,p)}l.wireframes?a.strokeStyle="rgba(255,165,0,0.7)":a.strokeStyle="orange",a.lineWidth=1,a.stroke()},o.separations=function(e,t,n){var o,i,r,s,a,l=n,c=e.options;for(l.beginPath(),a=0;a1?1:0;p Date: Mon, 12 Jun 2017 19:53:40 +0100 Subject: [PATCH 20/31] added constraint damping --- src/constraint/Constraint.js | 47 +++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/constraint/Constraint.js b/src/constraint/Constraint.js index 61ebd13..ab6df4c 100644 --- a/src/constraint/Constraint.js +++ b/src/constraint/Constraint.js @@ -28,7 +28,8 @@ var Common = require('../core/Common'); /** * Creates a new constraint. * All properties have default values, and many are pre-calculated automatically based on other properties. - * To simulate a revolute constraint (or pin joint) set `length: 0` and `stiffness: 1`. + * To simulate a revolute constraint (or pin joint) set `length: 0` and a high `stiffness` value (e.g. `0.7` or above). + * If the constraint is unstable, try lowering the `stiffness` value and / or increasing `engine.constraintIterations`. * See the properties section below for detailed information on what you can pass via the `options` object. * @method create * @param {} options @@ -63,7 +64,8 @@ var Common = require('../core/Common'); constraint.id = constraint.id || Common.nextId(); constraint.label = constraint.label || 'Constraint'; constraint.type = 'constraint'; - constraint.stiffness = constraint.stiffness || 1; + constraint.stiffness = constraint.stiffness || (constraint.length > 0 ? 1 : 0.7); + constraint.damping = constraint.damping || 0; constraint.angularStiffness = constraint.angularStiffness || 0; constraint.angleA = constraint.bodyA ? constraint.bodyA.angle : constraint.angleA; constraint.angleB = constraint.bodyB ? constraint.bodyB.angle : constraint.angleB; @@ -177,7 +179,22 @@ var Common = require('../core/Common'); inertiaTotal = (bodyA ? bodyA.inverseInertia : 0) + (bodyB ? bodyB.inverseInertia : 0), resistanceTotal = massTotal + inertiaTotal, torque, - share; + share, + normal, + normalVelocity, + relativeVelocity; + + if (constraint.damping) { + var zero = Vector.create(); + normal = Vector.div(delta, currentLength); + + relativeVelocity = Vector.sub( + bodyB && Vector.sub(bodyB.position, bodyB.positionPrev) || zero, + bodyA && Vector.sub(bodyA.position, bodyA.positionPrev) || zero + ); + + normalVelocity = Vector.dot(normal, relativeVelocity); + } if (bodyA && !bodyA.isStatic) { share = bodyA.inverseMass / massTotal; @@ -190,6 +207,12 @@ var Common = require('../core/Common'); bodyA.position.x -= force.x * share; bodyA.position.y -= force.y * share; + // apply damping + if (constraint.damping) { + bodyA.positionPrev.x -= constraint.damping * normal.x * normalVelocity * share; + bodyA.positionPrev.y -= constraint.damping * normal.y * normalVelocity * share; + } + // apply torque torque = (Vector.cross(pointA, force) / resistanceTotal) * Constraint._torqueDampen * bodyA.inverseInertia * (1 - constraint.angularStiffness); bodyA.constraintImpulse.angle -= torque; @@ -207,6 +230,12 @@ var Common = require('../core/Common'); bodyB.position.x += force.x * share; bodyB.position.y += force.y * share; + // apply damping + if (constraint.damping) { + bodyB.positionPrev.x += constraint.damping * normal.x * normalVelocity * share; + bodyB.positionPrev.y += constraint.damping * normal.y * normalVelocity * share; + } + // apply torque torque = (Vector.cross(pointB, force) / resistanceTotal) * Constraint._torqueDampen * bodyB.inverseInertia * (1 - constraint.angularStiffness); bodyB.constraintImpulse.angle += torque; @@ -366,6 +395,18 @@ var Common = require('../core/Common'); * @default 1 */ + /** + * A `Number` that specifies the damping of the constraint, + * i.e. the amount of resistance applied to each body based on their velocities to limit the amount of oscillation. + * Damping will only be apparent when the constraint also has a very low `stiffness`. + * A value of `0.1` means the constraint will apply heavy damping, resulting in little to no oscillation. + * A value of `0` means the constraint will apply no damping. + * + * @property damping + * @type number + * @default 0 + */ + /** * A `Number` that specifies the target resting length of the constraint. * It is calculated automatically in `Constraint.create` from initial positions of the `constraint.bodyA` and `constraint.bodyB`. From 08aa3f20f6e62de2cc7d6373f75e0390647ac752 Mon Sep 17 00:00:00 2001 From: liabru Date: Mon, 12 Jun 2017 19:55:17 +0100 Subject: [PATCH 21/31] update alpha build --- build/matter.js | 49 ++++++++++++++++-- build/matter.min.js | 120 ++++++++++++++++++++++---------------------- 2 files changed, 105 insertions(+), 64 deletions(-) diff --git a/build/matter.js b/build/matter.js index c605fbe..2070fa5 100644 --- a/build/matter.js +++ b/build/matter.js @@ -1,5 +1,5 @@ /** -* matter-js 0.12.0-alpha by @liabru 2017-05-03 +* matter-js 0.12.0-alpha by @liabru 2017-06-12 * http://brm.io/matter-js/ * License MIT */ @@ -3503,7 +3503,8 @@ var Common = _dereq_('../core/Common'); /** * Creates a new constraint. * All properties have default values, and many are pre-calculated automatically based on other properties. - * To simulate a revolute constraint (or pin joint) set `length: 0` and `stiffness: 1`. + * To simulate a revolute constraint (or pin joint) set `length: 0` and a high `stiffness` value (e.g. `0.7` or above). + * If the constraint is unstable, try lowering the `stiffness` value and / or increasing `engine.constraintIterations`. * See the properties section below for detailed information on what you can pass via the `options` object. * @method create * @param {} options @@ -3538,7 +3539,8 @@ var Common = _dereq_('../core/Common'); constraint.id = constraint.id || Common.nextId(); constraint.label = constraint.label || 'Constraint'; constraint.type = 'constraint'; - constraint.stiffness = constraint.stiffness || 1; + constraint.stiffness = constraint.stiffness || (constraint.length > 0 ? 1 : 0.7); + constraint.damping = constraint.damping || 0; constraint.angularStiffness = constraint.angularStiffness || 0; constraint.angleA = constraint.bodyA ? constraint.bodyA.angle : constraint.angleA; constraint.angleB = constraint.bodyB ? constraint.bodyB.angle : constraint.angleB; @@ -3652,7 +3654,22 @@ var Common = _dereq_('../core/Common'); inertiaTotal = (bodyA ? bodyA.inverseInertia : 0) + (bodyB ? bodyB.inverseInertia : 0), resistanceTotal = massTotal + inertiaTotal, torque, - share; + share, + normal, + normalVelocity, + relativeVelocity; + + if (constraint.damping) { + var zero = Vector.create(); + normal = Vector.div(delta, currentLength); + + relativeVelocity = Vector.sub( + bodyB && Vector.sub(bodyB.position, bodyB.positionPrev) || zero, + bodyA && Vector.sub(bodyA.position, bodyA.positionPrev) || zero + ); + + normalVelocity = Vector.dot(normal, relativeVelocity); + } if (bodyA && !bodyA.isStatic) { share = bodyA.inverseMass / massTotal; @@ -3665,6 +3682,12 @@ var Common = _dereq_('../core/Common'); bodyA.position.x -= force.x * share; bodyA.position.y -= force.y * share; + // apply damping + if (constraint.damping) { + bodyA.positionPrev.x -= constraint.damping * normal.x * normalVelocity * share; + bodyA.positionPrev.y -= constraint.damping * normal.y * normalVelocity * share; + } + // apply torque torque = (Vector.cross(pointA, force) / resistanceTotal) * Constraint._torqueDampen * bodyA.inverseInertia * (1 - constraint.angularStiffness); bodyA.constraintImpulse.angle -= torque; @@ -3682,6 +3705,12 @@ var Common = _dereq_('../core/Common'); bodyB.position.x += force.x * share; bodyB.position.y += force.y * share; + // apply damping + if (constraint.damping) { + bodyB.positionPrev.x += constraint.damping * normal.x * normalVelocity * share; + bodyB.positionPrev.y += constraint.damping * normal.y * normalVelocity * share; + } + // apply torque torque = (Vector.cross(pointB, force) / resistanceTotal) * Constraint._torqueDampen * bodyB.inverseInertia * (1 - constraint.angularStiffness); bodyB.constraintImpulse.angle += torque; @@ -3841,6 +3870,18 @@ var Common = _dereq_('../core/Common'); * @default 1 */ + /** + * A `Number` that specifies the damping of the constraint, + * i.e. the amount of resistance applied to each body based on their velocities to limit the amount of oscillation. + * Damping will only be apparent when the constraint also has a very low `stiffness`. + * A value of `0.1` means the constraint will apply heavy damping, resulting in little to no oscillation. + * A value of `0` means the constraint will apply no damping. + * + * @property damping + * @type number + * @default 0 + */ + /** * A `Number` that specifies the target resting length of the constraint. * It is calculated automatically in `Constraint.create` from initial positions of the `constraint.bodyA` and `constraint.bodyB`. diff --git a/build/matter.min.js b/build/matter.min.js index f68314c..c56544d 100644 --- a/build/matter.min.js +++ b/build/matter.min.js @@ -1,5 +1,5 @@ /** -* matter-js 0.12.0-alpha by @liabru 2017-05-03 +* matter-js 0.12.0-alpha by @liabru 2017-06-12 * http://brm.io/matter-js/ * License MIT */ @@ -29,62 +29,62 @@ v.velocity.y=v.position.y-v.positionPrev.y,y.velocity.x=y.position.x-y.positionP L=S.tangentImpulse-N}i.x=g.x*_+x.x*L,i.y=g.y*_+x.y*L,v.isStatic||v.isSleeping||(v.positionPrev.x+=i.x*v.inverseMass,v.positionPrev.y+=i.y*v.inverseMass,v.anglePrev+=r.cross(A,i)*v.inverseInertia),y.isStatic||y.isSleeping||(y.positionPrev.x-=i.x*y.inverseMass,y.positionPrev.y-=i.y*y.inverseMass,y.anglePrev-=r.cross(P,i)*y.inverseInertia)}}}}}()},{"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],11:[function(e,t,n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../geometry/Vector");!function(){o.collides=function(t,o,s){var a,l,c,d,u=!1;if(s){var p=t.parent,f=o.parent,m=p.speed*p.speed+p.angularSpeed*p.angularSpeed+f.speed*f.speed+f.angularSpeed*f.angularSpeed;u=s&&s.collided&&m<.2,d=s}else d={collided:!1,bodyA:t,bodyB:o};if(s&&u){var v=d.axisBody,y=v===t?o:t,g=[v.axes[s.axisNumber]];if(c=e(v.vertices,y.vertices,g),d.reused=!0,c.overlap<=0)return d.collided=!1,d}else{if(a=e(t.vertices,o.vertices,t.axes),a.overlap<=0)return d.collided=!1, d;if(l=e(o.vertices,t.vertices,o.axes),l.overlap<=0)return d.collided=!1,d;a.overlapi?i=a:a=0?s.index-1:d.length-1;i=d[f],c.x=i.x-u.x,c.y=i.y-u.y,l=-r.dot(n,c),a=i;var m=(s.index+1)%d.length;return i=d[m],c.x=i.x-u.x,c.y=i.y-u.y,o=-r.dot(n,c),o0&&(u.position.x+=c.x,u.position.y+=c.y),0!==c.angle&&(i.rotate(u.vertices,c.angle,n.position),l.rotate(u.axes,c.angle),d>0&&r.rotateAbout(u.position,c.angle,n.position,u.position)),a.update(u.bounds,u.vertices,n.velocity)}c.angle*=o._warming,c.x*=o._warming,c.y*=o._warming}}}}()},{"../core/Common":14,"../core/Sleeping":22,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],13:[function(e,t,n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../core/Sleeping"),s=e("../core/Mouse"),a=e("../core/Events"),l=e("../collision/Detector"),c=e("./Constraint"),d=e("../body/Composite"),u=e("../core/Common"),p=e("../geometry/Bounds");!function(){o.create=function(t,n){var i=(t?t.mouse:null)||(n?n.mouse:null);i||(t&&t.render&&t.render.canvas?i=s.create(t.render.canvas):n&&n.element?i=s.create(n.element):(i=s.create(),u.warn("MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected"))); -var r=c.create({label:"Mouse Constraint",pointA:i.position,pointB:{x:0,y:0},length:.01,stiffness:.1,angularStiffness:1,render:{strokeStyle:"#90EE90",lineWidth:3}}),l={type:"mouseConstraint",mouse:i,element:null,body:null,constraint:r,collisionFilter:{category:1,mask:4294967295,group:0}},p=u.extend(l,n);return a.on(t,"beforeUpdate",function(){var n=d.allBodies(t.world);o.update(p,n),e(p)}),p},o.update=function(e,t){var n=e.mouse,o=e.constraint,s=e.body;if(0===n.button){if(o.bodyB)r.set(o.bodyB,!1),o.pointA=n.position;else for(var c=0;c1?1:0;d>16)+o,r=(n>>8&255)+o,s=(255&n)+o;return"#"+(16777216+65536*(i<255?i<1?0:i:255)+256*(r<255?r<1?0:r:255)+(s<255?s<1?0:s:255)).toString(16).slice(1)},o.shuffle=function(e){for(var t=e.length-1;t>0;t--){var n=Math.floor(o.random()*(t+1)),i=e[t];e[t]=e[n],e[n]=i}return e},o.choose=function(e){return e[Math.floor(o.random()*e.length)]},o.isElement=function(e){try{return e instanceof HTMLElement}catch(t){return"object"==typeof e&&1===e.nodeType&&"object"==typeof e.style&&"object"==typeof e.ownerDocument}},o.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)},o.isFunction=function(e){return"function"==typeof e},o.isPlainObject=function(e){return"object"==typeof e&&e.constructor===Object; -},o.isString=function(e){return"[object String]"===toString.call(e)},o.clamp=function(e,t,n){return en?n:e},o.sign=function(e){return e<0?-1:1},o.now=function(){var e=window.performance||{};return e.now=function(){return e.now||e.webkitNow||e.msNow||e.oNow||e.mozNow||function(){return+new Date}}(),e.now()},o.random=function(t,n){return t="undefined"!=typeof t?t:0,n="undefined"!=typeof n?n:1,t+e()*(n-t)};var e=function(){return o._seed=(9301*o._seed+49297)%233280,o._seed/233280};o.colorToNumber=function(e){return e=e.replace("#",""),3==e.length&&(e=e.charAt(0)+e.charAt(0)+e.charAt(1)+e.charAt(1)+e.charAt(2)+e.charAt(2)),parseInt(e,16)},o.logLevel=1,o.log=function(){console&&o.logLevel>0&&o.logLevel<=3&&console.log.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},o.info=function(){console&&o.logLevel>0&&o.logLevel<=2&&console.info.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},o.warn=function(){console&&o.logLevel>0&&o.logLevel<=3&&console.warn.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments))); -},o.nextId=function(){return o._nextId++},o.indexOf=function(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0;n0&&d.trigger(o,"collisionStart",{pairs:w.collisionStart}),s.preSolvePosition(w.list),c=0;c0&&d.trigger(o,"collisionActive",{pairs:w.collisionActive}),w.collisionEnd.length>0&&d.trigger(o,"collisionEnd",{pairs:w.collisionEnd}),e(x),d.trigger(o,"afterUpdate",g),o},o.merge=function(e,t){if(f.extend(e,t),t.world){e.world=t.world,o.clear(e);for(var n=u.allBodies(e.world),i=0;ir?(i.warn("Plugin.register:",o.toString(t),"was upgraded to",o.toString(e)),o._registry[e.name]=e):n-1},o.isFor=function(e,t){var n=e.for&&o.dependencyParse(e.for);return!e.for||t.name===n.name&&o.versionSatisfies(t.version,n.range)},o.use=function(e,t){if(e.uses=(e.uses||[]).concat(t||[]),0===e.uses.length)return void i.warn("Plugin.use:",o.toString(e),"does not specify any dependencies to install.");for(var n=o.dependencies(e),r=i.topologicalSort(n),s=[],a=0;a0&&i.info(s.join(" "))},o.dependencies=function(e,t){var n=o.dependencyParse(e),r=n.name; -if(t=t||{},!(r in t)){e=o.resolve(e)||e,t[r]=i.map(e.uses||[],function(t){o.isPlugin(t)&&o.register(t);var r=o.dependencyParse(t),s=o.resolve(t);return s&&!o.versionSatisfies(s.version,r.range)?(i.warn("Plugin.dependencies:",o.toString(s),"does not satisfy",o.toString(r),"used by",o.toString(n)+"."),s._warned=!0,e._warned=!0):s||(i.warn("Plugin.dependencies:",o.toString(t),"used by",o.toString(n),"could not be resolved."),e._warned=!0),r.name});for(var s=0;s=i[2];if("^"===n.operator)return i[0]>0?s[0]===i[0]&&r.number>=n.number:i[1]>0?s[1]===i[1]&&s[2]>=i[2]:s[2]===i[2]}return e===t||"*"===e}}()},{"./Common":14}],21:[function(e,t,n){var o={};t.exports=o;var i=e("./Events"),r=e("./Engine"),s=e("./Common");!function(){var e,t;if("undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame,t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),!e){var n;e=function(e){n=setTimeout(function(){e(s.now())},1e3/60)},t=function(){clearTimeout(n); -}}o.create=function(e){var t={fps:60,correction:1,deltaSampleSize:60,counterTimestamp:0,frameCounter:0,deltaHistory:[],timePrev:null,timeScalePrev:1,frameRequestId:null,isFixed:!1,enabled:!0},n=s.extend(t,e);return n.delta=n.delta||1e3/n.fps,n.deltaMin=n.deltaMin||1e3/n.fps,n.deltaMax=n.deltaMax||1e3/(.5*n.fps),n.fps=1e3/n.delta,n},o.run=function(t,n){return"undefined"!=typeof t.positionIterations&&(n=t,t=o.create()),function i(r){t.frameRequestId=e(i),r&&t.enabled&&o.tick(t,n,r)}(),t},o.tick=function(e,t,n){var o,s=t.timing,a=1,l={timestamp:s.timestamp};i.trigger(e,"beforeTick",l),i.trigger(t,"beforeTick",l),e.isFixed?o=e.delta:(o=n-e.timePrev||e.delta,e.timePrev=n,e.deltaHistory.push(o),e.deltaHistory=e.deltaHistory.slice(-e.deltaSampleSize),o=Math.min.apply(null,e.deltaHistory),o=oe.deltaMax?e.deltaMax:o,a=o/e.delta,e.delta=o),0!==e.timeScalePrev&&(a*=s.timeScale/e.timeScalePrev),0===s.timeScale&&(a=0),e.timeScalePrev=s.timeScale,e.correction=a,e.frameCounter+=1, -n-e.counterTimestamp>=1e3&&(e.fps=e.frameCounter*((n-e.counterTimestamp)/1e3),e.counterTimestamp=n,e.frameCounter=0),i.trigger(e,"tick",l),i.trigger(t,"tick",l),t.world.isModified&&t.render&&t.render.controller&&t.render.controller.clear&&t.render.controller.clear(t.render),i.trigger(e,"beforeUpdate",l),r.update(t,o,a),i.trigger(e,"afterUpdate",l),t.render&&t.render.controller&&(i.trigger(e,"beforeRender",l),i.trigger(t,"beforeRender",l),t.render.controller.world(t.render),i.trigger(e,"afterRender",l),i.trigger(t,"afterRender",l)),i.trigger(e,"afterTick",l),i.trigger(t,"afterTick",l)},o.stop=function(e){t(e.frameRequestId)},o.start=function(e,t){o.run(e,t)}}()},{"./Common":14,"./Engine":15,"./Events":16}],22:[function(e,t,n){var o={};t.exports=o;var i=e("./Events");!function(){o._motionWakeThreshold=.18,o._motionSleepThreshold=.08,o._minBias=.9,o.update=function(e,t){for(var n=t*t*t,i=0;i0&&r.motion=r.sleepThreshold&&o.set(r,!0)):r.sleepCounter>0&&(r.sleepCounter-=1)}else o.set(r,!1)}},o.afterCollisions=function(e,t){for(var n=t*t*t,i=0;io._motionWakeThreshold*n&&o.set(c,!1)}}}},o.set=function(e,t){var n=e.isSleeping;t?(e.isSleeping=!0,e.sleepCounter=e.sleepThreshold,e.positionImpulse.x=0,e.positionImpulse.y=0,e.positionPrev.x=e.position.x,e.positionPrev.y=e.position.y,e.anglePrev=e.angle,e.speed=0,e.angularSpeed=0,e.motion=0,n||i.trigger(e,"sleepStart")):(e.isSleeping=!1,e.sleepCounter=0,n&&i.trigger(e,"sleepEnd"))}}()},{"./Events":16}],23:[function(e,t,n){(function(n){ -var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../core/Common"),s=e("../body/Body"),a=e("../geometry/Bounds"),l=e("../geometry/Vector"),c="undefined"!=typeof window?window.decomp:"undefined"!=typeof n?n.decomp:null;!function(){o.rectangle=function(e,t,n,o,a){a=a||{};var l={label:"Rectangle Body",position:{x:e,y:t},vertices:i.fromPath("L 0 0 L "+n+" 0 L "+n+" "+o+" L 0 "+o)};if(a.chamfer){var c=a.chamfer;l.vertices=i.chamfer(l.vertices,c.radius,c.quality,c.qualityMin,c.qualityMax),delete a.chamfer}return s.create(r.extend({},l,a))},o.trapezoid=function(e,t,n,o,a,l){l=l||{},a*=.5;var c,d=(1-2*a)*n,u=n*a,p=u+d,f=p+u;c=a<.5?"L 0 0 L "+u+" "+-o+" L "+p+" "+-o+" L "+f+" 0":"L 0 0 L "+p+" "+-o+" L "+f+" 0";var m={label:"Trapezoid Body",position:{x:e,y:t},vertices:i.fromPath(c)};if(l.chamfer){var v=l.chamfer;m.vertices=i.chamfer(m.vertices,v.radius,v.quality,v.qualityMin,v.qualityMax),delete l.chamfer}return s.create(r.extend({},m,l))},o.circle=function(e,t,n,i,s){i=i||{};var a={label:"Circle Body", -circleRadius:n};s=s||25;var l=Math.ceil(Math.max(10,Math.min(s,n)));return l%2===1&&(l+=1),o.polygon(e,t,l,n,r.extend({},a,i))},o.polygon=function(e,t,n,a,l){if(l=l||{},n<3)return o.circle(e,t,a,l);for(var c=2*Math.PI/n,d="",u=.5*c,p=0;p0&&i.area(P)1?(f=s.create(r.extend({parts:m.slice(0)},o)),s.setPosition(f,{x:e,y:t}),f):m[0]}}()}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../body/Body":1,"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],24:[function(e,t,n){ -var o={};t.exports=o;var i=e("../body/Composite"),r=e("../constraint/Constraint"),s=e("../core/Common"),a=e("../body/Body"),l=e("./Bodies");!function(){o.stack=function(e,t,n,o,r,s,l){for(var c,d=i.create({label:"Stack"}),u=e,p=t,f=0,m=0;mv&&(v=x),a.translate(g,{x:.5*h,y:.5*x}),u=g.bounds.max.x+r,i.addBody(d,g),c=g,f+=1}else u+=r}p+=v+s,u=e}return d},o.chain=function(e,t,n,o,a,l){for(var c=e.bodies,d=1;d0)for(c=0;c0&&(p=f[c-1+(l-1)*t],i.addConstraint(e,r.create(s.extend({bodyA:p,bodyB:u},a)))),o&&cp)){c=p-c;var m=c,v=n-1-c;if(!(sv)){1===u&&a.translate(d,{x:(s+(n%2===1?1:-1))*f,y:0});var y=d?s*f:0;return l(e+y+s*r,o,s,c,d,u)}}})},o.newtonsCradle=function(e,t,n,o,s){for(var a=i.create({label:"Newtons Cradle"}),c=0;ce.max.x&&(e.max.x=i.x),i.xe.max.y&&(e.max.y=i.y),i.y0?e.max.x+=n.x:e.min.x+=n.x,n.y>0?e.max.y+=n.y:e.min.y+=n.y)},o.contains=function(e,t){return t.x>=e.min.x&&t.x<=e.max.x&&t.y>=e.min.y&&t.y<=e.max.y},o.overlaps=function(e,t){return e.min.x<=t.max.x&&e.max.x>=t.min.x&&e.max.y>=t.min.y&&e.min.y<=t.max.y},o.translate=function(e,t){e.min.x+=t.x,e.max.x+=t.x,e.min.y+=t.y,e.max.y+=t.y},o.shift=function(e,t){ -var n=e.max.x-e.min.x,o=e.max.y-e.min.y;e.min.x=t.x,e.max.x=t.x+n,e.min.y=t.y,e.max.y=t.y+o}}()},{}],27:[function(e,t,n){var o={};t.exports=o;e("../geometry/Bounds");!function(){o.pathToVertices=function(t,n){var o,i,r,s,a,l,c,d,u,p,f,m,v=[],y=0,g=0,x=0;n=n||15;var h=function(e,t,n){var o=n%2===1&&n>1;if(!u||e!=u.x||t!=u.y){u&&o?(f=u.x,m=u.y):(f=0,m=0);var i={x:f+e,y:m+t};!o&&u||(u=i),v.push(i),g=f+e,x=m+t}},b=function(e){var t=e.pathSegTypeAsLetter.toUpperCase();if("Z"!==t){switch(t){case"M":case"L":case"T":case"C":case"S":case"Q":g=e.x,x=e.y;break;case"H":g=e.x;break;case"V":x=e.y}h(g,x,e.pathSegType)}};for(e(t),r=t.getTotalLength(),l=[],o=0;o0)return!1}return!0},o.scale=function(e,t,n,r){if(1===t&&1===n)return e;r=r||o.centre(e);for(var s,a,l=0;l=0?l-1:e.length-1],d=e[l],u=e[(l+1)%e.length],p=t[l0&&(r|=2),3===r)return!1;return 0!==r||null},o.hull=function(e){var t,n,o=[],r=[];for(e=e.slice(0),e.sort(function(e,t){var n=e.x-t.x;return 0!==n?n:e.y-t.y; -}),n=0;n=2&&i.cross3(r[r.length-2],r[r.length-1],t)<=0;)r.pop();r.push(t)}for(n=e.length-1;n>=0;n--){for(t=e[n];o.length>=2&&i.cross3(o[o.length-2],o[o.length-1],t)<=0;)o.pop();o.push(t)}return o.pop(),r.pop(),o.concat(r)}}()},{"../core/Common":14,"../geometry/Vector":28}],30:[function(e,t,n){var o=t.exports=e("../core/Matter");o.Body=e("../body/Body"),o.Composite=e("../body/Composite"),o.World=e("../body/World"),o.Contact=e("../collision/Contact"),o.Detector=e("../collision/Detector"),o.Grid=e("../collision/Grid"),o.Pairs=e("../collision/Pairs"),o.Pair=e("../collision/Pair"),o.Query=e("../collision/Query"),o.Resolver=e("../collision/Resolver"),o.SAT=e("../collision/SAT"),o.Constraint=e("../constraint/Constraint"),o.MouseConstraint=e("../constraint/MouseConstraint"),o.Common=e("../core/Common"),o.Engine=e("../core/Engine"),o.Events=e("../core/Events"),o.Mouse=e("../core/Mouse"),o.Runner=e("../core/Runner"),o.Sleeping=e("../core/Sleeping"),o.Plugin=e("../core/Plugin"), -o.Bodies=e("../factory/Bodies"),o.Composites=e("../factory/Composites"),o.Axes=e("../geometry/Axes"),o.Bounds=e("../geometry/Bounds"),o.Svg=e("../geometry/Svg"),o.Vector=e("../geometry/Vector"),o.Vertices=e("../geometry/Vertices"),o.Render=e("../render/Render"),o.RenderPixi=e("../render/RenderPixi"),o.World.add=o.Composite.add,o.World.remove=o.Composite.remove,o.World.addComposite=o.Composite.addComposite,o.World.addBody=o.Composite.addBody,o.World.addConstraint=o.Composite.addConstraint,o.World.clear=o.Composite.clear,o.Engine.run=o.Runner.run},{"../body/Body":1,"../body/Composite":2,"../body/World":3,"../collision/Contact":4,"../collision/Detector":5,"../collision/Grid":6,"../collision/Pair":7,"../collision/Pairs":8,"../collision/Query":9,"../collision/Resolver":10,"../collision/SAT":11,"../constraint/Constraint":12,"../constraint/MouseConstraint":13,"../core/Common":14,"../core/Engine":15,"../core/Events":16,"../core/Matter":17,"../core/Metrics":18,"../core/Mouse":19,"../core/Plugin":20, -"../core/Runner":21,"../core/Sleeping":22,"../factory/Bodies":23,"../factory/Composites":24,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Svg":27,"../geometry/Vector":28,"../geometry/Vertices":29,"../render/Render":31,"../render/RenderPixi":32}],31:[function(e,t,n){var o={};t.exports=o;var i=e("../core/Common"),r=e("../body/Composite"),s=e("../geometry/Bounds"),a=e("../core/Events"),l=e("../collision/Grid"),c=e("../geometry/Vector"),d=e("../core/Mouse");!function(){var e,t;"undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout(function(){e(i.now())},1e3/60)},t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),o.create=function(e){var t={controller:o,engine:null,element:null,canvas:null,mouse:null,frameRequestId:null,options:{width:800,height:600,pixelRatio:1,background:"#18181d", -wireframeBackground:"#0f0f13",hasBounds:!!e.bounds,enabled:!0,wireframes:!0,showSleeping:!0,showDebug:!1,showBroadphase:!1,showBounds:!1,showVelocity:!1,showCollisions:!1,showSeparations:!1,showAxes:!1,showPositions:!1,showAngleIndicator:!1,showIds:!1,showShadows:!1,showVertexNumbers:!1,showConvexHulls:!1,showInternalEdges:!1,showMousePosition:!1}},r=i.extend(t,e);return r.canvas&&(r.canvas.width=r.options.width||r.canvas.width,r.canvas.height=r.options.height||r.canvas.height),r.mouse=e.mouse,r.engine=e.engine,r.canvas=r.canvas||n(r.options.width,r.options.height),r.context=r.canvas.getContext("2d"),r.textures={},r.bounds=r.bounds||{min:{x:0,y:0},max:{x:r.canvas.width,y:r.canvas.height}},1!==r.options.pixelRatio&&o.setPixelRatio(r,r.options.pixelRatio),i.isElement(r.element)?r.element.appendChild(r.canvas):i.log("Render.create: options.element was undefined, render.canvas was created but not appended","warn"),r},o.run=function(t){!function n(i){t.frameRequestId=e(n),o.world(t)}()},o.stop=function(e){ -t(e.frameRequestId)},o.setPixelRatio=function(e,t){var n=e.options,o=e.canvas;"auto"===t&&(t=u(o)),n.pixelRatio=t,o.setAttribute("data-pixel-ratio",t),o.width=n.width*t,o.height=n.height*t,o.style.width=n.width+"px",o.style.height=n.height+"px",e.context.scale(t,t)},o.lookAt=function(e,t,n,o){o="undefined"==typeof o||o,t=i.isArray(t)?t:[t],n=n||{x:0,y:0};for(var r={min:{x:1/0,y:1/0},max:{x:-(1/0),y:-(1/0)}},s=0;sr.max.x&&(r.max.x=c.x),l.yr.max.y&&(r.max.y=c.y))}var u=r.max.x-r.min.x+2*n.x,p=r.max.y-r.min.y+2*n.y,f=e.canvas.height,m=e.canvas.width,v=m/f,y=u/p,g=1,x=1;y>v?x=y/v:g=v/y,e.options.hasBounds=!0,e.bounds.min.x=r.min.x,e.bounds.max.x=r.min.x+u*g,e.bounds.min.y=r.min.y,e.bounds.max.y=r.min.y+p*x,o&&(e.bounds.min.x+=.5*u-u*g*.5,e.bounds.max.x+=.5*u-u*g*.5,e.bounds.min.y+=.5*p-p*x*.5,e.bounds.max.y+=.5*p-p*x*.5), -e.bounds.min.x-=n.x,e.bounds.max.x-=n.x,e.bounds.min.y-=n.y,e.bounds.max.y-=n.y,e.mouse&&(d.setScale(e.mouse,{x:(e.bounds.max.x-e.bounds.min.x)/e.canvas.width,y:(e.bounds.max.y-e.bounds.min.y)/e.canvas.height}),d.setOffset(e.mouse,e.bounds.min))},o.startViewTransform=function(e){var t=e.bounds.max.x-e.bounds.min.x,n=e.bounds.max.y-e.bounds.min.y,o=t/e.options.width,i=n/e.options.height;e.context.scale(1/o,1/i),e.context.translate(-e.bounds.min.x,-e.bounds.min.y)},o.endViewTransform=function(e){e.context.setTransform(e.options.pixelRatio,0,0,e.options.pixelRatio,0,0)},o.world=function(e){var t,n=e.engine,i=n.world,u=e.canvas,p=e.context,m=e.options,v=r.allBodies(i),y=r.allConstraints(i),g=m.wireframes?m.wireframeBackground:m.background,x=[],h=[],b={timestamp:n.timing.timestamp};if(a.trigger(e,"beforeRender",b),e.currentBackground!==g&&f(e,g),p.globalCompositeOperation="source-in",p.fillStyle="transparent",p.fillRect(0,0,u.width,u.height),p.globalCompositeOperation="source-over",m.hasBounds){ -for(t=0;t=500){var c="";s.timing&&(c+="fps: "+Math.round(s.timing.fps)+l),e.debugString=c,e.debugTimestamp=o.timing.timestamp}if(e.debugString){n.font="12px Arial",a.wireframes?n.fillStyle="rgba(255,255,255,0.5)":n.fillStyle="rgba(0,0,0,0.5)";for(var d=e.debugString.split("\n"),u=0;u1?1:0;s1?1:0;a1?1:0;r1?1:0;l1?1:0;r1?1:0;r1?1:0;i0)){var u=o.activeContacts[0].vertex.x,p=o.activeContacts[0].vertex.y;2===o.activeContacts.length&&(u=(o.activeContacts[0].vertex.x+o.activeContacts[1].vertex.x)/2,p=(o.activeContacts[0].vertex.y+o.activeContacts[1].vertex.y)/2),i.bodyB===i.supports[0].body||i.bodyA.isStatic===!0?a.moveTo(u-8*i.normal.x,p-8*i.normal.y):a.moveTo(u+8*i.normal.x,p+8*i.normal.y),a.lineTo(u,p)}l.wireframes?a.strokeStyle="rgba(255,165,0,0.7)":a.strokeStyle="orange",a.lineWidth=1,a.stroke()},o.separations=function(e,t,n){var o,i,r,s,a,l=n,c=e.options;for(l.beginPath(),a=0;a1?1:0;p0?1:.7),t.damping=t.damping||0,t.angularStiffness=t.angularStiffness||0,t.angleA=t.bodyA?t.bodyA.angle:t.angleA,t.angleB=t.bodyB?t.bodyB.angle:t.angleB,t.plugin={},t},o.preSolveAll=function(e){for(var t=0;t0&&(u.position.x+=c.x,u.position.y+=c.y),0!==c.angle&&(i.rotate(u.vertices,c.angle,n.position),l.rotate(u.axes,c.angle),d>0&&r.rotateAbout(u.position,c.angle,n.position,u.position)),a.update(u.bounds,u.vertices,n.velocity)}c.angle*=o._warming,c.x*=o._warming,c.y*=o._warming}}}}()},{"../core/Common":14,"../core/Sleeping":22,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],13:[function(e,t,n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../core/Sleeping"),s=e("../core/Mouse"),a=e("../core/Events"),l=e("../collision/Detector"),c=e("./Constraint"),d=e("../body/Composite"),u=e("../core/Common"),p=e("../geometry/Bounds"); +!function(){o.create=function(t,n){var i=(t?t.mouse:null)||(n?n.mouse:null);i||(t&&t.render&&t.render.canvas?i=s.create(t.render.canvas):n&&n.element?i=s.create(n.element):(i=s.create(),u.warn("MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected")));var r=c.create({label:"Mouse Constraint",pointA:i.position,pointB:{x:0,y:0},length:.01,stiffness:.1,angularStiffness:1,render:{strokeStyle:"#90EE90",lineWidth:3}}),l={type:"mouseConstraint",mouse:i,element:null,body:null,constraint:r,collisionFilter:{category:1,mask:4294967295,group:0}},p=u.extend(l,n);return a.on(t,"beforeUpdate",function(){var n=d.allBodies(t.world);o.update(p,n),e(p)}),p},o.update=function(e,t){var n=e.mouse,o=e.constraint,s=e.body;if(0===n.button){if(o.bodyB)r.set(o.bodyB,!1),o.pointA=n.position;else for(var c=0;c1?1:0;d>16)+o,r=(n>>8&255)+o,s=(255&n)+o;return"#"+(16777216+65536*(i<255?i<1?0:i:255)+256*(r<255?r<1?0:r:255)+(s<255?s<1?0:s:255)).toString(16).slice(1)},o.shuffle=function(e){for(var t=e.length-1;t>0;t--){var n=Math.floor(o.random()*(t+1)),i=e[t];e[t]=e[n],e[n]=i}return e},o.choose=function(e){return e[Math.floor(o.random()*e.length)]},o.isElement=function(e){try{return e instanceof HTMLElement; +}catch(t){return"object"==typeof e&&1===e.nodeType&&"object"==typeof e.style&&"object"==typeof e.ownerDocument}},o.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)},o.isFunction=function(e){return"function"==typeof e},o.isPlainObject=function(e){return"object"==typeof e&&e.constructor===Object},o.isString=function(e){return"[object String]"===toString.call(e)},o.clamp=function(e,t,n){return en?n:e},o.sign=function(e){return e<0?-1:1},o.now=function(){var e=window.performance||{};return e.now=function(){return e.now||e.webkitNow||e.msNow||e.oNow||e.mozNow||function(){return+new Date}}(),e.now()},o.random=function(t,n){return t="undefined"!=typeof t?t:0,n="undefined"!=typeof n?n:1,t+e()*(n-t)};var e=function(){return o._seed=(9301*o._seed+49297)%233280,o._seed/233280};o.colorToNumber=function(e){return e=e.replace("#",""),3==e.length&&(e=e.charAt(0)+e.charAt(0)+e.charAt(1)+e.charAt(1)+e.charAt(2)+e.charAt(2)),parseInt(e,16)},o.logLevel=1,o.log=function(){ +console&&o.logLevel>0&&o.logLevel<=3&&console.log.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},o.info=function(){console&&o.logLevel>0&&o.logLevel<=2&&console.info.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},o.warn=function(){console&&o.logLevel>0&&o.logLevel<=3&&console.warn.apply(console,["matter-js:"].concat(Array.prototype.slice.call(arguments)))},o.nextId=function(){return o._nextId++},o.indexOf=function(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0;n0&&d.trigger(o,"collisionStart",{pairs:w.collisionStart}),s.preSolvePosition(w.list),c=0;c0&&d.trigger(o,"collisionActive",{pairs:w.collisionActive}),w.collisionEnd.length>0&&d.trigger(o,"collisionEnd",{pairs:w.collisionEnd}),e(x),d.trigger(o,"afterUpdate",g),o},o.merge=function(e,t){if(f.extend(e,t),t.world){e.world=t.world,o.clear(e);for(var n=u.allBodies(e.world),i=0;ir?(i.warn("Plugin.register:",o.toString(t),"was upgraded to",o.toString(e)),o._registry[e.name]=e):n-1},o.isFor=function(e,t){var n=e.for&&o.dependencyParse(e.for);return!e.for||t.name===n.name&&o.versionSatisfies(t.version,n.range)},o.use=function(e,t){if(e.uses=(e.uses||[]).concat(t||[]),0===e.uses.length)return void i.warn("Plugin.use:",o.toString(e),"does not specify any dependencies to install.");for(var n=o.dependencies(e),r=i.topologicalSort(n),s=[],a=0;a0&&i.info(s.join(" "))},o.dependencies=function(e,t){var n=o.dependencyParse(e),r=n.name;if(t=t||{},!(r in t)){e=o.resolve(e)||e,t[r]=i.map(e.uses||[],function(t){o.isPlugin(t)&&o.register(t);var r=o.dependencyParse(t),s=o.resolve(t);return s&&!o.versionSatisfies(s.version,r.range)?(i.warn("Plugin.dependencies:",o.toString(s),"does not satisfy",o.toString(r),"used by",o.toString(n)+"."),s._warned=!0,e._warned=!0):s||(i.warn("Plugin.dependencies:",o.toString(t),"used by",o.toString(n),"could not be resolved."),e._warned=!0),r.name});for(var s=0;s=i[2];if("^"===n.operator)return i[0]>0?s[0]===i[0]&&r.number>=n.number:i[1]>0?s[1]===i[1]&&s[2]>=i[2]:s[2]===i[2]; +}return e===t||"*"===e}}()},{"./Common":14}],21:[function(e,t,n){var o={};t.exports=o;var i=e("./Events"),r=e("./Engine"),s=e("./Common");!function(){var e,t;if("undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame,t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),!e){var n;e=function(e){n=setTimeout(function(){e(s.now())},1e3/60)},t=function(){clearTimeout(n)}}o.create=function(e){var t={fps:60,correction:1,deltaSampleSize:60,counterTimestamp:0,frameCounter:0,deltaHistory:[],timePrev:null,timeScalePrev:1,frameRequestId:null,isFixed:!1,enabled:!0},n=s.extend(t,e);return n.delta=n.delta||1e3/n.fps,n.deltaMin=n.deltaMin||1e3/n.fps,n.deltaMax=n.deltaMax||1e3/(.5*n.fps),n.fps=1e3/n.delta,n},o.run=function(t,n){return"undefined"!=typeof t.positionIterations&&(n=t,t=o.create()),function i(r){t.frameRequestId=e(i), +r&&t.enabled&&o.tick(t,n,r)}(),t},o.tick=function(e,t,n){var o,s=t.timing,a=1,l={timestamp:s.timestamp};i.trigger(e,"beforeTick",l),i.trigger(t,"beforeTick",l),e.isFixed?o=e.delta:(o=n-e.timePrev||e.delta,e.timePrev=n,e.deltaHistory.push(o),e.deltaHistory=e.deltaHistory.slice(-e.deltaSampleSize),o=Math.min.apply(null,e.deltaHistory),o=oe.deltaMax?e.deltaMax:o,a=o/e.delta,e.delta=o),0!==e.timeScalePrev&&(a*=s.timeScale/e.timeScalePrev),0===s.timeScale&&(a=0),e.timeScalePrev=s.timeScale,e.correction=a,e.frameCounter+=1,n-e.counterTimestamp>=1e3&&(e.fps=e.frameCounter*((n-e.counterTimestamp)/1e3),e.counterTimestamp=n,e.frameCounter=0),i.trigger(e,"tick",l),i.trigger(t,"tick",l),t.world.isModified&&t.render&&t.render.controller&&t.render.controller.clear&&t.render.controller.clear(t.render),i.trigger(e,"beforeUpdate",l),r.update(t,o,a),i.trigger(e,"afterUpdate",l),t.render&&t.render.controller&&(i.trigger(e,"beforeRender",l),i.trigger(t,"beforeRender",l),t.render.controller.world(t.render), +i.trigger(e,"afterRender",l),i.trigger(t,"afterRender",l)),i.trigger(e,"afterTick",l),i.trigger(t,"afterTick",l)},o.stop=function(e){t(e.frameRequestId)},o.start=function(e,t){o.run(e,t)}}()},{"./Common":14,"./Engine":15,"./Events":16}],22:[function(e,t,n){var o={};t.exports=o;var i=e("./Events");!function(){o._motionWakeThreshold=.18,o._motionSleepThreshold=.08,o._minBias=.9,o.update=function(e,t){for(var n=t*t*t,i=0;i0&&r.motion=r.sleepThreshold&&o.set(r,!0)):r.sleepCounter>0&&(r.sleepCounter-=1)}else o.set(r,!1)}},o.afterCollisions=function(e,t){for(var n=t*t*t,i=0;io._motionWakeThreshold*n&&o.set(c,!1)}}}},o.set=function(e,t){var n=e.isSleeping;t?(e.isSleeping=!0,e.sleepCounter=e.sleepThreshold,e.positionImpulse.x=0,e.positionImpulse.y=0,e.positionPrev.x=e.position.x,e.positionPrev.y=e.position.y,e.anglePrev=e.angle,e.speed=0,e.angularSpeed=0,e.motion=0,n||i.trigger(e,"sleepStart")):(e.isSleeping=!1,e.sleepCounter=0,n&&i.trigger(e,"sleepEnd"))}}()},{"./Events":16}],23:[function(e,t,n){(function(n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../core/Common"),s=e("../body/Body"),a=e("../geometry/Bounds"),l=e("../geometry/Vector"),c="undefined"!=typeof window?window.decomp:"undefined"!=typeof n?n.decomp:null;!function(){o.rectangle=function(e,t,n,o,a){a=a||{};var l={label:"Rectangle Body",position:{x:e,y:t},vertices:i.fromPath("L 0 0 L "+n+" 0 L "+n+" "+o+" L 0 "+o)};if(a.chamfer){var c=a.chamfer;l.vertices=i.chamfer(l.vertices,c.radius,c.quality,c.qualityMin,c.qualityMax), +delete a.chamfer}return s.create(r.extend({},l,a))},o.trapezoid=function(e,t,n,o,a,l){l=l||{},a*=.5;var c,d=(1-2*a)*n,u=n*a,p=u+d,f=p+u;c=a<.5?"L 0 0 L "+u+" "+-o+" L "+p+" "+-o+" L "+f+" 0":"L 0 0 L "+p+" "+-o+" L "+f+" 0";var m={label:"Trapezoid Body",position:{x:e,y:t},vertices:i.fromPath(c)};if(l.chamfer){var v=l.chamfer;m.vertices=i.chamfer(m.vertices,v.radius,v.quality,v.qualityMin,v.qualityMax),delete l.chamfer}return s.create(r.extend({},m,l))},o.circle=function(e,t,n,i,s){i=i||{};var a={label:"Circle Body",circleRadius:n};s=s||25;var l=Math.ceil(Math.max(10,Math.min(s,n)));return l%2===1&&(l+=1),o.polygon(e,t,l,n,r.extend({},a,i))},o.polygon=function(e,t,n,a,l){if(l=l||{},n<3)return o.circle(e,t,a,l);for(var c=2*Math.PI/n,d="",u=.5*c,p=0;p0&&i.area(P)1?(f=s.create(r.extend({parts:m.slice(0)},o)),s.setPosition(f,{x:e,y:t}),f):m[0]}}()}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../body/Body":1,"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],24:[function(e,t,n){var o={};t.exports=o;var i=e("../body/Composite"),r=e("../constraint/Constraint"),s=e("../core/Common"),a=e("../body/Body"),l=e("./Bodies");!function(){o.stack=function(e,t,n,o,r,s,l){for(var c,d=i.create({label:"Stack"}),u=e,p=t,f=0,m=0;mv&&(v=x),a.translate(g,{x:.5*h,y:.5*x}),u=g.bounds.max.x+r,i.addBody(d,g),c=g,f+=1}else u+=r}p+=v+s,u=e}return d},o.chain=function(e,t,n,o,a,l){ +for(var c=e.bodies,d=1;d0)for(c=0;c0&&(p=f[c-1+(l-1)*t],i.addConstraint(e,r.create(s.extend({bodyA:p,bodyB:u},a)))),o&&cp)){c=p-c;var m=c,v=n-1-c;if(!(sv)){ +1===u&&a.translate(d,{x:(s+(n%2===1?1:-1))*f,y:0});var y=d?s*f:0;return l(e+y+s*r,o,s,c,d,u)}}})},o.newtonsCradle=function(e,t,n,o,s){for(var a=i.create({label:"Newtons Cradle"}),c=0;ce.max.x&&(e.max.x=i.x),i.xe.max.y&&(e.max.y=i.y),i.y0?e.max.x+=n.x:e.min.x+=n.x,n.y>0?e.max.y+=n.y:e.min.y+=n.y)},o.contains=function(e,t){return t.x>=e.min.x&&t.x<=e.max.x&&t.y>=e.min.y&&t.y<=e.max.y},o.overlaps=function(e,t){return e.min.x<=t.max.x&&e.max.x>=t.min.x&&e.max.y>=t.min.y&&e.min.y<=t.max.y},o.translate=function(e,t){e.min.x+=t.x,e.max.x+=t.x,e.min.y+=t.y,e.max.y+=t.y},o.shift=function(e,t){var n=e.max.x-e.min.x,o=e.max.y-e.min.y;e.min.x=t.x,e.max.x=t.x+n,e.min.y=t.y,e.max.y=t.y+o}}()},{}],27:[function(e,t,n){var o={};t.exports=o;e("../geometry/Bounds");!function(){o.pathToVertices=function(t,n){var o,i,r,s,a,l,c,d,u,p,f,m,v=[],y=0,g=0,x=0;n=n||15;var h=function(e,t,n){var o=n%2===1&&n>1;if(!u||e!=u.x||t!=u.y){u&&o?(f=u.x,m=u.y):(f=0,m=0);var i={x:f+e,y:m+t};!o&&u||(u=i),v.push(i),g=f+e,x=m+t}},b=function(e){var t=e.pathSegTypeAsLetter.toUpperCase();if("Z"!==t){switch(t){case"M":case"L":case"T":case"C": +case"S":case"Q":g=e.x,x=e.y;break;case"H":g=e.x;break;case"V":x=e.y}h(g,x,e.pathSegType)}};for(e(t),r=t.getTotalLength(),l=[],o=0;o0)return!1}return!0},o.scale=function(e,t,n,r){if(1===t&&1===n)return e;r=r||o.centre(e);for(var s,a,l=0;l=0?l-1:e.length-1],d=e[l],u=e[(l+1)%e.length],p=t[l0&&(r|=2),3===r)return!1;return 0!==r||null},o.hull=function(e){var t,n,o=[],r=[];for(e=e.slice(0),e.sort(function(e,t){var n=e.x-t.x;return 0!==n?n:e.y-t.y}),n=0;n=2&&i.cross3(r[r.length-2],r[r.length-1],t)<=0;)r.pop();r.push(t)}for(n=e.length-1;n>=0;n--){for(t=e[n];o.length>=2&&i.cross3(o[o.length-2],o[o.length-1],t)<=0;)o.pop();o.push(t)}return o.pop(),r.pop(),o.concat(r)}}()},{"../core/Common":14,"../geometry/Vector":28}],30:[function(e,t,n){var o=t.exports=e("../core/Matter");o.Body=e("../body/Body"),o.Composite=e("../body/Composite"),o.World=e("../body/World"),o.Contact=e("../collision/Contact"),o.Detector=e("../collision/Detector"), +o.Grid=e("../collision/Grid"),o.Pairs=e("../collision/Pairs"),o.Pair=e("../collision/Pair"),o.Query=e("../collision/Query"),o.Resolver=e("../collision/Resolver"),o.SAT=e("../collision/SAT"),o.Constraint=e("../constraint/Constraint"),o.MouseConstraint=e("../constraint/MouseConstraint"),o.Common=e("../core/Common"),o.Engine=e("../core/Engine"),o.Events=e("../core/Events"),o.Mouse=e("../core/Mouse"),o.Runner=e("../core/Runner"),o.Sleeping=e("../core/Sleeping"),o.Plugin=e("../core/Plugin"),o.Bodies=e("../factory/Bodies"),o.Composites=e("../factory/Composites"),o.Axes=e("../geometry/Axes"),o.Bounds=e("../geometry/Bounds"),o.Svg=e("../geometry/Svg"),o.Vector=e("../geometry/Vector"),o.Vertices=e("../geometry/Vertices"),o.Render=e("../render/Render"),o.RenderPixi=e("../render/RenderPixi"),o.World.add=o.Composite.add,o.World.remove=o.Composite.remove,o.World.addComposite=o.Composite.addComposite,o.World.addBody=o.Composite.addBody,o.World.addConstraint=o.Composite.addConstraint,o.World.clear=o.Composite.clear, +o.Engine.run=o.Runner.run},{"../body/Body":1,"../body/Composite":2,"../body/World":3,"../collision/Contact":4,"../collision/Detector":5,"../collision/Grid":6,"../collision/Pair":7,"../collision/Pairs":8,"../collision/Query":9,"../collision/Resolver":10,"../collision/SAT":11,"../constraint/Constraint":12,"../constraint/MouseConstraint":13,"../core/Common":14,"../core/Engine":15,"../core/Events":16,"../core/Matter":17,"../core/Metrics":18,"../core/Mouse":19,"../core/Plugin":20,"../core/Runner":21,"../core/Sleeping":22,"../factory/Bodies":23,"../factory/Composites":24,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Svg":27,"../geometry/Vector":28,"../geometry/Vertices":29,"../render/Render":31,"../render/RenderPixi":32}],31:[function(e,t,n){var o={};t.exports=o;var i=e("../core/Common"),r=e("../body/Composite"),s=e("../geometry/Bounds"),a=e("../core/Events"),l=e("../collision/Grid"),c=e("../geometry/Vector"),d=e("../core/Mouse");!function(){var e,t;"undefined"!=typeof window&&(e=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||function(e){ +window.setTimeout(function(){e(i.now())},1e3/60)},t=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame),o.create=function(e){var t={controller:o,engine:null,element:null,canvas:null,mouse:null,frameRequestId:null,options:{width:800,height:600,pixelRatio:1,background:"#18181d",wireframeBackground:"#0f0f13",hasBounds:!!e.bounds,enabled:!0,wireframes:!0,showSleeping:!0,showDebug:!1,showBroadphase:!1,showBounds:!1,showVelocity:!1,showCollisions:!1,showSeparations:!1,showAxes:!1,showPositions:!1,showAngleIndicator:!1,showIds:!1,showShadows:!1,showVertexNumbers:!1,showConvexHulls:!1,showInternalEdges:!1,showMousePosition:!1}},r=i.extend(t,e);return r.canvas&&(r.canvas.width=r.options.width||r.canvas.width,r.canvas.height=r.options.height||r.canvas.height),r.mouse=e.mouse,r.engine=e.engine,r.canvas=r.canvas||n(r.options.width,r.options.height),r.context=r.canvas.getContext("2d"),r.textures={},r.bounds=r.bounds||{min:{x:0, +y:0},max:{x:r.canvas.width,y:r.canvas.height}},1!==r.options.pixelRatio&&o.setPixelRatio(r,r.options.pixelRatio),i.isElement(r.element)?r.element.appendChild(r.canvas):i.log("Render.create: options.element was undefined, render.canvas was created but not appended","warn"),r},o.run=function(t){!function n(i){t.frameRequestId=e(n),o.world(t)}()},o.stop=function(e){t(e.frameRequestId)},o.setPixelRatio=function(e,t){var n=e.options,o=e.canvas;"auto"===t&&(t=u(o)),n.pixelRatio=t,o.setAttribute("data-pixel-ratio",t),o.width=n.width*t,o.height=n.height*t,o.style.width=n.width+"px",o.style.height=n.height+"px",e.context.scale(t,t)},o.lookAt=function(e,t,n,o){o="undefined"==typeof o||o,t=i.isArray(t)?t:[t],n=n||{x:0,y:0};for(var r={min:{x:1/0,y:1/0},max:{x:-(1/0),y:-(1/0)}},s=0;sr.max.x&&(r.max.x=c.x),l.yr.max.y&&(r.max.y=c.y)); +}var u=r.max.x-r.min.x+2*n.x,p=r.max.y-r.min.y+2*n.y,f=e.canvas.height,m=e.canvas.width,v=m/f,y=u/p,g=1,x=1;y>v?x=y/v:g=v/y,e.options.hasBounds=!0,e.bounds.min.x=r.min.x,e.bounds.max.x=r.min.x+u*g,e.bounds.min.y=r.min.y,e.bounds.max.y=r.min.y+p*x,o&&(e.bounds.min.x+=.5*u-u*g*.5,e.bounds.max.x+=.5*u-u*g*.5,e.bounds.min.y+=.5*p-p*x*.5,e.bounds.max.y+=.5*p-p*x*.5),e.bounds.min.x-=n.x,e.bounds.max.x-=n.x,e.bounds.min.y-=n.y,e.bounds.max.y-=n.y,e.mouse&&(d.setScale(e.mouse,{x:(e.bounds.max.x-e.bounds.min.x)/e.canvas.width,y:(e.bounds.max.y-e.bounds.min.y)/e.canvas.height}),d.setOffset(e.mouse,e.bounds.min))},o.startViewTransform=function(e){var t=e.bounds.max.x-e.bounds.min.x,n=e.bounds.max.y-e.bounds.min.y,o=t/e.options.width,i=n/e.options.height;e.context.scale(1/o,1/i),e.context.translate(-e.bounds.min.x,-e.bounds.min.y)},o.endViewTransform=function(e){e.context.setTransform(e.options.pixelRatio,0,0,e.options.pixelRatio,0,0)},o.world=function(e){var t,n=e.engine,i=n.world,u=e.canvas,p=e.context,m=e.options,v=r.allBodies(i),y=r.allConstraints(i),g=m.wireframes?m.wireframeBackground:m.background,x=[],h=[],b={ +timestamp:n.timing.timestamp};if(a.trigger(e,"beforeRender",b),e.currentBackground!==g&&f(e,g),p.globalCompositeOperation="source-in",p.fillStyle="transparent",p.fillRect(0,0,u.width,u.height),p.globalCompositeOperation="source-over",m.hasBounds){for(t=0;t=500){var c="";s.timing&&(c+="fps: "+Math.round(s.timing.fps)+l),e.debugString=c,e.debugTimestamp=o.timing.timestamp}if(e.debugString){n.font="12px Arial",a.wireframes?n.fillStyle="rgba(255,255,255,0.5)":n.fillStyle="rgba(0,0,0,0.5)";for(var d=e.debugString.split("\n"),u=0;u1?1:0;s1?1:0;a1?1:0;r1?1:0;l1?1:0;r1?1:0;r1?1:0;i0)){var u=o.activeContacts[0].vertex.x,p=o.activeContacts[0].vertex.y;2===o.activeContacts.length&&(u=(o.activeContacts[0].vertex.x+o.activeContacts[1].vertex.x)/2,p=(o.activeContacts[0].vertex.y+o.activeContacts[1].vertex.y)/2),i.bodyB===i.supports[0].body||i.bodyA.isStatic===!0?a.moveTo(u-8*i.normal.x,p-8*i.normal.y):a.moveTo(u+8*i.normal.x,p+8*i.normal.y),a.lineTo(u,p)}l.wireframes?a.strokeStyle="rgba(255,165,0,0.7)":a.strokeStyle="orange",a.lineWidth=1,a.stroke()},o.separations=function(e,t,n){var o,i,r,s,a,l=n,c=e.options;for(l.beginPath(),a=0;a1?1:0;p Date: Mon, 26 Jun 2017 23:20:34 +0100 Subject: [PATCH 22/31] added constraint.render.type and constraint.render.anchor --- src/constraint/Constraint.js | 45 ++++++++++++++++++++++++------- src/render/Render.js | 52 ++++++++++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 17 deletions(-) diff --git a/src/constraint/Constraint.js b/src/constraint/Constraint.js index ab6df4c..42ab7bc 100644 --- a/src/constraint/Constraint.js +++ b/src/constraint/Constraint.js @@ -51,15 +51,6 @@ var Common = require('../core/Common'); constraint.length = typeof constraint.length !== 'undefined' ? constraint.length : length; - // render - var render = { - visible: true, - lineWidth: 2, - strokeStyle: '#ffffff' - }; - - constraint.render = Common.extend(render, constraint.render); - // option defaults constraint.id = constraint.id || Common.nextId(); constraint.label = constraint.label || 'Constraint'; @@ -71,6 +62,24 @@ var Common = require('../core/Common'); constraint.angleB = constraint.bodyB ? constraint.bodyB.angle : constraint.angleB; constraint.plugin = {}; + // render + var render = { + visible: true, + lineWidth: 2, + strokeStyle: '#ffffff', + type: 'line', + anchors: true + }; + + if (constraint.length === 0) { + render.type = 'pin'; + render.anchors = false; + } else if (constraint.stiffness < 0.9) { + render.type = 'spring'; + } + + constraint.render = Common.extend(render, constraint.render); + return constraint; }; @@ -353,6 +362,24 @@ var Common = require('../core/Common'); * @default a random colour */ + /** + * A `String` that defines the constraint rendering type. + * The possible values are 'line', 'pin', 'spring'. + * An appropriate render type will be automatically chosen unless one is given in options. + * + * @property render.type + * @type string + * @default 'line' + */ + + /** + * A `Boolean` that defines if the constraint's anchor points should be rendered. + * + * @property render.anchors + * @type boolean + * @default true + */ + /** * The first possible `Body` that this constraint is attached to. * diff --git a/src/render/Render.js b/src/render/Render.js index 85fe9c5..8070006 100644 --- a/src/render/Render.js +++ b/src/render/Render.js @@ -496,20 +496,47 @@ var Mouse = require('../core/Mouse'); continue; var bodyA = constraint.bodyA, - bodyB = constraint.bodyB; + bodyB = constraint.bodyB, + start, + end; if (bodyA) { - c.beginPath(); - c.moveTo(bodyA.position.x + constraint.pointA.x, bodyA.position.y + constraint.pointA.y); + start = Vector.add(bodyA.position, constraint.pointA); } else { - c.beginPath(); - c.moveTo(constraint.pointA.x, constraint.pointA.y); + start = constraint.pointA; } - if (bodyB) { - c.lineTo(bodyB.position.x + constraint.pointB.x, bodyB.position.y + constraint.pointB.y); + if (constraint.render.type === 'pin') { + c.beginPath(); + c.arc(start.x, start.y, 4, 0, 2 * Math.PI); + c.closePath(); } else { - c.lineTo(constraint.pointB.x, constraint.pointB.y); + if (bodyB) { + end = Vector.add(bodyB.position, constraint.pointB); + } else { + end = constraint.pointB; + } + + c.beginPath(); + c.moveTo(start.x, start.y); + + if (constraint.render.type === 'spring') { + var delta = Vector.sub(end, start), + normal = Vector.perp(Vector.normalise(delta)), + coils = Math.ceil(Common.clamp(constraint.length / 5, 12, 20)), + offset; + + for (var j = 0; j < coils; j += 1) { + offset = j % 2 === 0 ? 1 : -1; + + c.lineTo( + start.x + delta.x * (j / coils) + normal.x * offset * 4, + start.y + delta.y * (j / coils) + normal.y * offset * 4 + ); + } + } + + c.lineTo(end.x, end.y); } if (constraint.render.lineWidth) { @@ -517,6 +544,15 @@ var Mouse = require('../core/Mouse'); c.strokeStyle = constraint.render.strokeStyle; c.stroke(); } + + if (constraint.render.anchors) { + c.fillStyle = constraint.render.strokeStyle; + c.beginPath(); + c.arc(start.x, start.y, 3, 0, 2 * Math.PI); + c.arc(end.x, end.y, 3, 0, 2 * Math.PI); + c.closePath(); + c.fill(); + } } }; From b93c08fda3459999fc8cc442539d6331d968f812 Mon Sep 17 00:00:00 2001 From: liabru Date: Mon, 26 Jun 2017 23:20:58 +0100 Subject: [PATCH 23/31] added Example.constraints --- demo/index.html | 1 + demo/js/Demo.js | 6 ++ examples/constraints.js | 180 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 examples/constraints.js diff --git a/demo/index.html b/demo/index.html index e248179..dd2eb04 100644 --- a/demo/index.html +++ b/demo/index.html @@ -44,6 +44,7 @@ + diff --git a/demo/js/Demo.js b/demo/js/Demo.js index 4a7a498..a0dea63 100644 --- a/demo/js/Demo.js +++ b/demo/js/Demo.js @@ -118,6 +118,12 @@ init: Example.concave, sourceLink: sourceLinkRoot + '/concave.js' }, + { + name: 'Constraints', + id: 'constraints', + init: Example.constraints, + sourceLink: sourceLinkRoot + '/constraints.js' + }, { name: 'Double Pendulum', id: 'doublePendulum', diff --git a/examples/constraints.js b/examples/constraints.js new file mode 100644 index 0000000..5db0161 --- /dev/null +++ b/examples/constraints.js @@ -0,0 +1,180 @@ +var Example = Example || {}; + +Example.constraints = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.documentElement.clientWidth, 800), + height: Math.min(document.documentElement.clientHeight, 600), + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add stiff global constraint + var body = Bodies.polygon(150, 200, 5, 30); + + var constraint = Constraint.create({ + pointA: { x: 150, y: 100 }, + bodyB: body, + pointB: { x: -10, y: -10 } + }); + + World.add(world, [body, constraint]); + + // add soft global constraint + var body = Bodies.polygon(280, 100, 3, 30); + + var constraint = Constraint.create({ + pointA: { x: 280, y: 120 }, + bodyB: body, + pointB: { x: -10, y: -7 }, + stiffness: 0.001 + }); + + World.add(world, [body, constraint]); + + // add damped soft global constraint + var body = Bodies.polygon(400, 100, 4, 30); + + var constraint = Constraint.create({ + pointA: { x: 400, y: 120 }, + bodyB: body, + pointB: { x: -10, y: -10 }, + stiffness: 0.001, + damping: 0.05 + }); + + World.add(world, [body, constraint]); + + // add revolute constraint + var body = Bodies.rectangle(600, 200, 200, 20); + var ball = Bodies.circle(550, 150, 20); + + var constraint = Constraint.create({ + pointA: { x: 600, y: 200 }, + bodyB: body, + length: 0 + }); + + World.add(world, [body, ball, constraint]); + + // add revolute multi-body constraint + var body = Bodies.rectangle(500, 400, 100, 20, { collisionFilter: { group: -1 } }); + var ball = Bodies.circle(600, 400, 20, { collisionFilter: { group: -1 } }); + + var constraint = Constraint.create({ + bodyA: body, + bodyB: ball + }); + + World.add(world, [body, ball, constraint]); + + // add stiff multi-body constraint + var bodyA = Bodies.polygon(100, 400, 6, 20); + var bodyB = Bodies.polygon(200, 400, 1, 50); + + var constraint = Constraint.create({ + bodyA: bodyA, + pointA: { x: -10, y: -10 }, + bodyB: bodyB, + pointB: { x: -10, y: -10 } + }); + + World.add(world, [bodyA, bodyB, constraint]); + + // add soft global constraint + var bodyA = Bodies.polygon(300, 400, 4, 20); + var bodyB = Bodies.polygon(400, 400, 3, 30); + + var constraint = Constraint.create({ + bodyA: bodyA, + pointA: { x: -10, y: -10 }, + bodyB: bodyB, + pointB: { x: -10, y: -7 }, + stiffness: 0.001 + }); + + World.add(world, [bodyA, bodyB, constraint]); + + // add damped soft global constraint + var bodyA = Bodies.polygon(500, 400, 6, 30); + var bodyB = Bodies.polygon(600, 400, 7, 60); + + var constraint = Constraint.create({ + bodyA: bodyA, + pointA: { x: -10, y: -10 }, + bodyB: bodyB, + pointB: { x: -10, y: -10 }, + stiffness: 0.001, + damping: 0.1 + }); + + World.add(world, [bodyA, bodyB, constraint]); + + World.add(world, [ + // walls + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + // allow bodies on mouse to rotate + angularStiffness: 0, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file From b874f4dbc7a4d82bd653f3d8f95403b56162c4ff Mon Sep 17 00:00:00 2001 From: liabru Date: Mon, 26 Jun 2017 23:21:22 +0100 Subject: [PATCH 24/31] update alpha build --- build/matter.js | 99 ++++++++++++++++++++++++++++++++++++--------- build/matter.min.js | 42 +++++++++---------- 2 files changed, 102 insertions(+), 39 deletions(-) diff --git a/build/matter.js b/build/matter.js index 2070fa5..df0c000 100644 --- a/build/matter.js +++ b/build/matter.js @@ -1,5 +1,5 @@ /** -* matter-js 0.12.0-alpha by @liabru 2017-06-12 +* matter-js 0.12.0-alpha by @liabru 2017-06-26 * http://brm.io/matter-js/ * License MIT */ @@ -3526,15 +3526,6 @@ var Common = _dereq_('../core/Common'); constraint.length = typeof constraint.length !== 'undefined' ? constraint.length : length; - // render - var render = { - visible: true, - lineWidth: 2, - strokeStyle: '#ffffff' - }; - - constraint.render = Common.extend(render, constraint.render); - // option defaults constraint.id = constraint.id || Common.nextId(); constraint.label = constraint.label || 'Constraint'; @@ -3546,6 +3537,24 @@ var Common = _dereq_('../core/Common'); constraint.angleB = constraint.bodyB ? constraint.bodyB.angle : constraint.angleB; constraint.plugin = {}; + // render + var render = { + visible: true, + lineWidth: 2, + strokeStyle: '#ffffff', + type: 'line', + anchors: true + }; + + if (constraint.length === 0) { + render.type = 'pin'; + render.anchors = false; + } else if (constraint.stiffness < 0.9) { + render.type = 'spring'; + } + + constraint.render = Common.extend(render, constraint.render); + return constraint; }; @@ -3828,6 +3837,24 @@ var Common = _dereq_('../core/Common'); * @default a random colour */ + /** + * A `String` that defines the constraint rendering type. + * The possible values are 'line', 'pin', 'spring'. + * An appropriate render type will be automatically chosen unless one is given in options. + * + * @property render.type + * @type string + * @default 'line' + */ + + /** + * A `Boolean` that defines if the constraint's anchor points should be rendered. + * + * @property render.anchors + * @type boolean + * @default true + */ + /** * The first possible `Body` that this constraint is attached to. * @@ -8732,20 +8759,47 @@ var Mouse = _dereq_('../core/Mouse'); continue; var bodyA = constraint.bodyA, - bodyB = constraint.bodyB; + bodyB = constraint.bodyB, + start, + end; if (bodyA) { - c.beginPath(); - c.moveTo(bodyA.position.x + constraint.pointA.x, bodyA.position.y + constraint.pointA.y); + start = Vector.add(bodyA.position, constraint.pointA); } else { - c.beginPath(); - c.moveTo(constraint.pointA.x, constraint.pointA.y); + start = constraint.pointA; } - if (bodyB) { - c.lineTo(bodyB.position.x + constraint.pointB.x, bodyB.position.y + constraint.pointB.y); + if (constraint.render.type === 'pin') { + c.beginPath(); + c.arc(start.x, start.y, 4, 0, 2 * Math.PI); + c.closePath(); } else { - c.lineTo(constraint.pointB.x, constraint.pointB.y); + if (bodyB) { + end = Vector.add(bodyB.position, constraint.pointB); + } else { + end = constraint.pointB; + } + + c.beginPath(); + c.moveTo(start.x, start.y); + + if (constraint.render.type === 'spring') { + var delta = Vector.sub(end, start), + normal = Vector.perp(Vector.normalise(delta)), + coils = Math.ceil(Common.clamp(constraint.length / 5, 12, 20)), + offset; + + for (var j = 0; j < coils; j += 1) { + offset = j % 2 === 0 ? 1 : -1; + + c.lineTo( + start.x + delta.x * (j / coils) + normal.x * offset * 4, + start.y + delta.y * (j / coils) + normal.y * offset * 4 + ); + } + } + + c.lineTo(end.x, end.y); } if (constraint.render.lineWidth) { @@ -8753,6 +8807,15 @@ var Mouse = _dereq_('../core/Mouse'); c.strokeStyle = constraint.render.strokeStyle; c.stroke(); } + + if (constraint.render.anchors) { + c.fillStyle = constraint.render.strokeStyle; + c.beginPath(); + c.arc(start.x, start.y, 3, 0, 2 * Math.PI); + c.arc(end.x, end.y, 3, 0, 2 * Math.PI); + c.closePath(); + c.fill(); + } } }; diff --git a/build/matter.min.js b/build/matter.min.js index c56544d..d492197 100644 --- a/build/matter.min.js +++ b/build/matter.min.js @@ -1,5 +1,5 @@ /** -* matter-js 0.12.0-alpha by @liabru 2017-06-12 +* matter-js 0.12.0-alpha by @liabru 2017-06-26 * http://brm.io/matter-js/ * License MIT */ @@ -29,9 +29,9 @@ v.velocity.y=v.position.y-v.positionPrev.y,y.velocity.x=y.position.x-y.positionP L=S.tangentImpulse-N}i.x=g.x*_+x.x*L,i.y=g.y*_+x.y*L,v.isStatic||v.isSleeping||(v.positionPrev.x+=i.x*v.inverseMass,v.positionPrev.y+=i.y*v.inverseMass,v.anglePrev+=r.cross(A,i)*v.inverseInertia),y.isStatic||y.isSleeping||(y.positionPrev.x-=i.x*y.inverseMass,y.positionPrev.y-=i.y*y.inverseMass,y.anglePrev-=r.cross(P,i)*y.inverseInertia)}}}}}()},{"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],11:[function(e,t,n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../geometry/Vector");!function(){o.collides=function(t,o,s){var a,l,c,d,u=!1;if(s){var p=t.parent,f=o.parent,m=p.speed*p.speed+p.angularSpeed*p.angularSpeed+f.speed*f.speed+f.angularSpeed*f.angularSpeed;u=s&&s.collided&&m<.2,d=s}else d={collided:!1,bodyA:t,bodyB:o};if(s&&u){var v=d.axisBody,y=v===t?o:t,g=[v.axes[s.axisNumber]];if(c=e(v.vertices,y.vertices,g),d.reused=!0,c.overlap<=0)return d.collided=!1,d}else{if(a=e(t.vertices,o.vertices,t.axes),a.overlap<=0)return d.collided=!1, d;if(l=e(o.vertices,t.vertices,o.axes),l.overlap<=0)return d.collided=!1,d;a.overlapi?i=a:a=0?s.index-1:d.length-1;i=d[f],c.x=i.x-u.x,c.y=i.y-u.y,l=-r.dot(n,c),a=i;var m=(s.index+1)%d.length;return i=d[m],c.x=i.x-u.x,c.y=i.y-u.y,o=-r.dot(n,c),o0?1:.7),t.damping=t.damping||0,t.angularStiffness=t.angularStiffness||0,t.angleA=t.bodyA?t.bodyA.angle:t.angleA,t.angleB=t.bodyB?t.bodyB.angle:t.angleB,t.plugin={},t},o.preSolveAll=function(e){for(var t=0;t0&&(u.position.x+=c.x,u.position.y+=c.y),0!==c.angle&&(i.rotate(u.vertices,c.angle,n.position),l.rotate(u.axes,c.angle),d>0&&r.rotateAbout(u.position,c.angle,n.position,u.position)),a.update(u.bounds,u.vertices,n.velocity)}c.angle*=o._warming,c.x*=o._warming,c.y*=o._warming}}}}()},{"../core/Common":14,"../core/Sleeping":22,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],13:[function(e,t,n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../core/Sleeping"),s=e("../core/Mouse"),a=e("../core/Events"),l=e("../collision/Detector"),c=e("./Constraint"),d=e("../body/Composite"),u=e("../core/Common"),p=e("../geometry/Bounds"); +t.length="undefined"!=typeof t.length?t.length:i,t.id=t.id||c.nextId(),t.label=t.label||"Constraint",t.type="constraint",t.stiffness=t.stiffness||(t.length>0?1:.7),t.damping=t.damping||0,t.angularStiffness=t.angularStiffness||0,t.angleA=t.bodyA?t.bodyA.angle:t.angleA,t.angleB=t.bodyB?t.bodyB.angle:t.angleB,t.plugin={};var s={visible:!0,lineWidth:2,strokeStyle:"#ffffff",type:"line",anchors:!0};return 0===t.length?(s.type="pin",s.anchors=!1):t.stiffness<.9&&(s.type="spring"),t.render=c.extend(s,t.render),t},o.preSolveAll=function(e){for(var t=0;t0&&(u.position.x+=c.x,u.position.y+=c.y),0!==c.angle&&(i.rotate(u.vertices,c.angle,n.position),l.rotate(u.axes,c.angle),d>0&&r.rotateAbout(u.position,c.angle,n.position,u.position)),a.update(u.bounds,u.vertices,n.velocity)}c.angle*=o._warming,c.x*=o._warming,c.y*=o._warming}}}}()},{"../core/Common":14,"../core/Sleeping":22,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],13:[function(e,t,n){var o={};t.exports=o;var i=e("../geometry/Vertices"),r=e("../core/Sleeping"),s=e("../core/Mouse"),a=e("../core/Events"),l=e("../collision/Detector"),c=e("./Constraint"),d=e("../body/Composite"),u=e("../core/Common"),p=e("../geometry/Bounds"); !function(){o.create=function(t,n){var i=(t?t.mouse:null)||(n?n.mouse:null);i||(t&&t.render&&t.render.canvas?i=s.create(t.render.canvas):n&&n.element?i=s.create(n.element):(i=s.create(),u.warn("MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected")));var r=c.create({label:"Mouse Constraint",pointA:i.position,pointB:{x:0,y:0},length:.01,stiffness:.1,angularStiffness:1,render:{strokeStyle:"#90EE90",lineWidth:3}}),l={type:"mouseConstraint",mouse:i,element:null,body:null,constraint:r,collisionFilter:{category:1,mask:4294967295,group:0}},p=u.extend(l,n);return a.on(t,"beforeUpdate",function(){var n=d.allBodies(t.world);o.update(p,n),e(p)}),p},o.update=function(e,t){var n=e.mouse,o=e.constraint,s=e.body;if(0===n.button){if(o.bodyB)r.set(o.bodyB,!1),o.pointA=n.position;else for(var c=0;c1?1:0;d>16)+o,r=(n>>8&255)+o,s=(255&n)+o;return"#"+(16777216+65536*(i<255?i<1?0:i:255)+256*(r<255?r<1?0:r:255)+(s<255?s<1?0:s:255)).toString(16).slice(1)},o.shuffle=function(e){for(var t=e.length-1;t>0;t--){var n=Math.floor(o.random()*(t+1)),i=e[t];e[t]=e[n],e[n]=i}return e},o.choose=function(e){return e[Math.floor(o.random()*e.length)]},o.isElement=function(e){try{return e instanceof HTMLElement; @@ -71,20 +71,20 @@ window.setTimeout(function(){e(i.now())},1e3/60)},t=window.cancelAnimationFrame| y:0},max:{x:r.canvas.width,y:r.canvas.height}},1!==r.options.pixelRatio&&o.setPixelRatio(r,r.options.pixelRatio),i.isElement(r.element)?r.element.appendChild(r.canvas):i.log("Render.create: options.element was undefined, render.canvas was created but not appended","warn"),r},o.run=function(t){!function n(i){t.frameRequestId=e(n),o.world(t)}()},o.stop=function(e){t(e.frameRequestId)},o.setPixelRatio=function(e,t){var n=e.options,o=e.canvas;"auto"===t&&(t=u(o)),n.pixelRatio=t,o.setAttribute("data-pixel-ratio",t),o.width=n.width*t,o.height=n.height*t,o.style.width=n.width+"px",o.style.height=n.height+"px",e.context.scale(t,t)},o.lookAt=function(e,t,n,o){o="undefined"==typeof o||o,t=i.isArray(t)?t:[t],n=n||{x:0,y:0};for(var r={min:{x:1/0,y:1/0},max:{x:-(1/0),y:-(1/0)}},s=0;sr.max.x&&(r.max.x=c.x),l.yr.max.y&&(r.max.y=c.y)); }var u=r.max.x-r.min.x+2*n.x,p=r.max.y-r.min.y+2*n.y,f=e.canvas.height,m=e.canvas.width,v=m/f,y=u/p,g=1,x=1;y>v?x=y/v:g=v/y,e.options.hasBounds=!0,e.bounds.min.x=r.min.x,e.bounds.max.x=r.min.x+u*g,e.bounds.min.y=r.min.y,e.bounds.max.y=r.min.y+p*x,o&&(e.bounds.min.x+=.5*u-u*g*.5,e.bounds.max.x+=.5*u-u*g*.5,e.bounds.min.y+=.5*p-p*x*.5,e.bounds.max.y+=.5*p-p*x*.5),e.bounds.min.x-=n.x,e.bounds.max.x-=n.x,e.bounds.min.y-=n.y,e.bounds.max.y-=n.y,e.mouse&&(d.setScale(e.mouse,{x:(e.bounds.max.x-e.bounds.min.x)/e.canvas.width,y:(e.bounds.max.y-e.bounds.min.y)/e.canvas.height}),d.setOffset(e.mouse,e.bounds.min))},o.startViewTransform=function(e){var t=e.bounds.max.x-e.bounds.min.x,n=e.bounds.max.y-e.bounds.min.y,o=t/e.options.width,i=n/e.options.height;e.context.scale(1/o,1/i),e.context.translate(-e.bounds.min.x,-e.bounds.min.y)},o.endViewTransform=function(e){e.context.setTransform(e.options.pixelRatio,0,0,e.options.pixelRatio,0,0)},o.world=function(e){var t,n=e.engine,i=n.world,u=e.canvas,p=e.context,m=e.options,v=r.allBodies(i),y=r.allConstraints(i),g=m.wireframes?m.wireframeBackground:m.background,x=[],h=[],b={ timestamp:n.timing.timestamp};if(a.trigger(e,"beforeRender",b),e.currentBackground!==g&&f(e,g),p.globalCompositeOperation="source-in",p.fillStyle="transparent",p.fillRect(0,0,u.width,u.height),p.globalCompositeOperation="source-over",m.hasBounds){for(t=0;t=500){var c="";s.timing&&(c+="fps: "+Math.round(s.timing.fps)+l),e.debugString=c,e.debugTimestamp=o.timing.timestamp}if(e.debugString){n.font="12px Arial",a.wireframes?n.fillStyle="rgba(255,255,255,0.5)":n.fillStyle="rgba(0,0,0,0.5)";for(var d=e.debugString.split("\n"),u=0;u1?1:0;s1?1:0;a1?1:0;r1?1:0;l1?1:0;r1?1:0;r1?1:0;i0)){var u=o.activeContacts[0].vertex.x,p=o.activeContacts[0].vertex.y;2===o.activeContacts.length&&(u=(o.activeContacts[0].vertex.x+o.activeContacts[1].vertex.x)/2,p=(o.activeContacts[0].vertex.y+o.activeContacts[1].vertex.y)/2),i.bodyB===i.supports[0].body||i.bodyA.isStatic===!0?a.moveTo(u-8*i.normal.x,p-8*i.normal.y):a.moveTo(u+8*i.normal.x,p+8*i.normal.y),a.lineTo(u,p)}l.wireframes?a.strokeStyle="rgba(255,165,0,0.7)":a.strokeStyle="orange",a.lineWidth=1,a.stroke()},o.separations=function(e,t,n){var o,i,r,s,a,l=n,c=e.options;for(l.beginPath(),a=0;a1?1:0;p=500){var c="";s.timing&&(c+="fps: "+Math.round(s.timing.fps)+l),e.debugString=c,e.debugTimestamp=o.timing.timestamp}if(e.debugString){n.font="12px Arial",a.wireframes?n.fillStyle="rgba(255,255,255,0.5)":n.fillStyle="rgba(0,0,0,0.5)";for(var d=e.debugString.split("\n"),u=0;u1?1:0;s1?1:0;a1?1:0;r1?1:0;l1?1:0;r1?1:0;r1?1:0;i0)){var u=o.activeContacts[0].vertex.x,p=o.activeContacts[0].vertex.y;2===o.activeContacts.length&&(u=(o.activeContacts[0].vertex.x+o.activeContacts[1].vertex.x)/2,p=(o.activeContacts[0].vertex.y+o.activeContacts[1].vertex.y)/2),i.bodyB===i.supports[0].body||i.bodyA.isStatic===!0?a.moveTo(u-8*i.normal.x,p-8*i.normal.y):a.moveTo(u+8*i.normal.x,p+8*i.normal.y),a.lineTo(u,p); +}l.wireframes?a.strokeStyle="rgba(255,165,0,0.7)":a.strokeStyle="orange",a.lineWidth=1,a.stroke()},o.separations=function(e,t,n){var o,i,r,s,a,l=n,c=e.options;for(l.beginPath(),a=0;a1?1:0;p Date: Wed, 28 Jun 2017 00:20:36 +0100 Subject: [PATCH 25/31] improved spring and pin rendering --- src/constraint/Constraint.js | 2 +- src/render/Render.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/constraint/Constraint.js b/src/constraint/Constraint.js index 42ab7bc..2e5d596 100644 --- a/src/constraint/Constraint.js +++ b/src/constraint/Constraint.js @@ -71,7 +71,7 @@ var Common = require('../core/Common'); anchors: true }; - if (constraint.length === 0) { + if (constraint.length === 0 && constraint.stiffness > 0.1) { render.type = 'pin'; render.anchors = false; } else if (constraint.stiffness < 0.9) { diff --git a/src/render/Render.js b/src/render/Render.js index 8070006..ab30e15 100644 --- a/src/render/Render.js +++ b/src/render/Render.js @@ -508,7 +508,7 @@ var Mouse = require('../core/Mouse'); if (constraint.render.type === 'pin') { c.beginPath(); - c.arc(start.x, start.y, 4, 0, 2 * Math.PI); + c.arc(start.x, start.y, 3, 0, 2 * Math.PI); c.closePath(); } else { if (bodyB) { @@ -526,7 +526,7 @@ var Mouse = require('../core/Mouse'); coils = Math.ceil(Common.clamp(constraint.length / 5, 12, 20)), offset; - for (var j = 0; j < coils; j += 1) { + for (var j = 1; j < coils; j += 1) { offset = j % 2 === 0 ? 1 : -1; c.lineTo( From ac67ef8e5ce5554ac4fed480069a4c3b7ae09a1b Mon Sep 17 00:00:00 2001 From: liabru Date: Wed, 28 Jun 2017 00:21:17 +0100 Subject: [PATCH 26/31] fixed various constraints in examples --- examples/chains.js | 4 ++-- examples/doublePendulum.js | 14 ++++++++------ src/factory/Composites.js | 12 +++--------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/examples/chains.js b/examples/chains.js index c019b9d..91b08b2 100644 --- a/examples/chains.js +++ b/examples/chains.js @@ -43,7 +43,7 @@ Example.chains = function() { return Bodies.rectangle(x, y, 50, 20, { collisionFilter: { group: group } }); }); - Composites.chain(ropeA, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2 }); + Composites.chain(ropeA, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2, render: { type: 'line' } }); Composite.add(ropeA, Constraint.create({ bodyB: ropeA.bodies[0], pointB: { x: -25, y: 0 }, @@ -57,7 +57,7 @@ Example.chains = function() { return Bodies.circle(x, y, 20, { collisionFilter: { group: group } }); }); - Composites.chain(ropeB, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2 }); + Composites.chain(ropeB, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2, render: { type: 'line' } }); Composite.add(ropeB, Constraint.create({ bodyB: ropeB.bodies[0], pointB: { x: -20, y: 0 }, diff --git a/examples/doublePendulum.js b/examples/doublePendulum.js index bef6958..70dec15 100644 --- a/examples/doublePendulum.js +++ b/examples/doublePendulum.js @@ -42,7 +42,7 @@ Example.doublePendulum = function() { length = 200, width = 25; - var pendulum = Composites.stack(350, 160, 2, 1, 0, 0, function(x, y) { + var pendulum = Composites.stack(350, 160, 2, 1, -20, 0, function(x, y) { return Bodies.rectangle(x, y, length, width, { collisionFilter: { group: group }, frictionAir: 0, @@ -56,24 +56,26 @@ Example.doublePendulum = function() { pendulum.bodies[0].render.strokeStyle = '#4a485b'; pendulum.bodies[1].render.strokeStyle = '#4a485b'; + + world.gravity.scale = 0.002; - Composites.chain(pendulum, 0.5, 0, -0.5, 0, { + Composites.chain(pendulum, 0.45, 0, -0.45, 0, { stiffness: 1, length: 0, angularStiffness: 0.7, render: { - lineWidth: 0 + strokeStyle: '#4a485b' } }); Composite.add(pendulum, Constraint.create({ bodyB: pendulum.bodies[0], - pointB: { x: -length * 0.5, y: 0 }, - pointA: { x: pendulum.bodies[0].position.x - length * 0.5, y: pendulum.bodies[0].position.y }, + pointB: { x: -length * 0.42, y: 0 }, + pointA: { x: pendulum.bodies[0].position.x - length * 0.42, y: pendulum.bodies[0].position.y }, stiffness: 1, length: 0, render: { - lineWidth: 0 + strokeStyle: '#4a485b' } })); diff --git a/src/factory/Composites.js b/src/factory/Composites.js index 7ef9f3f..3c9adf7 100644 --- a/src/factory/Composites.js +++ b/src/factory/Composites.js @@ -274,10 +274,7 @@ var Bodies = require('./Bodies'); pointB: { x: wheelAOffset, y: wheelYOffset }, bodyA: wheelA, stiffness: 1, - length: 0, - render: { - lineWidth: 0 - } + length: 0 }); var axelB = Constraint.create({ @@ -285,10 +282,7 @@ var Bodies = require('./Bodies'); pointB: { x: wheelBOffset, y: wheelYOffset }, bodyA: wheelB, stiffness: 1, - length: 0, - render: { - lineWidth: 0 - } + length: 0 }); Composite.addBody(car, body); @@ -317,7 +311,7 @@ var Bodies = require('./Bodies'); */ Composites.softBody = function(xx, yy, columns, rows, columnGap, rowGap, crossBrace, particleRadius, particleOptions, constraintOptions) { particleOptions = Common.extend({ inertia: Infinity }, particleOptions); - constraintOptions = Common.extend({ stiffness: 0.2 }, constraintOptions); + constraintOptions = Common.extend({ stiffness: 0.2, render: { type: 'line', anchors: false } }, constraintOptions); var softBody = Composites.stack(xx, yy, columns, rows, columnGap, rowGap, function(x, y) { return Bodies.circle(x, y, particleRadius, particleOptions); From 477f2d7716caa12a4cb98169ea3b13f5d212ac25 Mon Sep 17 00:00:00 2001 From: liabru Date: Sun, 2 Jul 2017 23:56:24 +0100 Subject: [PATCH 27/31] upgraded matter-tools --- demo/lib/matter-tools.demo.js | 33 ++++++++++++++++++++++-------- demo/lib/matter-tools.gui.js | 22 +++++++++++++------- demo/lib/matter-tools.inspector.js | 17 +++++++++------ 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/demo/lib/matter-tools.demo.js b/demo/lib/matter-tools.demo.js index 17caa6d..cde684d 100644 --- a/demo/lib/matter-tools.demo.js +++ b/demo/lib/matter-tools.demo.js @@ -1,15 +1,15 @@ /*! - * matter-tools 0.9.1 by Liam Brummitt 2017-01-26 + * matter-tools 0.11.1 by Liam Brummitt 2017-07-02 * https://github.com/liabru/matter-tools * License MIT */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("Matter"), require("MatterTools")); + module.exports = factory(require("matter-js"), require("matter-tools")); else if(typeof define === 'function' && define.amd) - define(["Matter", "MatterTools"], factory); + define(["matter-js", "matter-tools"], factory); else if(typeof exports === 'object') - exports["Demo"] = factory(require("Matter"), require("MatterTools")); + exports["Demo"] = factory(require("matter-js"), require("matter-tools")); else root["MatterTools"] = root["MatterTools"] || {}, root["MatterTools"]["Demo"] = factory(root["Matter"], root["MatterTools"]); })(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_2__) { @@ -92,6 +92,8 @@ return /******/ (function(modules) { // webpackBootstrap resetOnOrientation: false, preventZoom: false, inline: false, + startExample: true, + appendTo: document.body, toolbar: { title: null, url: null, @@ -130,10 +132,18 @@ return /******/ (function(modules) { // webpackBootstrap demo.dom = Demo._createDom(demo); Demo._bindDom(demo); - if (options.inline) { + if (demo.inline) { demo.dom.root.classList.add('matter-demo-inline'); } + if (demo.appendTo) { + demo.appendTo.appendChild(demo.dom.root); + } + + if (demo.startExample) { + Demo.start(demo, demo.startExample); + } + return demo; }; @@ -145,7 +155,7 @@ return /******/ (function(modules) { // webpackBootstrap * @param {string} [initalExampleId] example to start (defaults to first) */ Demo.start = function (demo, initalExampleId) { - initalExampleId = initalExampleId || demo.examples[0].id; + initalExampleId = typeof initalExampleId === 'string' ? initalExampleId : demo.examples[0].id; if (window.location.hash.length > 0) { initalExampleId = window.location.hash.slice(1); @@ -421,7 +431,7 @@ return /******/ (function(modules) { // webpackBootstrap var preventZoomClass = options.preventZoom && Demo._isIOS ? 'prevent-zoom-ios' : ''; - root.innerHTML = '\n
\n
\n
\n
\n

\n ' + options.toolbar.title + ' \u2197︎\n

\n
\n
\n \n
\n \n { }\n \n \n \n
\n \n \u25B2\u25CF\u25A0\n \n
\n
\n
\n
\n '; + root.innerHTML = '\n
\n
\n
\n
\n

\n \n ' + options.toolbar.title + '\n \n \n \n \n \n

\n
\n
\n \n \n \n \n \n
\n \n { }\n \n \n \n
\n \n \n \n
\n
\n
\n
\n '; var dom = { root: root.firstElementChild, @@ -501,7 +511,12 @@ return /******/ (function(modules) { // webpackBootstrap root.innerHTML = ''; var lastStyle = document.head.querySelector('style:last-of-type'); - Common.domInsertBefore(root.firstElementChild, lastStyle); + + if (lastStyle) { + Common.domInsertBefore(root.firstElementChild, lastStyle); + } else { + document.head.appendChild(root.firstElementChild); + } }; Common.injectScript = function (url, id, callback) { @@ -531,7 +546,7 @@ return /******/ (function(modules) { // webpackBootstrap /* 4 */ /***/ function(module, exports) { - module.exports = "/*\n*\tMatterTools.Demo\n*/\n\n.matter-demo {\n font-family: Helvetica, Arial, sans-serif;\n display: flex;\n background: #14151f;\n align-items: center;\n justify-content: center;\n flex-direction: column;\n height: 100vh;\n}\n\n.matter-demo canvas {\n border-radius: 8px;\n max-width: 100%;\n max-height: 100%;\n}\n\n.matter-demo.matter-demo-inline canvas {\n max-height: calc(100% - 50px);\n}\n\n@media screen and (min-width: 900px) and (min-height: 600px) {\n .matter-demo.matter-demo-inline canvas {\n max-height: calc(100% - 100px);\n }\n}\n\n.matter-is-fullscreen .matter-demo {\n width: 100%;\n}\n\n.matter-is-fullscreen .dg.ac,\n.matter-is-fullscreen .ins-container {\n display: none;\n}\n\n.matter-header-outer {\n position: fixed;\n z-index: 100;\n top: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.2);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 400ms ease;\n}\n\n.matter-header-outer:hover {\n background: rgba(0, 0, 0, 0.7);\n}\n\n.matter-demo-inline .matter-header-outer {\n position: static;\n background: transparent;\n z-index: 0;\n width: 100%;\n}\n\n.matter-header {\n width: 100%;\n padding: 10px 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.matter-demo-inline .matter-header {\n padding: 10px;\n}\n\nbody .ins-container,\nbody .dg .dg.main,\nbody .dg .dg.main.a {\n padding-top: 52px;\n}\n\n@media screen and (min-width: 500px) {\n .matter-header {\n padding: 12px 20px;\n }\n\n .matter-demo-inline .matter-header {\n padding: 10px 30px 16px 30px;\n }\n}\n\n@media screen and (min-width: 900px) and (min-height: 600px) {\n .matter-demo-inline .matter-header {\n padding: 10px 30px 36px 30px;\n }\n}\n\n.matter-header-inner {\n display: flex;\n align-items: center;\n justify-content: space-between;\n max-width: 960px;\n width: 100%;\n}\n\n.matter-header h1 {\n display: none;\n margin: 0;\n width: 18px;\n overflow: hidden;\n}\n\n.matter-header h1 a {\n color: #f2f2f5;\n font-size: 15px;\n font-weight: 400;\n font-family: Helvetica, Arial, sans-serif;\n display: block;\n text-decoration: none;\n margin: 7px 0 0 0;\n padding: 0 0 2px 0;\n border-bottom: 2px solid transparent;\n white-space: nowrap;\n float: right;\n}\n\n@media screen and (min-width: 300px) {\n .matter-header h1 {\n display: inline;\n }\n}\n\n@media screen and (min-width: 600px) {\n .matter-header h1 {\n width: auto;\n overflow: visible;\n }\n}\n\n.btn-home {\n display: none;\n}\n\n.matter-header h1 a:hover {\n border-bottom: 2px solid #F5B862;\n}\n\n.matter-link {\n font-family: Helvetica, Arial, sans-serif;\n text-decoration: none;\n line-height: 13px;\n transform: translate(0, 3px) scale(0.8);\n}\n\n@media screen and (min-width: 500px) {\n .matter-link {\n transform: none;\n }\n}\n\n.matter-link i {\n transition: transform 400ms ease;\n}\n\n.matter-link:hover i {\n transition: transform 400ms ease;\n}\n\n.matter-link:hover i:nth-child(1) {\n transform: rotate(-26deg) translate3d(-4px, -7px, 0);\n}\n\n.matter-link i:nth-child(2) {\n transform: translate3d(0, 1px, 0);\n}\n\n.matter-link:hover i:nth-child(2) {\n transition-delay: 80ms;\n transform: translate3d(3px, -5px, 0);\n}\n\n.matter-link:hover i:nth-child(3) {\n transition-delay: 180ms;\n transform: translate3d(9px, 0, 0);\n}\n\n.matter-link i:nth-child(1) {\n display: inline-block;\n color: #76F09B;\n font-size: 30px;\n}\n\n.matter-link i:nth-child(2) {\n color: #F5B862;\n font-size: 16px;\n padding: 0 2px 0 0;\n display: inline-block;\n}\n\n.matter-link i:nth-child(3) {\n display: inline-block;\n color: #F55F5F; \n font-size: 46px;\n}\n\n.matter-toolbar {\n flex-grow: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: -6px 0 0 0;\n}\n\n.matter-select {\n background: transparent;\n color: #fff;\n font-size: 14px;\n height: 30px;\n width: 100%;\n outline: none;\n padding: 0 7px;\n margin: 0 0 -6px 0;\n border: 0;\n border-bottom: 2px solid rgba(0, 0, 0, 0.1);\n border-radius: 0;\n appearance: none;\n -moz-appearance: none;\n -webkit-appearance: none;\n}\n\n.prevent-zoom-ios .matter-select {\n font-size: 16px;\n}\n\n.matter-demo-inline .matter-select {\n border-bottom: 2px solid #3a3a3a;\n}\n\n.matter-select:hover {\n border-bottom-color: #F5B862;\n}\n\n.matter-select-wrapper {\n width: 20%;\n min-width: 100px;\n max-width: 200px;\n position: relative;\n display: inline-block;\n margin: 0 6% 0 0;\n}\n\n.matter-select-wrapper:hover:after {\n color: #fff;\n}\n\n.matter-select-wrapper:after {\n content: '▾';\n display: block;\n pointer-events: none;\n color: #cecece;\n font-size: 14px;\n position: absolute;\n top: 6px;\n right: 5px;\n}\n\n.prevent-zoom-ios .matter-select-wrapper:after {\n top: 4px;\n}\n\n.matter-btn {\n font-family: Helvetica, Arial, sans-serif;\n border: 0;\n background: rgba(0,0,0,0.1);\n padding: 2px 0 0 0;\n width: 40px;\n height: 33px;\n border-radius: 2px;\n margin: 0 0 -6px 0;\n display: inline-block;\n font-size: 16px;\n line-height: 1;\n color: #c2cad4;\n text-decoration: none;\n text-align: center;\n}\n\n.matter-demo-inline .matter-btn {\n background: #0f0f13;\n}\n\n.matter-btn:focus {\n outline: 0;\n}\n\n.matter-btn:hover {\n transform: translate(0px, -1px);\n}\n\n.matter-btn:active {\n transform: translate(0px, 1px);\n}\n\n.matter-btn:hover {\n background: #212a3a;\n}\n\n.matter-btn-reset:active {\n color: #76F09B;\n}\n\n.matter-btn-tools {\n display: none;\n font-size: 15px;\n padding-right: 3px;\n}\n\n.matter-gui-active .matter-btn-tools {\n color: #F55F5F;\n}\n\n.matter-btn-inspect {\n display: none;\n}\n\n.matter-inspect-active .matter-btn-inspect {\n color: #fff036;\n}\n\n.matter-btn-source {\n display: none;\n font-size: 12px;\n text-align: center;\n line-height: 31px;\n}\n\n.matter-btn-source:active {\n color: #F5B862;\n}\n\n.matter-btn-fullscreen {\n font-size: 20px;\n}\n\n.matter-btn-source:active {\n color: #F5B862;\n}\n\n.matter-is-fullscreen .matter-btn-tools,\n.matter-is-fullscreen .matter-btn-inspect {\n display: none;\n}\n\n.matter-is-fullscreen .matter-btn-fullscreen {\n color: #76F09B;\n}\n\n.ins-container,\nbody .dg {\n display: none;\n}\n\n@media screen and (min-width: 500px) {\n .ins-container,\n body .dg,\n .matter-btn-tools,\n .matter-btn-inspect,\n .matter-btn-source {\n display: block;\n }\n}" + module.exports = "/*\n*\tMatterTools.Demo\n*/\n\n.matter-demo {\n font-family: Helvetica, Arial, sans-serif;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n background: #14151f;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n -webkit-box-orient: vertical;\n -webkit-box-direction: normal;\n -ms-flex-direction: column;\n flex-direction: column;\n height: 100vh;\n}\n\n.matter-demo canvas {\n border-radius: 8px;\n max-width: 100%;\n max-height: 100%;\n}\n\n.matter-demo.matter-demo-inline canvas {\n max-height: calc(100% - 50px);\n}\n\n@media screen and (min-width: 900px) and (min-height: 600px) {\n .matter-demo.matter-demo-inline canvas {\n max-height: calc(100% - 100px);\n }\n}\n\n.matter-is-fullscreen .matter-demo {\n width: 100%;\n}\n\n.matter-is-fullscreen .dg.ac,\n.matter-is-fullscreen .ins-container {\n display: none;\n}\n\n.matter-header-outer {\n position: fixed;\n z-index: 100;\n top: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.2);\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n -webkit-transition: background 400ms ease;\n -o-transition: background 400ms ease;\n transition: background 400ms ease;\n}\n\n.matter-header-outer:hover {\n background: rgba(0, 0, 0, 0.7);\n}\n\n.matter-demo-inline .matter-header-outer {\n position: static;\n background: transparent;\n z-index: 0;\n width: 100%;\n}\n\n.matter-header {\n width: 100%;\n padding: 7px 20px 8px 20px;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n.matter-demo-inline .matter-header {\n padding: 10px;\n}\n\nbody .ins-container,\nbody .dg .dg.main,\nbody .dg .dg.main.a {\n padding-top: 52px;\n}\n\n@media screen and (min-width: 500px) {\n .matter-demo-inline .matter-header {\n padding: 10px 30px 16px 30px;\n }\n}\n\n@media screen and (min-width: 900px) and (min-height: 600px) {\n .matter-demo-inline .matter-header {\n padding: 10px 30px 36px 30px;\n }\n}\n\n.matter-header-inner {\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n -webkit-box-pack: justify;\n -ms-flex-pack: justify;\n justify-content: space-between;\n max-width: 960px;\n width: 100%;\n}\n\n.matter-header h1 {\n display: none;\n margin: 0;\n width: 18px;\n overflow: hidden;\n}\n\n.matter-header h1 a {\n color: #f2f2f5;\n font-size: 15px;\n font-weight: 400;\n font-family: Helvetica, Arial, sans-serif;\n display: block;\n text-decoration: none;\n padding: 8px 0 3px 0;\n border-bottom: 2px solid transparent;\n white-space: nowrap;\n float: right;\n}\n\n@media screen and (min-width: 300px) {\n .matter-header h1 {\n display: inline;\n }\n}\n\n@media screen and (min-width: 600px) {\n .matter-header h1 {\n width: auto;\n overflow: visible;\n }\n}\n\n.btn-home {\n display: none;\n}\n\n.matter-demo-title svg {\n fill: #fff;\n width: 16px;\n height: 16px;\n margin: 0px 0 -2px 4px;\n}\n\n.matter-header h1 a:hover {\n border-bottom: 2px solid #F5B862;\n}\n\n.matter-link {\n font-family: Helvetica, Arial, sans-serif;\n text-decoration: none;\n line-height: 13px;\n margin: 0 -10px 0 0;\n}\n\n.matter-logo {\n height: 33px;\n width: 52px;\n}\n\n.matter-logo #m-triangle {\n -webkit-transform-origin: 14px 856px;\n -ms-transform-origin: 14px 856px;\n transform-origin: 14px 856px;\n -webkit-transition: -webkit-transform 400ms ease;\n transition: -webkit-transform 400ms ease;\n -o-transition: transform 400ms ease;\n transition: transform 400ms ease;\n transition: transform 400ms ease, -webkit-transform 400ms ease;\n}\n\n.matter-logo:hover #m-triangle {\n -webkit-transform: rotate(-30deg) translate(-98px, -25px);\n -ms-transform: rotate(-30deg) translate(-98px, -25px);\n transform: rotate(-30deg) translate(-98px, -25px);\n}\n\n.matter-logo #m-circle {\n -webkit-transition: -webkit-transform 200ms ease;\n transition: -webkit-transform 200ms ease;\n -o-transition: transform 200ms ease;\n transition: transform 200ms ease;\n transition: transform 200ms ease, -webkit-transform 200ms ease;\n -webkit-transition-delay: 300ms;\n -o-transition-delay: 300ms;\n transition-delay: 300ms;\n}\n\n.matter-logo #m-square {\n -webkit-transition: -webkit-transform 150ms ease;\n transition: -webkit-transform 150ms ease;\n -o-transition: transform 150ms ease;\n transition: transform 150ms ease;\n transition: transform 150ms ease, -webkit-transform 150ms ease;\n -webkit-transition-delay: 400ms;\n -o-transition-delay: 400ms;\n transition-delay: 400ms;\n}\n\n.matter-logo:hover #m-circle {\n -webkit-transform: translate(18px, -33px);\n -ms-transform: translate(18px, -33px);\n transform: translate(18px, -33px);\n}\n\n.matter-logo:hover #m-square {\n -webkit-transform: translate(47px, -2px);\n -ms-transform: translate(47px, -2px);\n transform: translate(47px, -2px);\n}\n\n.matter-toolbar {\n -webkit-box-flex: 1;\n -ms-flex-positive: 1;\n flex-grow: 1;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n.matter-select {\n background: transparent;\n color: #fff;\n font-size: 15px;\n height: 30px;\n width: 100%;\n outline: none;\n padding: 0 7px;\n margin: 0;\n border: 0;\n border-radius: 0;\n appearance: none;\n -moz-appearance: none;\n -webkit-appearance: none;\n}\n\n.prevent-zoom-ios .matter-select {\n font-size: 16px;\n}\n\n.matter-select-wrapper {\n width: 20%;\n min-width: 100px;\n max-width: 200px;\n position: relative;\n display: inline-block;\n margin: 1px 6% 0 0;\n}\n\n.matter-select-wrapper:hover:after svg {\n fill: #fff;\n}\n\n.matter-select-wrapper svg {\n display: block;\n pointer-events: none;\n fill: #cecece;\n width: 22px;\n height: 22px;\n position: absolute;\n top: 4px;\n right: 5px;\n}\n\n.prevent-zoom-ios .matter-select-wrapper:after {\n top: 4px;\n}\n\n.matter-btn {\n font-family: Helvetica, Arial, sans-serif;\n border: 0;\n background: rgba(0,0,0,0.1);\n padding: 2px 0 0 0;\n width: 40px;\n height: 33px;\n border-radius: 2px;\n display: inline-block;\n font-size: 16px;\n line-height: 1;\n color: #c2cad4;\n text-decoration: none;\n text-align: center;\n}\n\n.matter-btn svg {\n fill: #fff;\n width: 16px;\n height: 16px;\n margin: 2px 0 0 0;\n}\n\n.matter-demo-inline .matter-btn {\n background: #0f0f13;\n}\n\n.matter-btn:focus {\n outline: 0;\n}\n\n.matter-btn:hover {\n -webkit-transform: translate(0px, -1px);\n -ms-transform: translate(0px, -1px);\n transform: translate(0px, -1px);\n}\n\n.matter-btn:active {\n -webkit-transform: translate(0px, 1px);\n -ms-transform: translate(0px, 1px);\n transform: translate(0px, 1px);\n}\n\n.matter-btn:hover {\n background: #212a3a;\n}\n\n.matter-btn-reset:active svg {\n fill: #76F09B;\n}\n\n.matter-btn-tools {\n display: none;\n font-size: 15px;\n padding-right: 3px;\n}\n\n.matter-gui-active .matter-btn-tools svg {\n fill: #F55F5F;\n}\n\n.matter-btn-inspect {\n display: none;\n}\n\n.matter-inspect-active .matter-btn-inspect svg {\n fill: #fff036;\n}\n\n.matter-btn-source {\n display: none;\n font-size: 12px;\n text-align: center;\n line-height: 31px;\n}\n\n.matter-btn-source:active {\n color: #F5B862;\n}\n\n.matter-btn-fullscreen {\n font-size: 18px;\n}\n\n.matter-btn-source:active svg {\n fill: #F5B862;\n}\n\n.matter-is-fullscreen .matter-btn-tools,\n.matter-is-fullscreen .matter-btn-inspect {\n display: none;\n}\n\n.matter-is-fullscreen .matter-btn-fullscreen svg {\n fill: #76F09B;\n}\n\n.ins-container,\nbody .dg {\n display: none;\n}\n\n@media screen and (min-width: 500px) {\n .ins-container,\n body .dg,\n .matter-btn-tools,\n .matter-btn-inspect,\n .matter-btn-source {\n display: block;\n }\n}" /***/ } /******/ ]) diff --git a/demo/lib/matter-tools.gui.js b/demo/lib/matter-tools.gui.js index 4d90a20..ada592a 100644 --- a/demo/lib/matter-tools.gui.js +++ b/demo/lib/matter-tools.gui.js @@ -1,15 +1,15 @@ /*! - * matter-tools 0.9.1 by Liam Brummitt 2017-01-26 + * matter-tools 0.11.1 by Liam Brummitt 2017-07-02 * https://github.com/liabru/matter-tools * License MIT */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("Matter"), require("MatterTools")); + module.exports = factory(require("matter-js"), require("matter-tools")); else if(typeof define === 'function' && define.amd) - define(["Matter", "MatterTools"], factory); + define(["matter-js", "matter-tools"], factory); else if(typeof exports === 'object') - exports["Gui"] = factory(require("Matter"), require("MatterTools")); + exports["Gui"] = factory(require("matter-js"), require("matter-tools")); else root["MatterTools"] = root["MatterTools"] || {}, root["MatterTools"]["Gui"] = factory(root["Matter"], root["MatterTools"]); })(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_2__) { @@ -92,7 +92,7 @@ return /******/ (function(modules) { // webpackBootstrap dat.GUI.TEXT_CLOSED = '▲'; dat.GUI.TEXT_OPEN = '▼'; - var datGui = new dat.GUI(); + var datGui = new dat.GUI({ autoPlace: false }); var gui = { engine: engine, @@ -170,6 +170,7 @@ return /******/ (function(modules) { // webpackBootstrap * @param {gui} gui */ Gui.destroy = function (gui) { + gui.datGui.domElement.parentElement.removeChild(gui.datGui.domElement); gui.datGui.destroy(); }; @@ -291,6 +292,8 @@ return /******/ (function(modules) { // webpackBootstrap render.add(gui.render.options, 'enabled'); render.open(); } + + document.body.appendChild(gui.datGui.domElement); }; var _addBody = function _addBody(gui) { @@ -416,7 +419,12 @@ return /******/ (function(modules) { // webpackBootstrap root.innerHTML = ''; var lastStyle = document.head.querySelector('style:last-of-type'); - Common.domInsertBefore(root.firstElementChild, lastStyle); + + if (lastStyle) { + Common.domInsertBefore(root.firstElementChild, lastStyle); + } else { + document.head.appendChild(root.firstElementChild); + } }; Common.injectScript = function (url, id, callback) { @@ -454,7 +462,7 @@ return /******/ (function(modules) { // webpackBootstrap /* 6 */ /***/ function(module, exports) { - module.exports = "/*\n*\tMatterTools.Gui\n*/\n\nbody .dg .c,\nbody .dg .cr.function,\nbody .dg .c select,\nbody .dg .property-name,\nbody .dg .title {\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -khtml-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\nbody .dg.main {\n z-index: 10;\n box-shadow: 0 0 30px rgba(0,0,0,0.2);\n height: 100%;\n background: rgb(28, 29, 47);\n position: fixed;\n top: 0;\n right: 0;\n}\n\nbody .dg.ac {\n position: static;\n top: inherit;\n left: inherit;\n bottom: inherit;\n right: inherit;\n}\n\n@media only screen and (max-width : 1500px) {\n body .dg.main {\n transform: translate(230px, 0);\n }\n\n body .dg.main:hover {\n transform: translate(0, 0);\n }\n\n body .dg.main {\n -webkit-transition: transform 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -moz-transition: transform 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -o-transition: transform 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n transition: transform 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415);\n\n -webkit-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -moz-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -o-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); \n transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415);\n \n transition-delay: 2s;\n -webkit-transition-delay: 2s;\n }\n\n body .dg.main:hover {\n -webkit-transition: transform 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -moz-transition: transform 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -o-transition: transform 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n transition: transform 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835);\n\n -webkit-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -moz-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -o-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); \n transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835);\n\n transition-delay: 0;\n -webkit-transition-delay: 0;\n }\n}\n\nbody .dg.main .close-button {\n display: none;\n}\n\nbody .dg.main::-webkit-scrollbar {\n background: #1c1c25;\n width: 12px;\n}\n\nbody .dg.main::-webkit-scrollbar-thumb {\n background: transparent;\n width: 5px;\n border-left: 5px solid transparent;\n border-right: 6px solid #2a2a31;\n border-radius: 0;\n}\n \nbody .dg {\n color: #9196ad;\n text-shadow: none !important;\n}\n\nbody .dg li:not(.folder) {\n height: 28px;\n background: #1c1c25;\n border-bottom: 0px;\n padding: 0 0 0 12px;\n}\n \nbody .dg li.save-row .button {\n text-shadow: none !important;\n}\n\nbody .dg li.title {\n padding-left: 22px;\n color: #6f7388;\n border-bottom: 1px solid #29292d;\n background: #0d0f1b url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 10px 10px no-repeat;\n}\n\nbody .dg .cr.boolean:hover {\n background: #232431;\n}\n\nbody .dg .cr.function {\n background: #262731;\n color: #6d7082;\n border-bottom: 1px solid #222535;\n border-top: 1px solid #3c3e48;\n}\n\nbody .dg .cr.function:hover {\n background: #30313e;\n}\n\nbody .dg .cr.function:active {\n transform: translateY(1px);\n}\n\nbody .dg .c,\nbody .dg .property-name {\n width: 50%;\n}\n\nbody .dg .c select {\n margin-top: 2px;\n margin-left: -5px;\n padding: 3px 5px;\n}\n\nbody .dg .c select,\nbody .dg .c input[type=text],\nbody .dg .cr.number input[type=text] {\n text-align: right;\n background: #191a23;\n color: #686c7b;\n border: 0;\n font-size: 10px;\n}\n\nbody .dg .cr.number,\nbody .dg .cr.boolean,\nbody .dg .cr.function {\n border-left: 0;\n}\n\nbody .dg .c select,\nbody .dg .c select:focus {\n width: 88px;\n outline: 0;\n}\n \nbody .dg .c input[type=text]:hover {\n background: #1c1d2f;\n}\n \nbody .dg .c input[type=text]:focus {\n background: #1c1d2f;\n color: #fff;\n}\n\nbody .dg .c input[type=checkbox] {\n margin-top: 9px;\n border: none;\n border-radius: 3px;\n appearance: none;\n -webkit-appearance: none;\n -moz-appearance: none;\n background: #35363e;\n display: block;\n width: 10px;\n height: 10px;\n float: right;\n}\n\nbody .dg .c input[type=checkbox]:checked {\n background: #5b5e6b;\n}\n\nbody .dg .c input[type=checkbox]:focus {\n outline: none;\n}\n \nbody .dg .c .slider {\n background: #252731;\n border-radius: 0;\n box-shadow: none;\n padding: 0;\n}\n\nbody .dg .c .slider:hover {\n background: #282b3a;\n}\n\nbody .dg .c .slider-fg {\n background: #32364a;\n border-radius: 0;\n margin-left: 0;\n padding-right: 0;\n}\n\nbody .dg .c .slider-fg:after {\n display: none;\n}\n\nbody .dg .c .slider:hover .slider-fg {\n background: #4d526b;\n}\n\nbody .dg li.folder {\n border-left: 0;\n}\n\nbody .dg.a {\n margin-right: 0;\n}" + module.exports = "/*\n*\tMatterTools.Gui\n*/\n\nbody .dg .c,\nbody .dg .cr.function,\nbody .dg .c select,\nbody .dg .property-name,\nbody .dg .title {\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\nbody .dg.main {\n z-index: 10;\n -webkit-box-shadow: 0 0 30px rgba(0,0,0,0.2);\n box-shadow: 0 0 30px rgba(0,0,0,0.2);\n height: 100%;\n background: rgb(28, 29, 47);\n position: fixed;\n overflow-y: scroll;\n top: 0;\n right: 0;\n padding: 50px 0 0 0;\n}\n\nbody .dg.ac {\n position: static;\n top: inherit;\n left: inherit;\n bottom: inherit;\n right: inherit;\n}\n\n@media only screen and (max-width : 1500px) {\n body .dg.main {\n -webkit-transform: translate(230px, 0);\n -ms-transform: translate(230px, 0);\n transform: translate(230px, 0);\n }\n\n body .dg.main:hover {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n transform: translate(0, 0);\n }\n\n body .dg.main {\n -webkit-transition: transform 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -o-transition: transform 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -webkit-transition: -webkit-transform 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n transition: -webkit-transform 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n transition: transform 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n transition: transform 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415), -webkit-transform 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415);\n\n -webkit-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -o-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); \n transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415);\n \n -o-transition-delay: 2s;\n \n transition-delay: 2s;\n -webkit-transition-delay: 2s;\n }\n\n body .dg.main:hover {\n -webkit-transition: transform 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -o-transition: transform 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -webkit-transition: -webkit-transform 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n transition: -webkit-transform 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n transition: transform 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n transition: transform 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835), -webkit-transform 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835);\n\n -webkit-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -o-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); \n transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835);\n\n -o-transition-delay: 0;\n\n transition-delay: 0;\n -webkit-transition-delay: 0;\n }\n}\n\nbody .dg.main .close-button {\n display: none;\n}\n\nbody .dg.main::-webkit-scrollbar {\n background: #1c1c25;\n width: 12px;\n}\n\nbody .dg.main::-webkit-scrollbar-thumb {\n background: transparent;\n width: 5px;\n border-left: 5px solid transparent;\n border-right: 6px solid #2a2a31;\n border-radius: 0;\n}\n \nbody .dg {\n color: #9196ad;\n text-shadow: none !important;\n}\n\nbody .dg li:not(.folder) {\n height: 28px;\n background: #1c1c25;\n border-bottom: 0px;\n padding: 0 0 0 12px;\n}\n \nbody .dg li.save-row .button {\n text-shadow: none !important;\n}\n\nbody .dg li.title {\n padding-left: 22px;\n color: #6f7388;\n border-bottom: 1px solid #29292d;\n background: #0d0f1b url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 10px 10px no-repeat;\n}\n\nbody .dg .cr.boolean:hover {\n background: #232431;\n}\n\nbody .dg .cr.function {\n background: #262731;\n color: #6d7082;\n border-bottom: 1px solid #222535;\n border-top: 1px solid #3c3e48;\n}\n\nbody .dg .cr.function:hover {\n background: #30313e;\n}\n\nbody .dg .cr.function:active {\n -webkit-transform: translateY(1px);\n -ms-transform: translateY(1px);\n transform: translateY(1px);\n}\n\nbody .dg .c,\nbody .dg .property-name {\n width: 50%;\n}\n\nbody .dg .c select {\n margin-top: 2px;\n margin-left: -5px;\n padding: 3px 5px;\n}\n\nbody .dg .c select,\nbody .dg .c input[type=text],\nbody .dg .cr.number input[type=text] {\n text-align: right;\n background: #191a23;\n color: #686c7b;\n border: 0;\n font-size: 10px;\n}\n\nbody .dg .cr.number,\nbody .dg .cr.boolean,\nbody .dg .cr.function {\n border-left: 0;\n}\n\nbody .dg .c select,\nbody .dg .c select:focus {\n width: 88px;\n outline: 0;\n}\n \nbody .dg .c input[type=text]:hover {\n background: #1c1d2f;\n}\n \nbody .dg .c input[type=text]:focus {\n background: #1c1d2f;\n color: #fff;\n}\n\nbody .dg .c input[type=checkbox] {\n margin-top: 9px;\n border: none;\n border-radius: 3px;\n appearance: none;\n -webkit-appearance: none;\n -moz-appearance: none;\n background: #35363e;\n display: block;\n width: 10px;\n height: 10px;\n float: right;\n}\n\nbody .dg .c input[type=checkbox]:checked {\n background: #5b5e6b;\n}\n\nbody .dg .c input[type=checkbox]:focus {\n outline: none;\n}\n \nbody .dg .c .slider {\n background: #252731;\n border-radius: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n padding: 0;\n}\n\nbody .dg .c .slider:hover {\n background: #282b3a;\n}\n\nbody .dg .c .slider-fg {\n background: #32364a;\n border-radius: 0;\n margin-left: 0;\n padding-right: 0;\n}\n\nbody .dg .c .slider-fg:after {\n display: none;\n}\n\nbody .dg .c .slider:hover .slider-fg {\n background: #4d526b;\n}\n\nbody .dg li.folder {\n border-left: 0;\n}\n\nbody .dg.a {\n margin-right: 0;\n}" /***/ } /******/ ]) diff --git a/demo/lib/matter-tools.inspector.js b/demo/lib/matter-tools.inspector.js index f987d95..8bad1d2 100644 --- a/demo/lib/matter-tools.inspector.js +++ b/demo/lib/matter-tools.inspector.js @@ -1,15 +1,15 @@ /*! - * matter-tools 0.9.1 by Liam Brummitt 2017-01-26 + * matter-tools 0.11.1 by Liam Brummitt 2017-07-02 * https://github.com/liabru/matter-tools * License MIT */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("Matter"), require("MatterTools"), require("jQuery")); + module.exports = factory(require("matter-js"), require("matter-tools"), require("jquery")); else if(typeof define === 'function' && define.amd) - define(["Matter", "MatterTools", "jQuery"], factory); + define(["matter-js", "matter-tools", "jquery"], factory); else if(typeof exports === 'object') - exports["Inspector"] = factory(require("Matter"), require("MatterTools"), require("jQuery")); + exports["Inspector"] = factory(require("matter-js"), require("matter-tools"), require("jquery")); else root["MatterTools"] = root["MatterTools"] || {}, root["MatterTools"]["Inspector"] = factory(root["Matter"], root["MatterTools"], root["jQuery"]); })(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_2__, __WEBPACK_EXTERNAL_MODULE_7__) { @@ -1275,7 +1275,12 @@ return /******/ (function(modules) { // webpackBootstrap root.innerHTML = ''; var lastStyle = document.head.querySelector('style:last-of-type'); - Common.domInsertBefore(root.firstElementChild, lastStyle); + + if (lastStyle) { + Common.domInsertBefore(root.firstElementChild, lastStyle); + } else { + document.head.appendChild(root.firstElementChild); + } }; Common.injectScript = function (url, id, callback) { @@ -1633,7 +1638,7 @@ return /******/ (function(modules) { // webpackBootstrap /* 11 */ /***/ function(module, exports) { - module.exports = "/*\n*\tMatterTools.Inspector\n*/\n\n.ins-container,\n.jstree {\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -khtml-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\n.ins-cursor-move canvas {\n cursor: move !important;\n}\n\n.ins-cursor-rotate canvas {\n cursor: ew-resize !important;\n}\n\n.ins-cursor-scale canvas {\n cursor: nwse-resize !important;\n}\n\n.ins-container {\n position: fixed;\n overflow: auto;\n overflow-x: hidden;\n z-index: 10;\n width: 245px;\n bottom: 0;\n top: 0;\n left: 0;\n background: #1c1c25;\n padding: 0;\n font-family: Arial;\n font-size: 12px;\n color: #aaa;\n box-shadow: 0 0 30px rgba(0,0,0,0.2);\n}\n\nbody .ins-container::-webkit-scrollbar {\n background: #1c1c25;\n width: 12px;\n}\n\nbody .ins-container::-webkit-scrollbar-thumb {\n background: transparent;\n width: 5px;\n border-left: 5px solid transparent;\n border-right: 6px solid #2a2a31;\n border-radius: 0;\n}\n\n@media only screen and (max-width : 1500px) {\n .ins-container {\n transform: translate(-230px, 0);\n }\n\n .ins-container:hover {\n transform: none;\n }\n\n .ins-container {\n -webkit-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -moz-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -o-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415);\n\n -webkit-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -moz-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -o-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); \n transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415);\n\n transition-delay: 3s;\n -webkit-transition-delay: 3s;\n }\n\n .ins-container:hover {\n -webkit-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -moz-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -o-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835);\n\n -webkit-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -moz-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -o-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); \n transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835);\n\n transition-delay: 0;\n -webkit-transition-delay: 0;\n }\n}\n\n.ins-add-button.ins-button {\n width: auto;\n height: auto;\n padding: 2px 5px;\n margin: 4px 0 0 0;\n right: 0px;\n min-width: 0;\n position: absolute;\n z-index: 100;\n}\n\n.ins-search-box {\n margin: 20px 0px 16px 13px;\n border: 0;\n padding: 7px 8px;\n font-size: 12px;\n width: 100%;\n box-sizing: border-box;\n border-radius: 3px;\n background: #111117;\n color: #919691;\n appearance: none;\n -webkit-appearance: none;\n -moz-appearance: none;\n}\n\n.ins-search-box:focus {\n background: #15151d;\n border: 0;\n outline: 0;\n}\n\n.ins-search-box::-webkit-search-cancel-button {\n appearance: none;\n -webkit-appearance: none;\n -moz-appearance: none;\n height: 15px;\n width: 8px;\n cursor: pointer;\n}\n\n.ins-search-box::-webkit-search-cancel-button:before {\n height: 10px;\n width: 10px;\n content: 'x';\n font-family: Arial;\n line-height: 0;\n font-size: 13px;\n color: #999;\n font-weight: bold;\n cursor: pointer;\n}\n\n.ins-search-box::-webkit-input-placeholder {\n color: #777;\n}\n\n.ins-search-box:-moz-placeholder {\n color: #777;\n}\n\n.ins-search-box::-moz-placeholder {\n color: #777;\n}\n\n.ins-search-box:-ms-input-placeholder { \n color: #777;\n}\n\n.ins-world-tree {\n\n}\n\n.ins-control-group {\n display: block;\n clear: both;\n overflow: hidden;\n padding: 14px 20px 12px 20px;\n background: #0d0f1b;\n border-bottom: 1px solid #29292d;\n}\n\n.ins-button {\n display: block;\n float: left;\n font-size: 11px;\n line-height: 1;\n padding: 10px 11px;\n min-width: 49px;\n text-align: center;\n background: #0d0f1b;\n border: 0;\n color: #aaa;\n border-radius: 2px;\n box-sizing: border-box;\n outline: none;\n margin: 0;\n}\n\n.ins-button:hover {\n background: #212a3a;\n}\n\n.ins-button:active {\n transform: translateY(2px);\n background: #212a3a;\n}\n\n.ins-button::-moz-focus-inner {\n padding: 0;\n border: 0;\n}\n\n.jstree-default .jstree-search {\n font-style: italic;\n color: #aaa;\n font-weight: normal;\n}\n\n.jstree-default .jstree-wholerow-hovered,\n.jstree-default .jstree-hovered {\n background: transparent;\n border-radius: 0;\n box-shadow: none;\n}\n\n.jstree-default .jstree-wholerow {\n height: 26px;\n}\n\n.jstree-default .jstree-wholerow-clicked,\n.jstree-default .jstree-clicked {\n background: transparent;\n border-radius: 0;\n box-shadow: none;\n transition: none;\n}\n\n.jstree-default .jstree-leaf .jstree-clicked {\n color: #bbb !important;\n\n -webkit-transition: color 100ms linear; \n -moz-transition: color 100ms linear; \n -o-transition: color 100ms linear; \n transition: color 100ms linear; \n}\n\n.jstree-default .jstree-anchor {\n line-height: 27px;\n}\n\n.jstree-default .jstree-container-ul> .jstree-node > .jstree-anchor:before,\n.jstree-default .jstree-open > .jstree-children > .jstree-node > .jstree-anchor:before {\n content: '';\n display: block;\n position: absolute;\n left: 0;\n right: 1px;\n height: 26px;\n background: transparent;\n border-radius: 0;\n box-shadow: none;\n border-right: none;\n pointer-events: none;\n background: rgba(0,0,0,0);\n\n -webkit-transition: background 100ms linear; \n -moz-transition: background 100ms linear; \n -o-transition: background 100ms linear; \n transition: background 100ms linear; \n}\n\n.jstree-default .jstree-anchor.jstree-clicked:before {\n background: rgba(58, 63, 88, 0.35) !important;\n\n -webkit-transition: background 100ms linear; \n -moz-transition: background 100ms linear; \n -o-transition: background 100ms linear; \n transition: background 100ms linear; \n\n pointer-events: none;\n}\n\n.jstree-default .jstree-node,\n.jstree-default .jstree-leaf .jstree-ocl,\n.jstree-default .jstree-icon {\n background: transparent;\n}\n\n.jstree-default .jstree-node {\n margin-left: 10px;\n}\n\n.jstree-default .jstree-icon {\n position: relative;\n}\n\n.jstree-default .jstree-icon:before {\n display: block;\n pointer-events: none;\n color: #d6d6d6;\n font-style: normal;\n font-size: 11px;\n position: absolute;\n top: 0px;\n left: 10px;\n}\n\n.jstree-default .jstree-open > .jstree-icon:before {\n content: '▾';\n transform: rotate(180deg);\n top: 2px;\n}\n\n.jstree-default .jstree-closed > .jstree-icon:before {\n content: '▾';\n}\n\n.jstree-leaf .jstree-icon:before {\n display: none;\n}\n\n.jstree-default .jstree-open .jstree-ocl {\n background-position: -38px -1px;\n}\n\n.jstree-default .jstree-closed .jstree-ocl {\n background-position: -4px -2px;\n}\n\n.jstree-anchor {\n padding: 1px 0;\n transition: none;\n}\n\n.jstree-anchor .jstree-icon {\n display: none;\n}\n\n.jstree-node-type-bodies > .jstree-anchor,\n.jstree-node-type-constraints > .jstree-anchor,\n.jstree-node-type-composites > .jstree-anchor {\n color: #888;\n}\n\n.ins-container *::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n}\n\n.ins-container *::-webkit-scrollbar-thumb:vertical {\n border-left: 3px solid #1c1c25;\n background: #1c1d2f;\n width: 10px;\n}\n\n.ins-container *::-webkit-scrollbar-thumb:horizontal {\n border-top: 3px solid #1c1c25;\n background: #1c1d2f;\n height: 10px;\n}\n\n.ins-container *::-webkit-scrollbar-track,\n.ins-container *::-webkit-scrollbar-corner {\n background: transparent;\n}\n\n#vakata-dnd {\n font-family: Arial;\n font-size: 12px;\n color: #aaa;\n}" + module.exports = "/*\n*\tMatterTools.Inspector\n*/\n\n.ins-container,\n.jstree {\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\n.ins-cursor-move canvas {\n cursor: move !important;\n}\n\n.ins-cursor-rotate canvas {\n cursor: ew-resize !important;\n}\n\n.ins-cursor-scale canvas {\n cursor: nwse-resize !important;\n}\n\n.ins-container {\n position: fixed;\n overflow: auto;\n overflow-x: hidden;\n z-index: 10;\n width: 245px;\n bottom: 0;\n top: 0;\n left: 0;\n background: #1c1c25;\n padding: 0;\n font-family: Arial;\n font-size: 12px;\n color: #aaa;\n -webkit-box-shadow: 0 0 30px rgba(0,0,0,0.2);\n box-shadow: 0 0 30px rgba(0,0,0,0.2);\n}\n\nbody .ins-container::-webkit-scrollbar {\n background: #1c1c25;\n width: 12px;\n}\n\nbody .ins-container::-webkit-scrollbar-thumb {\n background: transparent;\n width: 5px;\n border-left: 5px solid transparent;\n border-right: 6px solid #2a2a31;\n border-radius: 0;\n}\n\n@media only screen and (max-width : 1500px) {\n .ins-container {\n -webkit-transform: translate(-230px, 0);\n -ms-transform: translate(-230px, 0);\n transform: translate(-230px, 0);\n }\n\n .ins-container:hover {\n -webkit-transform: none;\n -ms-transform: none;\n transform: none;\n }\n\n .ins-container {\n -webkit-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -o-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); \n transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415);\n\n -webkit-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); \n -o-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); \n transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415);\n\n -o-transition-delay: 3s;\n\n transition-delay: 3s;\n -webkit-transition-delay: 3s;\n }\n\n .ins-container:hover {\n -webkit-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -o-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); \n transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835);\n\n -webkit-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); \n -o-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); \n transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835);\n\n -o-transition-delay: 0;\n\n transition-delay: 0;\n -webkit-transition-delay: 0;\n }\n}\n\n.ins-add-button.ins-button {\n width: auto;\n height: auto;\n padding: 2px 5px;\n margin: 4px 0 0 0;\n right: 0px;\n min-width: 0;\n position: absolute;\n z-index: 100;\n}\n\n.ins-search-box {\n margin: 20px 0px 16px 13px;\n border: 0;\n padding: 7px 8px;\n font-size: 12px;\n width: 100%;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n border-radius: 3px;\n background: #111117;\n color: #919691;\n appearance: none;\n -webkit-appearance: none;\n -moz-appearance: none;\n}\n\n.ins-search-box:focus {\n background: #15151d;\n border: 0;\n outline: 0;\n}\n\n.ins-search-box::-webkit-search-cancel-button {\n appearance: none;\n -webkit-appearance: none;\n -moz-appearance: none;\n height: 15px;\n width: 8px;\n cursor: pointer;\n}\n\n.ins-search-box::-webkit-search-cancel-button:before {\n height: 10px;\n width: 10px;\n content: 'x';\n font-family: Arial;\n line-height: 0;\n font-size: 13px;\n color: #999;\n font-weight: bold;\n cursor: pointer;\n}\n\n.ins-search-box::-webkit-input-placeholder {\n color: #777;\n}\n\n.ins-search-box:-moz-placeholder {\n color: #777;\n}\n\n.ins-search-box::-moz-placeholder {\n color: #777;\n}\n\n.ins-search-box:-ms-input-placeholder { \n color: #777;\n}\n\n.ins-world-tree {\n\n}\n\n.ins-control-group {\n display: block;\n clear: both;\n overflow: hidden;\n padding: 14px 20px 12px 20px;\n background: #0d0f1b;\n border-bottom: 1px solid #29292d;\n}\n\n.ins-button {\n display: block;\n float: left;\n font-size: 11px;\n line-height: 1;\n padding: 10px 11px;\n min-width: 49px;\n text-align: center;\n background: #0d0f1b;\n border: 0;\n color: #aaa;\n border-radius: 2px;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n outline: none;\n margin: 0;\n}\n\n.ins-button:hover {\n background: #212a3a;\n}\n\n.ins-button:active {\n -webkit-transform: translateY(2px);\n -ms-transform: translateY(2px);\n transform: translateY(2px);\n background: #212a3a;\n}\n\n.ins-button::-moz-focus-inner {\n padding: 0;\n border: 0;\n}\n\n.jstree-default .jstree-search {\n font-style: italic;\n color: #aaa;\n font-weight: normal;\n}\n\n.jstree-default .jstree-wholerow-hovered,\n.jstree-default .jstree-hovered {\n background: transparent;\n border-radius: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n\n.jstree-default .jstree-wholerow {\n height: 26px;\n}\n\n.jstree-default .jstree-wholerow-clicked,\n.jstree-default .jstree-clicked {\n background: transparent;\n border-radius: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n -webkit-transition: none;\n -o-transition: none;\n transition: none;\n}\n\n.jstree-default .jstree-leaf .jstree-clicked {\n color: #bbb !important;\n\n -webkit-transition: color 100ms linear; \n -o-transition: color 100ms linear; \n transition: color 100ms linear; \n}\n\n.jstree-default .jstree-anchor {\n line-height: 27px;\n}\n\n.jstree-default .jstree-container-ul> .jstree-node > .jstree-anchor:before,\n.jstree-default .jstree-open > .jstree-children > .jstree-node > .jstree-anchor:before {\n content: '';\n display: block;\n position: absolute;\n left: 0;\n right: 1px;\n height: 26px;\n background: transparent;\n border-radius: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n border-right: none;\n pointer-events: none;\n background: rgba(0,0,0,0);\n\n -webkit-transition: background 100ms linear; \n -o-transition: background 100ms linear; \n transition: background 100ms linear; \n}\n\n.jstree-default .jstree-anchor.jstree-clicked:before {\n background: rgba(58, 63, 88, 0.35) !important;\n\n -webkit-transition: background 100ms linear; \n -o-transition: background 100ms linear; \n transition: background 100ms linear; \n\n pointer-events: none;\n}\n\n.jstree-default .jstree-node,\n.jstree-default .jstree-leaf .jstree-ocl,\n.jstree-default .jstree-icon {\n background: transparent;\n}\n\n.jstree-default .jstree-node {\n margin-left: 10px;\n}\n\n.jstree-default .jstree-icon {\n position: relative;\n}\n\n.jstree-default .jstree-icon:before {\n display: block;\n pointer-events: none;\n color: #d6d6d6;\n font-style: normal;\n font-size: 11px;\n position: absolute;\n top: 0px;\n left: 10px;\n}\n\n.jstree-default .jstree-open > .jstree-icon:before {\n content: '▾';\n -webkit-transform: rotate(180deg);\n -ms-transform: rotate(180deg);\n transform: rotate(180deg);\n top: 2px;\n}\n\n.jstree-default .jstree-closed > .jstree-icon:before {\n content: '▾';\n}\n\n.jstree-leaf .jstree-icon:before {\n display: none;\n}\n\n.jstree-default .jstree-open .jstree-ocl {\n background-position: -38px -1px;\n}\n\n.jstree-default .jstree-closed .jstree-ocl {\n background-position: -4px -2px;\n}\n\n.jstree-anchor {\n padding: 1px 0;\n -webkit-transition: none;\n -o-transition: none;\n transition: none;\n}\n\n.jstree-anchor .jstree-icon {\n display: none;\n}\n\n.jstree-node-type-bodies > .jstree-anchor,\n.jstree-node-type-constraints > .jstree-anchor,\n.jstree-node-type-composites > .jstree-anchor {\n color: #888;\n}\n\n.ins-container *::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n}\n\n.ins-container *::-webkit-scrollbar-thumb:vertical {\n border-left: 3px solid #1c1c25;\n background: #1c1d2f;\n width: 10px;\n}\n\n.ins-container *::-webkit-scrollbar-thumb:horizontal {\n border-top: 3px solid #1c1c25;\n background: #1c1d2f;\n height: 10px;\n}\n\n.ins-container *::-webkit-scrollbar-track,\n.ins-container *::-webkit-scrollbar-corner {\n background: transparent;\n}\n\n#vakata-dnd {\n font-family: Arial;\n font-size: 12px;\n color: #aaa;\n}" /***/ } /******/ ]) From 48611c51def49869b2c496eec1c0632fd5bba59f Mon Sep 17 00:00:00 2001 From: liabru Date: Thu, 6 Jul 2017 21:49:42 +0100 Subject: [PATCH 28/31] added Examples.ragdoll --- demo/index.html | 1 + demo/js/Demo.js | 6 + examples/ragdoll.js | 498 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 505 insertions(+) create mode 100644 examples/ragdoll.js diff --git a/demo/index.html b/demo/index.html index dd2eb04..95f4b7b 100644 --- a/demo/index.html +++ b/demo/index.html @@ -53,6 +53,7 @@ + diff --git a/demo/js/Demo.js b/demo/js/Demo.js index a0dea63..4ff0a57 100644 --- a/demo/js/Demo.js +++ b/demo/js/Demo.js @@ -172,6 +172,12 @@ init: Example.newtonsCradle, sourceLink: sourceLinkRoot + '/newtonsCradle.js' }, + { + name: 'Ragdoll', + id: 'ragdoll', + init: Example.ragdoll, + sourceLink: sourceLinkRoot + '/ragdoll.js' + }, { name: 'Pyramid', id: 'pyramid', diff --git a/examples/ragdoll.js b/examples/ragdoll.js new file mode 100644 index 0000000..8b66c34 --- /dev/null +++ b/examples/ragdoll.js @@ -0,0 +1,498 @@ +var Example = Example || {}; + +Example.ragdoll = function() { + var Engine = Matter.Engine, + Events = Matter.Events, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Common = Matter.Common, + Composite = Matter.Composite, + Composites = Matter.Composites, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies, + Vector = Matter.Vector; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.documentElement.clientWidth, 800), + height: Math.min(document.documentElement.clientHeight, 600), + showAngleIndicator: true, + background: '#0f0f13' + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // create stairs + var stairCount = (render.bounds.max.y - render.bounds.min.y) / 50; + + var stack = Composites.stack(0, 0, stairCount + 2, 1, 0, 0, function(x, y, column) { + return Bodies.rectangle(x - 50, y + column * 50, 100, 1000, { + isStatic: true, + render: { + fillStyle: '#222' + } + }); + }); + + // create obstacles + var obstacles = Composites.stack(300, 0, 15, 3, 10, 10, function(x, y, column) { + var sides = Math.round(Common.random(1, 8)), + options = { + render: { + fillStyle: Common.choose(['#006BA6', '#0496FF', '#D81159', '#8F2D56']) + } + }; + + switch (Math.round(Common.random(0, 1))) { + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(25, 50), Common.random(25, 50), options); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(25, 30), options); + } + case 1: + return Bodies.polygon(x, y, sides, Common.random(25, 50), options); + } + }); + + var ragdolls = Composite.create(); + + for (var i = 0; i < 1; i += 1) { + var ragdoll = Example.ragdoll.ragdoll(200, -1000 * i, 1.3); + + Composite.add(ragdolls, ragdoll); + } + + World.add(world, [stack, obstacles, ragdolls]); + + var timeScaleTarget = 1, + counter = 0; + + Events.on(engine, 'afterUpdate', function(event) { + // tween the timescale for slow-mo + if (mouse.button === -1) { + engine.timing.timeScale += (timeScaleTarget - engine.timing.timeScale) * 0.05; + } else { + engine.timing.timeScale = 1; + } + + counter += 1; + + // every 1.5 sec + if (counter >= 60 * 1.5) { + + // flip the timescale + if (timeScaleTarget < 1) { + timeScaleTarget = 1; + } else { + timeScaleTarget = 0.05; + } + + // reset counter + counter = 0; + } + + for (var i = 0; i < stack.bodies.length; i += 1) { + var body = stack.bodies[i]; + + // animate stairs + Body.translate(body, { + x: -0.5 * engine.timing.timeScale, + y: -0.5 * engine.timing.timeScale + }); + + // loop stairs when they go off screen + if (body.position.x < -50) { + Body.setPosition(body, { + x: 50 * (stack.bodies.length - 1), + y: 25 + render.bounds.max.y + (body.bounds.max.y - body.bounds.min.y) * 0.5 + }); + + Body.setVelocity(body, { + x: 0, + y: 0 + }); + } + } + + for (i = 0; i < ragdolls.composites.length; i += 1) { + var ragdoll = ragdolls.composites[i], + bounds = Composite.bounds(ragdoll); + + // move ragdolls back to the top of the screen + if (bounds.min.y > render.bounds.max.y + 100) { + Composite.translate(ragdoll, { + x: -bounds.min.x * 0.9, + y: -render.bounds.max.y - 400 + }); + } + } + + for (i = 0; i < obstacles.bodies.length; i += 1) { + var body = obstacles.bodies[i], + bounds = body.bounds; + + // move obstacles back to the top of the screen + if (bounds.min.y > render.bounds.max.y + 100) { + Body.translate(body, { + x: -bounds.min.x, + y: -render.bounds.max.y - 300 + }); + } + } + }); + + // add mouse control and make the mouse revolute + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.6, + length: 0, + angularStiffness: 0, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; + +Example.ragdoll.ragdoll = function(x, y, scale, options) { + scale = typeof scale === 'undefined' ? 1 : scale; + + var Body = Matter.Body, + Bodies = Matter.Bodies, + Constraint = Matter.Constraint, + Composite = Matter.Composite, + Common = Matter.Common; + + var headOptions = Common.extend({ + label: 'head', + collisionFilter: { + group: Body.nextGroup(true) + }, + chamfer: { + radius: [15 * scale, 15 * scale, 15 * scale, 15 * scale] + }, + render: { + fillStyle: '#FFBC42' + } + }, options); + + var chestOptions = Common.extend({ + label: 'chest', + collisionFilter: { + group: Body.nextGroup(true) + }, + chamfer: { + radius: [20 * scale, 20 * scale, 26 * scale, 26 * scale] + }, + render: { + fillStyle: '#E0A423' + } + }, options); + + var leftArmOptions = Common.extend({ + label: 'left-arm', + collisionFilter: { + group: Body.nextGroup(true) + }, + chamfer: { + radius: 10 * scale + }, + render: { + fillStyle: '#FFBC42' + } + }, options); + + var leftLowerArmOptions = Common.extend({}, leftArmOptions, { + render: { + fillStyle: '#E59B12' + } + }); + + var rightArmOptions = Common.extend({ + label: 'right-arm', + collisionFilter: { + group: Body.nextGroup(true) + }, + chamfer: { + radius: 10 * scale + }, + render: { + fillStyle: '#FFBC42' + } + }, options); + + var rightLowerArmOptions = Common.extend({}, rightArmOptions, { + render: { + fillStyle: '#E59B12' + } + }); + + var leftLegOptions = Common.extend({ + label: 'left-leg', + collisionFilter: { + group: Body.nextGroup(true) + }, + chamfer: { + radius: 10 * scale + }, + render: { + fillStyle: '#FFBC42' + } + }, options); + + var leftLowerLegOptions = Common.extend({}, leftLegOptions, { + render: { + fillStyle: '#E59B12' + } + }); + + var rightLegOptions = Common.extend({ + label: 'right-leg', + collisionFilter: { + group: Body.nextGroup(true) + }, + chamfer: { + radius: 10 * scale + }, + render: { + fillStyle: '#FFBC42' + } + }, options); + + var rightLowerLegOptions = Common.extend({}, rightLegOptions, { + render: { + fillStyle: '#E59B12' + } + }); + + var head = Bodies.rectangle(x, y - 60 * scale, 34 * scale, 40 * scale, headOptions); + var chest = Bodies.rectangle(x, y, 55 * scale, 80 * scale, chestOptions); + var rightUpperArm = Bodies.rectangle(x + 39 * scale, y - 15 * scale, 20 * scale, 40 * scale, rightArmOptions); + var rightLowerArm = Bodies.rectangle(x + 39 * scale, y + 25 * scale, 20 * scale, 60 * scale, rightLowerArmOptions); + var leftUpperArm = Bodies.rectangle(x - 39 * scale, y - 15 * scale, 20 * scale, 40 * scale, leftArmOptions); + var leftLowerArm = Bodies.rectangle(x - 39 * scale, y + 25 * scale, 20 * scale, 60 * scale, leftLowerArmOptions); + var leftUpperLeg = Bodies.rectangle(x - 20 * scale, y + 57 * scale, 20 * scale, 40 * scale, leftLegOptions); + var leftLowerLeg = Bodies.rectangle(x - 20 * scale, y + 97 * scale, 20 * scale, 60 * scale, leftLowerLegOptions); + var rightUpperLeg = Bodies.rectangle(x + 20 * scale, y + 57 * scale, 20 * scale, 40 * scale, rightLegOptions); + var rightLowerLeg = Bodies.rectangle(x + 20 * scale, y + 97 * scale, 20 * scale, 60 * scale, rightLowerLegOptions); + + var chestToRightUpperArm = Constraint.create({ + bodyA: chest, + pointA: { + x: 24 * scale, + y: -23 * scale + }, + pointB: { + x: 0, + y: -8 * scale + }, + bodyB: rightUpperArm, + stiffness: 0.6, + render: { + visible: false + } + }); + + var chestToLeftUpperArm = Constraint.create({ + bodyA: chest, + pointA: { + x: -24 * scale, + y: -23 * scale + }, + pointB: { + x: 0, + y: -8 * scale + }, + bodyB: leftUpperArm, + stiffness: 0.6, + render: { + visible: false + } + }); + + var chestToLeftUpperLeg = Constraint.create({ + bodyA: chest, + pointA: { + x: -10 * scale, + y: 30 * scale + }, + pointB: { + x: 0, + y: -10 * scale + }, + bodyB: leftUpperLeg, + stiffness: 0.6, + render: { + visible: false + } + }); + + var chestToRightUpperLeg = Constraint.create({ + bodyA: chest, + pointA: { + x: 10 * scale, + y: 30 * scale + }, + pointB: { + x: 0, + y: -10 * scale + }, + bodyB: rightUpperLeg, + stiffness: 0.6, + render: { + visible: false + } + }); + + var upperToLowerRightArm = Constraint.create({ + bodyA: rightUpperArm, + bodyB: rightLowerArm, + pointA: { + x: 0, + y: 15 * scale + }, + pointB: { + x: 0, + y: -25 * scale + }, + stiffness: 0.6, + render: { + visible: false + } + }); + + var upperToLowerLeftArm = Constraint.create({ + bodyA: leftUpperArm, + bodyB: leftLowerArm, + pointA: { + x: 0, + y: 15 * scale + }, + pointB: { + x: 0, + y: -25 * scale + }, + stiffness: 0.6, + render: { + visible: false + } + }); + + var upperToLowerLeftLeg = Constraint.create({ + bodyA: leftUpperLeg, + bodyB: leftLowerLeg, + pointA: { + x: 0, + y: 20 * scale + }, + pointB: { + x: 0, + y: -20 * scale + }, + stiffness: 0.6, + render: { + visible: false + } + }); + + var upperToLowerRightLeg = Constraint.create({ + bodyA: rightUpperLeg, + bodyB: rightLowerLeg, + pointA: { + x: 0, + y: 20 * scale + }, + pointB: { + x: 0, + y: -20 * scale + }, + stiffness: 0.6, + render: { + visible: false + } + }); + + var headContraint = Constraint.create({ + bodyA: head, + pointA: { + x: 0, + y: 25 * scale + }, + pointB: { + x: 0, + y: -35 * scale + }, + bodyB: chest, + stiffness: 0.6, + render: { + visible: false + } + }); + + var legToLeg = Constraint.create({ + bodyA: leftLowerLeg, + bodyB: rightLowerLeg, + stiffness: 0.01, + render: { + visible: false + } + }); + + var person = Composite.create({ + bodies: [ + chest, head, leftLowerArm, leftUpperArm, + rightLowerArm, rightUpperArm, leftLowerLeg, + rightLowerLeg, leftUpperLeg, rightUpperLeg + ], + constraints: [ + upperToLowerLeftArm, upperToLowerRightArm, chestToLeftUpperArm, + chestToRightUpperArm, headContraint, upperToLowerLeftLeg, + upperToLowerRightLeg, chestToLeftUpperLeg, chestToRightUpperLeg, + legToLeg + ] + }); + + return person; +}; \ No newline at end of file From c9294ebe6e32b9625d6fb421eff77eae8aaa5d98 Mon Sep 17 00:00:00 2001 From: liabru Date: Thu, 6 Jul 2017 21:50:08 +0100 Subject: [PATCH 29/31] upgraded matter-wrap --- demo/lib/matter-wrap.js | 134 +++++++++++++++++++++++++++++++--------- 1 file changed, 105 insertions(+), 29 deletions(-) diff --git a/demo/lib/matter-wrap.js b/demo/lib/matter-wrap.js index 5d16c49..933b8bf 100644 --- a/demo/lib/matter-wrap.js +++ b/demo/lib/matter-wrap.js @@ -1,15 +1,15 @@ /*! - * matter-wrap 0.1.2 by Liam Brummitt 2017-02-12 + * matter-wrap 0.2.0 by Liam Brummitt 2017-07-04 * https://github.com/liabru/matter-wrap * License MIT */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("Matter")); + module.exports = factory(require("matter-js")); else if(typeof define === 'function' && define.amd) - define(["Matter"], factory); + define(["matter-js"], factory); else if(typeof exports === 'object') - exports["MatterWrap"] = factory(require("Matter")); + exports["MatterWrap"] = factory(require("matter-js")); else root["MatterWrap"] = factory(root["Matter"]); })(this, function(__WEBPACK_EXTERNAL_MODULE_0__) { @@ -104,7 +104,7 @@ var Matter = __webpack_require__(0); var MatterWrap = { // plugin meta name: 'matter-wrap', // PLUGIN_NAME - version: '0.1.0', // PLUGIN_VERSION + version: '0.1.3', // PLUGIN_VERSION for: 'matter-js@^0.12.0', // installs the plugin where `base` is `Matter` @@ -117,7 +117,7 @@ var MatterWrap = { Engine: { /** - * Updates the engine by wrapping bodies inside `engine.world`. + * Updates the engine by wrapping bodies and composites inside `engine.world`. * This is called automatically by the plugin. * @function MatterWrap.Engine.update * @param {Matter.Engine} engine The engine to update. @@ -125,7 +125,8 @@ var MatterWrap = { */ update: function update(engine) { var world = engine.world, - bodies = Matter.Composite.allBodies(world); + bodies = Matter.Composite.allBodies(world), + composites = Matter.Composite.allComposites(world); for (var i = 0; i < bodies.length; i += 1) { var body = bodies[i]; @@ -134,46 +135,114 @@ var MatterWrap = { MatterWrap.Body.wrap(body, body.plugin.wrap); } } + + for (i = 0; i < composites.length; i += 1) { + var composite = composites[i]; + + if (composite.plugin.wrap) { + MatterWrap.Composite.wrap(composite, composite.plugin.wrap); + } + } + } + }, + + Bounds: { + /** + * Returns a translation vector that wraps the `objectBounds` inside the `bounds`. + * @function MatterWrap.Bounds.wrap + * @param {Matter.Bounds} objectBounds The bounds of the object to wrap inside the bounds. + * @param {Matter.Bounds} bounds The bounds to wrap the body inside. + * @returns {?Matter.Vector} A translation vector (only if wrapping is required). + */ + wrap: function wrap(objectBounds, bounds) { + var x = null, + y = null; + + if (typeof bounds.min.x !== 'undefined' && typeof bounds.max.x !== 'undefined') { + if (objectBounds.min.x > bounds.max.x) { + x = bounds.min.x - objectBounds.max.x; + } else if (objectBounds.max.x < bounds.min.x) { + x = bounds.max.x - objectBounds.min.x; + } + } + + if (typeof bounds.min.y !== 'undefined' && typeof bounds.max.y !== 'undefined') { + if (objectBounds.min.y > bounds.max.y) { + y = bounds.min.y - objectBounds.max.y; + } else if (objectBounds.max.y < bounds.min.y) { + y = bounds.max.y - objectBounds.min.y; + } + } + + if (x !== null || y !== null) { + return { + x: x || 0, + y: y || 0 + }; + } } }, Body: { /** - * Wraps the `body` position such that it always stay within the given bounds. + * Wraps the `body` position such that it always stays within the given bounds. * Upon crossing a boundary the body will appear on the opposite side of the bounds, * while maintaining its velocity. * This is called automatically by the plugin. - * @function MatterAttractors.Body.wrap + * @function MatterWrap.Body.wrap * @param {Matter.Body} body The body to wrap. * @param {Matter.Bounds} bounds The bounds to wrap the body inside. - * @returns {void} No return value. + * @returns {?Matter.Vector} The translation vector that was applied (only if wrapping was required). */ wrap: function wrap(body, bounds) { - var x = null, - y = null; + var translation = MatterWrap.Bounds.wrap(body.bounds, bounds); - if (typeof bounds.min.x !== 'undefined' && typeof bounds.max.x !== 'undefined') { - if (body.bounds.min.x > bounds.max.x) { - x = bounds.min.x - (body.bounds.max.x - body.position.x); - } else if (body.bounds.max.x < bounds.min.x) { - x = bounds.max.x - (body.bounds.min.x - body.position.x); - } + if (translation) { + Matter.Body.translate(body, translation); } - if (typeof bounds.min.y !== 'undefined' && typeof bounds.max.y !== 'undefined') { - if (body.bounds.min.y > bounds.max.y) { - y = bounds.min.y - (body.bounds.max.y - body.position.y); - } else if (body.bounds.max.y < bounds.min.y) { - y = bounds.max.y - (body.bounds.min.y - body.position.y); - } + return translation; + } + }, + + Composite: { + /** + * Returns the union of the bounds of all of the composite's bodies + * (not accounting for constraints). + * @function MatterWrap.Composite.bounds + * @param {Matter.Composite} composite The composite. + * @returns {Matter.Bounds} The composite bounds. + */ + bounds: function bounds(composite) { + var bodies = Matter.Composite.allBodies(composite), + vertices = []; + + for (var i = 0; i < bodies.length; i += 1) { + var body = bodies[i]; + vertices.push(body.bounds.min, body.bounds.max); } - if (x !== null || y !== null) { - Matter.Body.setPosition(body, { - x: x || body.position.x, - y: y || body.position.y - }); + return Matter.Bounds.create(vertices); + }, + + /** + * Wraps the `composite` position such that it always stays within the given bounds. + * Upon crossing a boundary the composite will appear on the opposite side of the bounds, + * while maintaining its velocity. + * This is called automatically by the plugin. + * @function MatterWrap.Composite.wrap + * @param {Matter.Composite} composite The composite to wrap. + * @param {Matter.Bounds} bounds The bounds to wrap the composite inside. + * @returns {?Matter.Vector} The translation vector that was applied (only if wrapping was required). + */ + wrap: function wrap(composite, bounds) { + var translation = MatterWrap.Bounds.wrap(MatterWrap.Composite.bounds(composite), bounds); + + if (translation) { + Matter.Composite.translate(composite, translation); } + + return translation; } } }; @@ -194,6 +263,13 @@ module.exports = MatterWrap; * @memberof Matter.Body */ +/** + * This plugin adds a new property `composite.plugin.wrap` to instances of `Matter.Composite`. + * This is a `Matter.Bounds` instance that specifies the wrapping region. + * @property {Matter.Bounds} composite.plugin.wrap + * @memberof Matter.Composite + */ + /***/ }) /******/ ]); }); \ No newline at end of file From 79ffcf891e9024181ed59e3cd40760449572f1b7 Mon Sep 17 00:00:00 2001 From: liabru Date: Thu, 6 Jul 2017 21:51:23 +0100 Subject: [PATCH 30/31] added Composite.bounds --- src/body/Composite.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/body/Composite.js b/src/body/Composite.js index ee15d93..885669c 100644 --- a/src/body/Composite.js +++ b/src/body/Composite.js @@ -532,6 +532,24 @@ var Body = require('./Body'); return composite; }; + /** + * Returns the union of the bounds of all of the composite's bodies. + * @method bounds + * @param {composite} composite The composite. + * @returns {bounds} The composite bounds. + */ + Composite.bounds = function(composite) { + var bodies = Matter.Composite.allBodies(composite), + vertices = []; + + for (var i = 0; i < bodies.length; i += 1) { + var body = bodies[i]; + vertices.push(body.bounds.min, body.bounds.max); + } + + return Matter.Bounds.create(vertices); + }; + /* * * Events Documentation From 48940088df15335c3b2a200ffc9ca84c84bb2913 Mon Sep 17 00:00:00 2001 From: liabru Date: Thu, 6 Jul 2017 21:53:31 +0100 Subject: [PATCH 31/31] tweaked Example.doublePendulum --- examples/doublePendulum.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/doublePendulum.js b/examples/doublePendulum.js index 70dec15..24240ea 100644 --- a/examples/doublePendulum.js +++ b/examples/doublePendulum.js @@ -60,7 +60,7 @@ Example.doublePendulum = function() { world.gravity.scale = 0.002; Composites.chain(pendulum, 0.45, 0, -0.45, 0, { - stiffness: 1, + stiffness: 0.9, length: 0, angularStiffness: 0.7, render: { @@ -72,7 +72,7 @@ Example.doublePendulum = function() { bodyB: pendulum.bodies[0], pointB: { x: -length * 0.42, y: 0 }, pointA: { x: pendulum.bodies[0].position.x - length * 0.42, y: pendulum.bodies[0].position.y }, - stiffness: 1, + stiffness: 0.9, length: 0, render: { strokeStyle: '#4a485b'