Jump to content

game.time depends on the monitor refresh rate


hellspawn_bg
 Share

Recommended Posts

I recently came across on a really strange behavior with game.time. What I am trying to do is to update my character position regardless of the monitor refresh rate, i.e regardless if my monitor is setup on 60hz, or 50hz, I want to move my character the same amount of pixels for the same amount of time. In a previous topic, I have been advised to update the position at a factor of the elapsed time since the last frame.

// Get the time in seconds since the last framevar deltaTime = game.time.elapsed / 1000;// Move the character to the right at 500 pixels per second, regardless of frameratecharacter.x += 500 * deltaTime;

Doing so surprisingly didn't fixed my problem and my character was still moving slower at 50hz than on 60hz. Digging into the issue showed that the math was correct, but the game.time is falling behind the 'real' time when running on 50hz. I have setup a simple example, which shows this behaviour. I am moving a ball from the left side of the screen to the right. Once the ball leaves the screen, I determ what time has passed both using game.time and Date(). Running this example on 60hz shows similar values, while running on 50hz shows a big difference between both times with game.time falling behind from 'real' time.

test.prototype = {        this.ball = null,    this.phaserTime = 0,    this.startTime = 0,        this.timeSet = false;        this.collisionDetected = false;        preload: function() {        this.game.load.image('img', 'ball.png');    },        create: function() {                this.ball = this.game.add.sprite(0, this.game.world.centerY, 'img');                this.game.physics.arcade.enable(this.ball);                this.ball.checkWorldBounds = true;        this.ball.events.onOutOfBounds.add(this.worldCollide, this);    },        update:function() {                if(this.collisionDetected) {            return;        }                if(!this.timeSet) {            this.startTime = Date.now();            this.phaserTime = 0;                        this.timeSet = true;        }                var deltaTime = this.game.time.elapsed / 1000;                this.ball.x += 300 * deltaTime;        this.phaserTime += deltaTime;    },    worldCollide: function() {        this.collisionDetected = true;        var realTime = (Date.now() - this.startTime) / 1000;                 var deltaTime = this.game.time.elapsed / 1000;             this.phaserTime += deltaTime;                console.log('Phaser time', this.phaserTime);        console.log('Real Time', realTime);    }}
Test on 60hz
update - 122 calls
Phaser time - 2.017 sec
Real Time - 2.027 sec
 
Test on 50hz
update - 121 calls
Phaser time - 2.029 sec
Real Time - 2.411 sec

 

If someone can explain this behavior I would be really grateful as I really want to make my game independent from the monitor frequency.

Link to comment
Share on other sites

I can't explain but I can tell you that those 90's games (snes/genesis) had the same issue.

 

For instance the european version of the game "streets of rage" was slower than the US and Japanese version.

because of the 50/60hz standards...

 

Not only the game action, the music too ...

Link to comment
Share on other sites

The issue seen on older games is due to them usually not having any frame skipping code. These games typically just assumed the system would always be running at a set speed, and so 'choppiness' didn't really exist, instead you got 'slowdown' in games. Frame skipping to keep a constant speed is a relatively recent thing in gaming.

 

As for the issue itself, I can only think that somewhere in Phaser or pixi's code an assumption is being made that RAF will ideally run at 60hz, which is the assumption I incorrectly believed until very recently.

Link to comment
Share on other sites

There are various lines relating to 1/60th of a second, but I can't see anything obviously wrong. There's game.time.timeCap which is set to 1 / 60 * 1000 (~16.67ms) so you could maybe try tweaking this value and deltaCap (which confusingly is in seconds, so 1 / 60 [~0.0167s] for 60fps) to see if they affect the outcome.

Link to comment
Share on other sites

I'm going to go out on a limb and back timeCap being only around 16.67ms and this code from time/Time.js as the culprits -

        //  spike-dislike        if (this.elapsed > this.timeCap)        {            //  For some reason the time between now and the last time the game was updated was larger than our timeCap            //  This can happen if the Stage.disableVisibilityChange is true and you swap tabs, which makes the raf pause.            //  In this case we'll drop to some default values to stop the game timers going nuts.            this.elapsed = this.timeCap;        }

It makes sense to "pause" the game for some of the time delta is it is too big, but >16ms is just not that big, I think timeCap should default to a number like 1000 ms or more. My hunch is that it should be something much larger than even the worst conceivably playable framerate, and should just stop the game from having to work with unexpected huge time deltas (when they get too much bigger than what is tested for the game and they would be bound to create some strange behaviour)

Link to comment
Share on other sites

One approach taken by other engines (like XNA) to deal with large spikes is to simply chunk them up into digestable pieces; and this is done all the time. This prevents, among other things, issues like "large spikes cause objects to pass through stuff instead of colliding."

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

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