diff --git a/examples/wip/timer simple.js b/examples/wip/timer simple.js new file mode 100644 index 000000000..bacea4d66 --- /dev/null +++ b/examples/wip/timer simple.js @@ -0,0 +1,45 @@ + +var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.image('mushroom', 'assets/sprites/mushroom2.png'); + +} + +var timer; + +function create() { + + game.stage.backgroundColor = '#007236'; + + timer = game.time.create(1000, false); + + timer.repeat(1, 10); + + timer.onEvent.add(addSprite, this); + + timer.start(); + + // text = game.add.text(0, 0, "Text Above Sprites", { font: "64px Arial", fill: "#00bff3", align: "center" }); + +} + +function addSprite() { + + game.add.sprite(game.world.randomX, game.world.randomY, 'mushroom'); + +} + +function update() { + + + +} + +function render() { + + game.debug.renderText(timer.ms, 32, 32); + // game.debug.renderCameraInfo(game.camera, 32, 32); + +} diff --git a/src/time/Time.js b/src/time/Time.js index 879d33458..789686af0 100644 --- a/src/time/Time.js +++ b/src/time/Time.js @@ -118,10 +118,55 @@ Phaser.Time = function (game) { */ this._justResumed = false; + /** + * @property {array} _timers - Internal store of Phaser.Timer objects. + * @private + */ + this._timers = []; + }; Phaser.Time.prototype = { + /** + * Creates a new Phaser.Timer object. + * @method Phaser.Time#create + * @param {number} [timeUnit=1000] - The number of ms that represent 1 unit of time. For example a timer that ticks every second would have a timeUnit value of 1000. + * @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. + */ + create: function (timeUnit, autoDestroy) { + + if (typeof autoDestroy === 'undefined') { autoDestroy = true; } + + var timer = new Phaser.Timer(this.game, timeUnit, autoDestroy); + + if (typeof delay !== 'undefined') + { + timer.add(delay); + } + + this._timers.push(timer); + + return timer; + + }, + + /** + * Remove all Timer objects, regardless of their state. + * @method Phaser.Time#removeAll + */ + removeAll: function () { + + for (var i = 0; i < this._timers.length; i++) + { + this._timers[i].destroy(); + } + + this._timers = []; + + }, + /** * Updates the game clock and calculate the fps. This is called automatically by Phaser.Game. * @method Phaser.Time#update @@ -171,6 +216,23 @@ Phaser.Time.prototype = { this.pausedTime = this.now - this._pauseStarted; } + var i = 0; + var len = this._timers.length; + + while (i < len) + { + if (this._timers[i].update(this.now)) + { + i++; + } + else + { + this._timers.splice(i, 1); + + len--; + } + } + }, /** diff --git a/src/time/Timer.js b/src/time/Timer.js index 8723de8cc..7f6f06dd5 100644 --- a/src/time/Timer.js +++ b/src/time/Timer.js @@ -5,14 +5,21 @@ */ /** -* Timer constructor. +* A Timer is a way to create small re-usable or disposable objects that do nothing but wait for a specific moment in time, and then dispatch an event. +* You can add as many events to a Timer as you like, each with their own delays. A Timer uses its own timeUnit, which directly correlates to milliseconds. +* For example a Timer with a timeUnit of 250 would fire an event every quarter of a second. * * @class Phaser.Timer -* @classdesc A Timer +* @classdesc A Timer is a way to create small re-usable or disposable objects that do nothing but wait for a specific moment in time, and then dispatch an event. * @constructor * @param {Phaser.Game} game A reference to the currently running game. +* @param {number} [timeUnit=1000] - The number of ms that represent 1 unit of time. For example a timer that ticks every second would have a timeUnit value of 1000. +* @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). */ -Phaser.Timer = function (game) { +Phaser.Timer = function (game, timeUnit, autoDestroy) { + + if (typeof timeUnit === 'undefined') { timeUnit = Phaser.Timer.SECOND; } + if (typeof autoDestroy === 'undefined') { autoDestroy = true; } /** * @property {Phaser.Game} game - Local reference to game. @@ -20,92 +27,154 @@ Phaser.Timer = function (game) { this.game = game; /** - * The time at which this Timer instance started. - * @property {number} _started + * @property {number} _started - The time at which this Timer instance started. * @private * @default */ this._started = 0; /** - * The time (in ms) that the last second counter ticked over. - * @property {number} _timeLastSecond - * @private + * @property {boolean} running - True if the Timer is actively running. * @default */ - this._timeLastSecond = 0; - 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). + */ + this.autoDestroy = autoDestroy; + + /** + * @property {boolean} expired - An expired Timer is one in which all of its events have been dispatched and none are pending. + * @default + */ + this.expired = false; + + /** + * @property {array} events - An array holding the event data. + */ this.events = []; + /** + * This is the event you should listen for. It will be dispatched whenever one of your events is triggered. + * It will pass whatever properties you set-up for the event as parameters. + * @property {Phaser.Signal} onEvent + */ this.onEvent = new Phaser.Signal(); - // Need to add custom FPS rate, for now we'll just use seconds + /** + * @property {number} timeUnit - The unit of time being used by this Timer. + */ + this.timeUnit = timeUnit; }; +/** +* @constant +* @type {number} +*/ +Phaser.Timer.MINUTE = 60000; + +/** +* @constant +* @type {number} +*/ +Phaser.Timer.SECOND = 1000; + +/** +* @constant +* @type {number} +*/ +Phaser.Timer.HALF = 500; + +/** +* @constant +* @type {number} +*/ +Phaser.Timer.QUARTER = 250; + Phaser.Timer.prototype = { - // delay could be from now, when the timer is created, or relative to an already running timer + /** + * Creates a new Event on this Timer. + * @method Phaser.Timer#_create + * @private + */ + _create: function (delay, loop, repeatCount, args) { - // add: function (delay, callback, callbackContext) { + this.events.push({ + delay: delay, + tick: delay, + expired: false, + repeatCount: repeatCount, + loop: loop, + args: args + }); + + this.expired = false; + + }, + + /** + * Adds a new Event to this Timer. The event will fire after the given amount of 'delay' has passed if the Timer is running. + * Call Timer.start() once you have added all of the Events you require for this Timer. + * @method Phaser.Timer#add + * @param {number} [delay] - The number of timeUnits before the Timer will dispatch its onEvent signal. + */ add: function (delay) { - this.events.push({ - delay: delay, - dispatched: false, - repeatCount: 0, - loop: false, - args: Array.prototype.splice.call(arguments, 1) - }); - - // this.events.push({ - // delay: delay, - // dispatched: false, - // callback: callback, - // callbackContext: callbackContext, - // args: Array.prototype.splice.call(arguments, 3) - // }); + this._create(delay, false, 0, Array.prototype.splice.call(arguments, 1)); }, + /** + * 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' has passed if the Timer is running. + * Call Timer.start() once you have added all of the Events you require for this Timer. + * @method Phaser.Timer#repeat + * @param {number} [delay] - The number of timeUnits before the Timer will dispatch its onEvent signal. + * @param {number} [count] - The number of times to repeat this Event. + */ repeat: function (delay, count) { - this.events.push({ - delay: delay, - dispatched: false, - repeatCount: count, - loop: false, - args: Array.prototype.splice.call(arguments, 2) - }); + this._create(delay, false, count, Array.prototype.splice.call(arguments, 2)); }, + /** + * 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' has passed if the Timer is running. + * Call Timer.start() once you have added all of the Events you require for this Timer. + * @method Phaser.Timer#loop + * @param {number} [delay] - The number of timeUnits before the Timer will dispatch its onEvent signal. + */ loop: function (delay) { - this.events.push({ - delay: delay, - dispatched: false, - loop: true, - args: Array.prototype.splice.call(arguments, 2) - }); + this._create(delay, true, 0, Array.prototype.splice.call(arguments, 1)); }, + /** + * Starts this Timer running. + * @method Phaser.Timer#start + */ start: function() { this._started = this.game.time.now; this.running = true; - // sort the events based on delay here, also don't run unless events is populated - // add ability to auto-stop once all events are done - // add support for maximum duration - // add support for delay before starting - // add signals? - }, + /** + * Stops this Timer from running. Does not cause it to be destroyed if autoDestroy is set to true. + * @method Phaser.Timer#stop + */ stop: function() { this.running = false; @@ -113,46 +182,104 @@ Phaser.Timer.prototype = { }, - update: function() { - - // TODO: Game Paused support + /** + * The main Timer update event. + * @method Phaser.Timer#update + * @protected + * @param {number} time - The time from the core game clock. + * @return {boolean} True if there are still events waiting to be dispatched, otherwise false if this Timer can be deleted. + */ + update: function(time) { if (this.running) { - var seconds = this.seconds(); + var now = (time - this._started) / this.timeUnit; + var expired = 0; for (var i = 0, len = this.events.length; i < len; i++) { - if (this.events[i].dispatched === false && seconds >= this.events[i].delay) + if (this.events[i].expired === false && now >= this.events[i].tick) { if (this.events[i].loop) { + this.events[i].tick += this.events[i].delay - (now - this.events[i].tick); this.onEvent.dispatch.apply(this, this.events[i].args); - this.events[i].delay = seconds + this.events[i].delay; } else if (this.events[i].repeatCount > 0) { this.events[i].repeatCount--; + this.events[i].tick += this.events[i].delay - (now - this.events[i].tick); this.onEvent.dispatch.apply(this, this.events[i].args); - this.events[i].delay = seconds + this.events[i].delay; } else { - this.events[i].dispatched = true; - // this.events[i].callback.apply(this.events[i].callbackContext, this.events[i].args); + this.events[i].expired = true; this.onEvent.dispatch.apply(this, this.events[i].args); - // ought to slice it now } } + + if (this.events[i].expired) + { + expired++; + } } + + // There are no events left at all + if (expired === this.events.length) + { + this.expired = true; + } + } + + if (this.expired && this.autoDestroy) + { + return false; + } + else + { + return true; } }, - seconds: function() { - return (this.game.time.now - this._started) * 0.001; + /** + * Destroys this Timer. Events are not dispatched. + * @method Phaser.Timer#destroy + */ + destroy: function() { + + this.onEvent.removeAll(); + this.running = false; + this.events = []; + } }; +/** +* @name Phaser.Timer#ms +* @property {number} ms - The duration in milliseconds that this Timer has been running for. +* @readonly +*/ +Object.defineProperty(Phaser.Timer.prototype, "ms", { + + get: function () { + return this.game.time.now - this._started; + } + +}); + +/** +* @name Phaser.Timer#seconds +* @property {number} seconds - The duration in seconds that this Timer has been running for. +* @readonly +*/ +Object.defineProperty(Phaser.Timer.prototype, "seconds", { + + get: function () { + return (this.game.time.now - this._started) * 0.001; + } + +}); + Phaser.Timer.prototype.constructor = Phaser.Timer; diff --git a/src/tween/TweenManager.js b/src/tween/TweenManager.js index 63efdc07d..b6f652267 100644 --- a/src/tween/TweenManager.js +++ b/src/tween/TweenManager.js @@ -81,9 +81,9 @@ Phaser.TweenManager.prototype = { * @param {Phaser.Tween} tween - The tween object you want to add. * @returns {Phaser.Tween} The tween object you added to the manager. */ - add: function ( tween ) { + add: function (tween) { - this._add.push( tween ); + this._add.push(tween); }, @@ -106,14 +106,13 @@ Phaser.TweenManager.prototype = { * @method Phaser.TweenManager#remove * @param {Phaser.Tween} tween - The tween object you want to remove. */ - remove: function ( tween ) { + remove: function (tween) { - var i = this._tweens.indexOf( tween ); - - if ( i !== -1 ) { + var i = this._tweens.indexOf(tween); + if (i !== -1) + { this._tweens[i].pendingDelete = true; - } }, @@ -126,7 +125,7 @@ Phaser.TweenManager.prototype = { */ update: function () { - if ( this._tweens.length === 0 && this._add.length === 0 ) + if (this._tweens.length === 0 && this._add.length === 0) { return false; } @@ -134,20 +133,18 @@ Phaser.TweenManager.prototype = { var i = 0; var numTweens = this._tweens.length; - while ( i < numTweens ) { - - if ( this._tweens[ i ].update( this.game.time.now ) ) { - + while (i < numTweens) + { + if (this._tweens[i].update(this.game.time.now)) + { i++; - - } else { - - this._tweens.splice( i, 1 ); + } + else + { + this._tweens.splice(i, 1); numTweens--; - } - } // If there are any new tweens to be added, do so now - otherwise they can be spliced out of the array before ever running @@ -183,7 +180,8 @@ Phaser.TweenManager.prototype = { */ pauseAll: function () { - for (var i = this._tweens.length - 1; i >= 0; i--) { + for (var i = this._tweens.length - 1; i >= 0; i--) + { this._tweens[i].pause(); } @@ -196,7 +194,8 @@ Phaser.TweenManager.prototype = { */ resumeAll: function () { - for (var i = this._tweens.length - 1; i >= 0; i--) { + for (var i = this._tweens.length - 1; i >= 0; i--) + { this._tweens[i].resume(); }