Skip to content

Commit b906463

Browse files
committed
Internally the Time class has been updated to split out the RAF and SetTimeout implementations. This cuts down the update loop workload significantly, which was causing a performance optimization bottleneck in V8.
1 parent 39cf0fb commit b906463

2 files changed

Lines changed: 133 additions & 45 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ Version 2.4 - "Katar" - in dev
253253
* Phaser.DeviceButton.ctrlKey is a boolean that holds if the control key was held down or not during the last button event.
254254
* Phaser.GamepadButton has been removed and now uses DeviceButton instead. Three internal API changes took place: `processButtonDown` is renamed to `start`, `processButtonUp` is renamed to `stop` and `processButtonFloat` is renamed to `padFloat`. If you extended GamepadButton in your own code you need to replace it with DeviceButton.
255255
* MSPointer now checks the `pointerType` property of the DOM event and if it matches 'mouse' it will update `Input.mousePointer`, rather than `Input.pointer1` (or whatever the next free Pointer was).
256+
* Time.suggestedFps is now only populated if `Time.advancedTiming` is enabled.
256257

257258
### p2.js Upgraded to version 0.7.0
258259

@@ -405,6 +406,7 @@ For the full list of p2 additions please read [their change log](https://github.
405406
* LoaderParser.bitmapFont, xmlBitmapFont and jsonBitmapFont all now return the font data rather than write it to the now deprecated PIXI.BitmapText.fonts global array.
406407
* PIXI.BitmapText has been removed as a global array, as it is no longer used.
407408
* PIXI has been made available for Phaser when using requireJS (thanks @mkristo #1923)
409+
* Internally the Time class has been updated to split out the RAF and SetTimeout implementations. This cuts down the update loop workload significantly, which was causing a performance optimization bottleneck in V8.
408410

409411
### Bug Fixes
410412

src/time/Time.js

Lines changed: 131 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ Phaser.Time = function (game) {
111111

112112
/**
113113
* The suggested frame rate for your game, based on an averaged real frame rate.
114+
* This value is only populated if `Time.advancedTiming` is enabled.
114115
*
115116
* _Note:_ This is not available until after a few frames have passed; use it after a few seconds (eg. after the menus)
116117
*
@@ -129,7 +130,7 @@ Phaser.Time = function (game) {
129130
this.slowMotion = 1.0;
130131

131132
/**
132-
* If true then advanced profiling, including the fps rate, fps min/max and msMin/msMax are updated.
133+
* If true then advanced profiling, including the fps rate, fps min/max, suggestedFps and msMin/msMax are updated.
133134
* @property {boolean} advancedTiming
134135
* @default
135136
*/
@@ -336,11 +337,49 @@ Phaser.Time.prototype = {
336337
*/
337338
update: function (time) {
338339

340+
if (this.game.raf._isSetTimeOut)
341+
{
342+
this.updateSetTimeout(time);
343+
}
344+
else
345+
{
346+
this.updateRAF(time);
347+
}
348+
349+
if (this.advancedTiming)
350+
{
351+
this.updateAdvancedTiming();
352+
}
353+
354+
// Paused but still running?
355+
if (!this.game.paused)
356+
{
357+
// Our internal Phaser.Timer
358+
this.events.update(this.time);
359+
360+
if (this._timers.length)
361+
{
362+
this.updateTimers();
363+
}
364+
}
365+
366+
},
367+
368+
/**
369+
* setTimeOut specific time update handler.
370+
* Called automatically by Time.update.
371+
*
372+
* @method Phaser.Time#updateSetTimeout
373+
* @private
374+
* @param {number} time - The current relative timestamp; see {@link Phaser.Time#now now}.
375+
*/
376+
updateSetTimeout: function (time) {
377+
339378
// Set to the old Date.now value
340379
var previousDateNow = this.time;
341380

342-
// this.time always holds Date.now, this.now may hold the RAF high resolution time value if RAF is available (otherwise it also holds Date.now)
343-
this.time = Date.now();
381+
// With SetTimeout the time value is always the same as Date.now, so no need to get it again
382+
this.time = time;
344383

345384
// Adjust accordingly.
346385
this.elapsedMS = this.time - previousDateNow;
@@ -360,64 +399,111 @@ Phaser.Time.prototype = {
360399
// time when the next call is expected if using timers
361400
this.timeCallExpected = time + this.timeToCall;
362401

363-
// count the number of time.update calls
364-
this._frameCount++;
365-
this._elapsedAccumulator += this.elapsed;
402+
// Set the physics elapsed time... this will always be 1 / this.desiredFps because we're using fixed time steps in game.update now
403+
this.physicsElapsed = 1 / this.desiredFps;
366404

367-
// occasionally recalculate the suggestedFps based on the accumulated elapsed time
368-
if (this._frameCount >= this.desiredFps * 2)
369-
{
370-
// this formula calculates suggestedFps in multiples of 5 fps
371-
this.suggestedFps = Math.floor(200 / (this._elapsedAccumulator / this._frameCount)) * 5;
372-
this._frameCount = 0;
373-
this._elapsedAccumulator = 0;
374-
}
405+
this.physicsElapsedMS = this.physicsElapsed * 1000;
406+
407+
},
408+
409+
/**
410+
* raf specific time update handler.
411+
* Called automatically by Time.update.
412+
*
413+
* @method Phaser.Time#updateRAF
414+
* @private
415+
* @param {number} time - The current relative timestamp; see {@link Phaser.Time#now now}.
416+
*/
417+
updateRAF: function (time) {
418+
419+
// Set to the old Date.now value
420+
var previousDateNow = this.time;
421+
422+
// this.time always holds Date.now, this.now may hold the RAF high resolution time value if RAF is available (otherwise it also holds Date.now)
423+
this.time = Date.now();
424+
425+
// Adjust accordingly.
426+
this.elapsedMS = this.time - previousDateNow;
427+
428+
// 'now' is currently still holding the time of the last call, move it into prevTime
429+
this.prevTime = this.now;
430+
431+
// update 'now' to hold the current time
432+
this.now = time;
433+
434+
// elapsed time between previous call and now
435+
this.elapsed = this.now - this.prevTime;
375436

376437
// Set the physics elapsed time... this will always be 1 / this.desiredFps because we're using fixed time steps in game.update now
377438
this.physicsElapsed = 1 / this.desiredFps;
378439

379440
this.physicsElapsedMS = this.physicsElapsed * 1000;
380441

381-
if (this.advancedTiming)
382-
{
383-
this.msMin = Math.min(this.msMin, this.elapsed);
384-
this.msMax = Math.max(this.msMax, this.elapsed);
442+
},
385443

386-
this.frames++;
444+
/**
445+
* Handles the updating of the Phaser.Timers (if any)
446+
* Called automatically by Time.update.
447+
*
448+
* @method Phaser.Time#updateTimers
449+
* @private
450+
*/
451+
updateTimers: function () {
452+
453+
// Any game level timers
454+
var i = 0;
455+
var len = this._timers.length;
387456

388-
if (this.now > this._timeLastSecond + 1000)
457+
while (i < len)
458+
{
459+
if (this._timers[i].update(this.time))
460+
{
461+
i++;
462+
}
463+
else
389464
{
390-
this.fps = Math.round((this.frames * 1000) / (this.now - this._timeLastSecond));
391-
this.fpsMin = Math.min(this.fpsMin, this.fps);
392-
this.fpsMax = Math.max(this.fpsMax, this.fps);
393-
this._timeLastSecond = this.now;
394-
this.frames = 0;
465+
// Timer requests to be removed
466+
this._timers.splice(i, 1);
467+
len--;
395468
}
396469
}
397470

398-
// Paused but still running?
399-
if (!this.game.paused)
471+
},
472+
473+
/**
474+
* Handles the updating of the advanced timing values (if enabled)
475+
* Called automatically by Time.update.
476+
*
477+
* @method Phaser.Time#updateAdvancedTiming
478+
* @private
479+
*/
480+
updateAdvancedTiming: function () {
481+
482+
// count the number of time.update calls
483+
this._frameCount++;
484+
this._elapsedAccumulator += this.elapsed;
485+
486+
// occasionally recalculate the suggestedFps based on the accumulated elapsed time
487+
if (this._frameCount >= this.desiredFps * 2)
400488
{
401-
// Our internal Phaser.Timer
402-
this.events.update(this.time);
489+
// this formula calculates suggestedFps in multiples of 5 fps
490+
this.suggestedFps = Math.floor(200 / (this._elapsedAccumulator / this._frameCount)) * 5;
491+
this._frameCount = 0;
492+
this._elapsedAccumulator = 0;
493+
}
403494

404-
// Any game level timers
405-
var i = 0;
406-
var len = this._timers.length;
495+
this.msMin = Math.min(this.msMin, this.elapsed);
496+
this.msMax = Math.max(this.msMax, this.elapsed);
407497

408-
while (i < len)
409-
{
410-
if (this._timers[i].update(this.time))
411-
{
412-
i++;
413-
}
414-
else
415-
{
416-
// Timer requests to be removed
417-
this._timers.splice(i, 1);
418-
len--;
419-
}
420-
}
498+
this.frames++;
499+
500+
if (this.now > this._timeLastSecond + 1000)
501+
{
502+
this.fps = Math.round((this.frames * 1000) / (this.now - this._timeLastSecond));
503+
this.fpsMin = Math.min(this.fpsMin, this.fps);
504+
this.fpsMax = Math.max(this.fpsMax, this.fps);
505+
this._timeLastSecond = this.now;
506+
this.frames = 0;
421507
}
422508

423509
},

0 commit comments

Comments
 (0)