Jump to content

Frame rate independent movement


kurhlaa
 Share

Recommended Posts

Hi,

While it should be an easy question, I can't get a fixed movement speed. By "fixed" I mean frame rate independent. According to the manuals it could be done inside update function like this:

function update(time, delta) {
    ...
    container.body.setVelocityX(speed * delta);
    ...
}

.. where "container" is a normal Phaser 3 container and "speed" is predefined.

The problem is that I still get noticeably different speeds (for example, small vs big canvas). I check it by measuring a time to get from point A to point B.

How can this be improved/fixed? Do I need to turn on something that is turned off by default?

Link to comment
Share on other sites

@tips4design, with modifying position I loose collisions and my player goes through the tilemap's tiles. Speed is small enough. I try to init tilemap collisions like this:

...
groundLayer = map.createDynamicLayer('ground', groundTiles, 0, 0);
groundLayer.setCollisionByExclusion([-1]);
...
scene.physics.add.collider(container, groundLayer);
...

and move player with:

container.object.x += speed * delta;

 

Do I need to enable collisions in some other way? With setVelocityX() collisions work fine.

Link to comment
Share on other sites

If you are using a physics engine, you need to call its update using fixed timestep. Both Arcade and matter.js have that available, if you look at the docs. Though I'm not sure it's properly implemented.

In comes down to doing what is described here: https://gafferongames.com/post/fix_your_timestep/, basically decoupling render and physics update. I also talked about that here:

 

Link to comment
Share on other sites

@Antriel, thanks for info and link! However, I'm very new to Phaser 3, I need some more help and tips. This is what I am trying now as a game JavaScript base:

class PlatformerScene extends Phaser.Scene {
    constructor() {
        super({ key: 'PlatformerScene' })
        this.accumulator = 0;
        this.fps = 60;  // Physics checks 60 times/s
        this.physicsTimestep = 1000 / this.fps;

        console.log("constructor");
    }

    preload() {
        console.log("preload");
    }

    create() {
        console.log("create");
    }

    update(timestamp, elapsed) {
        console.log("update");

        this.accumulator += elapsed;
        while (this.accumulator >= this.physicsTimestep) {
            this.accumulator -= this.physicsTimestep;
            this.physics.update(this.physicsTimestep);
        }
        this.render(timestamp, elapsed);
    }
}


var config = {
    type: Phaser.AUTO,
    width:  window.innerWidth,
    height: window.innerHeight,
    backgroundColor: '#000404',
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: 300 },
            debug: false
        }
    },
    scene: PlatformerScene
}

game = new Phaser.Game(config);

Is this the right way for decoupling render and physics update?

Also of course I get 2 errors about unknown functions:

  • this.physics.update(this.physicsTimestep);
  • this.render(timestamp, elapsed);

What are they and how to get them working properly? Can you add basic examples to my code?

 

Link to comment
Share on other sites

Is this.render(timestamp, elapsed) logically the same as function update(time, delta) from default Phaser.Scene in my first post, so I just need to copy the content?

If Yes - another question stays about calling physics update method.

Link to comment
Share on other sites

Phaser's Arcade Physics already uses the step delta. You just need to assign a velocity and Phaser will do the rest.

container.body.setVelocityX(speed);

If all you need is objects moving at (very nearly) the same speed, regardless of frame rate, that's it.

Link to comment
Share on other sites

@samme that would be very nice :) then why my game becomes extremely slow on some PC when FPS drops to 10-15 for some reason? Not just skipping some frames/positions to save the same total speed, it is much slower visually.

I use Phaser 3.10.1

Link to comment
Share on other sites

@Antriel, just to clarify - you agree that with the latest Phaser 3 version and default update/movement function it should be enough to get the same movement speed on different FPS/devices?

function update(time, delta) {
    ...
    container.body.setVelocityX(speed);
    ...
}

Physics func. runs in a separate loop too?!

Link to comment
Share on other sites

Hi @Antriel,

I've recorded a Performance profile in a Chromium browser when the speed became extremely slow. Picture is attached.

If I understand this right:

- yellow columns represent timestamps when Phaser functions were triggered (by window.requestAnimationFrame ?)

- I don't see the code in between of these columns.

 

If step is 1 physics calculation iteration (it is inside of these columns, light yellow color) - we clearly see, that there are still no fixed timesteps. Physics calculations still depend on FPS ? In my case the distance between columns is ~80-100ms. Ideally there should be another columns (physics) with a 16ms step, right?

 

However, after some time (during recording) things start to move much faster, but FPS is still ~10-15, and there is still nothing among these yellow columns.

fps.png

Link to comment
Share on other sites

I'm not really sure what's happening here from just the pic. It looks as if the RAF was throttled by the browser, considering the total time is just ~7ms.

32 minutes ago, kurhlaa said:

If step is 1 physics calculation iteration (it is inside of these columns, light yellow color) - we clearly see, that there are still no fixed timesteps. Physics calculations still depend on FPS ? In my case the distance between columns is ~80-100ms. Ideally there should be another columns (physics) with a 16ms step, right?

No, there shouldn't be any additional columns. You do physics along with the render, but you do enough physics steps to catch up if needed (or none if not enough time passed).

If the movement rate (not FPS) isn't stable, it means the fixed timestep isn't implemented properly.

Link to comment
Share on other sites

Quote

If the movement rate (not FPS) isn't stable, it means the fixed timestep isn't implemented properly.

This is how i actually conducted my tests.

Two users simultaneously pressing left arrow on two completely different machines for the same amount of time, should have their characters arrive at the exact same map coordinates regardless if 1 is getting 30fps and the other is getting 60.  If they dont, you messed up.

It also is the way in how you can compensate for lag if you're trying to sync a multiplayer game.  It's a lot of craziness involved to simulate a synced looking illusion with a multiplayer game when users have different frame rates and different connections combined.

Link to comment
Share on other sites

50 minutes ago, aylictal said:

It also is the way in how you can compensate for lag if you're trying to sync a multiplayer game.  It's a lot of craziness involved to simulate a synced looking illusion with a multiplayer game when users have different frame rates and different connections combined.

In a multiplayer game you would want to make your own syncing solution as Phaser smooths out the delta time.

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...