Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timing, frame-rate consistency improvements and features #777

Merged
merged 52 commits into from
Feb 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
0784a5b
Added readonly body.deltaTime
liabru Sep 1, 2019
db8b73f
Added updateVelocity argument to Body.setPosition, Body.setAngle, Bod…
liabru Sep 1, 2019
d7e4f58
Changed examples to be delta independent
liabru Sep 1, 2019
516494e
Added substeps feature to Matter.Runner
liabru Sep 1, 2019
fba5af2
updated edge build
liabru Sep 1, 2019
7c6cda0
added clamping to position resolver damping
liabru Sep 1, 2019
f5311a6
updated edge build
liabru Sep 1, 2019
e29d03b
revert edge build
liabru Mar 10, 2020
8cfc234
Merge branch 'master' into timing-improve
liabru Mar 11, 2020
6f5af77
fix issues with engine event.delta
liabru Mar 11, 2020
3117dfd
change Body.applyForce for timing, add initial body.deltaTime
liabru Mar 11, 2020
298e3e4
fix lint
liabru Mar 11, 2020
85ff776
updated alpha build
liabru Mar 11, 2020
207c2f3
merge branch 'master' into timing-improve
liabru Dec 31, 2020
6ed74e1
fix lint
liabru Dec 31, 2020
7fce5d8
Merge branch 'master' into timing-improve
liabru Dec 20, 2021
4230a8b
Merge branch 'master' into timing-improve
liabru Dec 23, 2021
10a2a07
update timing improvements
liabru Dec 23, 2021
bf90bdd
use Body.getVelocity in Matter.Render
liabru Dec 26, 2021
b2bd492
improved Example.newtonsCradle
liabru Dec 29, 2021
ec38638
update Example.ragdoll
liabru Dec 30, 2021
5ddac71
update Example.manipulation
liabru Dec 31, 2021
11d5e73
update Example.staticFriction and Example.timeScale
liabru Jan 1, 2022
87af8a1
improved delta consistency
liabru Jan 1, 2022
7130c4a
refactor resolver friction multiplier
liabru Jan 3, 2022
d52f7e6
update body velocity properties after resolving
liabru Jan 4, 2022
70600a8
changed engine collisionStart event to trigger after resolving and af…
liabru Jan 4, 2022
db780c3
update Matter.Body docs
liabru Jan 4, 2022
181d08b
add docs for Matter.Body velocity properties including unit details
liabru Jan 4, 2022
fda962f
added Body.timeUnit
liabru Jan 4, 2022
fe98528
tidy and refactor
liabru Jan 4, 2022
b6de9ed
derive velocity from position in setters
liabru Jan 5, 2022
6579dfd
use speed getter in Matter.Sleeping and Matter.Render
liabru Jan 6, 2022
3ff6ff4
added speed setters to Body.set
liabru Jan 6, 2022
85a9eb2
improve Matter.Body docs for functions and properties including readonly
liabru Jul 27, 2022
50fc8f2
improve Matter.Engine docs
liabru Jul 27, 2022
a572968
remove unused delta params
liabru Aug 5, 2022
07d13fe
improve delta factors in resolver and constraint stiffness
liabru Aug 5, 2022
1b4e288
Merge branch 'master' into timing-improve
liabru Aug 6, 2022
c6a1a6d
improve slingshot example constraint
liabru Aug 6, 2022
9dc6be7
improve delta factors in resolver and constraint stiffness
liabru Aug 6, 2022
ee7b008
clamp resolver slop
liabru Aug 7, 2022
cce3152
refactor Resolver.solvePosition damping argument
liabru Sep 2, 2022
36575b3
refactor and tidy
liabru Sep 2, 2022
dc46472
rename internal Common._timeUnit to Common._baseDelta
liabru Sep 2, 2022
66e291b
refactor body base delta constant
liabru Sep 2, 2022
db7c4a1
move substeps to another branch
liabru Sep 2, 2022
903228a
remove alpha build
liabru Sep 2, 2022
f8b64b6
change remove example to use timestamps
liabru Nov 19, 2022
f7da964
revert Body.applyForce
liabru Dec 28, 2022
3a8264c
improve Body.applyForce docs
liabru Dec 28, 2022
6bb2855
update body docs
liabru Dec 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ Example.bridge = function() {
});

