From a96ced0d82e9a15ce024e3bfed1bce6727af60c0 Mon Sep 17 00:00:00 2001 From: Cameron Foale Date: Sat, 2 Nov 2013 17:04:32 +1100 Subject: [PATCH 1/9] Add a postUpdate function to plugins, which is called after World.postUpdate --- src/core/Game.js | 1 + src/core/Plugin.js | 6 ++++++ src/core/PluginManager.js | 30 ++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/src/core/Game.js b/src/core/Game.js index ca1a0635..9f4122ea 100644 --- a/src/core/Game.js +++ b/src/core/Game.js @@ -437,6 +437,7 @@ Phaser.Game.prototype = { this.plugins.update(); this.world.postUpdate(); + this.plugins.postUpdate(); this.renderer.render(this.stage._stage); this.plugins.render(); diff --git a/src/core/Plugin.js b/src/core/Plugin.js index 14cfc3d8..68a03029 100644 --- a/src/core/Plugin.js +++ b/src/core/Plugin.js @@ -50,6 +50,12 @@ Phaser.Plugin = function (game, parent) { * @default */ this.hasUpdate = false; + + /** + * @property {boolean} hasPostUpdate - A flag to indicate if this plugin has a postUpdate method. + * @default + */ + this.hasPostUpdate = false; /** * @property {boolean} hasRender - A flag to indicate if this plugin has a render method. diff --git a/src/core/PluginManager.js b/src/core/PluginManager.js index 98eaea40..932d7bab 100644 --- a/src/core/PluginManager.js +++ b/src/core/PluginManager.js @@ -77,6 +77,12 @@ Phaser.PluginManager.prototype = { result = true; } + if (typeof plugin['postUpdate'] === 'function') + { + plugin.hasPostUpdate = true; + result = true; + } + if (typeof plugin['render'] === 'function') { plugin.hasRender = true; @@ -176,6 +182,30 @@ Phaser.PluginManager.prototype = { }, + /** + * PostUpdate is the last thing to be called before the world render. + * In particular, it is called after the world postUpdate, which means the camera has been adjusted. + * It only calls plugins who have active=true. + * + * @method Phaser.PluginManager#postUpdate + */ + postUpdate: function () { + + if (this._pluginsLength == 0) + { + return; + } + + for (this._p = 0; this._p < this._pluginsLength; this._p++) + { + if (this.plugins[this._p].active && this.plugins[this._p].hasPostUpdate) + { + this.plugins[this._p].postUpdate(); + } + } + + }, + /** * Render is called right after the Game Renderer completes, but before the State.render. * It only calls plugins who have visible=true. From 3227918c57e1b0cf1c57156bdf42f6b64fb4c447 Mon Sep 17 00:00:00 2001 From: beeglebug Date: Sat, 2 Nov 2013 11:24:00 +0000 Subject: [PATCH 2/9] fix #154 Button now goes back to over state when setFrames used in action --- src/gameobjects/Button.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gameobjects/Button.js b/src/gameobjects/Button.js index 63bceb82..1dd1a331 100644 --- a/src/gameobjects/Button.js +++ b/src/gameobjects/Button.js @@ -197,7 +197,7 @@ Phaser.Button.prototype.setFrames = function (overFrame, outFrame, downFrame) { { this._onDownFrameName = downFrame; - if (this.input.pointerOver()) + if (this.input.pointerDown()) { this.frameName = downFrame; } @@ -206,7 +206,7 @@ Phaser.Button.prototype.setFrames = function (overFrame, outFrame, downFrame) { { this._onDownFrameID = downFrame; - if (this.input.pointerOver()) + if (this.input.pointerDown()) { this.frame = downFrame; } From 4593a42a5bf86d50e67c60978101edc998fbb2aa Mon Sep 17 00:00:00 2001 From: KLV Date: Sun, 3 Nov 2013 23:43:47 +0100 Subject: [PATCH 3/9] Mouse property to say what button is being clicked It follows the convention that already was in the file 0 for left, 1 for middle and 2 for right. It also changes to -1 when mouseUp. --- src/input/Mouse.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/input/Mouse.js b/src/input/Mouse.js index 3a781c01..6abbd983 100644 --- a/src/input/Mouse.js +++ b/src/input/Mouse.js @@ -41,6 +41,11 @@ Phaser.Mouse = function (game) { * @default */ this.mouseUpCallback = null; + /** + * @property {Description} mouseTypeDown - The type of click. -1 for not clicking + * @default + */ + this.mouseTypeDown = -1; /** * You can disable all Input by setting disabled = true. While set all new input related events will be ignored. @@ -119,6 +124,8 @@ Phaser.Mouse.prototype = { event.preventDefault(); + this.mouseTypeDown = event.which - 1; + if (this.mouseDownCallback) { this.mouseDownCallback.call(this.callbackContext, event); @@ -169,6 +176,8 @@ Phaser.Mouse.prototype = { event.preventDefault(); + this.mouseTypeDown = -1; + if (this.mouseUpCallback) { this.mouseUpCallback.call(this.callbackContext, event); @@ -262,4 +271,4 @@ Phaser.Mouse.prototype = { } -}; \ No newline at end of file +}; From e8bac6c8c7b8f40fc95279f7997fbb60e5cf4815 Mon Sep 17 00:00:00 2001 From: wKLV Date: Mon, 4 Nov 2013 00:16:36 +0100 Subject: [PATCH 4/9] Check type uses the static values --- src/input/Mouse.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/input/Mouse.js b/src/input/Mouse.js index 6abbd983..2ad0683d 100644 --- a/src/input/Mouse.js +++ b/src/input/Mouse.js @@ -63,6 +63,11 @@ Phaser.Mouse = function (game) { }; +/** +* @constant +* @type {number} +*/ +Phaser.Mouse.NO_BUTTON = -1; /** * @constant * @type {number} @@ -81,6 +86,7 @@ Phaser.Mouse.MIDDLE_BUTTON = 1; */ Phaser.Mouse.RIGHT_BUTTON = 2; + Phaser.Mouse.prototype = { /** @@ -124,7 +130,9 @@ Phaser.Mouse.prototype = { event.preventDefault(); - this.mouseTypeDown = event.which - 1; + if (event.which === 1) this.mouseTypeDown = Phaser.Mouse.LEFT_BUTTON; + else if (event.which === 2) this.mouseTypeDown = Phaser.Mouse.MIDDLE_BUTON; + else if (event.which === 3) this.mouseTypeDown = Phaser.Mouse.RIGHT_BUTTON; if (this.mouseDownCallback) { @@ -176,7 +184,7 @@ Phaser.Mouse.prototype = { event.preventDefault(); - this.mouseTypeDown = -1; + this.mouseTypeDown = Phaser.Mouse.NO_BUTTON; if (this.mouseUpCallback) { From 8678373754e16a395a52a917ac5e1220ba3b7ba6 Mon Sep 17 00:00:00 2001 From: wKLV Date: Mon, 4 Nov 2013 00:18:59 +0100 Subject: [PATCH 5/9] fix typo --- src/input/Mouse.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/Mouse.js b/src/input/Mouse.js index 2ad0683d..5734dc35 100644 --- a/src/input/Mouse.js +++ b/src/input/Mouse.js @@ -131,7 +131,7 @@ Phaser.Mouse.prototype = { event.preventDefault(); if (event.which === 1) this.mouseTypeDown = Phaser.Mouse.LEFT_BUTTON; - else if (event.which === 2) this.mouseTypeDown = Phaser.Mouse.MIDDLE_BUTON; + else if (event.which === 2) this.mouseTypeDown = Phaser.Mouse.MIDDLE_BUTTON; else if (event.which === 3) this.mouseTypeDown = Phaser.Mouse.RIGHT_BUTTON; if (this.mouseDownCallback) From c1d60d7e19b29c54c3c0a5fd2d33681bd47f49c2 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 4 Nov 2013 00:04:19 +0000 Subject: [PATCH 6/9] getAnimation and RAF callback ID checks added --- README.md | 4 +++- src/animation/AnimationManager.js | 21 +++++++++++++++++++++ src/system/RequestAnimationFrame.js | 13 ++++++++++--- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d400587f..3db34021 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,9 @@ Change Log Version 1.1.3 - in build -* +* New: Sprite.animations.getAnimation will return an animation instance which was added by name. +* Updated: RequestAnimationFrame now retains the callbackID which is passed to cancelRequestAnimationFrame. + Version 1.1.2 - November 1st 2013 diff --git a/src/animation/AnimationManager.js b/src/animation/AnimationManager.js index 68f6d445..0de12ac3 100644 --- a/src/animation/AnimationManager.js +++ b/src/animation/AnimationManager.js @@ -261,6 +261,27 @@ Phaser.AnimationManager.prototype = { }, + /** + * Returns an animation that was previously added by name. + * + * @method Phaser.AnimationManager#getAnimation + * @param {string} name - The name of the animation to be returned, e.g. "fire". + * @return {Phaser.Animation|boolean} The Animation instance, if found, otherwise false. + */ + getAnimation: function (name) { + + if (typeof name == 'string') + { + if (this._anims[name]) + { + return this._anims[name]; + } + } + + return false; + + }, + /** * Refreshes the current frame data back to the parent Sprite and also resets the texture data. * diff --git a/src/system/RequestAnimationFrame.js b/src/system/RequestAnimationFrame.js index 6fe2ae74..8d3ca09f 100644 --- a/src/system/RequestAnimationFrame.js +++ b/src/system/RequestAnimationFrame.js @@ -50,6 +50,13 @@ Phaser.RequestAnimationFrame = function(game) { */ this._onLoop = null; + /** + * The callback ID used when calling cancel + * @property _timeOutID + * @private + */ + this._timeOutID = null; + }; Phaser.RequestAnimationFrame.prototype = { @@ -83,7 +90,7 @@ Phaser.RequestAnimationFrame.prototype = { return _this.updateRAF(time); }; - window.requestAnimationFrame(this._onLoop); + this._timeOutID = window.requestAnimationFrame(this._onLoop); } }, @@ -97,7 +104,7 @@ Phaser.RequestAnimationFrame.prototype = { this.game.update(time); - window.requestAnimationFrame(this._onLoop); + this._timeOutID = window.requestAnimationFrame(this._onLoop); }, @@ -125,7 +132,7 @@ Phaser.RequestAnimationFrame.prototype = { } else { - window.cancelAnimationFrame; + window.cancelAnimationFrame(this._timeOutID); } this.isRunning = false; From 19ddad80956478ccb6595bdc84078c78398e5781 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Mon, 4 Nov 2013 03:16:17 +0000 Subject: [PATCH 7/9] Mouse handler updates. --- README.md | 6 ++ src/input/InputHandler.js | 46 ++++++++++---- src/input/Mouse.js | 70 ++++++++++++++-------- tutorials/01 Getting Started/index.html | 80 +++++++++++++++++++++++++ 4 files changed, 166 insertions(+), 36 deletions(-) create mode 100644 tutorials/01 Getting Started/index.html diff --git a/README.md b/README.md index 3db34021..d5773c02 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,13 @@ Change Log Version 1.1.3 - in build * New: Sprite.animations.getAnimation will return an animation instance which was added by name. +* New: Added Mouse.button which is set to the button that was pressed: Phaser.Mouse.LEFT_BUTTON, MIDDLE_BUTTON or RIGHT_BUTTON (thanks wKLV) +* New: Added Mouse.pointerLock signal which you can listen to whenever the browser enters or leaves pointer lock mode. +* Fixed: Mouse.stop now uses the true useCapture, which means the event listeners stop listening correctly (thanks beeglebug) * Updated: RequestAnimationFrame now retains the callbackID which is passed to cancelRequestAnimationFrame. +* Updated: Button now goes back to over state when setFrames used in action (thanks beeglebug) +* Updated: plugins now have a postUpdate callback (thanks cocoademon) + Version 1.1.2 - November 1st 2013 diff --git a/src/input/InputHandler.js b/src/input/InputHandler.js index 711f4c31..19879e08 100644 --- a/src/input/InputHandler.js +++ b/src/input/InputHandler.js @@ -405,28 +405,50 @@ Phaser.InputHandler.prototype = { /** * Is the Pointer over this Sprite? * @method Phaser.InputHandler#pointerOver - * @param {Pointer} pointer - * @return {bool + * @param {number} [index] - The ID number of a Pointer to check. If you don't provide a number it will check all Pointers. + * @return {boolean} True if the given pointer (if a index was given, or any pointer if not) is over this object. */ - pointerOver: function (pointer) { + pointerOver: function (index) { - pointer = pointer || 0; - - return this._pointerData[pointer].isOver; + if (typeof index === 'undefined') + { + for (var i = 0; i < 10; i++) + { + if (this._pointerData[i].isOver) + { + return true; + } + } + } + else + { + return this._pointerData[index].isOver; + } }, /** * Is the Pointer outside of this Sprite? * @method Phaser.InputHandler#pointerOut - * @param {Pointer} pointer - * @return {boolean} + * @param {number} [index] - The ID number of a Pointer to check. If you don't provide a number it will check all Pointers. + * @return {boolean} True if the given pointer (if a index was given, or any pointer if not) is out of this object. */ pointerOut: function (pointer) { - pointer = pointer || 0; - - return this._pointerData[pointer].isOut; + if (typeof index === 'undefined') + { + for (var i = 0; i < 10; i++) + { + if (this._pointerData[i].isOut) + { + return true; + } + } + } + else + { + return this._pointerData[index].isOut; + } }, @@ -547,6 +569,8 @@ Phaser.InputHandler.prototype = { return false; } + // For an enabled sprite that may have been clicked + if (this.draggable && this._draggedPointerID == pointer.id) { return this.updateDrag(pointer); diff --git a/src/input/Mouse.js b/src/input/Mouse.js index 5734dc35..155666c0 100644 --- a/src/input/Mouse.js +++ b/src/input/Mouse.js @@ -25,27 +25,28 @@ Phaser.Mouse = function (game) { this.callbackContext = this.game; /** - * @property {Description} mouseDownCallback - Description. + * @property {function} mouseDownCallback - Description. * @default */ this.mouseDownCallback = null; /** - * @property {Description} mouseMoveCallback - Description. + * @property {function} mouseMoveCallback - Description. * @default */ this.mouseMoveCallback = null; /** - * @property {Description} mouseUpCallback - Description. + * @property {function} mouseUpCallback - Description. * @default */ this.mouseUpCallback = null; + /** - * @property {Description} mouseTypeDown - The type of click. -1 for not clicking + * @property {number} button- The type of click, either: Phaser.Mouse.NO_BUTTON, Phaser.Mouse.LEFT_BUTTON, Phaser.Mouse.MIDDLE_BUTTON or Phaser.Mouse.RIGHT_BUTTON. * @default */ - this.mouseTypeDown = -1; + this.button = -1; /** * You can disable all Input by setting disabled = true. While set all new input related events will be ignored. @@ -61,6 +62,13 @@ Phaser.Mouse = function (game) { */ this.locked = false; + /** + * This event is dispatched when the browser enters or leaves pointer lock state. + * @property {Phaser.Signal} pointerLock + * @default + */ + this.pointerLock = new Phaser.Signal; + }; /** @@ -86,7 +94,6 @@ Phaser.Mouse.MIDDLE_BUTTON = 1; */ Phaser.Mouse.RIGHT_BUTTON = 2; - Phaser.Mouse.prototype = { /** @@ -122,7 +129,7 @@ Phaser.Mouse.prototype = { }, /** - * Description. + * The internal method that handles the mouse down event from the browser. * @method Phaser.Mouse#onMouseDown * @param {MouseEvent} event */ @@ -130,9 +137,18 @@ Phaser.Mouse.prototype = { event.preventDefault(); - if (event.which === 1) this.mouseTypeDown = Phaser.Mouse.LEFT_BUTTON; - else if (event.which === 2) this.mouseTypeDown = Phaser.Mouse.MIDDLE_BUTTON; - else if (event.which === 3) this.mouseTypeDown = Phaser.Mouse.RIGHT_BUTTON; + if (event.which === 1) + { + this.button = Phaser.Mouse.LEFT_BUTTON; + } + else if (event.which === 2) + { + this.button = Phaser.Mouse.MIDDLE_BUTTON; + } + else if (event.which === 3) + { + this.button = Phaser.Mouse.RIGHT_BUTTON; + } if (this.mouseDownCallback) { @@ -151,7 +167,7 @@ Phaser.Mouse.prototype = { }, /** - * Description + * The internal method that handles the mouse move event from the browser. * @method Phaser.Mouse#onMouseMove * @param {MouseEvent} event */ @@ -176,7 +192,7 @@ Phaser.Mouse.prototype = { }, /** - * Description. + * The internal method that handles the mouse up event from the browser. * @method Phaser.Mouse#onMouseUp * @param {MouseEvent} event */ @@ -184,7 +200,7 @@ Phaser.Mouse.prototype = { event.preventDefault(); - this.mouseTypeDown = Phaser.Mouse.NO_BUTTON; + this.button = Phaser.Mouse.NO_BUTTON; if (this.mouseUpCallback) { @@ -203,7 +219,9 @@ Phaser.Mouse.prototype = { }, /** - * Description. + * If the browser supports it you can request that the pointer be locked to the browser window. + * This is classically known as 'FPS controls', where the pointer can't leave the browser until the user presses an exit key. + * If the browser successfully enters a locked state the event Phaser.Mouse.pointerLock will be dispatched and the first parameter will be 'true'. * @method Phaser.Mouse#requestPointerLock */ requestPointerLock: function () { @@ -222,15 +240,15 @@ Phaser.Mouse.prototype = { return _this.pointerLockChange(event); }; - document.addEventListener('pointerlockchange', this._pointerLockChange, false); - document.addEventListener('mozpointerlockchange', this._pointerLockChange, false); - document.addEventListener('webkitpointerlockchange', this._pointerLockChange, false); + document.addEventListener('pointerlockchange', this._pointerLockChange, true); + document.addEventListener('mozpointerlockchange', this._pointerLockChange, true); + document.addEventListener('webkitpointerlockchange', this._pointerLockChange, true); } }, /** - * Description. + * Internal pointerLockChange handler. * @method Phaser.Mouse#pointerLockChange * @param {MouseEvent} event */ @@ -242,17 +260,19 @@ Phaser.Mouse.prototype = { { // Pointer was successfully locked this.locked = true; + this.pointerLock.dispatch(true); } else { // Pointer was unlocked this.locked = false; + this.pointerLock.dispatch(false); } }, /** - * Description. + * Internal release pointer lock handler. * @method Phaser.Mouse#releasePointerLock */ releasePointerLock: function () { @@ -261,9 +281,9 @@ Phaser.Mouse.prototype = { document.exitPointerLock(); - document.removeEventListener('pointerlockchange', this._pointerLockChange); - document.removeEventListener('mozpointerlockchange', this._pointerLockChange); - document.removeEventListener('webkitpointerlockchange', this._pointerLockChange); + document.removeEventListener('pointerlockchange', this._pointerLockChange, true); + document.removeEventListener('mozpointerlockchange', this._pointerLockChange, true); + document.removeEventListener('webkitpointerlockchange', this._pointerLockChange, true); }, @@ -273,9 +293,9 @@ Phaser.Mouse.prototype = { */ stop: function () { - this.game.stage.canvas.removeEventListener('mousedown', this._onMouseDown); - this.game.stage.canvas.removeEventListener('mousemove', this._onMouseMove); - this.game.stage.canvas.removeEventListener('mouseup', this._onMouseUp); + this.game.stage.canvas.removeEventListener('mousedown', this._onMouseDown, true); + this.game.stage.canvas.removeEventListener('mousemove', this._onMouseMove, true); + this.game.stage.canvas.removeEventListener('mouseup', this._onMouseUp, true); } diff --git a/tutorials/01 Getting Started/index.html b/tutorials/01 Getting Started/index.html new file mode 100644 index 00000000..f4bb3802 --- /dev/null +++ b/tutorials/01 Getting Started/index.html @@ -0,0 +1,80 @@ + + + + + Phaser Tutorial 01 - Getting Started + + + + + +

Getting started with Phaser

+ +

Part 1 - Setting up your development environment

+ +

In this tutorial we're going to cover setting-up a development enviornment with which you can build your Phaser games. This will include running a local web server, picking an IDE, getting the latest version of Phaser and checking it all works together properly.

+ +

"But why do I need a local web server anyway? Can't I just drag the html files onto my browser?"

+ +

Not these days, no. I appreciate that it's a bit confusing, even contradictory at times, but it all boils down to browser security in the end. If you're making a static html web site, with a few images in it, then you can happily drag this into your browser and see the end results. You can also "Save As" entire web pages locally and re-open them, with all the contents mostly intact. So why can't you drag an HTML5 game into a browser and have it work?

+ +

It's to do with the protocol used to access the files. When you request anything over the web you're using http - and the server level security is enough to ensure you can only access files you're meant to. But when you drag a file in it's loaded via the local file system (technically file://) and that is a massively restricted one, for obvious reasons. Under file:// there's no concept of domains, no server level security - just a raw file system. Ask yourself this: do you really want JavaScript to have the ability to load files from your local file system? The immediate answer should of course be "no way!". If JavaScript had free reign while operating under file:// there would be nothing stopping it loading up any system file it fancied and sending it off over the net to anywhere it liked.

+ +

Because this is so dangerous browsers lock themselves down tighter than Alcatraz when running under file://. Every single page becomes treated as a unique local domain. That is why "Save Web page" work, to a degree. They still are under the same cross-site restrictions as if they were on a live server. (to a degree, they still can't save anything or send data out or load data like a game), but also why "Save Web page" cannot make a cross site request, i.e. it can't load or send local data elsewhere. There's a quite detailed post here about it: http://blog.chromium.org/2008/12/security-in-depth-local-web-pages.html + + + + Due to the way that web browser sandbox security works you will need a local web server running. This is so that your games can load in external assets like images and music. By default web browsers are unable to load local files, as if you think about it for a moment you should be grateful for that fact! Although there are ways to modify your browsers start-up settings to bypass the sandbox security we really don't recommend it, and as you're building games for the web it's only sensible that you run a local environment that as closely emulates the web on which your game will be running anyway.

+ + +

Download the latest version of Phaser

+ + +

In this tutorial we're going to build a game that will introduce some of the core features of Phaser to you. Before we begin there are a few things you'll need to have set-up if you haven't already:

+ +

Download the latest version of Phaser

+ +

The latest version of Phaser is available to download from github. At the time of writing that is version 1.1.2. If you aren't familiar with using git then github offer a handy "Download as zip" option which will download the whole repository in a single zip file. You can then unzip this locally and get to all the files. If you are happy using git then pull down the latest version of the repositiory before starting.

+ +

Set-up your development environment

+ +

Method 1: Run a local web server

+ +http://cesanta.com/downloads.html + +

On Windows there are lots of "single install" bundles available. These are easy-to-install files that package together popular web technologies like Apache, PHP and MySQL and install them all for you at once, often with a handy system-tray icon to manage them too. We would recommend either WAMP Server or XAMPP. Instead of an 'all in one' bundle you could also download just the web server on its own. Microsoft provide IIS and Apache can be downloaded for Windows as well.

+ +

Note: Skype likes to steal port 80 by default. This is the traditional port for a web server to run over and it might interfer with WAMP or similar being able to start. To disable this within Skype go to "Tools - Options - Connection" and uncheck the "Use port 80 and 443 as alternatives for incoming connections" checkbox.

+ +

On OS X you could download MAMP which comes in two versions (one free, one paid for). Or there are guides for setting up a local web server manually, such as this guide written for Mountain Lion. + +

Method 2: grunt connect

+ +

Grunt is an extremely powerful tool to have installed, regardless if you use it as a web server or not. At its essence it's a JavaScript based task runner and allows you to automate tedious time consuming tasks. But it can also be configured with Connect for serving local files and here's a guide on doing just that. + +

Method 3: Simple HTTP Server with Python

+ +

If you need a quick web server running and you don't want to mess around with setting up apache or something similar, then Python can help. Python comes with a simple built in HTTP server. With the help of this little HTTP server you can turn any directory in your system into your web server directory. The only thing you need to have installed is Python. Read the full guide here. + +

Method 4: http-server for node.js

+ +

http-server is a simple, zero-configuration command-line http server for node.js. It is powerful enough for production usage, but it's simple and hackable enough to be used for testing, local development, and learning. Or as the web site says "Serving up static files like they were turtles strapped to rockets". Get the npm and instructions from the http-server web site.

+ +

Method 5: php 5 built-in web server

+ +

As of PHP 5.4.0, the CLI SAPI provides a built-in web server. It's only really suitable for development purposes and servers all files sequentially, but it's easily powerful enough for testing HTML5 games. It's invoked from a single command-line call and you can find details on how to do this in the PHP Manual

. + + + + +

Method 2: Run in the cloud

+ + + + + \ No newline at end of file From 2e576fa9a71a04fc85f64f3e36dabc28e794b607 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Mon, 4 Nov 2013 20:43:59 +0000 Subject: [PATCH 8/9] Input Handler updates, orientation screen and World visibility --- README.md | 2 + examples/wip/pivot.js | 49 +++++++++++ src/core/Game.js | 6 +- src/core/World.js | 16 ++++ src/gameobjects/Button.js | 20 +++++ src/input/InputHandler.js | 44 ++++++---- src/input/Pointer.js | 1 - src/system/StageScaleMode.js | 162 +++++++++++++++++++++++++---------- 8 files changed, 236 insertions(+), 64 deletions(-) create mode 100644 examples/wip/pivot.js diff --git a/README.md b/README.md index d5773c02..468a9806 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ Version 1.1.3 - in build * New: Sprite.animations.getAnimation will return an animation instance which was added by name. * New: Added Mouse.button which is set to the button that was pressed: Phaser.Mouse.LEFT_BUTTON, MIDDLE_BUTTON or RIGHT_BUTTON (thanks wKLV) * New: Added Mouse.pointerLock signal which you can listen to whenever the browser enters or leaves pointer lock mode. +* New: StageScaleMode.forceOrientation allows you to lock your game to one orientation and display a Sprite (i.e. a "please rotate" screen) when incorrect. +* New: World.visible boolean added, toggles rendering of the world on/off entirely. * Fixed: Mouse.stop now uses the true useCapture, which means the event listeners stop listening correctly (thanks beeglebug) * Updated: RequestAnimationFrame now retains the callbackID which is passed to cancelRequestAnimationFrame. * Updated: Button now goes back to over state when setFrames used in action (thanks beeglebug) diff --git a/examples/wip/pivot.js b/examples/wip/pivot.js new file mode 100644 index 00000000..3bc4b2ed --- /dev/null +++ b/examples/wip/pivot.js @@ -0,0 +1,49 @@ +var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.image('atari', 'assets/sprites/atari130xe.png'); + game.load.image('mushroom', 'assets/sprites/mushroom2.png'); + +} + +var sprite1; +var sprite2; + +function create() { + + game.stage.backgroundColor = '#2d2d2d'; + + // This will check Sprite vs. Sprite collision + + sprite1 = game.add.sprite(300, 300, 'atari'); + sprite1.name = 'atari'; + sprite1.body.immovable = true; + + sprite1.anchor.setTo(0.5, 0.5); + sprite1.pivot.x = 250; + sprite1.pivot.y = 300; + + // sprite2 = game.add.sprite(0, 0, 'mushroom'); + // sprite2.name = 'mushroom'; + +} + +function update() { + + sprite1.angle += 1; + sprite1.pivot.x = game.input.x; + sprite1.pivot.y = game.input.y; + +} + +function render() { + + game.debug.renderPixel(sprite1.pivot.x, sprite1.pivot.y); + + // game.debug.renderSpriteInfo(sprite1, 100, 400); + game.debug.renderSpriteBounds(sprite1); + // game.debug.renderSpriteInfo(sprite2, 100, 100); + // game.debug.renderSpriteBounds(sprite2); +} + diff --git a/src/core/Game.js b/src/core/Game.js index 9f4122ea..9b37005b 100644 --- a/src/core/Game.js +++ b/src/core/Game.js @@ -422,7 +422,11 @@ Phaser.Game.prototype = { this.time.update(time); - if (!this._paused) + if (this._paused) + { + this.renderer.render(this.stage._stage); + } + else { this.plugins.preUpdate(); this.physics.preUpdate(); diff --git a/src/core/World.js b/src/core/World.js index 61bc6692..3f2d4609 100644 --- a/src/core/World.js +++ b/src/core/World.js @@ -258,3 +258,19 @@ Object.defineProperty(Phaser.World.prototype, "randomY", { } }); + +/** +* @name Phaser.World#visible +* @property {boolean} visible - Gets or sets the visible state of the World. +*/ +Object.defineProperty(Phaser.World.prototype, "visible", { + + get: function () { + return this._container.visible; + }, + + set: function (value) { + this._container.visible = value; + } + +}); diff --git a/src/gameobjects/Button.js b/src/gameobjects/Button.js index 53f49dd1..77ad8b1d 100644 --- a/src/gameobjects/Button.js +++ b/src/gameobjects/Button.js @@ -169,6 +169,13 @@ Phaser.Button = function (game, x, y, key, callback, callbackContext, overFrame, */ this.freezeFrames = false; + /** + * When the Button is clicked you can optionally force the state to "out". + * @property {boolean} forceOut + * @default + */ + this.forceOut = true; + this.setFrames(overFrame, outFrame, downFrame); if (callback !== null) @@ -513,8 +520,21 @@ Phaser.Button.prototype.onInputUpHandler = function (pointer) { this.onUpSound.play(this.onUpSoundMarker); } + if (this.forceOut && this.freezeFrames == false) + { + if (this._onOutFrameName != null) + { + this.frameName = this._onOutFrameName; + } + else if (this._onOutFrameID != null) + { + this.frame = this._onOutFrameID; + } + } + if (this.onInputUp) { this.onInputUp.dispatch(this, pointer); } + }; diff --git a/src/input/InputHandler.js b/src/input/InputHandler.js index 19879e08..a2d8abaf 100644 --- a/src/input/InputHandler.js +++ b/src/input/InputHandler.js @@ -410,20 +410,25 @@ Phaser.InputHandler.prototype = { */ pointerOver: function (index) { - if (typeof index === 'undefined') + if (this.enabled) { - for (var i = 0; i < 10; i++) + if (typeof index === 'undefined') { - if (this._pointerData[i].isOver) + for (var i = 0; i < 10; i++) { - return true; + if (this._pointerData[i].isOver) + { + return true; + } } } + else + { + return this._pointerData[index].isOver; + } } - else - { - return this._pointerData[index].isOver; - } + + return false; }, @@ -435,20 +440,25 @@ Phaser.InputHandler.prototype = { */ pointerOut: function (pointer) { - if (typeof index === 'undefined') + if (this.enabled) { - for (var i = 0; i < 10; i++) + if (typeof index === 'undefined') { - if (this._pointerData[i].isOut) + for (var i = 0; i < 10; i++) { - return true; + if (this._pointerData[i].isOut) + { + return true; + } } } + else + { + return this._pointerData[index].isOut; + } } - else - { - return this._pointerData[index].isOut; - } + + return false; }, @@ -569,8 +579,6 @@ Phaser.InputHandler.prototype = { return false; } - // For an enabled sprite that may have been clicked - if (this.draggable && this._draggedPointerID == pointer.id) { return this.updateDrag(pointer); diff --git a/src/input/Pointer.js b/src/input/Pointer.js index 402e2e55..855846a6 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -397,7 +397,6 @@ Phaser.Pointer.prototype = { } return this; - } // Work out which object is on the top diff --git a/src/system/StageScaleMode.js b/src/system/StageScaleMode.js index 142e4610..c9318806 100644 --- a/src/system/StageScaleMode.js +++ b/src/system/StageScaleMode.js @@ -17,45 +17,19 @@ Phaser.StageScaleMode = function (game, width, height) { /** - * @property {number} _startHeight - Stage height when starting the game. - * @default - * @private + * @property {Phaser.Game} game - A reference to the currently running game. */ - this._startHeight = 0; + this.game = game; /** - * @property {boolean} forceLandscape - If the game should be forced to use Landscape mode, this is set to true by Game.Stage - * @default + * @property {number} width - Width of the stage after calculation. */ - this.forceLandscape = false; + this.width = width; /** - * @property {boolean} forcePortrait - If the game should be forced to use Portrait mode, this is set to true by Game.Stage - * @default + * @property {number} height - Height of the stage after calculation. */ - this.forcePortrait = false; - - /** - * @property {boolean} incorrectOrientation - If the game should be forced to use a specific orientation and the device currently isn't in that orientation this is set to true. - * @default - */ - this.incorrectOrientation = false; - - /** - * @property {boolean} pageAlignHorizontally - If you wish to align your game in the middle of the page then you can set this value to true. -
  • It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing.
  • -
  • It doesn't care about any other DOM element that may be on the page, it literally just sets the margin.
- * @default - */ - this.pageAlignHorizontally = false; - - /** - * @property {boolean} pageAlignVertically - If you wish to align your game in the middle of the page then you can set this value to true. -
  • It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing. -
  • It doesn't care about any other DOM element that may be on the page, it literally just sets the margin.
- * @default - */ - this.pageAlignVertically = false; + this.height = height; /** * @property {number} minWidth - Minimum width the canvas should be scaled to (in pixels). @@ -84,14 +58,45 @@ Phaser.StageScaleMode = function (game, width, height) { this.maxHeight = null; /** - * @property {number} width - Width of the stage after calculation. + * @property {number} _startHeight - Stage height when starting the game. + * @default + * @private */ - this.width = width; + this._startHeight = 0; /** - * @property {number} height - Height of the stage after calculation. + * @property {boolean} forceLandscape - If the game should be forced to use Landscape mode, this is set to true by Game.Stage + * @default */ - this.height = height; + this.forceLandscape = false; + + /** + * @property {boolean} forcePortrait - If the game should be forced to use Portrait mode, this is set to true by Game.Stage + * @default + */ + this.forcePortrait = false; + + /** + * @property {boolean} incorrectOrientation - If the game should be forced to use a specific orientation and the device currently isn't in that orientation this is set to true. + * @default + */ + this.incorrectOrientation = false; + + /** + * @property {boolean} pageAlignHorizontally - If you wish to align your game in the middle of the page then you can set this value to true. + * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing. + * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin. + * @default + */ + this.pageAlignHorizontally = false; + + /** + * @property {boolean} pageAlignVertically - If you wish to align your game in the middle of the page then you can set this value to true. + * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing. + * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin. + * @default + */ + this.pageAlignVertically = false; /** * @property {number} _width - Cached stage width for full screen mode. @@ -113,18 +118,20 @@ Phaser.StageScaleMode = function (game, width, height) { */ this.maxIterations = 5; - /** - * @property {Phaser.Game} game - A reference to the currently running game. - */ - this.game = game; /** - * @property {Description} enterLandscape - Description. + * @property {PIXI.Sprite} orientationSprite - The Sprite that is optionally displayed if the browser enters an unsupported orientation. + * @default + */ + this.orientationSprite = null; + + /** + * @property {Phaser.Signal} enterLandscape - The event that is dispatched when the browser enters landscape orientation. */ this.enterLandscape = new Phaser.Signal(); /** - * @property {Description} enterPortrait - Description. + * @property {Phaser.Signal} enterPortrait - The event that is dispatched when the browser enters horizontal orientation. */ this.enterPortrait = new Phaser.Signal(); @@ -145,7 +152,7 @@ Phaser.StageScaleMode = function (game, width, height) { } /** - * @property {Description} scaleFactor - Description. + * @property {Phaser.Point} scaleFactor - The scale factor based on the game dimensions vs. the scaled dimensions. */ this.scaleFactor = new Phaser.Point(1, 1); @@ -298,6 +305,54 @@ Phaser.StageScaleMode.prototype = { }, + /** + * If you need your game to run in only one orientation you can force that to happen. + * The optional orientationImage is displayed when the game is in the incorrect orientation. + * @method Phaser.StageScaleMode#forceOrientation + * @param {boolean} forceLandscape - true if the game should run in landscape mode only. + * @param {boolean} forcePortrait - true if the game should run in portrait mode only. + * @param {string} [forcePortrait=''] - The string of an image in the Phaser.Cache to display when this game is in the incorrect orientation. + */ + forceOrientation: function (forceLandscape, forcePortrait, orientationImage) { + + this.forceLandscape = forceLandscape; + + if (typeof forcePortrait === 'undefined') + { + this.forcePortrait = false; + } + + if (typeof orientationImage !== 'undefined') + { + if (orientationImage == null || this.game.cache.checkImageKey(orientationImage) == false) + { + orientationImage = '__default'; + } + + this.orientationSprite = new PIXI.Sprite(PIXI.TextureCache[orientationImage]); + this.orientationSprite.anchor.x = 0.5; + this.orientationSprite.anchor.y = 0.5; + this.orientationSprite.position.x = this.game.width / 2; + this.orientationSprite.position.y = this.game.height / 2; + + this.checkOrientationState(); + + if (this.incorrectOrientation) + { + this.orientationSprite.visible = true; + this.game.world.visible = false; + } + else + { + this.orientationSprite.visible = false; + this.game.world.visible = true; + } + + this.game.stage._stage.addChild(this.orientationSprite); + } + + }, + /** * Checks if the browser is in the correct orientation for your game (if forceLandscape or forcePortrait have been set) * @method Phaser.StageScaleMode#checkOrientationState @@ -312,6 +367,13 @@ Phaser.StageScaleMode.prototype = { // Back to normal this.game.paused = false; this.incorrectOrientation = false; + + if (this.orientationSprite) + { + this.orientationSprite.visible = false; + this.game.world.visible = true; + } + this.refresh(); } } @@ -322,6 +384,13 @@ Phaser.StageScaleMode.prototype = { // Show orientation screen this.game.paused = true; this.incorrectOrientation = true; + + if (this.orientationSprite && this.orientationSprite.visible == false) + { + this.orientationSprite.visible = true; + this.game.world.visible = false; + } + this.refresh(); } } @@ -381,6 +450,9 @@ Phaser.StageScaleMode.prototype = { { this.refresh(); } + + this.checkOrientationState(); + }, /** @@ -420,7 +492,7 @@ Phaser.StageScaleMode.prototype = { /** * Set screen size automatically based on the scaleMode. - * @param {Description} force - If force is true it will try to resize the game regardless of the document dimensions. + * @param {boolean} force - If force is true it will try to resize the game regardless of the document dimensions. */ setScreenSize: function (force) { @@ -533,6 +605,8 @@ Phaser.StageScaleMode.prototype = { this.scaleFactor.x = this.game.width / this.width; this.scaleFactor.y = this.game.height / this.height; + this.checkOrientationState(); + }, /** From fa8533f5d10008d3c50c2544d7e9d6c2763096b5 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Mon, 4 Nov 2013 20:45:51 +0000 Subject: [PATCH 9/9] Added Tetris sprites --- resources/wip/rotations.png | Bin 0 -> 4545 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 resources/wip/rotations.png diff --git a/resources/wip/rotations.png b/resources/wip/rotations.png new file mode 100644 index 0000000000000000000000000000000000000000..2b2f140210556f24cd318c842505498f7c44328e GIT binary patch literal 4545 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 literal 0 HcmV?d00001