Skip to content

Commit

Permalink
Added readonly body.deltaTime
Browse files Browse the repository at this point in the history
Added delta property to engine update event
Added delta argument to various internal functions
Changed timeScale argument to use delta instead on various internal functions
Fixed issues when using an engine update delta of 0
Improved time independence for friction, air friction, restitution, sleeping, collisions, constraints
Removed optional correction argument from Engine.update
Removed correction and timeScale from Body.update and Matter.Runner
  • Loading branch information
liabru committed Sep 1, 2019
1 parent 2ec247b commit 0784a5b
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 107 deletions.
43 changes: 28 additions & 15 deletions src/body/Body.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ module.exports = Body;
var Vertices = require('../geometry/Vertices');
var Vector = require('../geometry/Vector');
var Sleeping = require('../core/Sleeping');
var Render = require('../render/Render');
var Common = require('../core/Common');
var Bounds = require('../geometry/Bounds');
var Axes = require('../geometry/Axes');

(function() {

Body._timeCorrection = true;
Body._inertiaScale = 4;
Body._nextCollidingGroupId = 1;
Body._nextNonCollidingGroupId = -1;
Expand Down Expand Up @@ -95,6 +95,7 @@ var Axes = require('../geometry/Axes');
area: 0,
mass: 0,
inertia: 0,
deltaTime: null,
_original: null
};

Expand Down Expand Up @@ -462,8 +463,8 @@ var Axes = require('../geometry/Axes');
*/
Body.setPosition = function(body, position) {
var delta = Vector.sub(position, body.position);
body.positionPrev.x += delta.x;
body.positionPrev.y += delta.y;
body.positionPrev.x += delta.x;
body.positionPrev.y += delta.y;

for (var i = 0; i < body.parts.length; i++) {
var part = body.parts[i];
Expand All @@ -482,7 +483,7 @@ var Axes = require('../geometry/Axes');
*/
Body.setAngle = function(body, angle) {
var delta = angle - body.angle;
body.anglePrev += delta;
body.anglePrev += delta;

for (var i = 0; i < body.parts.length; i++) {
var part = body.parts[i];
Expand Down Expand Up @@ -625,26 +626,28 @@ var Axes = require('../geometry/Axes');
* Performs a simulation step for the given `body`, including updating position and angle using Verlet integration.
* @method update
* @param {body} body
* @param {number} deltaTime
* @param {number} timeScale
* @param {number} correction
* @param {number} [deltaTime=16.666]
*/
Body.update = function(body, deltaTime, timeScale, correction) {
var deltaTimeSquared = Math.pow(deltaTime * timeScale * body.timeScale, 2);
Body.update = function(body, deltaTime) {
deltaTime = (typeof deltaTime !== 'undefined' ? deltaTime : Common._timeUnit) * body.timeScale;

var deltaTimeSquared = deltaTime * deltaTime,
correction = Body._timeCorrection ? deltaTime / (body.deltaTime || deltaTime) : 1;

// from the previous step
var frictionAir = 1 - body.frictionAir * timeScale * body.timeScale,
velocityPrevX = body.position.x - body.positionPrev.x,
velocityPrevY = body.position.y - body.positionPrev.y;
var frictionAir = 1 - body.frictionAir * (deltaTime / Common._timeUnit),
velocityPrevX = (body.position.x - body.positionPrev.x) * correction,
velocityPrevY = (body.position.y - body.positionPrev.y) * correction;

// update velocity with Verlet integration
body.velocity.x = (velocityPrevX * frictionAir * correction) + (body.force.x / body.mass) * deltaTimeSquared;
body.velocity.y = (velocityPrevY * frictionAir * correction) + (body.force.y / body.mass) * deltaTimeSquared;
body.velocity.x = (velocityPrevX * frictionAir) + (body.force.x / body.mass) * deltaTimeSquared;
body.velocity.y = (velocityPrevY * frictionAir) + (body.force.y / body.mass) * deltaTimeSquared;

body.positionPrev.x = body.position.x;
body.positionPrev.y = body.position.y;
body.position.x += body.velocity.x;
body.position.y += body.velocity.y;
body.deltaTime = deltaTime;

// update angular velocity with Verlet integration
body.angularVelocity = ((body.angle - body.anglePrev) * frictionAir * correction) + (body.torque / body.inertia) * deltaTimeSquared;
Expand Down Expand Up @@ -880,7 +883,7 @@ var Axes = require('../geometry/Axes');
/**
* A `Vector` that _measures_ the current velocity of the body after the last `Body.update`. It is read-only.
* If you need to modify a body's velocity directly, you should either apply a force or simply change the body's `position` (as the engine uses position-Verlet integration).
*
*
* @readOnly
* @property velocity
* @type vector
Expand Down Expand Up @@ -1109,6 +1112,16 @@ var Axes = require('../geometry/Axes');
* @default 1
*/

/**
* A `Number` that records the last delta time value used to update this body.
* This is automatically updated by the engine inside of `Body.update`.
*
* @readOnly
* @property deltaTime
* @type number
* @default null
*/

/**
* An `Object` that defines the rendering properties to be consumed by the module `Matter.Render`.
*
Expand Down
5 changes: 3 additions & 2 deletions src/collision/Detector.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ var Bounds = require('../geometry/Bounds');
* @method collisions
* @param {pair[]} broadphasePairs
* @param {engine} engine
* @param {number} delta
* @return {array} collisions
*/
Detector.collisions = function(broadphasePairs, engine) {
Detector.collisions = function(broadphasePairs, engine, delta) {
var collisions = [],
pairsTable = engine.pairs.table;

Expand Down Expand Up @@ -66,7 +67,7 @@ var Bounds = require('../geometry/Bounds');
}

// narrow phase
var collision = SAT.collides(partA, partB, previousCollision);
var collision = SAT.collides(partA, partB, previousCollision, delta);

// @if DEBUG
metrics.narrowphaseTests += 1;
Expand Down
25 changes: 14 additions & 11 deletions src/collision/Resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ var Bounds = require('../geometry/Bounds');
* @method solvePosition
* @param {pair[]} pairs
* @param {body[]} bodies
* @param {number} timeScale
* @param {number} delta
*/
Resolver.solvePosition = function(pairs, bodies, timeScale) {
Resolver.solvePosition = function(pairs, bodies, delta) {
var i,
normalX,
normalY,
Expand All @@ -68,7 +68,8 @@ var Bounds = require('../geometry/Bounds');
bodyBtoAX,
bodyBtoAY,
positionImpulse,
impulseCoefficient = timeScale * Resolver._positionDampen;
timeScale = delta / Common._timeUnit,
impulseCoefficient = Resolver._positionDampen * timeScale;

for (i = 0; i < bodies.length; i++) {
var body = bodies[i];
Expand Down Expand Up @@ -231,10 +232,12 @@ var Bounds = require('../geometry/Bounds');
* Find a solution for pair velocities.
* @method solveVelocity
* @param {pair[]} pairs
* @param {number} timeScale
* @param {number} delta
*/
Resolver.solveVelocity = function(pairs, timeScale) {
var timeScaleSquared = timeScale * timeScale,
Resolver.solveVelocity = function(pairs, delta) {
var timeScale = delta / Common._timeUnit,
timeScale2 = timeScale * timeScale,
timeScale3 = timeScale2 * timeScale,
impulse = Vector._temp[0],
tempA = Vector._temp[1],
tempB = Vector._temp[2],
Expand Down Expand Up @@ -287,10 +290,10 @@ var Bounds = require('../geometry/Bounds');
var tangentImpulse = tangentVelocity,
maxFriction = Infinity;

if (tangentSpeed > pair.friction * pair.frictionStatic * normalForce * timeScaleSquared) {
maxFriction = tangentSpeed;
if (tangentSpeed > pair.friction * pair.frictionStatic * normalForce * timeScale3) {
maxFriction = tangentSpeed * timeScale;
tangentImpulse = Common.clamp(
pair.friction * tangentVelocityDirection * timeScaleSquared,
pair.friction * tangentVelocityDirection * timeScale3,
-maxFriction, maxFriction
);
}
Expand All @@ -304,7 +307,7 @@ var Bounds = require('../geometry/Bounds');
tangentImpulse *= share;

// handle high velocity and resting collisions separately
if (normalVelocity < 0 && normalVelocity * normalVelocity > Resolver._restingThresh * timeScaleSquared) {
if (normalVelocity < 0 && normalVelocity * normalVelocity > Resolver._restingThresh * timeScale2) {
// high normal velocity so clear cached contact normal impulse
contact.normalImpulse = 0;
} else {
Expand All @@ -316,7 +319,7 @@ var Bounds = require('../geometry/Bounds');
}

// handle high velocity and resting collisions separately
if (tangentVelocity * tangentVelocity > Resolver._restingThreshTangent * timeScaleSquared) {
if (tangentVelocity * tangentVelocity > Resolver._restingThreshTangent * timeScale2) {
// high tangent velocity so clear cached contact tangent impulse
contact.tangentImpulse = 0;
} else {
Expand Down
13 changes: 10 additions & 3 deletions src/collision/SAT.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,30 @@ module.exports = SAT;

var Vertices = require('../geometry/Vertices');
var Vector = require('../geometry/Vector');
var Common = require('../core/Common');

(function() {

SAT._reuseMotionThresh = 0.2;

/**
* Detect collision between two bodies using the Separating Axis Theorem.
* @method collides
* @param {body} bodyA
* @param {body} bodyB
* @param {collision} previousCollision
* @param {number} [delta=0]
* @return {collision} collision
*/
SAT.collides = function(bodyA, bodyB, previousCollision) {
SAT.collides = function(bodyA, bodyB, previousCollision, delta) {
var overlapAB,
overlapBA,
minOverlap,
collision,
canReusePrevCol = false;
canReusePrevCol = false,
timeScale = delta / Common._timeUnit;

delta = typeof delta !== 'undefined' ? delta : 0;

if (previousCollision) {
// estimate total motion
Expand All @@ -39,7 +46,7 @@ var Vector = require('../geometry/Vector');

// we may be able to (partially) reuse collision result
// but only safe if collision was resting
canReusePrevCol = previousCollision && previousCollision.collided && motion < 0.2;
canReusePrevCol = previousCollision && previousCollision.collided && motion < SAT._reuseMotionThresh * timeScale * timeScale;

// reuse collision object
collision = previousCollision;
Expand Down
26 changes: 15 additions & 11 deletions src/constraint/Constraint.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,11 @@ var Common = require('../core/Common');
* @private
* @method solveAll
* @param {constraint[]} constraints
* @param {number} timeScale
* @param {number} delta
*/
Constraint.solveAll = function(constraints, timeScale) {
Constraint.solveAll = function(constraints, delta) {
var timeScale = Common.clamp(delta / Common._timeUnit, 0, 1);

// Solve fixed constraints first.
for (var i = 0; i < constraints.length; i += 1) {
var constraint = constraints[i],
Expand Down Expand Up @@ -183,7 +185,9 @@ var Common = require('../core/Common');

// solve distance constraint with Gauss-Siedel method
var difference = (currentLength - constraint.length) / currentLength,
stiffness = constraint.stiffness < 1 ? constraint.stiffness * timeScale : constraint.stiffness,
isRigid = constraint.stiffness >= 1 || constraint.length === 0,
stiffness = isRigid ? constraint.stiffness : constraint.stiffness * timeScale * timeScale,
damping = constraint.damping * timeScale,
force = Vector.mult(delta, difference * stiffness),
massTotal = (bodyA ? bodyA.inverseMass : 0) + (bodyB ? bodyB.inverseMass : 0),
inertiaTotal = (bodyA ? bodyA.inverseInertia : 0) + (bodyB ? bodyB.inverseInertia : 0),
Expand All @@ -193,8 +197,8 @@ var Common = require('../core/Common');
normal,
normalVelocity,
relativeVelocity;

if (constraint.damping) {
if (damping > 0) {
var zero = Vector.create();
normal = Vector.div(delta, currentLength);

Expand All @@ -218,9 +222,9 @@ var Common = require('../core/Common');
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;
if (damping > 0) {
bodyA.positionPrev.x -= damping * normal.x * normalVelocity * share;
bodyA.positionPrev.y -= damping * normal.y * normalVelocity * share;
}

// apply torque
Expand All @@ -241,9 +245,9 @@ var Common = require('../core/Common');
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;
if (damping > 0) {
bodyB.positionPrev.x += damping * normal.x * normalVelocity * share;
bodyB.positionPrev.y += damping * normal.y * normalVelocity * share;
}

// apply torque
Expand Down
1 change: 1 addition & 0 deletions src/core/Common.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module.exports = Common;

(function() {

Common._timeUnit = 1000 / 60;
Common._nextId = 0;
Common._seed = 0;
Common._nowStartTime = +(new Date());
Expand Down
Loading

0 comments on commit 0784a5b

Please sign in to comment.