Question about matter.js and it's update loop

Hey there!

I had a quite extensive look into phaser 3 with matter.js the last couple of weeks and am at a crossroads right now. The main issue lies within the game update loop and how matter.js works and updates with it.

I work on a 144hz monitor and was not able to get the physics simulation running at the same perceived speed on a 60hz monitor (or edge browser, which runs at 72fps on 144hz monitors). All of the matter.js examples on the phaser website run more than twice as fast at 144fps as they do at 60fps. So I guess that this is a known issue and nobody found a solution yet or it is plainly not possible.

As far as I know, it is currently not possible to limit RAF of browser to a specific framerate. Also Matter.js does not have it’s own fixed update loop, but updates together with the core game update loop, which is tied to RAF. I have no idea what matter.set60Hz; or matter.set30Hz really does other than internally changing the deltaTime of matter. It’s still updating 144 times a second, thinking it updates at a lower rate (meaning at set30Hz(), the physics update even faster!)

Even disabling autoUpdate and stepping the matter physics manually in the update loop and providing the game loops delta time does not lead to a consistent feel. It makes it behave even worse.

So my question is: Does anyone know if it’s even remotely possible to get a grip at this issue? Are there any examples out there providing a hint? If it’s not possible to get the physics simulation run consistent at a fps range of 60 to 144fps, then I have to look at a different engine.

Sorry for the long post, but I’m really lost at the moment. It seems like (almost) nobody is talking about this but it’s deal breaker for me.

Cheers!

Phaser v3.22 is going to have a variable-size delta for Matter by default.

Before Phaser v3.22, I believe you can pass getDelta in Matter’s config

{ getDelta: function (time, delta) { return delta; } }

or set the same property on the world

this.matter.world.getDelta = function (time, delta) { return delta; };
1 Like

Thanks for your quick response, I really appreciate it.

Your tip is on point and I have already tried this solution to fix the delta issues with matter (along lots of other ways) but it does not work as it should… at least not like I expected it to…

I just spend over an hour to really get behind the issue because in some cases it seemed to work and others it doesn’t and I was able to narrow it down a bit. I saw how the gravitational pull worked just as I wanted to, framerate independent, but my applied forces or manually set velocities did not. But I think I got my head around it now… I will try to fix up my prototype tomorrow and hopefully it will work framerate independent by then.

I thought that when you apply a force, it’s applied to the object as an framerate independent unit. But it seems like that the current delta is automatically taken into account. When manually setting velocities, it’s not the case and you have to integrate the delta into the velocity calculation yourself. At least it looks that way. In my debug workspace, I was able to get all the forces and velocities framerate independent with this (new found) knowledge

Thanks a lot for leading me in the right direction. Seems like I was just misunderstandig some crucial facts regarding forces and velocities.

I think I was a little to hasty with my optimism yesterday. While forces kinda work correctly and take delta times into account, objects without forces are moving completely without interferences of delta times.

Exmaple: An object without friction moving at a constant velocity (e.g in space or wahtever). The new position every update step is updated without a delta, therefore the object is moving faster on higher framerates.

I found this little thread talking about this exact issue (without any solutions, I’m afraid): https://github.com/photonstorm/phaser/issues/3957 (answer of bulboka from 19th december of 2018)

Matter.js Body.update seems very strange to me.

The velocity is not multiplied by deltaTime, when changing the position.
The force is multiplied by deltaTime squared (why squared?), though it is reset to zero every frame
after update. So strictly speaking it’s not a force but something like an impulse and there’s no reason
to multiply it by time.

Maybe all of it was done in the name of performance optimization or for some other reasons, but the
point is that Matter.js is not framerate independent in any way, no matter what timeDelta you’re
assing to it.

This is a real bummer. I don’t know if it’s really a matter.js issue or some problem with the implementation in phaser3 but I can’t really use it this way (and I’m kinda surprised that anyone can actually use it like that… >60hz monitors are not that of a niche, I would say)

I am facing the exact same problem right now ; physic is very different on a 144 Hz screen and a 60 Hz one.
I think it is a MatterJS issue https://github.com/liabru/matter-js/issues/851
The only solution I see is to use another physics engine like PlanckJS, which doesn’t have this problem.

Hi Guys… I have just hit this problem…

I have managed to limit my game update frame rate loop to 60Hz on a really fast computer with 144Hz monitor, but matter is obviously still running wild as gravity appears to be much stronger on my sons computer than it is on mine.

My game is completely broken on his machine. I have tried setting the following in create, but its made no difference.

this.matter.world.update60Hz();
this.matter.set60Hz();

— Just tested and when he sets his monitor to 60Hz its fine. So its down to his 144Hz monitor.

Do you manage a solution?
Any help much appreciated, spent at least a day on this so far.

Having done some more reading, I am really worried about this. I get the feeling that I have just spent 3 months of my life working 12 + hours a day to only find out that this is not a solvable problem. This could be a killer. Really looking for some guidance here.

Have asked on the matter.js forum as well.

If you are sure that your game is actually doing only 60 updates a second, you could set world.autoUpdate to false and just do a world.step() every frame.

I am testing that now - Thanks for getting back to me…

Thankyou very much. That is now proven to work on 144Hz monitor.

In Create…
this.matter.world.autoUpdate = false;

