matter-js
matter-js copied to clipboard
Engine.update doesn't scale time correctly
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
+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.
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 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.
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.
I am experiencing the same behavior as @jakobmulvad.
You guys might want to use a constant time interval or jump ship. I'm pretty sure this library is dead.
yeah I've been just using constant intervals.
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 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 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 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.
If you are using MatterJS browser and need deterministic:
https://stackoverflow.com/a/77872867/4421162