The demo runs twice as fast on the 160hz monitor than it does on the 60hz monitor
I recorded it on my phone to show the difference in simulation speed
https://gfycat.com/HugeAmusingChameleon
I believe this is because of an assumption that requestAnimationFrame target FPS is 60, where as on a higher refresh rate RAF can be called at 140fps
Same issue occurring for me and others
I've been trying to find out how to fix this as well. Running a game, using MatterJS physics, on 2 different monitors (144hz and 60hz) is like putting on fast forward.
I think the issue is that while Matter.Runner should be able to handle this, it actually doesn't because runner.deltaMin and runner.deltaMax clamp the frame delta for stability reasons, but this always assumes a 60hz monitor.
So I'll mark this as a bug, thanks for the report. In the meantime I think the easiest fix is to use Runner.create({ fps: 120 }). I can't test this so please give it a shot and tell me if that does work.
As for detecting the refresh rate automatically, well that might actually be a little tricky, but it would probably take some testing using requestAnimationFrame. Either way I need to revisit Matter.Runner at some point and I'll take this into account.
A proper solution would be to run in a fixed timestep. Keep in mind that frame rate can be dynamic, i.e. change at any time during single game.
I had this issue with my users a while back and I fixed it by altering the deltaMin and deltaMax so that it didn't assume 60 fps.
I then had one other issue regarding monitor refresh rate and differing performance which may be worth mentioning here: setting velocity via setVelocity() currently does not normalize the velocity parameter. It currently sets the velocity to units-per-delta-time-of-last-frame, which differs with varying refresh rates. See https://github.com/liabru/matter-js/issues/637 for the issue I opened for that one.
@wmike1987 how did you go about fixing deltaMin and deltaMax so they do not assume 60 fps? I'm also interested in how you fixed the velocity issue.
Edit: Fellow googlers, I limited my fps for monitors with higher refresh rates like so below. I feel like this might be the best solution for now. This also makes it so we do not have to do any weird velocity calculations, because we'll only update the engine on specific intervals while the renderer keeps running.
You can check an example of this from a game I made for Ludum Dare 45:
馃幃 https://reutemeteut.dries.io
@liabru is this a correct implementation?
First, I declare the engine, renderer and runner.
engine = Engine.create({});
render = Render.create({
engine,
element: this.container,
options: {
width: this.width,
height: this.height,
},
} as any);
runner = (Runner as any).create({});
followed by a couple of variables that i'll be using to calculate delta (differentiating time in between frames gets rendered) and only let the engine update (using runner's tick method) when it is above the required interval.
// fps should be locked at:
const fps = 60;
// init of now to base value
const now = Date.now();
// setting then to base value
const then = this.now;
// what I want time in between frames to be
const interval = 1000 / this.fps;
// init of delta
const delta = 0;
I then run my renderer and call a custom update method.
Render.run(render);
this.update();
In my update method I call requestAnimationFrame, passing the function as a parameter. When it gets called by requestAnimationFrame, it gets passed a time variable, a total time since first called requestAnimationFrame, I calculate delta, and only call the tick method on my renderer, when it is above the locked the interval. 1000 ms / 60 fps.
public update = (time = 0) => {
requestAnimationFrame(this.update);
this.now = Date.now();
this.delta = this.now - this.then;
if (this.delta > this.interval) {
Runner.tick(runner, engine, time);
this.then = this.now - (this.delta % this.interval);
}
};
@hellos3b @driescroons ,
there are many ways how to fix this issue. I tried to suggest a solution in the issue I linked above that is independent from any hardware loop time as it identify it during the first two loops, plus for a more realistic simulation it calculates both delta and correction parameters.
Not sure if this helps your case, as it should be well tested, but if it works I don't see what this shouldn't be a sort of default generic solution.
Most helpful comment
I've been trying to find out how to fix this as well. Running a game, using MatterJS physics, on 2 different monitors (144hz and 60hz) is like putting on fast forward.