In update

  update(time, delta) {
        frameTime += delta;
        if (frameTime > 16.5) {
            frameTime -= 16.5;

           Game Updates


            this.matter.world.step();
            this.gameCycle++;
        }
}

I think this fairly crude, I understand there might be a way to make this better, but I don’t understand how to do it… Any suggestions ?

I don’t think frameTime is necessary. You can just do step(delta). And I would use a more exact 1000/60.

Ahh - Yes I understand, but that is my main game update loop as well. Have updated to 1000/60. Cheers again for your help

You still shouldn’t use frameTime. Always use delta, and update your game proportionally. i.e. multiply everything with delta / (1000/60). This works for every Hz setting.
Your loop is not correct, because frameTime will grow if delta is large when the game is slow for some reason. On 144 Hz it will then do a couple of too fast updates. You should at least check if delta is large, and then subtract that. And on 50 Hz your game runs at 5/6 of expected speed.

Thanks again Milton…
I’m sorry but I don’t quite understand.

What do you mean by multiply everything with delta / (1000/60).?
I’d be very grateful if you could give a code sample.

Cheers
Martin

What do you think step(delta) does? It updates the physics proportionately. So if let’s say a tablet is running at 30Hz, the engine knows it has to take bigger steps in order to keep up. And for 144Hz it takes smaller steps. thus more fluid.

Let’s take someone with a 50Hz system. so an update comes every 20ms.
Your code is tuned to a certain speed. Let’s say every tick you move x += 10.
After a second on a 60Hz system you have moved 600 positions.
After a second on a 50Hz system you have moved 500 positions.

To correct this, you should multiply with delta / (1000/60), so x += 10 * delta / (1000/60). Which makes any refresh rate move the same distance, only more fluid on higher Hz, and less on lower, but at least play as intended.

So i’ve just started testing my game on a slower machine without a dedicated GPU.
My game is much slower, (even though the monitor has a 60 hz refresh rate).

Following on from what you’ve already said, would a valid the approach to making the game run at the same speed on slower machines be to try and work out what the frame rate i’m getting is (if its less than 60) and then divide by that?

e.g. x += 10 * delta / (1000/ (average of last 10 frames if less than 60) )

Sorry if that is not correct…

That would negate any correction. On a slow system, let’s say 50 updates a second, delta is 20. So 20 / (1000/50) equals 1 again :slight_smile:
The whole point is that your game is optimized for 60 updates a second. To correct any difference to that, you have to mention the number 60.
So 20 / (1000/60) equals 1.2. So it takes bigger steps.

Got Ya. That’s super helpful. I am super slowly wrapping my head around that…
So I have multiple things that move.

Some are driven by phaser setPosition / setAngle etc, and others are driven by Matter physics. E.g. ApplyForce, set Velocity.

So I am hoping that

this.matter.world.step(delta); will take care of the matter physics movements

and

Then apply the delta as you’ve said to my other movements
Thanks so much for your kind patience. I will start testing that now, and make sure i get same the same results on different machines.

Here’s my game as it stands. https://city-saviour.web.app/
May not work if your running a fast monitor yet…

After two weeks, I have finally just about got my head around the matter problem, with the help of Antriel, Milton and others (Thanks Guys) and there is no simple answer.

There are two options for a matter in terms of timing, both with pluses and minuses. I have tried to describe them here as I understand them.

1. Fixed Timestep

Pro’s

  • Provides consistency across different computers, e.g gravity, forces etc as long as the computer is not CPU bound.

Cons.

  • If the PC is CPU Bound e.g cant cope with the amount of collisions or other stuff going on in the world, then the frame rate can drop to a crawl. Running my opening title sequence (cpu throttled x6) dropped to 4fps with a fixed timestep of 16.66

How to implement a fixed timestep - Thanks Antriel

var matterTimeStep = 16.66;
this.matter.world.autoUpdate = false;

    update(time, delta) {
            accumulator += delta;
            while(accumulator >= matterTimeStep) {
                accumulator -= matterTimeStep;

                //Game Logic - this force will be the same regardless of framerate because of fixed timing
                var force = 0.08
                player.obj.applyForce({xAngle * force, yAngle* force})

                this.matter.world.step(matterTimeStep);
            }
    }

2. Delta Timestep

Pro’s

  • Matter physics will run faster on a CPU bound PC, because the matter engine will be stepped more when the CPU can’t keep up. My opening title sequence as above (cpu throttled x6) ran at 25FPS compared to 4fps. Better for physics when game timing is not so important. However on a really fast pc, the physics is stepped more often and therefore forces in the example below are applied more often. making objects move faster.

Con’s

  • No consistency for forces such as gravity across various machines, meaning gravity and other forces will be will likely be different on different pc’s. Not good for a game.

How to implement a delta timestep - Thanks Milton

this.matter.world.autoUpdate = false;
    update(time, delta) {
          //Game Logic - apply delta to the force.

          var force = 0.08;
          //did try var force = 0.08 * delta / (1000/60), but was jumpy.

          player.obj.applyForce({xAngle * force, yAngle* force})

          this.matter.world.step(delta);
    }

I have ended up with a combination of the two methods.
Title sequences (lots of collisions) run using the delta.
Game runs with fixed timestep.

Cheers for all your help guys. I might still be missing something fundamental, please let me know.
I am just trying to document my findings for someone else.

It would be great if someone cleverer than me could sort this out…