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

Engine.update doesn't scale time correctly

Open Technostalgic opened this issue 8 years ago • 12 comments

So this seems like a pretty gamebreaking issue to me, but basically it seems like the only timestep that can correctly calculate physics is 1/60th of a second. I tried lowering the step to 10% if that and it seems like the only thing affected is the velocity. The bodies' angular velocity made them rotate just as fast as they did with a timescale of 1.0, also the collisions were off, even with a restitution of 1.0, the bodies didn't bounce at all

EDIT: Here's a case I threw together look at line 16

Technostalgic avatar Dec 15 '16 02:12 Technostalgic

+1. Causing major problems for me at the moment trying to synchronize my server and client.

I was before using pretty simple updating logic where I would get the delta time each tick and just engine.update(deltaTime);

This was changed to constantly updating the engine in 16 ms intervals to help the client and the server stay in sync and all of a sudden all the constants I tweaked (player acceleration, gravity, jump velocity) were completely wrong. Going back through at the moment and retweaking everything to match the old version.

This seems like a very high priority issue IMO. Pretty core for a physics engine.

kujukuju avatar Dec 30 '16 08:12 kujukuju

Just as a heads up, I'm not really versed in physics engines, so if I have made any wrong assumptions or have missed something fundamental please let me know.

I'm having what I think is the same issue with high values of dt (when FPS is dropping) when using Matter to develop a simple game.

@Technostalgic I used your codepen to put together my use case, thanks! https://codepen.io/nullorvoid/pen/xdEbXj

Changing line 90 between updateMatter(OK); and updateMatter(BROKEN); you can see the difference in the way the boxes interact, they manage to get into a pretty inconsistent state.

In this sample, when we set dt to high it will appear faster because the tick of the animation loop is running much faster than the physics, but I do not think the speed it is running is directly related to the issue in the engine.

For the collisions that are overlapping I guess they are running into collision tunneling? or the calculations are being done based on the the time at dt rather than the time at the collision (not interpolating backwards?) which would mean you would have higher velocity in the calculation? Or the point of impact is not correctly done? (Guessing)

I had a quick dig around in the code to see if I could initially identify the problem and potential fixes to the code itself before looking at work around solutions.

I found that bodies do take into account dt when updating https://github.com/liabru/matter-js/blob/0.10.0/src/body/Body.js#L534

however in the collision system I'm not sure how this part works https://github.com/liabru/matter-js/blob/master/src/collision/Resolver.js#L70 it does not seem to take into account the time and interpolate? I'm not sure how this should be corrected but it seems like it would be a problem if it was not interpolated at high dt?

Except looking into Matter more deeply is there anything that I am doing wrong? Or any solutions that have been tried?

I have thought about ticking the physics engine at a fixed interval, but that will have a noticeable effect in low fps environments if I only tick it once per frame. The game itself will look like it's running slower although it will not cause errors it's not the desired effect I would like.

The second is to tick the physics engine in smaller increments but for the full dt. ie if dt was 32, call the engine update twice with 16. This seems like a hack and would negatively effect performance of any device that has low FPS to start with, with a slow device it takes between 10-20ms to do the physics update

Splitting the second option out into a webworker might solve some of this problem, but will also require a lot of work to move positions of bodies in matter to the drawing engine of the game via events. It also might need to have items tweened between positions rather than the update loop, this could get quite complex pretty quickly.

Any ideas would be appreciated.

nullorvoid avatar Apr 24 '17 07:04 nullorvoid

@nullorvoid For what it's worth, I've tried to run https://github.com/liabru/matter-js/blob/ccd/build/matter.js from the ccd branch on your codepen, and it doesn't solve the problem.

ronkorving avatar Apr 27 '17 02:04 ronkorving

I'm also experiencing problems with time scaling. It is not only the delta you pass in to update but also the engine.timing.timeScale property. Objects where I set the velocity directly through Body.setVelocity seem to ignore time scaling while objects where I apply a force works correctly.

jakobmulvad avatar May 14 '17 14:05 jakobmulvad

I am experiencing the same behavior as @jakobmulvad.

BrittMcDanel avatar Mar 29 '18 18:03 BrittMcDanel

You guys might want to use a constant time interval or jump ship. I'm pretty sure this library is dead.

kujukuju avatar Mar 29 '18 19:03 kujukuju

yeah I've been just using constant intervals.

Technostalgic avatar Mar 30 '18 01:03 Technostalgic

I've been trying to run the engine on node.js as close to browser as possible.
I noticed the docs suggest setInterval + Engine.update, but I've had some bad experience with this. I think it's better to use Runner.tick, as mentioned in #101.

There are two ways to do this, either with a requestAnimtationFrame polyfill for node, or to use setInterval + Runner.tick. I'm not 100% sure if this is correct, but I looked in the code, and made a demo: https://jsfiddle.net/472qa9mh/ . The demo creates three identical worlds, and use the same setup for Runner, which is 60 fps, but with a setInterval of 10, 30 and 60 fps to simulate lag.

I would expect all triangles to land simultaneously, but at least for me the middle and last one are almost identical, even when the middle has half the update cycle.

eirikb avatar Jul 07 '18 12:07 eirikb

@eirikb Unfortunately, this is an issue with the Matter.js library and for as far as I'm aware there's not much you can do about it unless you figure out a way to solve it in the source. You might just want to ensure that the engine always runs at 30fps for example, and adjust for any additional lag by calling it twice if the framerate ends up being below 30fps.

oli414 avatar Jul 07 '18 13:07 oli414

@oli414 I'm not sure I understand. I should not use Runner.tick (or Runner at all)? Do you have an example?

I tried simply setting Runner to have 30 fps, but then it became even worse. I noticed that I can't have a setInterval of greater than 30 fps, so then requestAnimationFrame (on browser) might be very wrong? Here is a demo: https://jsfiddle.net/472qa9mh/2/

eirikb avatar Jul 08 '18 11:07 eirikb

@eirikb requestAnimationFrame runs at 60 fps (or at least tries to). The reason I would suggest running at 30 fps instead of 60 fps is that you'll have a smaller chance of running into the issue due to different frame rates. This depends of course on the resources you have available.

oli414 avatar Jul 08 '18 12:07 oli414

If you are using MatterJS browser and need deterministic:

https://stackoverflow.com/a/77872867/4421162

SUCHiDEV avatar Jan 24 '24 12:01 SUCHiDEV