hellspawn_bg Posted September 24, 2014 Share Posted September 24, 2014 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 60hzupdate - 122 callsPhaser time - 2.017 secReal Time - 2.027 sec Test on 50hzupdate - 121 callsPhaser time - 2.029 secReal 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 More sharing options...
JUL Posted September 24, 2014 Share Posted September 24, 2014 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 More sharing options...
lewster32 Posted September 24, 2014 Share Posted September 24, 2014 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 More sharing options...
lewster32 Posted September 24, 2014 Share Posted September 24, 2014 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. clark 1 Link to comment Share on other sites More sharing options...
chg Posted September 24, 2014 Share Posted September 24, 2014 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 More sharing options...
ashes999 Posted September 24, 2014 Share Posted September 24, 2014 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 More sharing options...
Recommended Posts