Composites.chain(bridge, 0.3, 0, -0.3, 0, {
stiffness: 1,
length: 0,
stiffness: 0.99,
length: 0.0001,
render: {
visible: false
}
Expand Down
9 changes: 5 additions & 4 deletions examples/compositeManipulation.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,20 @@ Example.compositeManipulation = function() {
engine.gravity.y = 0;

Events.on(engine, 'afterUpdate', function(event) {
var time = engine.timing.timestamp;
var time = engine.timing.timestamp,
timeScale = (event.delta || (1000 / 60)) / 1000;

Composite.translate(stack, {
x: Math.sin(time * 0.001) * 2,
x: Math.sin(time * 0.001) * 10 * timeScale,
y: 0
});

Composite.rotate(stack, Math.sin(time * 0.001) * 0.01, {
Composite.rotate(stack, Math.sin(time * 0.001) * 0.75 * timeScale, {
x: 300,
y: 300
});

var scale = 1 + (Math.sin(time * 0.001) * 0.01);
var scale = 1 + (Math.sin(time * 0.001) * 0.75 * timeScale);

Composite.scale(stack, scale, scale, {
x: 300,
Expand Down
13 changes: 11 additions & 2 deletions examples/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,19 @@ Example.events = function() {
// do something with event.object
});

var lastTime = Common.now();

// an example of using beforeUpdate event on an engine
Events.on(engine, 'beforeUpdate', function(event) {
var engine = event.source;

// apply random forces every 5 secs
if (event.timestamp % 5000 < 50)
if (Common.now() - lastTime >= 5000) {
shakeScene(engine);

// update last time
lastTime = Common.now();
}
});

// an example of using collisionStart event on an engine
Expand Down Expand Up @@ -102,14 +108,17 @@ Example.events = function() {
Composite.add(world, stack);

var shakeScene = function(engine) {
var timeScale = (1000 / 60) / engine.timing.lastDelta;
var bodies = Composite.allBodies(engine.world);

for (var i = 0; i < bodies.length; i++) {
var body = bodies[i];

if (!body.isStatic && body.position.y >= 500) {
var forceMagnitude = 0.02 * body.mass;
// scale force for mass and time applied
var forceMagnitude = (0.03 * body.mass) * timeScale;

// apply the force over a single update
Body.applyForce(body, body.position, {
x: (forceMagnitude + Common.random() * forceMagnitude) * Common.choose([1, -1]),
y: -forceMagnitude + Common.random() * -forceMagnitude
Expand Down
75 changes: 44 additions & 31 deletions examples/manipulation.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,24 @@ Example.manipulation = function() {
Runner.run(runner, engine);

// add bodies
var bodyA = Bodies.rectangle(100, 200, 50, 50, { isStatic: true, render: { fillStyle: '#060a19' } }),
var bodyA = Bodies.rectangle(100, 300, 50, 50, { isStatic: true, render: { fillStyle: '#060a19' } }),
bodyB = Bodies.rectangle(200, 200, 50, 50),
bodyC = Bodies.rectangle(300, 200, 50, 50),
bodyD = Bodies.rectangle(400, 200, 50, 50),
bodyE = Bodies.rectangle(550, 200, 50, 50),
bodyF = Bodies.rectangle(700, 200, 50, 50),
bodyG = Bodies.circle(400, 100, 25, { render: { fillStyle: '#060a19' } }),
partA = Bodies.rectangle(600, 200, 120, 50, { render: { fillStyle: '#060a19' } }),
partB = Bodies.rectangle(660, 200, 50, 190, { render: { fillStyle: '#060a19' } }),
bodyG = Bodies.circle(400, 100, 25, { render: { fillStyle: '#060a19' } });

// add compound body
var partA = Bodies.rectangle(600, 200, 120 * 0.8, 50 * 0.8, { render: { fillStyle: '#060a19' } }),
partB = Bodies.rectangle(660, 200, 50 * 0.8, 190 * 0.8, { render: { fillStyle: '#060a19' } }),
compound = Body.create({
parts: [partA, partB],
isStatic: true
});

Body.setPosition(compound, { x: 600, y: 300 });

Composite.add(world, [bodyA, bodyB, bodyC, bodyD, bodyE, bodyF, bodyG, compound]);

Composite.add(world, [
Expand All @@ -59,48 +63,57 @@ Example.manipulation = function() {
Bodies.rectangle(0, 300, 50, 600, { isStatic: true })
]);

var counter = 0,
scaleFactor = 1.01;
var lastTime = 0,
scaleRate = 0.6;

Events.on(runner, 'afterTick', function(event) {
counter += 1;
Events.on(engine, 'beforeUpdate', function(event) {
var timeScale = (event.delta || (1000 / 60)) / 1000;

if (counter === 40)
Body.setStatic(bodyG, true);

if (scaleFactor > 1) {
Body.scale(bodyF, scaleFactor, scaleFactor);
Body.scale(compound, 0.995, 0.995);
if (scaleRate > 0) {
Body.scale(bodyF, 1 + (scaleRate * timeScale), 1 + (scaleRate * timeScale));

// modify bodyE vertices
bodyE.vertices[0].x -= 0.2;
bodyE.vertices[0].y -= 0.2;
bodyE.vertices[1].x += 0.2;
bodyE.vertices[1].y -= 0.2;
bodyE.vertices[0].x -= 0.2 * timeScale;
bodyE.vertices[0].y -= 0.2 * timeScale;
bodyE.vertices[1].x += 0.2 * timeScale;
bodyE.vertices[1].y -= 0.2 * timeScale;
Body.setVertices(bodyE, bodyE.vertices);
}

// make bodyA move up and down
// body is static so must manually update velocity for friction to work
var py = 300 + 100 * Math.sin(engine.timing.timestamp * 0.002);
Body.setVelocity(bodyA, { x: 0, y: py - bodyA.position.y });
Body.setPosition(bodyA, { x: 100, y: py });

// make compound body move up and down and rotate constantly
Body.setVelocity(compound, { x: 0, y: py - compound.position.y });
Body.setAngularVelocity(compound, 0.02);
Body.setPosition(compound, { x: 600, y: py });
Body.rotate(compound, 0.02);
// manual update velocity required for older releases
if (Matter.version === '0.18.0') {
Body.setVelocity(bodyA, { x: 0, y: py - bodyA.position.y });
Body.setVelocity(compound, { x: 0, y: py - compound.position.y });
Body.setAngularVelocity(compound, 1 * Math.PI * timeScale);
}

// move body and update velocity
Body.setPosition(bodyA, { x: 100, y: py }, true);

// move compound body move up and down and update velocity
Body.setPosition(compound, { x: 600, y: py }, true);

// rotate compound body and update angular velocity
Body.rotate(compound, 1 * Math.PI * timeScale, null, true);

// after first 0.8 sec (simulation time)
if (engine.timing.timestamp >= 800)
Body.setStatic(bodyG, true);

// every 1.5 sec
if (counter >= 60 * 1.5) {
// every 1.5 sec (simulation time)
if (engine.timing.timestamp - lastTime >= 1500) {
Body.setVelocity(bodyB, { x: 0, y: -10 });
Body.setAngle(bodyC, -Math.PI * 0.26);
Body.setAngularVelocity(bodyD, 0.2);

// reset counter
counter = 0;
scaleFactor = 1;
// stop scaling
scaleRate = 0;

// update last time
lastTime = engine.timing.timestamp;
}
});

Expand Down
2 changes: 1 addition & 1 deletion examples/newtonsCradle.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Example.newtonsCradle.newtonsCradle = function(xx, yy, number, size, length) {
for (var i = 0; i < number; i++) {
var separation = 1.9,
circle = Bodies.circle(xx + i * (size * separation), yy + length, size,
{ inertia: Infinity, restitution: 1, friction: 0, frictionAir: 0.0001, slop: 1 }),
{ inertia: Infinity, restitution: 1, friction: 0, frictionAir: 0, slop: size * 0.02 }),
constraint = Constraint.create({ pointA: { x: xx + i * (size * separation), y: yy }, bodyB: circle });

Composite.addBody(newtonsCradle, circle);
Expand Down
25 changes: 11 additions & 14 deletions examples/ragdoll.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ Example.ragdoll = function() {
Common = Matter.Common,
Composite = Matter.Composite,
Composites = Matter.Composites,
Constraint = Matter.Constraint,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
Bodies = Matter.Bodies,
Vector = Matter.Vector;
Bodies = Matter.Bodies;

// create engine
var engine = Engine.create(),
Expand Down Expand Up @@ -82,39 +80,38 @@ Example.ragdoll = function() {
Composite.add(world, [stack, obstacles, ragdolls]);

var timeScaleTarget = 1,
counter = 0;
lastTime = Common.now();

Events.on(engine, 'afterUpdate', function(event) {
var timeScale = (event.delta || (1000 / 60)) / 1000;

// tween the timescale for slow-mo
if (mouse.button === -1) {
engine.timing.timeScale += (timeScaleTarget - engine.timing.timeScale) * 0.05;
engine.timing.timeScale += (timeScaleTarget - engine.timing.timeScale) * 3 * timeScale;
} else {
engine.timing.timeScale = 1;
}

counter += 1;

// every 1.5 sec
if (counter >= 60 * 1.5) {

// every 2 sec (real time)
if (Common.now() - lastTime >= 2000) {
// flip the timescale
if (timeScaleTarget < 1) {
timeScaleTarget = 1;
} else {
timeScaleTarget = 0.05;
}

// reset counter
counter = 0;
// update last time
lastTime = Common.now();
}

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
x: -30 * timeScale,
y: -30 * timeScale
});

// loop stairs when they go off screen
Expand Down
9 changes: 4 additions & 5 deletions examples/remove.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Example.remove = function() {
Runner.run(runner, engine);

var stack = null,
updateCount = 0;
lastTimestamp = 0;

var createStack = function() {
return Composites.stack(20, 20, 10, 5, 0, 0, function(x, y) {
Expand Down Expand Up @@ -62,14 +62,13 @@ Example.remove = function() {
};

// add and remove stacks every few updates
Events.on(engine, 'afterUpdate', function() {
Events.on(engine, 'afterUpdate', function(event) {
// limit rate
if (stack && updateCount <= 50) {
updateCount += 1;
if (stack && event.timestamp - lastTimestamp < 800) {
return;
}

updateCount = 0;
lastTimestamp = event.timestamp;

// remove last stack
if (stack) {
Expand Down
9 changes: 9 additions & 0 deletions examples/slingshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Example.slingshot = function() {
Constraint = Matter.Constraint,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
Body = Matter.Body,
Composite = Matter.Composite,
Bodies = Matter.Bodies;

Expand Down Expand Up @@ -41,6 +42,8 @@ Example.slingshot = function() {
elastic = Constraint.create({
pointA: anchor,
bodyB: rock,
length: 0.01,
damping: 0.01,
stiffness: 0.05
});

Expand All @@ -58,6 +61,12 @@ Example.slingshot = function() {

Events.on(engine, 'afterUpdate', function() {
if (mouseConstraint.mouse.button === -1 && (rock.position.x > 190 || rock.position.y < 430)) {
// Limit maximum speed of current rock.
if (Body.getSpeed(rock) > 45) {
Body.setSpeed(rock, 45);
}

// Release current rock and add a new one.
rock = Bodies.polygon(170, 450, 7, 20, rockOptions);
Composite.add(engine.world, rock);
elastic.bodyB = rock;
Expand Down
20 changes: 10 additions & 10 deletions examples/staticFriction.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ Example.staticFriction = function() {

// add bodies
var body = Bodies.rectangle(400, 500, 200, 60, { isStatic: true, chamfer: 10, render: { fillStyle: '#060a19' } }),
size = 50,
counter = -1;
size = 50;

var stack = Composites.stack(350, 470 - 6 * size, 1, 6, 0, 0, function(x, y) {
return Bodies.rectangle(x, y, size * 2, size, {
Expand All @@ -56,18 +55,19 @@ Example.staticFriction = function() {
Bodies.rectangle(0, 300, 50, 600, { isStatic: true })
]);

Events.on(engine, 'beforeUpdate', function(event) {
counter += 0.014;

if (counter < 0) {
Events.on(engine, 'beforeUpdate', function() {
if (engine.timing.timestamp < 1500) {
return;
}

var px = 400 + 100 * Math.sin(counter);
var px = 400 + 100 * Math.sin((engine.timing.timestamp - 1500) * 0.001);

// manual update velocity required for older releases
if (Matter.version === '0.18.0') {
Body.setVelocity(body, { x: px - body.position.x, y: 0 });
}

// body is static so must manually update velocity for friction to work
Body.setVelocity(body, { x: px - body.position.x, y: 0 });
Body.setPosition(body, { x: px, y: body.position.y });
Body.setPosition(body, { x: px, y: body.position.y }, true);
});

// add mouse control
Expand Down
Loading