Phaser.Timer is now feature complete and fully documented. You can create Phaser.TimerEvents on a Timer and lots of new examples have been provided.

This commit is contained in:
photonstorm 2014-01-09 00:59:37 +00:00
parent 35e61172e1
commit c6c579e6b3
16 changed files with 812 additions and 328 deletions

View file

@ -99,6 +99,7 @@ module.exports = function (grunt) {
'src/tween/Easing.js', 'src/tween/Easing.js',
'src/time/Time.js', 'src/time/Time.js',
'src/time/Timer.js', 'src/time/Timer.js',
'src/time/TimerEvent.js',
'src/animation/AnimationManager.js', 'src/animation/AnimationManager.js',
'src/animation/Animation.js', 'src/animation/Animation.js',
'src/animation/Frame.js', 'src/animation/Frame.js',

View file

@ -59,6 +59,7 @@ Significant API changes:
New features: New features:
* Phaser.Timer is now feature complete and fully documented. You can create Phaser.TimerEvents on a Timer and lots of new examples have been provided.
* Gamepad API support has been added with lots of new examples (thanks Karl Macklin) * Gamepad API support has been added with lots of new examples (thanks Karl Macklin)
* Phaser.Game constructor can now be passed a single object containing all of your game settings + Stage settings. Useful for advanced configurations. * Phaser.Game constructor can now be passed a single object containing all of your game settings + Stage settings. Useful for advanced configurations.
* The width/height given to Phaser.Game can now be percentages, i.e. "100%" will set the width to the maximum window innerWidth. * The width/height given to Phaser.Game can now be percentages, i.e. "100%" will set the width to the maximum window innerWidth.
@ -102,6 +103,7 @@ New Examples:
* Particles - Rain by Jens Anders Bakke. * Particles - Rain by Jens Anders Bakke.
* Particles - Snow by Jens Anders Bakke. * Particles - Snow by Jens Anders Bakke.
* Groups - Nested Groups - showing how to embed one Group into another Group. * Groups - Nested Groups - showing how to embed one Group into another Group.
* Time - Lots of new examples showing how to use the Phaser.Timer class.
Updates: Updates:
@ -132,7 +134,7 @@ Updates:
* Button.clearFrames method has been added. * Button.clearFrames method has been added.
* Device.quirksMode is a boolean that informs you if the page is in strict (false) or quirks (true) mode. * Device.quirksMode is a boolean that informs you if the page is in strict (false) or quirks (true) mode.
* Canvas.getOffset now runs a strict/quirks check and uses document.documentElement when calculating scrollTop and scrollLeft to avoid Chrome console warnings. * Canvas.getOffset now runs a strict/quirks check and uses document.documentElement when calculating scrollTop and scrollLeft to avoid Chrome console warnings.
* The Time class now has three new methods: addEvent, repeatEvent and loopEvent. See the new Timer examples to show how to use them. * The Time class now has its own Phaser.Timer which you can access through game.time.events. See the new Timer examples to show how to use them.
Bug Fixes: Bug Fixes:

View file

@ -113,6 +113,7 @@
<script src="$path/src/time/Time.js"></script> <script src="$path/src/time/Time.js"></script>
<script src="$path/src/time/Timer.js"></script> <script src="$path/src/time/Timer.js"></script>
<script src="$path/src/time/TimerEvent.js"></script>
<script src="$path/src/animation/AnimationManager.js"></script> <script src="$path/src/animation/AnimationManager.js"></script>
<script src="$path/src/animation/Animation.js"></script> <script src="$path/src/animation/Animation.js"></script>

View file

@ -350,6 +350,10 @@
"file": "group+transform.js", "file": "group+transform.js",
"title": "group transform" "title": "group transform"
}, },
{
"file": "nested+groups.js",
"title": "nested groups"
},
{ {
"file": "recyling.js", "file": "recyling.js",
"title": "recyling" "title": "recyling"
@ -797,6 +801,28 @@
"title": "swap tiles" "title": "swap tiles"
} }
], ],
"time": [
{
"file": "basic+looped+event.js",
"title": "basic looped event"
},
{
"file": "basic+repeat+event.js",
"title": "basic repeat event"
},
{
"file": "basic+timed+event.js",
"title": "basic timed event"
},
{
"file": "remove+event.js",
"title": "remove event"
},
{
"file": "timed+slideshow.js",
"title": "timed slideshow"
}
],
"tweens": [ "tweens": [
{ {
"file": "bounce.js", "file": "bounce.js",

View file

@ -118,6 +118,7 @@
<script src="../src/time/Time.js"></script> <script src="../src/time/Time.js"></script>
<script src="../src/time/Timer.js"></script> <script src="../src/time/Timer.js"></script>
<script src="../src/time/TimerEvent.js"></script>
<script src="../src/animation/AnimationManager.js"></script> <script src="../src/animation/AnimationManager.js"></script>
<script src="../src/animation/Animation.js"></script> <script src="../src/animation/Animation.js"></script>

View file

@ -118,6 +118,7 @@
<script src="../src/time/Time.js"></script> <script src="../src/time/Time.js"></script>
<script src="../src/time/Timer.js"></script> <script src="../src/time/Timer.js"></script>
<script src="../src/time/TimerEvent.js"></script>
<script src="../src/animation/AnimationManager.js"></script> <script src="../src/animation/AnimationManager.js"></script>
<script src="../src/animation/Animation.js"></script> <script src="../src/animation/Animation.js"></script>

View file

@ -0,0 +1,43 @@
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, render: render });
function preload() {
game.load.image('ball', 'assets/sprites/pangball.png');
}
var counter = 0;
var text = 0;
function create() {
game.stage.backgroundColor = '#6688ee';
text = game.add.text(game.world.centerX, game.world.centerY, 'Counter: 0', { font: "64px Arial", fill: "#ffffff", align: "center" });
text.anchor.setTo(0.5, 0.5);
// Here we'll create a basic looped event.
// A looped event is like a repeat event but with no limit, it will literally repeat itself forever, or until
// The first parameter is how long to wait before the event fires. In this case 1 second (you could pass in 1000 as the value as well.)
// The next two parameters are the function to call ('updateCounter') and the context under which that will happen.
game.time.events.loop(Phaser.Timer.SECOND, updateCounter, this);
}
function updateCounter() {
counter++;
text.content = 'Counter: ' + counter;
}
function render() {
game.debug.renderText("Time until event: " + game.time.events.duration.toFixed(0), 32, 32);
game.debug.renderText("Next tick: " + game.time.events.next.toFixed(0), 32, 64);
}

View file

@ -0,0 +1,47 @@
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, render: render });
function preload() {
game.load.image('ball', 'assets/sprites/pangball.png');
}
function create() {
game.stage.backgroundColor = '#6688ee';
// Here we'll create a basic repeating event.
// The way a repeating event works is that it is placed into the queue once,
// and when it runs its 'repeatCounter' is reduced by 1 and it's moved back into the queue again.
// To this end the queue will only ever have 1 event actually in it.
// The first parameter is how long to wait before the event fires. In this case 2 seconds (you could pass in 2000 as the value as well.)
// The second parameter is how many times the event will run in total. Here we'll run it 10 times.
// The next two parameters are the function to call ('createBall') and the context under which that will happen.
// Once the event has been called 10 times it will never be called again.
game.time.events.repeat(Phaser.Timer.SECOND * 2, 10, createBall, this);
}
function createBall() {
// A bouncey ball sprite just to visually see what's going on.
var ball = game.add.sprite(game.world.randomX, 0, 'ball');
ball.body.gravity.y = 200;
ball.body.bounce.y = 0.5;
ball.body.collideWorldBounds = true;
}
function render() {
game.debug.renderText("Time until event: " + game.time.events.duration.toFixed(0), 32, 32);
game.debug.renderText("Next tick: " + game.time.events.next.toFixed(0), 32, 64);
}

