matter-js icon indicating copy to clipboard operation
matter-js copied to clipboard

Updating body not accounting for delta time when only velocity is set?

Open wmike1987 opened this issue 6 years ago • 6 comments

I'm seeing differing body speeds (visually, not body.speed) when framerates differ. Movement is meant be framerate independent but it doesn't appear to be with respect to only velocity. I think this line is the issue (in Body.update()).

body.velocity.x = (velocityPrevX * frictionAir * correction) + (body.force.x / body.mass) * deltaTimeSquared;

body.velocity.y = (velocityPrevY * frictionAir * correction) + (body.force.y / body.mass) * deltaTimeSquared;

The logic here will disregard delta time if force == 0 and will thus update the body with the same velocity if our frame rate is 60 or 30. Am I missing something, or using the engine wrong?

Mike

wmike1987 avatar Jul 16 '18 16:07 wmike1987

Any comment about this one?

wmike1987 avatar Sep 04 '18 14:09 wmike1987

I noticed this as well and I'm having a pretty hard time wrapping my head around it. I'm probably misunderstanding the math, but it seems like velocity isn't distance / time but is more like distance / timestep. I'm sure this makes sense to the engine but it makes dealing with and changing velocities super confusing.

MDFL64 avatar Oct 29 '18 01:10 MDFL64

It does seem strange but this actually falls out of the math from position Verlet integration:

 xi+1 = xi + (xi - xi-1) + a * dt * dt

Check out this derivation, note that this assumes a constant time step. To account for a changing time step the author introduces a time correction scheme, which is what is implemented in the engine, though it's only intended for handling short dips since it's not that accurate. Hopefully that helps.

liabru avatar Nov 16 '18 21:11 liabru

Oh ok, thank you so much. I see how this all works now, indeed matter.js is implementing the time correction scheme proposed in that article, however calling setVelocity() on a body updates the body's previous position, which essentially sets the velocity to units per delta-time-of-last-frame rather than normalizing it to something like units per second, or whatever. So really I need to scale the initial velocity I give my bodies to mean the same thing regardless of frame rate.

wmike1987 avatar Nov 18 '18 02:11 wmike1987

It does seem strange but this actually falls out of the math from position Verlet integration:

 xi+1 = xi + (xi - xi-1) + a * dt * dt

Check out this derivation, note that this assumes a constant time step. To account for a changing time step the author introduces a time correction scheme, which is what is implemented in the engine, though it's only intended for handling short dips since it's not that accurate. Hopefully that helps.

I think the formula is correct (see also Wikipedia Velocity integration).

According to my understanding, your code in Body.update calculates essentially

v[i] = (x[i] - x[i-1])
v[i+1] = v[i] + a * dt * dt
x[i+1] = x[i] + v[i+1]

However, velocities should be defined as the difference of current and previous position divided by the time step to make it "physically correct" i.e.

v[i] = (x[i] - x[i-1]) / dt
v[i+1] = v[i] + a * dt
x[i+1] = x[i] + v[i+1] * dt

This eliminates the strange dt * dt and the result of the position update is the same as before, but the velocity update is different/correct.

Qbyte248 avatar Dec 25 '20 01:12 Qbyte248

@Qbyte248 it looks like you're assuming a fixed timestep there, which as it stands the engine does not assume, so it can't be simplified or rearranged that way in this case (you'll need a dt and a dt-1 term).

The latest discussion on this topic is found in the PR #777 which intends to normalise velocities among other things, please do try that out and help review if you're interested.

liabru avatar Dec 29 '20 14:12 liabru

Closing as I think this was covered by #777 which is now released in 0.19.0 (see the release notes). Thanks again.

liabru avatar Mar 16 '23 00:03 liabru