From 35e61172e12e4b9d3c14b0427f18bbb291843a74 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Wed, 8 Jan 2014 11:21:30 +0000 Subject: [PATCH] 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. The Time class now has three new methods: addEvent, repeatEvent and loopEvent. See the new Timer examples to show how to use them. --- README.md | 3 + examples/wip/timer simple.js | 24 ++++---- src/core/Game.js | 1 + src/system/Canvas.js | 20 ++++++- src/system/Device.js | 8 +++ src/time/Time.js | 82 +++++++++++++++++++++++----- src/time/Timer.js | 103 ++++++++++++++++++++++++----------- 7 files changed, 179 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 66d7a543..01acebc7 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,9 @@ Updates: * Added in prototype.constructor definitions to every class (thanks darkoverlordofdata) * Group.destroy has a new parameter: destroyChildren (boolean) which will optionally call the destroy method of all Group children. * 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. +* 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. Bug Fixes: diff --git a/examples/wip/timer simple.js b/examples/wip/timer simple.js index bacea4d6..e5c69fd3 100644 --- a/examples/wip/timer simple.js +++ b/examples/wip/timer simple.js @@ -4,6 +4,7 @@ var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: function preload() { game.load.image('mushroom', 'assets/sprites/mushroom2.png'); + game.load.image('sonic', 'assets/sprites/pangball.png'); } @@ -13,33 +14,30 @@ function create() { game.stage.backgroundColor = '#007236'; - timer = game.time.create(1000, false); + // 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. + game.time.repeatEvent(Phaser.Timer.SECOND, 10, addSprite, this, 'mushroom'); - 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" }); + // Every 1.5 seconds we will call the addSprite function. This will happen 5 times and then stop. + game.time.repeatEvent(1500, 10, addSprite, this, 'sonic'); } -function addSprite() { +function addSprite(key) { - game.add.sprite(game.world.randomX, game.world.randomY, 'mushroom'); +console.log(arguments); + + game.add.sprite(game.world.randomX, game.world.randomY, key); } function update() { - - } function render() { - game.debug.renderText(timer.ms, 32, 32); + game.debug.renderText(game.time._timer.ms, 32, 32); // game.debug.renderCameraInfo(game.camera, 32, 32); } diff --git a/src/core/Game.js b/src/core/Game.js index 08e1f7c3..c7674234 100644 --- a/src/core/Game.js +++ b/src/core/Game.js @@ -431,6 +431,7 @@ Phaser.Game.prototype = { this.net = new Phaser.Net(this); this.debug = new Phaser.Utils.Debug(this); + this.time.boot(); this.stage.boot(); this.world.boot(); this.input.boot(); diff --git a/src/system/Canvas.js b/src/system/Canvas.js index ded7c813..fb4fc74f 100644 --- a/src/system/Canvas.js +++ b/src/system/Canvas.js @@ -5,7 +5,7 @@ */ /** -* The Canvas class handles everything related to the <canvas> tag as a DOM Element, like styles, offset, aspect ratio +* The Canvas class handles everything related to creating the `canvas` DOM tag that Phaser will use, including styles, offset and aspect ratio. * * @class Phaser.Canvas * @static @@ -56,8 +56,22 @@ Phaser.Canvas = { var box = element.getBoundingClientRect(); var clientTop = element.clientTop || document.body.clientTop || 0; var clientLeft = element.clientLeft || document.body.clientLeft || 0; - var scrollTop = window.pageYOffset || element.scrollTop || document.body.scrollTop; - var scrollLeft = window.pageXOffset || element.scrollLeft || document.body.scrollLeft; + + // Without this check Chrome is now throwing console warnings about strict vs. quirks :( + + var scrollTop = 0; + var scrollLeft = 0; + + if (document.compatMode === 'CSS1Compat') + { + scrollTop = window.pageYOffset || document.documentElement.scrollTop || element.scrollTop || 0; + scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || element.scrollLeft || 0; + } + else + { + scrollTop = window.pageYOffset || document.body.scrollTop || element.scrollTop || 0; + scrollLeft = window.pageXOffset || document.body.scrollLeft || element.scrollLeft || 0; + } point.x = box.left + scrollLeft - clientLeft; point.y = box.top + scrollTop - clientTop; diff --git a/src/system/Device.js b/src/system/Device.js index de1bb784..dc9e61c7 100644 --- a/src/system/Device.js +++ b/src/system/Device.js @@ -150,6 +150,12 @@ Phaser.Device = function () { */ this.vibration = false; + /** + * @property {boolean} quirksMode - Is the browser running in strict mode (false) or quirks mode? (true) + * @default + */ + this.quirksMode = false; + // Browser /** @@ -414,6 +420,8 @@ Phaser.Device.prototype = { this.pointerLock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document; + this.quirksMode = (document.compatMode === 'CSS1Compat') ? false : true; + }, /** diff --git a/src/time/Time.js b/src/time/Time.js index e2324744..fbcf4d04 100644 --- a/src/time/Time.js +++ b/src/time/Time.js @@ -108,11 +108,11 @@ Phaser.Time = function (game) { */ this.lastTime = 0; - this._timer = new Phaser.Timer(this.game, 1, false); - - // Listen for game pause/resume events - this.game.onPause.add(this.gamePaused, this); - this.game.onResume.add(this.gameResumed, this); + /** + * @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. @@ -126,29 +126,82 @@ Phaser.Time = function (game) { */ this._timers = []; + // Listen for game pause/resume events + this.game.onPause.add(this.gamePaused, this); + this.game.onResume.add(this.gameResumed, this); + }; Phaser.Time.prototype = { + /** + * @method Phaser.Time#boot + */ + boot: function () { + this._timer.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. * @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) { + create: function (autoDestroy) { if (typeof autoDestroy === 'undefined') { autoDestroy = true; } - var timer = new Phaser.Timer(this.game, timeUnit, autoDestroy); - - if (typeof delay !== 'undefined') - { - timer.add(delay); - } + var timer = new Phaser.Timer(this.game, autoDestroy); this._timers.push(timer); @@ -220,6 +273,9 @@ Phaser.Time.prototype = { this.pausedTime = this.now - this._pauseStarted; } + // Our internal timer + this._timer.update(this.now); + var i = 0; var len = this._timers.length; diff --git a/src/time/Timer.js b/src/time/Timer.js index d2699857..e84b8102 100644 --- a/src/time/Timer.js +++ b/src/time/Timer.js @@ -25,7 +25,7 @@ Phaser.Timer = function (game, autoDestroy) { this.game = game; /** - * @property {number} _started - The time at which this Timer instance started. + * @property {number} _started - The time at which this Timer instance started running. * @private * @default */ @@ -60,11 +60,9 @@ Phaser.Timer = function (game, autoDestroy) { 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 + * @property {Phaser.Signal} onComplete - This signal will be dispatched when this Timer has completed, meaning there are no more events in the queue. */ - this.onEvent = new Phaser.Signal(); + this.onComplete = new Phaser.Signal(); /** * @property {number} nextTick - The time the next tick will occur. Do not set this value directly. @@ -110,14 +108,29 @@ Phaser.Timer.prototype = { * Creates a new Event on this Timer. * @method Phaser.Timer#_create * @private + * @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 {number} repeatCount - The number of times the event will repeat. + * @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 {array} arguments - The values to be sent to your callback function when it is called. */ - create: function (delay, loop, repeatCount, args) { + create: function (delay, loop, repeatCount, callback, callbackContext, args) { +console.log(arguments); + var tick = delay; + + if (this.running) + { + tick += this._now; + } this.events.push({ delay: delay, - tick: delay, - repeatCount: repeatCount, + tick: tick, + repeatCount: repeatCount - 1, loop: loop, + callback: callback, + callbackContext: callbackContext, args: args }); @@ -127,17 +140,19 @@ Phaser.Timer.prototype = { }, - // Need to do a Stop Watch example - /** * 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. + * If the Timer is already running the delay will be calculated based on the timers current time. * @method Phaser.Timer#add - * @param {number} [delay] - The number of milliseconds before the Timer will dispatch its onEvent signal. + * @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. */ - add: function (delay) { + add: function (delay, callback, callbackContext) { - this.create(delay, false, 0, Array.prototype.splice.call(arguments, 1)); + this.create(delay, false, 0, callback, callbackContext, Array.prototype.splice.call(arguments, 3)); }, @@ -145,13 +160,17 @@ Phaser.Timer.prototype = { * 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. + * If the Timer is already running the delay will be calculated based on the timers current time. * @method Phaser.Timer#repeat - * @param {number} [delay] - The number of milliseconds before the Timer will dispatch its onEvent signal. - * @param {number} [count] - The number of times to repeat this Event. + * @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 the event will repeat. + * @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. */ - repeat: function (delay, count) { + repeat: function (delay, repeatCount, callback, callbackContext) { - this.create(delay, false, count, Array.prototype.splice.call(arguments, 2)); + this.create(delay, false, repeatCount, callback, callbackContext, Array.prototype.splice.call(arguments, 4)); }, @@ -159,12 +178,16 @@ Phaser.Timer.prototype = { * 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. + * If the Timer is already running the delay will be calculated based on the timers current time. * @method Phaser.Timer#loop - * @param {number} [delay] - The number of milliseconds before the Timer will dispatch its onEvent signal. + * @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. */ - loop: function (delay) { + loop: function (delay, callback, callbackContext) { - this.create(delay, true, 0, Array.prototype.splice.call(arguments, 1)); + this.create(delay, true, 0, callback, callbackContext, Array.prototype.splice.call(arguments, 3)); }, @@ -190,15 +213,27 @@ Phaser.Timer.prototype = { }, + /** + * Orders the events on this Timer so they are in tick order. + * @method Phaser.Timer#order + */ order: function () { - // Sort the events so the one with the lowest tick is first - this.events.sort(this.sortHandler); + if (this.events.length > 0) + { + // Sort the events so the one with the lowest tick is first + this.events.sort(this.sortHandler); - this.nextTick = this.events[0].tick; + this.nextTick = this.events[0].tick; + } }, + /** + * Sort handler used by Phaser.Timer.order. + * @method Phaser.Timer#sortHandler + * @protected + */ sortHandler: function (a, b) { if (a.tick < b.tick) @@ -219,16 +254,17 @@ Phaser.Timer.prototype = { * @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. + * @return {boolean} True if there are still events waiting to be dispatched, otherwise false if this Timer can be destroyed. */ update: function(time) { this._now = time - this._started; - if (this.running && this._now >= this.nextTick) + var len = this.events.length; + + if (this.running && this._now >= this.nextTick && len > 0) { var i = 0; - var len = this.events.length; while (i < len) { @@ -237,17 +273,17 @@ Phaser.Timer.prototype = { if (this.events[i].loop) { this.events[i].tick += this.events[i].delay - (this._now - this.events[i].tick); - this.onEvent.dispatch.apply(this, this.events[i].args); + this.events[i].callback.apply(this.events[i].callbackContext, this.events[i].args); } else if (this.events[i].repeatCount > 0) { this.events[i].repeatCount--; this.events[i].tick += this.events[i].delay - (this._now - this.events[i].tick); - this.onEvent.dispatch.apply(this, this.events[i].args); + this.events[i].callback.apply(this.events[i].callbackContext, this.events[i].args); } else { - this.onEvent.dispatch.apply(this, this.events[i].args); + this.events[i].callback.apply(this.events[i].callbackContext, this.events[i].args); this.events.splice(i, 1); len--; } @@ -260,10 +296,11 @@ Phaser.Timer.prototype = { } } - // There are no events left at all + // There are no events left if (this.events.length > 0) { this.expired = true; + this.onComplete.dispatch(this); } else { @@ -288,7 +325,7 @@ Phaser.Timer.prototype = { */ destroy: function() { - this.onEvent.removeAll(); + this.onComplete.removeAll(); this.running = false; this.events = []; @@ -304,7 +341,7 @@ Phaser.Timer.prototype = { Object.defineProperty(Phaser.Timer.prototype, "ms", { get: function () { - return this.game.time.now - this._started; + return this._now; } }); @@ -317,7 +354,7 @@ Object.defineProperty(Phaser.Timer.prototype, "ms", { Object.defineProperty(Phaser.Timer.prototype, "seconds", { get: function () { - return (this.game.time.now - this._started) * 0.001; + return this._now * 0.001; } });