View file

@ -0,0 +1,37 @@
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, render: render });
function preload() {
game.load.image('bisley', 'assets/pics/alex-bisleys_horsy_5.png');
}
var picture;
function create() {
game.stage.backgroundColor = '#6688ee';
picture = game.add.sprite(game.world.centerX, game.world.centerY, 'bisley');
picture.anchor.setTo(0.5, 0.5);
// Here we'll create a basic timed event. This is a one-off event, it won't repeat or loop:
// The first parameter is how long to wait before the event fires. In this case 4 seconds (you could pass in 4000 as the value as well.)
// The next parameter is the function to call ('fadePicture') and finally the context under which that will happen.
game.time.events.add(Phaser.Timer.SECOND * 4, fadePicture, this);
}
function fadePicture() {
game.add.tween(picture).to( { alpha: 0 }, 2000, Phaser.Easing.Linear.None, true);
}
function render() {
game.debug.renderText("Time until event: " + game.time.events.duration, 32, 32);
}

View file

@ -0,0 +1,55 @@
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { create: create, render: render });
var counters = [];
var text = [];
var timerEvents = [];
var i = 9;
function create() {
game.stage.backgroundColor = '#6688ee';
for (var i = 0; i < 10; i++)
{
counters[i] = 0;
text[i] = game.add.text(game.world.centerX, 80 + (40 * i), 'Counter ' + i + ' = 0', { font: "32px Arial", fill: "#ffffff", align: "center" });
text[i].anchor.setTo(0.5, 0);
// Here we create our timer events. They will be set to loop at a random value between 250ms and 1000ms
timerEvents[i] = game.time.events.loop(game.rnd.integerInRange(250, 1000), updateCounter, this, i);
}
// Click to remove
game.input.onDown.add(removeCounter, this);
}
function updateCounter(idx) {
counters[idx]++;
text[idx].content = 'Counter ' + idx + ' = ' + counters[idx];
}
function removeCounter() {
if (i >= 0)
{
// Removes the timer, starting with the top one and working down
game.time.events.remove(timerEvents[i]);
// Just updates the text
text[i].style.fill = '#3344aa';
text[i].content = 'Counter ' + i + ' removed';
i--;
}
}
function render() {
game.debug.renderText("Queued events: " + game.time.events.length + ' - click to remove', 32, 32);
}

View file

