Timer.timeCap is a new setting allowing your Timers to protect against unexpectedly large delta timers.

This commit is contained in:
photonstorm 2014-04-28 13:22:29 +01:00
parent 95fe57e4fe
commit 838027a93b
4 changed files with 85 additions and 30 deletions

View file

@ -130,6 +130,7 @@ Version 2.0.4 - "Mos Shirare" - in development
* Color.RGBtoString converts an rgba color into a # or 0x color string.
* Color.HSVColorWheel will return an array with 360 color objects for each segment of an HSV color wheel, you can optionally set the saturation and value amounts.
* Color.HSLColorWheel will return an array with 360 color objects for each segment of an HSL color wheel, you can optionally set the saturation and lightness amounts.
* Timer.timeCap is a new setting allowing your Timers to protect against unexpectedly large delta timers.
### Bug Fixes

View file

@ -233,6 +233,7 @@ Phaser.SoundManager.prototype = {
/**
* Stops all the sounds in the game.
*
* @method Phaser.SoundManager#stopAll
*/
stopAll: function () {
@ -249,6 +250,7 @@ Phaser.SoundManager.prototype = {
/**
* Pauses all the sounds in the game.
*
* @method Phaser.SoundManager#pauseAll
*/
pauseAll: function () {
@ -264,7 +266,8 @@ Phaser.SoundManager.prototype = {
},
/**
* resumes every sound in the game.
* Resumes every sound in the game.
*
* @method Phaser.SoundManager#resumeAll
*/
resumeAll: function () {
@ -281,6 +284,7 @@ Phaser.SoundManager.prototype = {
/**
* Decode a sound by its assets key.
*
* @method Phaser.SoundManager#decode
* @param {string} key - Assets key of the sound to be decoded.
* @param {Phaser.Sound} [sound] - Its buffer will be set to decoded data.
@ -313,6 +317,7 @@ Phaser.SoundManager.prototype = {
/**
* Updates every sound in the game.
*
* @method Phaser.SoundManager#update
*/
update: function () {
@ -340,6 +345,7 @@ Phaser.SoundManager.prototype = {
/**
* Adds a new Sound into the SoundManager.
*
* @method Phaser.SoundManager#add
* @param {string} key - Asset key for the sound.
* @param {number} [volume=1] - Default value for the volume.

View file

@ -86,6 +86,11 @@ Phaser.Time = function (game) {
*/
this.deltaCap = 0;
/**
* @property {number} timeCap - If the difference in time between two frame updates exceeds this value, the frame time is reset to avoid huge elapsed counts.
*/
this.timeCap = 1000;
/**
* @property {number} frames - The number of frames record in the last second. Only calculated if Time.advancedTiming is true.
*/
@ -212,7 +217,7 @@ Phaser.Time.prototype = {
*
* @method Phaser.Time#update
* @protected
* @param {number} time - The current timestamp, either performance.now or Date.now depending on the browser.
* @param {number} time - The current timestamp.
*/
update: function (time) {
@ -222,6 +227,15 @@ Phaser.Time.prototype = {
this.elapsed = this.now - this.time;
// spike-dislike
if (this.game.stage.disableVisibilityChange && 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 = 1 / 30;
}
// Calculate physics elapsed, ensure it's > 0, use 1/60 as a fallback
this.physicsElapsed = this.elapsed / 1000 || 1 / 60;

View file

@ -42,6 +42,12 @@ Phaser.Timer = function (game, autoDestroy) {
*/
this.expired = false;
/**
* @property {number} elapsed - Elapsed time since the last frame (in ms).
* @protected
*/
this.elapsed = 0;
/**
* @property {array<Phaser.TimerEvent>} events - An array holding all of this timers Phaser.TimerEvent objects. Use the methods add, repeat and loop to populate it.
*/
@ -59,6 +65,11 @@ Phaser.Timer = function (game, autoDestroy) {
*/
this.nextTick = 0;
/**
* @property {number} timeCap - If the difference in time between two frame updates exceeds this value, the event times are reset to avoid catch-up situations.
*/
this.timeCap = 1000;
/**
* @property {boolean} paused - The paused state of the Timer. You can pause the timer by calling Timer.pause() and Timer.resume() or by the game pausing.
* @readonly
@ -369,7 +380,8 @@ Phaser.Timer.prototype = {
},
/**
* The main Timer update event, called automatically by the Game clock.
* The main Timer update event, called automatically by Phaser.Time.update.
*
* @method Phaser.Timer#update
* @protected
* @param {number} time - The time from the core game clock.
@ -382,7 +394,18 @@ Phaser.Timer.prototype = {
return true;
}
this.elapsed = time - this._now;
this._now = time;
// spike-dislike
if (this.game.stage.disableVisibilityChange && 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 need to adjust the TimerEvents and nextTick.
this.adjustEvents(time - this.elapsed);
}
this._marked = 0;
// Clears events marked for deletion and resets _len and _i to 0.
@ -487,6 +510,43 @@ Phaser.Timer.prototype = {
},
/**
* Adjusts the time of all pending events and the nextTick by the given baseTime.
*
* @method Phaser.Timer#adjustEvents
*/
adjustEvents: function (baseTime) {
for (var i = 0; i < this.events.length; i++)
{
if (!this.events[i].pendingDelete)
{
// Work out how long there would have been from when the game paused until the events next tick
var t = this.events[i].tick - baseTime;
if (t < 0)
{
t = 0;
}
// Add the difference on to the time now
this.events[i].tick = this._now + t;
}
}
var d = this.nextTick - baseTime;
if (d < 0)
{
this.nextTick = this._now;
}
else
{
this.nextTick = this._now + d;
}
},
/**
* Resumes the Timer and updates all pending events.
*
@ -502,33 +562,7 @@ Phaser.Timer.prototype = {
this._pauseTotal += this.game.time.pauseDuration;
this._now = this.game.time.now;
for (var i = 0; i < this.events.length; i++)
{
if (!this.events[i].pendingDelete)
{
// Work out how long there would have been from when the game paused until the events next tick
var t = this.events[i].tick - this._pauseStarted;
if (t < 0)
{
t = 0;
}
// Add the difference on to the time now
this.events[i].tick = this._now + t;
}
}
var d = this.nextTick - this._pauseStarted;
if (d < 0)
{
this.nextTick = this._now;
}
else
{
this.nextTick = this._now + d;
}
this.adjustEvents(this._pauseStarted);
this.paused = false;
this._codePaused = false;