Skip to content

Commit eec8466

Browse files
committed
Merge pull request phaserjs#1363 from pnstickne/wip-time-clarify
Time - clarify, Game update expose, and Sprite lifespan update
2 parents 7aaa63e + e28197e commit eec8466

3 files changed

Lines changed: 116 additions & 50 deletions

File tree

src/core/Game.js

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -287,46 +287,58 @@ Phaser.Game = function (width, height, renderer, parent, state, transparent, ant
287287
*/
288288
this._codePaused = false;
289289

290+
/**
291+
* The number of the logic update applied this render frame, starting from 0.
292+
*
293+
* The first update is `updateNumber === 0` and the last update is `updateNumber === updatesThisFrame.`
294+
* @property {number} updateNumber
295+
* @protected
296+
*/
297+
this.updateNumber = 0;
298+
299+
/**
300+
* Number of logic updates expected to occur this render frame;
301+
* will be 1 unless there are catch-ups required (and allowed).
302+
* @property {integer} updatesThisFrame
303+
* @protected
304+
*/
305+
this.updatesThisFrame = 1;
306+
290307
/**
291308
* @property {number} _deltaTime - accumulate elapsed time until a logic update is due
292309
* @private
293310
*/
294311
this._deltaTime = 0;
295312

296313
/**
297-
* @property {number} count - Update iteration counter.
298-
* @protected
299-
*/
300-
this.count = 0;
301-
302-
/**
303-
* @property {number} _lastCount - remember how many 'catch-up' iterations were used on the logicUpdate last frame
304-
* @private
305-
*/
314+
* @property {number} _lastCount - remember how many 'catch-up' iterations were used on the logicUpdate last frame
315+
* @private
316+
*/
306317
this._lastCount = 0;
307318

308319
/**
309-
* @property {number} _spiralling - if the 'catch-up' iterations are spiralling out of control, this counter is incremented
310-
* @private
311-
*/
320+
* @property {number} _spiralling - if the 'catch-up' iterations are spiralling out of control, this counter is incremented
321+
* @private
322+
*/
312323
this._spiralling = 0;
313324

314325
/**
315-
* @property {Phaser.Signal} fpsProblemNotifier - if the game is struggling to maintain the desiredFps, this signal will be dispatched
316-
* to suggest that the program adjust it's fps closer to the Time.suggestedFps value
317-
* @public
318-
*/
326+
* If the game is struggling to maintain the desired FPS, this signal will be dispatched.
327+
* The desired/chosen FPS should probably be closer to the {@link Phaser.Time#suggestedFps} value.
328+
* @property {Phaser.Signal} fpsProblemNotifier
329+
* @public
330+
*/
319331
this.fpsProblemNotifier = new Phaser.Signal();
320332

321333
/**
322-
* @property {boolean} forceSingleUpdate - Should the game loop force a logic update, regardless of the delta timer? Set to true if you know you need this. You can toggle it on the fly.
323-
*/
334+
* @property {boolean} forceSingleUpdate - Should the game loop force a logic update, regardless of the delta timer? Set to true if you know you need this. You can toggle it on the fly.
335+
*/
324336
this.forceSingleUpdate = false;
325337

326338
/**
327-
* @property {number} _nextNotification - the soonest game.time.time value that the next fpsProblemNotifier can be dispatched
328-
* @private
329-
*/
339+
* @property {number} _nextNotification - the soonest game.time.time value that the next fpsProblemNotifier can be dispatched
340+
* @private
341+
*/
330342
this._nextFpsNotification = 0;
331343

332344
// Parse the configuration object (if any)
@@ -710,32 +722,39 @@ Phaser.Game.prototype = {
710722

711723
// call the game update logic multiple times if necessary to "catch up" with dropped frames
712724
// unless forceSingleUpdate is true
713-
this.count = 0;
725+
var count = 0;
726+
727+
this.updatesThisFrame = Math.floor(this._deltaTime / slowStep);
728+
if (this.forceSingleUpdate)
729+
{
730+
this.updatesThisFrame = Math.min(1, this.updatesThisFrame);
731+
}
714732

715733
while (this._deltaTime >= slowStep)
716734
{
717735
this._deltaTime -= slowStep;
736+
this.updateNumber = count;
718737
this.updateLogic(1.0 / this.time.desiredFps);
719-
this.count++;
738+
count++;
720739

721-
if (this.forceSingleUpdate && this.count === 1)
740+
if (this.forceSingleUpdate && count === 1)
722741
{
723742
break;
724743
}
725744
}
726745

727746
// detect spiralling (if the catch-up loop isn't fast enough, the number of iterations will increase constantly)
728-
if (this.count > this._lastCount)
747+
if (count > this._lastCount)
729748
{
730749
this._spiralling++;
731750
}
732-
else if (this.count < this._lastCount)
751+
else if (count < this._lastCount)
733752
{
734753
// looks like it caught up successfully, reset the spiral alert counter
735754
this._spiralling = 0;
736755
}
737756

738-
this._lastCount = this.count;
757+
this._lastCount = count;
739758

740759
// call the game render update exactly once every frame unless we're playing catch-up from a spiral condition
741760
this.updateRender(this._deltaTime / slowStep);

src/gameobjects/Sprite.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,12 @@ Phaser.Sprite = function (game, x, y, key, frame) {
116116
this.health = 1;
117117

118118
/**
119-
* If you would like the Sprite to have a lifespan once 'born' you can set this to a positive value. Handy for particles, bullets, etc.
120-
* The lifespan is decremented by game.time.elapsed each update, once it reaches zero the kill() function is called.
121-
* @property {number} lifespan - The lifespan of the Sprite (in ms) before it will be killed.
119+
* To given a Sprite a lifespan, in milliseconds, once 'born' you can set this to a positive value. Handy for particles, bullets, etc.
120+
*
121+
* The lifespan is decremented by `game.time.physicsElapsed` (converted to milliseconds) each logic update,
122+
* and {@link Phaser.Sprite.kill kill} is called once the lifespan reaches 0.
123+
*
124+
* @property {number} lifespan
122125
* @default
123126
*/
124127
this.lifespan = 0;
@@ -249,7 +252,7 @@ Phaser.Sprite.prototype.preUpdate = function() {
249252
// Only apply lifespan decrement in the first updateLogic pass.
250253
if (this.lifespan > 0 && this.game.count === 0)
251254
{
252-
this.lifespan -= this.game.time.elapsedMS;
255+
this.lifespan -= 1000 * this.game.time.physicsElapsed;
253256

254257
if (this.lifespan <= 0)
255258
{

src/time/Time.js

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,55 +16,92 @@ Phaser.Time = function (game) {
1616

1717
/**
1818
* @property {Phaser.Game} game - Local reference to game.
19+
* @protected
1920
*/
2021
this.game = game;
2122

2223
/**
23-
* @property {number} time - This always contains the Date.now value.
24+
* The `Date.now()` value when the time was last updated.
25+
* @property {integer} time
2426
* @protected
2527
*/
2628
this.time = 0;
2729

2830
/**
29-
* @property {number} prevTime - The time the previous update occurred.
31+
* The `now` when the previous update occurred.
32+
* @property {number} prevTime
3033
* @protected
3134
*/
3235
this.prevTime = 0;
3336

3437
/**
35-
* @property {number} now - The high resolution RAF timer value (if RAF is available) or Date.now if using setTimeout.
38+
* An increasing value representing cumulative milliseconds since an undisclosed epoch.
39+
*
40+
* This value must _not_ be used with `Date.now()`.
41+
*
42+
* The source may either be from a high-res source (eg. if RAF is available) or the standard Date.now;
43+
* the value can only be relied upon within a particular game instance.
44+
*
45+
* @property {number} now
3646
* @protected
3747
*/
3848
this.now = 0;
3949

4050
/**
41-
* @property {number} elapsed - Elapsed time since the last frame. In ms if running under setTimeout or an integer if using RAF.
51+
* Elapsed time since the last time update, in milliseconds, based on `now`.
52+
*
53+
* This value _may_ include time that the game is paused/inactive.
54+
*
55+
* _Note:_ This is updated only once per game loop - even if multiple logic update steps are done.
56+
* Use {@link Phaser.Timer#physicsTime physicsTime} as a basis of game/logic calculations instead.
57+
*
58+
* @property {number} elapsed
4259
* @see Phaser.Time.time
4360
* @protected
4461
*/
4562
this.elapsed = 0;
4663

4764
/**
48-
* @property {number} elapsedMS - The time in ms since the last update. Will vary dramatically based on system performance, do not use for physics calculations!
65+
* The time in ms since the last time update, in milliseconds, based on `time`.
66+
*
67+
* This value is corrected for game pauses and will be "about zero" after a game is resumed.
68+
*
69+
* _Note:_ This is updated once per game loop - even if multiple logic update steps are done.
70+
* Use {@link Phaser.Timer#physicsTime physicsTime} as a basis of game/logic calculations instead.
71+
*
72+
* @property {integer} elapsedMS
4973
* @protected
5074
*/
5175
this.elapsedMS = 0;
5276

5377
/**
54-
* @property {number} pausedTime - Records how long the game has been paused for. Is reset each time the game pauses.
55-
* @protected
78+
* The physics update delta, in fractional seconds.
79+
*
80+
* This should be used as an applicable multiplier by all logic update steps (eg. `preUpdate/postUpdate/update`)
81+
* to ensure consistent game timing.
82+
*
83+
* With fixed-step updates this normally equivalent to `1.0 / desiredFps`.
84+
*
85+
* @property {number} physicsElapsed
5686
*/
57-
this.pausedTime = 0;
87+
this.physicsElapsed = 0;
5888

5989
/**
60-
* @property {number} desiredFps - The desired frame rate of your game.
90+
* The desired frame rate of the game.
91+
*
92+
* This is used is used to calculate the physic/logic multiplier and how to apply catch-up logic updates.
93+
*
94+
* @property {number} desiredFps
6195
* @default
6296
*/
6397
this.desiredFps = 60;
6498

6599
/**
66-
* @property {number} suggestedFps = The suggested frame rate for your game, based on an averaged real frame rate.
67-
* NOTE: Not available until after a few frames have passed, it is recommended to use this after a few seconds (eg. after the menus)
100+
* The suggested frame rate for your game, based on an averaged real frame rate.
101+
*
102+
* _Note:_ This is not available until after a few frames have passed; use it after a few seconds (eg. after the menus)
103+
*
104+
* @property {number} suggestedFps
68105
* @default
69106
*/
70107
this.suggestedFps = null;
@@ -109,27 +146,34 @@ Phaser.Time = function (game) {
109146
this.msMax = 0;
110147

111148
/**
112-
* @property {number} physicsElapsed - The physics motion value as used by Arcade Physics. Equivalent to 1.0 / Time.desiredFps.
149+
* The number of render frames record in the last second. Only calculated if Time.advancedTiming is true.
150+
* @property {integer} frames
113151
*/
114-
this.physicsElapsed = 0;
152+
this.frames = 0;
115153

116154
/**
117-
* @property {number} frames - The number of frames record in the last second. Only calculated if Time.advancedTiming is true.
155+
* The `time` when the game was last paused.
156+
* @property {number} pausedTime
157+
* @protected
118158
*/
119-
this.frames = 0;
159+
this.pausedTime = 0;
120160

121161
/**
122-
* @property {number} pauseDuration - Records how long the game was paused for in miliseconds.
162+
* Records how long the game was last paused, in miliseconds.
163+
* (This is not updated until the game is resumed.)
164+
* @property {number} pauseDuration
123165
*/
124166
this.pauseDuration = 0;
125167

126168
/**
127169
* @property {number} timeToCall - The value that setTimeout needs to work out when to next update
170+
* @protected
128171
*/
129172
this.timeToCall = 0;
130173

131174
/**
132175
* @property {number} timeExpected - The time when the next call is expected when using setTimer to control the update loop
176+
* @protected
133177
*/
134178
this.timeExpected = 0;
135179

@@ -272,13 +316,13 @@ Phaser.Time.prototype = {
272316
update: function (time) {
273317

274318
// Set to the old Date.now value
275-
this.elapsedMS = this.time;
319+
var previousDateNow = this.time;
276320

277321
// 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)
278322
this.time = Date.now();
279323

280324
// Adjust accorindlgy.
281-
this.elapsedMS = this.time - this.elapsedMS;
325+
this.elapsedMS = this.time - previousDateNow;
282326

283327
// 'now' is currently still holding the time of the last call, move it into prevTime
284328
this.prevTime = this.now;
@@ -446,4 +490,4 @@ Phaser.Time.prototype = {
446490

447491
};
448492

449-
Phaser.Time.prototype.constructor = Phaser.Time;
493+
Phaser.Time.prototype.constructor = Phaser.Time;

0 commit comments

Comments
 (0)