@ -0,0 +1,94 @@
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, render: render });
function preload() {
game.load.image('picture1', 'assets/pics/cougar_sanity_train.png');
game.load.image('picture2', 'assets/pics/cougar-face_of_nature.png');
game.load.image('picture3', 'assets/pics/destop-rewarding.png');
game.load.image('picture4', 'assets/pics/destop-unknown.png');
game.load.image('picture5', 'assets/pics/questar.png');
game.load.image('picture6', 'assets/pics/seven_seas_andromeda_fairfax.png');
game.load.image('picture7', 'assets/pics/slayer-sorry_im_the_beast.png');
}
var pictureA;
var pictureB;
var timer;
var current = 3;
function create() {
game.stage.backgroundColor = '#000';
pictureA = game.add.sprite(game.world.centerX, game.world.centerY, 'picture1');
pictureA.anchor.setTo(0.5, 0.5);
pictureA.scale.setTo(2, 2);
pictureB = game.add.sprite(game.world.centerX, game.world.centerY, 'picture2');
pictureB.anchor.setTo(0.5, 0.5);
pictureB.scale.setTo(2, 2);
pictureB.alpha = 0;
// Create our Timer
timer = game.time.create(false);
// Set a TimerEvent to occur after 3 seconds
timer.add(3000, fadePictures, this);
// Start the timer running - this is important!
// It won't start automatically, allowing you to hook it to button events and the like.
timer.start();
}
function fadePictures() {
// Cross-fade the two pictures
var tween;
if (pictureA.alpha === 1)
{
tween = game.add.tween(pictureA).to( { alpha: 0 }, 2000, Phaser.Easing.Linear.None, true);
game.add.tween(pictureB).to( { alpha: 1 }, 2000, Phaser.Easing.Linear.None, true);
}
else
{
game.add.tween(pictureA).to( { alpha: 1 }, 2000, Phaser.Easing.Linear.None, true);
tween = game.add.tween(pictureB).to( { alpha: 0 }, 2000, Phaser.Easing.Linear.None, true);
}
// When the cross-fade is complete we swap the image being shown by the now hidden picture
tween.onComplete.add(changePicture, this);
}
function changePicture() {
if (pictureA.alpha === 0)
{
pictureA.loadTexture('picture' + current);
}
else
{
pictureB.loadTexture('picture' + current);
}
current++;
if (current > 7)
{
current = 1;
}
// And set a new TimerEvent to occur after 3 seconds
timer.add(3000, fadePictures, this);
}
function render() {
game.debug.renderText("Time until event: " + timer.duration.toFixed(0), 10, 20);
}

View file

@ -14,6 +14,8 @@ function create() {
game.stage.backgroundColor = '#007236'; game.stage.backgroundColor = '#007236';
// Every second we will call the addSprite function. This will happen 10 times and then stop. // Every second we will call the addSprite function. This will happen 10 times and then stop.
// The final parameter is the one that will be sent to the addSprite function and in this case is the sprite key. // The final parameter is the one that will be sent to the addSprite function and in this case is the sprite key.
game.time.repeatEvent(Phaser.Timer.SECOND, 10, addSprite, this, 'mushroom'); game.time.repeatEvent(Phaser.Timer.SECOND, 10, addSprite, this, 'mushroom');

View file

@ -255,9 +255,11 @@ Phaser.Canvas = {
*/ */
setImageRenderingCrisp: function (canvas) { setImageRenderingCrisp: function (canvas) {
canvas.style['image-rendering'] = 'optimizeSpeed';
canvas.style['image-rendering'] = 'crisp-edges'; canvas.style['image-rendering'] = 'crisp-edges';
canvas.style['image-rendering'] = '-moz-crisp-edges'; canvas.style['image-rendering'] = '-moz-crisp-edges';
canvas.style['image-rendering'] = '-webkit-optimize-contrast'; canvas.style['image-rendering'] = '-webkit-optimize-contrast';
canvas.style['image-rendering'] = 'optimize-contrast';
canvas.style.msInterpolationMode = 'nearest-neighbor'; canvas.style.msInterpolationMode = 'nearest-neighbor';
return canvas; return canvas;

View file

@ -14,121 +14,132 @@
*/ */
Phaser.Time = function (game) { Phaser.Time = function (game) {
/** /**
* @property {Phaser.Game} game - Local reference to game. * @property {Phaser.Game} game - Local reference to game.
*/ */
this.game = game; this.game = game;
/** /**
* @property {number} _started - The time at which the Game instance started. * @property {number} physicsElapsed - The elapsed time calculated for the physics motion updates.
* @private */
*/ this.physicsElapsed = 0;
this._started = 0;
/** /**
* @property {number} _timeLastSecond - The time (in ms) that the last second counter ticked over. * @property {number} time - Game time counter.
* @private */
*/ this.time = 0;
this._timeLastSecond = 0;
/** /**
* @property {number} _pauseStarted - The time the game started being paused. * @property {number} pausedTime - Records how long the game has been paused for. Is reset each time the game pauses.
* @private */
*/ this.pausedTime = 0;
this._pauseStarted = 0;
/** /**
* @property {number} physicsElapsed - The elapsed time calculated for the physics motion updates. * @property {number} now - The time right now.
*/ */
this.physicsElapsed = 0; this.now = 0;
/** /**
* @property {number} time - Game time counter. * @property {number} elapsed - Elapsed time since the last frame (in ms).
*/ */
this.time = 0; this.elapsed = 0;
/** /**
* @property {number} pausedTime - Records how long the game has been paused for. Is reset each time the game pauses. * @property {number} fps - Frames per second.
*/ */
this.pausedTime = 0; this.fps = 0;
/** /**
* @property {number} now - The time right now. * @property {number} fpsMin - The lowest rate the fps has dropped to.
*/ */
this.now = 0; this.fpsMin = 1000;
/** /**
* @property {number} elapsed - Elapsed time since the last frame (in ms). * @property {number} fpsMax - The highest rate the fps has reached (usually no higher than 60fps).
*/ */
this.elapsed = 0; this.fpsMax = 0;
/** /**
* @property {number} fps - Frames per second. * @property {number} msMin - The minimum amount of time the game has taken between two frames.
*/ * @default
this.fps = 0; */
this.msMin = 1000;
/** /**
* @property {number} fpsMin - The lowest rate the fps has dropped to. * @property {number} msMax - The maximum amount of time the game has taken between two frames.
*/ */
this.fpsMin = 1000; this.msMax = 0;
/** /**
* @property {number} fpsMax - The highest rate the fps has reached (usually no higher than 60fps). * @property {number} frames - The number of frames record in the last second.
*/ */
this.fpsMax = 0; this.frames = 0;
/** /**
* @property {number} msMin - The minimum amount of time the game has taken between two frames. * @property {number} pauseDuration - Records how long the game was paused for in miliseconds.
* @default */
*/ this.pauseDuration = 0;
this.msMin = 1000;
/** /**
* @property {number} msMax - The maximum amount of time the game has taken between two frames. * @property {number} timeToCall - The value that setTimeout needs to work out when to next update
*/ */
this.msMax = 0; this.timeToCall = 0;
/** /**
* @property {number} frames - The number of frames record in the last second. * @property {number} lastTime - Internal value used by timeToCall as part of the setTimeout loop
*/ */
this.frames = 0; this.lastTime = 0;
/** /**
* @property {number} pauseDuration - Records how long the game was paused for in miliseconds. * @property {Phaser.Timer} events - This is a Phaser.Timer object bound to the master clock to which you can add timed events.
*/ */
this.pauseDuration = 0; this.events = new Phaser.Timer(this.game, false);
/** /**
* @property {number} timeToCall - The value that setTimeout needs to work out when to next update * @property {number} _started - The time at which the Game instance started.
*/
this.timeToCall = 0;
/**
* @property {number} lastTime - Internal value used by timeToCall as part of the setTimeout loop
*/
this.lastTime = 0;
/**
* @property {Phaser.Timer} _timer - Internal Phaser.Timer object.
* @private
*/
this._timer = new Phaser.Timer(this.game, false);
/**
* @property {boolean} _justResumed - Internal value used to recover from the game pause state.
* @private * @private
*/ */
this._justResumed = false; this._started = 0;
/** /**
* @property {array} _timers - Internal store of Phaser.Timer objects. * @property {number} _timeLastSecond - The time (in ms) that the last second counter ticked over.
* @private * @private
*/ */
this._timers = []; this._timeLastSecond = 0;
// Listen for game pause/resume events /**
this.game.onPause.add(this.gamePaused, this); * @property {number} _pauseStarted - The time the game started being paused.
this.game.onResume.add(this.gameResumed, this); * @private
*/
this._pauseStarted = 0;
/**
* @property {boolean} _justResumed - Internal value used to recover from the game pause state.
* @private
*/
this._justResumed = false;
/**
* @property {array} _timers - Internal store of Phaser.Timer objects.
* @private
*/
this._timers = [];
/**
* @property {number} _len - Temp. array length variable.
* @private
*/
this._len = 0;
/**
* @property {number} _i - Temp. array counter variable.
* @private
*/
this._i = 0;
// Listen for game pause/resume events
this.game.onPause.add(this.gamePaused, this);
this.game.onResume.add(this.gameResumed, this);
}; };
@ -137,77 +148,29 @@ Phaser.Time.prototype = {
/** /**
* @method Phaser.Time#boot * @method Phaser.Time#boot
*/ */
boot: function () { boot: function () {
this._timer.start(); this.events.start();
},
/**
* Adds a new Event to this Timer. The event will fire after the given amount of 'delay' in milliseconds has passed, once the Timer has started running.
* Call Timer.start() once you have added all of the Events you require for this Timer. The delay is in relation to when the Timer starts, not the time it was added.
* @method Phaser.Time#addEvent
* @param {number} delay - The number of milliseconds that should elapse before the Timer will call the given callback.
* @param {function} callback - The callback that will be called when the Timer event occurs.
* @param {object} callbackContext - The context in which the callback will be called.
* @param {...} arguments - The values to be sent to your callback function when it is called.
*/
addEvent: function (delay, callback, callbackContext) {
this._timer.create(delay, false, 0, callback, callbackContext, Array.prototype.splice.call(arguments, 3));
},
/**
* Adds a new Event to this Timer that will repeat for the given number of iterations.
* The event will fire after the given amount of 'delay' milliseconds has passed once the Timer has started running.
* Call Timer.start() once you have added all of the Events you require for this Timer. The delay is in relation to when the Timer starts, not the time it was added.
* @method Phaser.Time#repeatEvent
* @param {number} delay - The number of milliseconds that should elapse before the Timer will call the given callback.
* @param {number} repeatCount - The number of times to repeat the event.
* @param {function} callback - The callback that will be called when the Timer event occurs.
* @param {object} callbackContext - The context in which the callback will be called.
* @param {...} arguments - The values to be sent to your callback function when it is called.
*/
repeatEvent: function (delay, repeatCount, callback, callbackContext) {
this._timer.create(delay, false, repeatCount, callback, callbackContext, Array.prototype.splice.call(arguments, 4));
},
/**
* Adds a new looped Event to this Timer that will repeat forever or until the Timer is stopped.
* The event will fire after the given amount of 'delay' milliseconds has passed once the Timer has started running.
* Call Timer.start() once you have added all of the Events you require for this Timer. The delay is in relation to when the Timer starts, not the time it was added.
* @method Phaser.Time#loopEvent
* @param {number} delay - The number of milliseconds that should elapse before the Timer will call the given callback.
* @param {function} callback - The callback that will be called when the Timer event occurs.
* @param {object} callbackContext - The context in which the callback will be called.
* @param {...} arguments - The values to be sent to your callback function when it is called.
*/
loopEvent: function (delay, callback, callbackContext) {
this._timer.create(delay, true, 0, callback, callbackContext, Array.prototype.splice.call(arguments, 3));
}, },
/** /**
* Creates a new stand-alone Phaser.Timer object. * Creates a new stand-alone Phaser.Timer object.
* @method Phaser.Time#create * @method Phaser.Time#create
* @param {boolean} [autoDestroy=true] - A Timer that is set to automatically destroy itself will do so after all of its events have been dispatched (assuming no looping events). * @param {boolean} [autoDestroy=true] - A Timer that is set to automatically destroy itself will do so after all of its events have been dispatched (assuming no looping events).
* @return {Phaser.Timer} The Timer object that was created. * @return {Phaser.Timer} The Timer object that was created.
*/ */
create: function (autoDestroy) { create: function (autoDestroy) {
if (typeof autoDestroy === 'undefined') { autoDestroy = true; } if (typeof autoDestroy === 'undefined') { autoDestroy = true; }
var timer = new Phaser.Timer(this.game, autoDestroy); var timer = new Phaser.Timer(this.game, autoDestroy);
this._timers.push(timer); this._timers.push(timer);
return timer; return timer;
}, },
/** /**
* Remove all Timer objects, regardless of their state. * Remove all Timer objects, regardless of their state.
@ -215,147 +178,164 @@ Phaser.Time.prototype = {
*/ */
removeAll: function () { removeAll: function () {
for (var i = 0; i < this._timers.length; i++) for (var i = 0; i < this._timers.length; i++)
{ {
this._timers[i].destroy(); this._timers[i].destroy();
} }
this._timers = []; this._timers = [];
}, },
/** /**
* Updates the game clock and calculate the fps. This is called automatically by Phaser.Game. * Updates the game clock and calculate the fps. This is called automatically by Phaser.Game.
* @method Phaser.Time#update * @method Phaser.Time#update
* @param {number} time - The current timestamp, either performance.now or Date.now depending on the browser. * @param {number} time - The current timestamp, either performance.now or Date.now depending on the browser.
*/ */
update: function (time) { update: function (time) {
this.now = time; this.now = time;
if (this._justResumed) if (this._justResumed)
{
this.time = this.now;
this._justResumed = false;
}
this.timeToCall = this.game.math.max(0, 16 - (time - this.lastTime));
this.elapsed = this.now - this.time;
this.msMin = this.game.math.min(this.msMin, this.elapsed);
this.msMax = this.game.math.max(this.msMax, this.elapsed);
this.frames++;
if (this.now > this._timeLastSecond + 1000)
{
this.fps = Math.round((this.frames * 1000) / (this.now - this._timeLastSecond));
this.fpsMin = this.game.math.min(this.fpsMin, this.fps);
this.fpsMax = this.game.math.max(this.fpsMax, this.fps);
this._timeLastSecond = this.now;
this.frames = 0;
}
this.time = this.now;
this.lastTime = time + this.timeToCall;
this.physicsElapsed = 1.0 * (this.elapsed / 1000);
// Clamp the delta
if (this.physicsElapsed > 1)
{
this.physicsElapsed = 1;
}
// Paused?
if (this.game.paused)
{
this.pausedTime = this.now - this._pauseStarted;
}
// Our internal timer
this._timer.update(this.now);
var i = 0;
var len = this._timers.length;
while (i < len)
{ {
if (this._timers[i].update(this.now)) this.time = this.now;
{ this._justResumed = false;
i++;
}
else
{
this._timers.splice(i, 1);
len--; this.events.resume();
for (var i = 0; i < this._timers.length; i++)
{
this._timers[i].resume();
} }
} }
}, this.timeToCall = this.game.math.max(0, 16 - (time - this.lastTime));
/** this.elapsed = this.now - this.time;
* Called when the game enters a paused state.
* @method Phaser.Time#gamePaused
* @private
*/
gamePaused: function () {
this._pauseStarted = this.now; this.msMin = this.game.math.min(this.msMin, this.elapsed);
this.msMax = this.game.math.max(this.msMax, this.elapsed);
}, this.frames++;
/** if (this.now > this._timeLastSecond + 1000)
* Called when the game resumes from a paused state. {
* @method Phaser.Time#gameResumed this.fps = Math.round((this.frames * 1000) / (this.now - this._timeLastSecond));
* @private this.fpsMin = this.game.math.min(this.fpsMin, this.fps);
*/ this.fpsMax = this.game.math.max(this.fpsMax, this.fps);
gameResumed: function () { this._timeLastSecond = this.now;
this.frames = 0;
}
// Level out the elapsed timer to avoid spikes this.time = this.now;
this.time = Date.now(); this.lastTime = time + this.timeToCall;
this.pauseDuration = this.pausedTime; this.physicsElapsed = 1.0 * (this.elapsed / 1000);
this._justResumed = true;
}, // Clamp the delta
if (this.physicsElapsed > 1)
{
this.physicsElapsed = 1;
}
/** // Paused?
* The number of seconds that have elapsed since the game was started. if (this.game.paused)
* @method Phaser.Time#totalElapsedSeconds {
* @return {number} this.pausedTime = this.now - this._pauseStarted;
*/ }
totalElapsedSeconds: function() { else
return (this.now - this._started) * 0.001; {
}, // Our internal Phaser.Timer
this.events.update(this.now);
/** // Any game level timers
* How long has passed since the given time. this._i = 0;
* @method Phaser.Time#elapsedSince this._len = this._timers.length;
* @param {number} since - The time you want to measure against.
* @return {number} The difference between the given time and now.
*/
elapsedSince: function (since) {
return this.now - since;
},
/** while (this._i < this._len)
* How long has passed since the given time (in seconds). {
* @method Phaser.Time#elapsedSecondsSince if (this._timers[this._i].update(this.now))
* @param {number} since - The time you want to measure (in seconds). {
* @return {number} Duration between given time and now (in seconds). this._i++;
*/ }
elapsedSecondsSince: function (since) { else
return (this.now - since) * 0.001; {
}, this._timers.splice(this._i, 1);
/** this._len--;
* Resets the private _started value to now. }
* @method Phaser.Time#reset }
*/ }
reset: function () {
this._started = this.now; },
}
/**
* Called when the game enters a paused state.
* @method Phaser.Time#gamePaused
* @private
*/
gamePaused: function () {
this._pauseStarted = this.now;
this.events.pause();
for (var i = 0; i < this._timers.length; i++)
{
this._timers[i].pause();
}
},
/**
* Called when the game resumes from a paused state.
* @method Phaser.Time#gameResumed
* @private
*/
gameResumed: function () {
// Level out the elapsed timer to avoid spikes
this.time = Date.now();
this.pauseDuration = this.pausedTime;
this._justResumed = true;
},
/**
* The number of seconds that have elapsed since the game was started.
* @method Phaser.Time#totalElapsedSeconds
* @return {number}
*/
totalElapsedSeconds: function() {
return (this.now - this._started) * 0.001;
},
/**
* How long has passed since the given time.
* @method Phaser.Time#elapsedSince
* @param {number} since - The time you want to measure against.
* @return {number} The difference between the given time and now.
*/
elapsedSince: function (since) {
return this.now - since;
},
/**
* How long has passed since the given time (in seconds).
* @method Phaser.Time#elapsedSecondsSince
* @param {number} since - The time you want to measure (in seconds).
* @return {number} Duration between given time and now (in seconds).
*/
elapsedSecondsSince: function (since) {
return (this.now - since) * 0.001;
},
/**
* Resets the private _started value to now.
* @method Phaser.Time#reset
*/
reset: function () {
this._started = this.now;
}
}; };

View file

@ -25,24 +25,11 @@ Phaser.Timer = function (game, autoDestroy) {
this.game = game; this.game = game;
/** /**
* @property {number} _started - The time at which this Timer instance started running. * @property {boolean} running - True if the Timer is actively running. Do not switch this boolean, if you wish to pause the timer then use Timer.pause() instead.
* @private
* @default
*/
this._started = 0;
/**
* @property {boolean} running - True if the Timer is actively running.
* @default * @default
*/ */
this.running = false; this.running = false;
/**
* @property {boolean} pauseWithGame - If true then the timer will update itself automatically if the game pauses, otherwise it will carry on dispatching regardless.
* @default
*/
this.pauseWithGame = true;
/** /**
* @property {boolean} autoDestroy - A Timer that is set to automatically destroy itself will do so after all of its events have been dispatched (assuming no looping events). * @property {boolean} autoDestroy - A Timer that is set to automatically destroy itself will do so after all of its events have been dispatched (assuming no looping events).
*/ */
@ -50,12 +37,13 @@ Phaser.Timer = function (game, autoDestroy) {
/** /**
* @property {boolean} expired - An expired Timer is one in which all of its events have been dispatched and none are pending. * @property {boolean} expired - An expired Timer is one in which all of its events have been dispatched and none are pending.
* @readonly
* @default * @default
*/ */
this.expired = false; this.expired = false;
/** /**
* @property {array} events - An array holding the event data. * @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.
*/ */
this.events = []; this.events = [];
@ -65,17 +53,50 @@ Phaser.Timer = function (game, autoDestroy) {
this.onComplete = new Phaser.Signal(); this.onComplete = new Phaser.Signal();
/** /**
* @property {number} nextTick - The time the next tick will occur. Do not set this value directly. * @property {number} nextTick - The time the next tick will occur.
* @readonly
* @protected * @protected
*/ */
this.nextTick = 0; this.nextTick = 0;
/**
* @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
* @default
*/
this.paused = false;
/**
* @property {number} _started - The time at which this Timer instance started running.
* @private
* @default
*/
this._started = 0;
/**
* @property {number} _pauseStarted - The time the game started being paused.
* @private
*/
this._pauseStarted = 0;
/** /**
* @property {number} _now - The current start-time adjusted time. * @property {number} _now - The current start-time adjusted time.
* @protected * @private
*/ */
this._now = 0; this._now = 0;
/**
* @property {number} _len - Temp. array length variable.
* @private
*/
this._len = 0;
/**
* @property {number} _i - Temp. array counter variable.
* @private
*/
this._i = 0;
}; };
/** /**
@ -105,8 +126,8 @@ Phaser.Timer.QUARTER = 250;
Phaser.Timer.prototype = { Phaser.Timer.prototype = {
/** /**
* Creates a new Event on this Timer. * Creates a new TimerEvent on this Timer. Use the methods add, repeat or loop instead of this.
* @method Phaser.Timer#_create * @method Phaser.Timer#create
* @private * @private
* @param {number} delay - The number of milliseconds that should elapse before the Timer will call the given callback. * @param {number} delay - The number of milliseconds that should elapse before the Timer will call the given callback.
* @param {boolean} loop - Should the event loop or not? * @param {boolean} loop - Should the event loop or not?
@ -114,9 +135,10 @@ Phaser.Timer.prototype = {
* @param {function} callback - The callback that will be called when the Timer event occurs. * @param {function} callback - The callback that will be called when the Timer event occurs.
* @param {object} callbackContext - The context in which the callback will be called. * @param {object} callbackContext - The context in which the callback will be called.
* @param {array} arguments - The values to be sent to your callback function when it is called. * @param {array} arguments - The values to be sent to your callback function when it is called.
* @return {Phaser.TimerEvent} The Phaser.TimerEvent object that was created.
*/ */
create: function (delay, loop, repeatCount, callback, callbackContext, args) { create: function (delay, loop, repeatCount, callback, callbackContext, args) {
console.log(arguments);
var tick = delay; var tick = delay;
if (this.running) if (this.running)
@ -124,20 +146,16 @@ console.log(arguments);
tick += this._now; tick += this._now;
} }
this.events.push({ var event = new Phaser.TimerEvent(this, delay, tick, repeatCount, loop, callback, callbackContext, args);
delay: delay,
tick: tick, this.events.push(event);
repeatCount: repeatCount - 1,
loop: loop,
callback: callback,
callbackContext: callbackContext,
args: args
});
this.order(); this.order();
this.expired = false; this.expired = false;
return event;
}, },
/** /**
@ -149,10 +167,11 @@ console.log(arguments);
* @param {function} callback - The callback that will be called when the Timer event occurs. * @param {function} callback - The callback that will be called when the Timer event occurs.
* @param {object} callbackContext - The context in which the callback will be called. * @param {object} callbackContext - The context in which the callback will be called.
* @param {...} arguments - The values to be sent to your callback function when it is called. * @param {...} arguments - The values to be sent to your callback function when it is called.
* @return {Phaser.TimerEvent} The Phaser.TimerEvent object that was created.
*/ */
add: function (delay, callback, callbackContext) { add: function (delay, callback, callbackContext) {
this.create(delay, false, 0, callback, callbackContext, Array.prototype.splice.call(arguments, 3)); return this.create(delay, false, 0, callback, callbackContext, Array.prototype.splice.call(arguments, 3));
}, },
@ -167,10 +186,11 @@ console.log(arguments);
* @param {function} callback - The callback that will be called when the Timer event occurs. * @param {function} callback - The callback that will be called when the Timer event occurs.
* @param {object} callbackContext - The context in which the callback will be called. * @param {object} callbackContext - The context in which the callback will be called.
* @param {...} arguments - The values to be sent to your callback function when it is called. * @param {...} arguments - The values to be sent to your callback function when it is called.
* @return {Phaser.TimerEvent} The Phaser.TimerEvent object that was created.
*/ */
repeat: function (delay, repeatCount, callback, callbackContext) { repeat: function (delay, repeatCount, callback, callbackContext) {
this.create(delay, false, repeatCount, callback, callbackContext, Array.prototype.splice.call(arguments, 4)); return this.create(delay, false, repeatCount, callback, callbackContext, Array.prototype.splice.call(arguments, 4));
}, },
@ -184,10 +204,11 @@ console.log(arguments);
* @param {function} callback - The callback that will be called when the Timer event occurs. * @param {function} callback - The callback that will be called when the Timer event occurs.
* @param {object} callbackContext - The context in which the callback will be called. * @param {object} callbackContext - The context in which the callback will be called.
* @param {...} arguments - The values to be sent to your callback function when it is called. * @param {...} arguments - The values to be sent to your callback function when it is called.
* @return {Phaser.TimerEvent} The Phaser.TimerEvent object that was created.
*/ */
loop: function (delay, callback, callbackContext) { loop: function (delay, callback, callbackContext) {
this.create(delay, true, 0, callback, callbackContext, Array.prototype.splice.call(arguments, 3)); return this.create(delay, true, 0, callback, callbackContext, Array.prototype.splice.call(arguments, 3));
}, },
@ -214,7 +235,27 @@ console.log(arguments);
}, },
/** /**
* Orders the events on this Timer so they are in tick order. * Removes a pending TimerEvent from the queue.
* @param {Phaser.TimerEvent} event - The event to remove from the queue.
* @method Phaser.Timer#remove
*/
remove: function(event) {
for (var i = 0; i < this.events.length; i++)
{
if (this.events[i] === event)
{
this.events.splice(i, 1);
return true;
}
}
return false;
},
/**
* Orders the events on this Timer so they are in tick order. This is called automatically when new events are created.
* @method Phaser.Timer#order * @method Phaser.Timer#order
*/ */
order: function () { order: function () {
@ -258,37 +299,42 @@ console.log(arguments);
*/ */
update: function(time) { update: function(time) {
if (this.paused)
{
return true;
}
this._now = time - this._started; this._now = time - this._started;
var len = this.events.length; this._len = this.events.length;
if (this.running && this._now >= this.nextTick && len > 0) if (this.running && this._now >= this.nextTick && this._len > 0)
{ {
var i = 0; this._i = 0;
while (i < len) while (this._i < this._len)
{ {
if (this._now >= this.events[i].tick) if (this._now >= this.events[this._i].tick)
{ {
if (this.events[i].loop) if (this.events[this._i].loop === true)
{ {
this.events[i].tick += this.events[i].delay - (this._now - this.events[i].tick); this.events[this._i].tick += this.events[this._i].delay - (this._now - this.events[this._i].tick);
this.events[i].callback.apply(this.events[i].callbackContext, this.events[i].args); this.events[this._i].callback.apply(this.events[this._i].callbackContext, this.events[this._i].args);
} }
else if (this.events[i].repeatCount > 0) else if (this.events[this._i].repeatCount > 0)
{ {
this.events[i].repeatCount--; this.events[this._i].repeatCount--;
this.events[i].tick += this.events[i].delay - (this._now - this.events[i].tick); this.events[this._i].tick += this.events[this._i].delay - (this._now - this.events[this._i].tick);
this.events[i].callback.apply(this.events[i].callbackContext, this.events[i].args); this.events[this._i].callback.apply(this.events[this._i].callbackContext, this.events[this._i].args);
} }
else else
{ {
this.events[i].callback.apply(this.events[i].callbackContext, this.events[i].args); this.events[this._i].callback.apply(this.events[this._i].callbackContext, this.events[this._i].args);
this.events.splice(i, 1); this.events.splice(this._i, 1);
len--; this._len--;
} }
i++; this._i++;
} }
else else
{ {
@ -296,15 +342,15 @@ console.log(arguments);
} }
} }
// There are no events left // Are there any events left?
if (this.events.length > 0) if (this.events.length > 0)
{ {
this.expired = true; this.order();
this.onComplete.dispatch(this);
} }
else else
{ {
this.order(); this.expired = true;
this.onComplete.dispatch(this);
} }
} }
@ -319,6 +365,37 @@ console.log(arguments);
}, },
/**
* Pauses the Timer and all events in the queue.
* @method Phaser.Timer#pause
*/
pause: function () {
this._pauseStarted = this.game.time.now;
this.paused = true;
},
/**
* Resumes the Timer and updates all pending events.
* @method Phaser.Timer#resume
*/
resume: function () {
var pauseDuration = this.game.time.now - this._pauseStarted;
for (var i = 0; i < this.events.length; i++)
{
this.events[i].tick += pauseDuration;
}
this.nextTick += pauseDuration;
this.paused = false;
},
/** /**
* Destroys this Timer. Events are not dispatched. * Destroys this Timer. Events are not dispatched.
* @method Phaser.Timer#destroy * @method Phaser.Timer#destroy
@ -333,6 +410,54 @@ console.log(arguments);
}; };
/**
* @name Phaser.Timer#next
* @property {number} next - The time at which the next event will occur.
* @readonly
*/
Object.defineProperty(Phaser.Timer.prototype, "next", {
get: function () {
return this.nextTick;
}
});
/**
* @name Phaser.Timer#duration
* @property {number} duration - The duration in ms remaining until the next event will occur.
* @readonly
*/
Object.defineProperty(Phaser.Timer.prototype, "duration", {
get: function () {
if (this.running && this.nextTick > this._now)
{
return this.nextTick - this._now;
}
else
{
return 0;
}
}
});
/**
* @name Phaser.Timer#length
* @property {number} length - The number of pending events in the queue.
* @readonly
*/
Object.defineProperty(Phaser.Timer.prototype, "length", {
get: function () {
return this.events.length;
}
});
/** /**
* @name Phaser.Timer#ms * @name Phaser.Timer#ms
* @property {number} ms - The duration in milliseconds that this Timer has been running for. * @property {number} ms - The duration in milliseconds that this Timer has been running for.

67
src/time/TimerEvent.js Normal file
View file

@ -0,0 +1,67 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2013 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* A TimerEvent is a single event that is processed by a Phaser.Timer. It consists of a delay, which is a value in milliseconds after which the event will fire.
* It can call a specific callback, passing in optional parameters.
*
* @class Phaser.TimerEvent
* @classdesc A TimerEvent is a single event that is processed by a Phaser.Timer. It consists of a delay, which is a value in milliseconds after which the event will fire.
* @constructor
* @param {Phaser.Timer} timer - The Timer object that this TimerEvent belongs to.
* @param {number} delay - The delay in ms at which this TimerEvent fires.
* @param {number} tick - The tick is the next game clock time that this event will fire at.
* @param {number} repeatCount - If this TimerEvent repeats it will do so this many times.
* @param {boolean} loop - True if this TimerEvent loops, otherwise false.
* @param {function} callback - The callback that will be called when the TimerEvent occurs.
* @param {object} callbackContext - The context in which the callback will be called.
* @param {array} arguments - The values to be passed to the callback.
*/
Phaser.TimerEvent = function (timer, delay, tick, repeatCount, loop, callback, callbackContext, args) {
/**
* @property {Phaser.Timer} timer - The Timer object that this TimerEvent belongs to.
*/
this.timer = timer;
/**
* @property {number} delay - The delay in ms at which this TimerEvent fires.
*/
this.delay = delay;
/**
* @property {number} tick - The tick is the next game clock time that this event will fire at.
*/
this.tick = tick;
/**
* @property {number} repeatCount - If this TimerEvent repeats it will do so this many times.
*/
this.repeatCount = repeatCount - 1;
/**
* @property {boolean} loop - True if this TimerEvent loops, otherwise false.
*/
this.loop = loop;
/**
* @property {function} callback - The callback that will be called when the TimerEvent occurs.
*/
this.callback = callback;
/**
* @property {object} callbackContext - The context in which the callback will be called.
*/
this.callbackContext = callbackContext;
/**
* @property {array} arguments - The values to be passed to the callback.
*/
this.args = args;
};
Phaser.TimerEvent.prototype.constructor = Phaser.TimerEvent;