From 22b1ce9b9d617807589e180ae3b44328c2bd5892 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Wed, 5 Mar 2014 02:36:08 +0000 Subject: [PATCH] Added Phasers new Physics Manager and restored the pre-1.1.4 ArcadePhysics system. The new manager can handle multiple physics systems running in parallel, which could be extremely useful for lots of games. --- README.md | 1 + build/config.php | 30 +- build/phaser.d.ts | 2 +- examples/wip/physics-1.js | 54 + src/animation/Animation.js | 2 - src/core/Game.js | 4 +- src/core/GameNoPhysics.js | 729 -------- src/core/StateManager.js | 11 +- src/gameobjects/Image.js | 13 +- src/gameobjects/Sprite.js | 33 +- src/geom/Circle.js | 2 +- src/physics/Physics.js | 145 ++ src/physics/arcade/Body.js | 635 +++++++ ...rcadePhysics.js => BrokenArcadePhysics.js} | 0 src/physics/arcade/QuadTree.js | 265 +++ src/physics/arcade/TempSprite.js | 1126 ++++++++++++ src/physics/arcade/World.js | 1611 +++++++++++++++++ src/physics/{ => p2}/Body.js | 0 src/physics/{ => p2}/CollisionGroup.js | 4 +- src/physics/{ => p2}/ContactMaterial.js | 16 +- src/physics/{ => p2}/InversePointProxy.js | 14 +- src/physics/{ => p2}/Material.js | 8 +- src/physics/{ => p2}/PointProxy.js | 14 +- src/physics/{ => p2}/Spring.js | 8 +- src/physics/{ => p2}/World.js | 183 +- src/utils/Debug.js | 2 +- 26 files changed, 4004 insertions(+), 908 deletions(-) create mode 100644 examples/wip/physics-1.js delete mode 100644 src/core/GameNoPhysics.js create mode 100644 src/physics/Physics.js create mode 100644 src/physics/arcade/Body.js rename src/physics/arcade/{ArcadePhysics.js => BrokenArcadePhysics.js} (100%) create mode 100644 src/physics/arcade/QuadTree.js create mode 100644 src/physics/arcade/TempSprite.js create mode 100644 src/physics/arcade/World.js rename src/physics/{ => p2}/Body.js (100%) rename src/physics/{ => p2}/CollisionGroup.js (80%) rename src/physics/{ => p2}/ContactMaterial.js (69%) rename src/physics/{ => p2}/InversePointProxy.js (70%) rename src/physics/{ => p2}/Material.js (66%) rename src/physics/{ => p2}/PointProxy.js (72%) rename src/physics/{ => p2}/Spring.js (87%) rename src/physics/{ => p2}/World.js (81%) diff --git a/README.md b/README.md index 8ae0ef02..9634ff9a 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,7 @@ Bug Fixes: * You can now load in CSV Tilemaps again and they get created properly (fixes #391) * Tilemap.putTile can now insert a tile into a null/blank area of the map (before it could only replace existing tiles) * Tilemap.putTile now correctly re-calculates the collision data based on the new collideIndexes array (fixes #371) +* Circle.circumferencePoint using the asDegrees parameter would apply degToRad instead of radToDeg (thanks Ziriax, fixes #509) TO DO: diff --git a/build/config.php b/build/config.php index aa105f96..1281d836 100644 --- a/build/config.php +++ b/build/config.php @@ -135,14 +135,20 @@ - - - - - - - - + + + + + + + + + + + + + + @@ -154,4 +160,12 @@ EOL; + +/* + + + + +*/ + ?> \ No newline at end of file diff --git a/build/phaser.d.ts b/build/phaser.d.ts index 44e3ac6b..79b54741 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -1450,7 +1450,7 @@ declare module Phaser { static intersectsRectangle(c: Phaser.Circle, r: Phaser.Rectangle): boolean; //methods circumference(): number; - circumferencePoint(angle: number, asDegrees: number, output?: Phaser.Point): Phaser.Point; + circumferencePoint(angle: number, asDegrees: boolean, output?: Phaser.Point): Phaser.Point; clone(out: Phaser.Circle): Phaser.Circle; contains(x: number, y: number): boolean; copyFrom(source: any): Circle; diff --git a/examples/wip/physics-1.js b/examples/wip/physics-1.js new file mode 100644 index 00000000..b50fd293 --- /dev/null +++ b/examples/wip/physics-1.js @@ -0,0 +1,54 @@ + +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(50, 200, 'atari'); + sprite1.name = 'atari'; + + sprite2 = game.add.sprite(700, 220, 'mushroom'); + sprite2.name = 'mushroom'; + + // Enable the physics bodies of both sprites + game.physics.enable([sprite1, sprite2]); + + // And move 'em + sprite1.body.velocity.x = 100; + sprite2.body.velocity.x = -100; + +} + +function update() { + + // object1, object2, collideCallback, processCallback, callbackContext + game.physics.arcade.collide(sprite1, sprite2, collisionHandler, null, this); + +} + +function collisionHandler (obj1, obj2) { + + // The two sprites are colliding + game.stage.backgroundColor = '#992d2d'; + +} + +function render() { + + // game.debug.physicsBody(sprite1.body); + // game.debug.physicsBody(sprite2.body); + +} \ No newline at end of file diff --git a/src/animation/Animation.js b/src/animation/Animation.js index e410ed21..74412c42 100644 --- a/src/animation/Animation.js +++ b/src/animation/Animation.js @@ -139,8 +139,6 @@ Phaser.Animation = function (game, parent, name, frameData, frames, delay, loop) // Set-up some event listeners this.game.onPause.add(this.onPause, this); this.game.onResume.add(this.onResume, this); - - console.log('animation created', this); }; diff --git a/src/core/Game.js b/src/core/Game.js index 9a88793f..a3a244eb 100644 --- a/src/core/Game.js +++ b/src/core/Game.js @@ -172,7 +172,7 @@ Phaser.Game = function (width, height, renderer, parent, state, transparent, ant this.world = null; /** - * @property {Phaser.Physics.World} physics - Reference to the physics world. + * @property {Phaser.Physics} physics - Reference to the physics manager. */ this.physics = null; @@ -414,7 +414,7 @@ Phaser.Game.prototype = { this.tweens = new Phaser.TweenManager(this); this.input = new Phaser.Input(this); this.sound = new Phaser.SoundManager(this); - this.physics = new Phaser.Physics.World(this, this.physicsConfig); + this.physics = new Phaser.Physics(this, this.physicsConfig); this.particles = new Phaser.Particles(this); this.plugins = new Phaser.PluginManager(this, this); this.net = new Phaser.Net(this); diff --git a/src/core/GameNoPhysics.js b/src/core/GameNoPhysics.js deleted file mode 100644 index d4b69b6b..00000000 --- a/src/core/GameNoPhysics.js +++ /dev/null @@ -1,729 +0,0 @@ -/** -* @author Richard Davey -* @copyright 2014 Photon Storm Ltd. -* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} -*/ - -/** -* Game constructor -* -* Instantiate a new Phaser.Game object. -* @class Phaser.Game -* @classdesc This is where the magic happens. The Game object is the heart of your game, -* providing quick access to common functions and handling the boot process. -* "Hell, there are no rules here - we're trying to accomplish something." -* Thomas A. Edison -* @constructor -* @param {number} [width=800] - The width of your game in game pixels. -* @param {number} [height=600] - The height of your game in game pixels. -* @param {number} [renderer=Phaser.AUTO] - Which renderer to use: Phaser.AUTO will auto-detect, Phaser.WEBGL, Phaser.CANVAS or Phaser.HEADLESS (no rendering at all). -* @param {string|HTMLElement} [parent=''] - The DOM element into which this games canvas will be injected. Either a DOM ID (string) or the element itself. -* @param {object} [state=null] - The default state object. A object consisting of Phaser.State functions (preload, create, update, render) or null. -* @param {boolean} [transparent=false] - Use a transparent canvas background or not. -* @param {boolean} [antialias=true] - Draw all image textures anti-aliased or not. The default is for smooth textures, but disable if your game features pixel art. -*/ -Phaser.Game = function (width, height, renderer, parent, state, transparent, antialias) { - - /** - * @property {number} id - Phaser Game ID (for when Pixi supports multiple instances). - */ - this.id = Phaser.GAMES.push(this) - 1; - - /** - * @property {object} config - The Phaser.Game configuration object. - */ - this.config = null; - - /** - * @property {HTMLElement} parent - The Games DOM parent. - * @default - */ - this.parent = ''; - - /** - * @property {number} width - The Game width (in pixels). - * @default - */ - this.width = 800; - - /** - * @property {number} height - The Game height (in pixels). - * @default - */ - this.height = 600; - - /** - * @property {boolean} transparent - Use a transparent canvas background or not. - * @default - */ - this.transparent = false; - - /** - * @property {boolean} antialias - Anti-alias graphics (in WebGL this helps with edges, in Canvas2D it retains pixel-art quality). - * @default - */ - this.antialias = true; - - /** - * @property {number} renderer - The Pixi Renderer - * @default - */ - this.renderer = Phaser.AUTO; - - /** - * @property {number} renderType - The Renderer this game will use. Either Phaser.AUTO, Phaser.CANVAS or Phaser.WEBGL. - */ - this.renderType = Phaser.AUTO; - - /** - * @property {number} state - The StateManager. - */ - this.state = null; - - /** - * @property {boolean} isBooted - Whether the game engine is booted, aka available. - * @default - */ - this.isBooted = false; - - /** - * @property {boolean} id -Is game running or paused? - * @default - */ - this.isRunning = false; - - /** - * @property {Phaser.RequestAnimationFrame} raf - Automatically handles the core game loop via requestAnimationFrame or setTimeout - */ - this.raf = null; - - /** - * @property {Phaser.GameObjectFactory} add - Reference to the Phaser.GameObjectFactory. - */ - this.add = null; - - /** - * @property {Phaser.GameObjectCreator} make - Reference to the GameObject Creator. - */ - this.make = null; - - /** - * @property {Phaser.Cache} cache - Reference to the assets cache. - * @default - */ - this.cache = null; - - /** - * @property {Phaser.Input} input - Reference to the input manager - * @default - */ - this.input = null; - - /** - * @property {Phaser.Loader} load - Reference to the assets loader. - * @default - */ - this.load = null; - - /** - * @property {Phaser.Math} math - Reference to the math helper. - */ - this.math = null; - - /** - * @property {Phaser.Net} net - Reference to the network class. - */ - this.net = null; - - /** - * @property {Phaser.ScaleManager} scale - The game scale manager. - */ - this.scale = null; - - /** - * @property {Phaser.SoundManager} sound - Reference to the sound manager. - */ - this.sound = null; - - /** - * @property {Phaser.Stage} stage - Reference to the stage. - */ - this.stage = null; - - /** - * @property {Phaser.TimeManager} time - Reference to game clock. - */ - this.time = null; - - /** - * @property {Phaser.TweenManager} tweens - Reference to the tween manager. - */ - this.tweens = null; - - /** - * @property {Phaser.World} world - Reference to the world. - */ - this.world = null; - - /** - * @property {Phaser.RandomDataGenerator} rnd - Instance of repeatable random data generator helper. - */ - this.rnd = null; - - /** - * @property {Phaser.Device} device - Contains device information and capabilities. - */ - this.device = null; - - /** - * @property {Phaser.Physics.PhysicsManager} camera - A handy reference to world.camera. - */ - this.camera = null; - - /** - * @property {HTMLCanvasElement} canvas - A handy reference to renderer.view, the canvas that the game is being rendered in to. - */ - this.canvas = null; - - /** - * @property {Context} context - A handy reference to renderer.context (only set for CANVAS games, not WebGL) - */ - this.context = null; - - /** - * @property {Phaser.Utils.Debug} debug - A set of useful debug utilitie. - */ - this.debug = null; - - /** - * @property {boolean} stepping - Enable core loop stepping with Game.enableStep(). - * @default - * @readonly - */ - this.stepping = false; - - /** - * @property {boolean} stepping - An internal property used by enableStep, but also useful to query from your own game objects. - * @default - * @readonly - */ - this.pendingStep = false; - - /** - * @property {number} stepCount - When stepping is enabled this contains the current step cycle. - * @default - * @readonly - */ - this.stepCount = 0; - - /** - * @property {boolean} _paused - Is game paused? - * @private - * @default - */ - this._paused = false; - - /** - * @property {boolean} _codePaused - Was the game paused via code or a visibility change? - * @private - * @default - */ - this._codePaused = false; - - // Parse the configuration object (if any) - if (arguments.length === 1 && typeof arguments[0] === 'object') - { - this.parseConfig(arguments[0]); - } - else - { - if (typeof width !== 'undefined') - { - this.width = width; - } - - if (typeof height !== 'undefined') - { - this.height = height; - } - - if (typeof renderer !== 'undefined') - { - this.renderer = renderer; - this.renderType = renderer; - } - - if (typeof parent !== 'undefined') - { - this.parent = parent; - } - - if (typeof transparent !== 'undefined') - { - this.transparent = transparent; - } - - if (typeof antialias !== 'undefined') - { - this.antialias = antialias; - } - - this.state = new Phaser.StateManager(this, state); - } - - var _this = this; - - this._onBoot = function () { - return _this.boot(); - } - - if (document.readyState === 'complete' || document.readyState === 'interactive') - { - window.setTimeout(this._onBoot, 0); - } - else - { - document.addEventListener('DOMContentLoaded', this._onBoot, false); - window.addEventListener('load', this._onBoot, false); - } - - return this; - -}; - -Phaser.Game.prototype = { - - /** - * Parses a Game configuration object. - * - * @method Phaser.Game#parseConfig - * @protected - */ - parseConfig: function (config) { - - this.config = config; - - if (config['width']) - { - this.width = Phaser.Utils.parseDimension(config['width'], 0); - } - - if (config['height']) - { - this.height = Phaser.Utils.parseDimension(config['height'], 1); - } - - if (config['renderer']) - { - this.renderer = config['renderer']; - this.renderType = config['renderer']; - } - - if (config['parent']) - { - this.parent = config['parent']; - } - - if (config['transparent']) - { - this.transparent = config['transparent']; - } - - if (config['antialias']) - { - this.antialias = config['antialias']; - } - - var state = null; - - if (config['state']) - { - state = config['state']; - } - - this.state = new Phaser.StateManager(this, state); - - }, - - /** - * Initialize engine sub modules and start the game. - * - * @method Phaser.Game#boot - * @protected - */ - boot: function () { - - if (this.isBooted) - { - return; - } - - if (!document.body) - { - window.setTimeout(this._onBoot, 20); - } - else - { - document.removeEventListener('DOMContentLoaded', this._onBoot); - window.removeEventListener('load', this._onBoot); - - this.onPause = new Phaser.Signal(); - this.onResume = new Phaser.Signal(); - - this.isBooted = true; - - this.device = new Phaser.Device(this); - this.math = Phaser.Math; - this.rnd = new Phaser.RandomDataGenerator([(Date.now() * Math.random()).toString()]); - - this.stage = new Phaser.Stage(this, this.width, this.height); - this.scale = new Phaser.ScaleManager(this, this.width, this.height); - - this.setUpRenderer(); - - this.device.checkFullScreenSupport(); - - this.world = new Phaser.World(this); - this.add = new Phaser.GameObjectFactory(this); - this.make = new Phaser.GameObjectCreator(this); - this.cache = new Phaser.Cache(this); - this.load = new Phaser.Loader(this); - this.time = new Phaser.Time(this); - this.tweens = new Phaser.TweenManager(this); - this.input = new Phaser.Input(this); - this.sound = new Phaser.SoundManager(this); - this.plugins = new Phaser.PluginManager(this, this); - 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(); - this.sound.boot(); - this.state.boot(); - - this.showDebugHeader(); - - this.isRunning = true; - - if (this.config && this.config['forceSetTimeOut']) - { - this.raf = new Phaser.RequestAnimationFrame(this, this.config['forceSetTimeOut']); - } - else - { - this.raf = new Phaser.RequestAnimationFrame(this, false); - } - - this.raf.start(); - } - - }, - - /** - * Displays a Phaser version debug header in the console. - * - * @method Phaser.Game#showDebugHeader - * @protected - */ - showDebugHeader: function () { - - var v = Phaser.DEV_VERSION; - var r = 'Canvas'; - var a = 'HTML Audio'; - - if (this.renderType == Phaser.WEBGL) - { - r = 'WebGL'; - } - else if (this.renderType == Phaser.HEADLESS) - { - r = 'Headless'; - } - - if (this.device.webAudio) - { - a = 'WebAudio'; - } - - if (this.device.chrome) - { - var args = [ - '%c %c %c Phaser v' + v + ' - Renderer: ' + r + ' - Audio: ' + a + ' %c %c ', - 'background: #00bff3', - 'background: #0072bc', - 'color: #ffffff; background: #003471', - 'background: #0072bc', - 'background: #00bff3' - ]; - - console.log.apply(console, args); - } - else - { - console.log('Phaser v' + v + '.np - Renderer: ' + r + ' - Audio: ' + a); - } - - }, - - /** - * Checks if the device is capable of using the requested renderer and sets it up or an alternative if not. - * - * @method Phaser.Game#setUpRenderer - * @protected - */ - setUpRenderer: function () { - - if (this.device.trident) - { - // Pixi WebGL renderer on IE11 doesn't work correctly at the moment, the pre-multiplied alpha gets all washed out. - // So we're forcing canvas for now until this is fixed, sorry. It's got to be better than no game appearing at all, right? - this.renderType = Phaser.CANVAS; - } - - if (this.renderType === Phaser.HEADLESS || this.renderType === Phaser.CANVAS || (this.renderType === Phaser.AUTO && this.device.webGL === false)) - { - if (this.device.canvas) - { - if (this.renderType === Phaser.AUTO) - { - this.renderType = Phaser.CANVAS; - } - - this.renderer = new PIXI.CanvasRenderer(this.width, this.height, this.canvas, this.transparent); - this.context = this.renderer.context; - } - else - { - throw new Error('Phaser.Game - cannot create Canvas or WebGL context, aborting.'); - } - } - else - { - // They requested WebGL, and their browser supports it - this.renderType = Phaser.WEBGL; - this.renderer = new PIXI.WebGLRenderer(this.width, this.height, this.canvas, this.transparent, this.antialias); - this.context = null; - } - - if (!this.antialias) - { - this.stage.smoothed = false; - } - - Phaser.Canvas.addToDOM(this.canvas, this.parent, true); - Phaser.Canvas.setTouchAction(this.canvas); - - }, - - /** - * The core game loop. - * - * @method Phaser.Game#update - * @protected - * @param {number} time - The current time as provided by RequestAnimationFrame. - */ - update: function (time) { - - this.time.update(time); - - if (this._paused) - { - this.input.update(); - - if (this.renderType !== Phaser.HEADLESS) - { - this.renderer.render(this.stage); - this.plugins.render(); - this.state.render(); - - this.plugins.postRender(); - } - } - else - { - if (!this.pendingStep) - { - if (this.stepping) - { - this.pendingStep = true; - } - - this.state.preUpdate(); - this.plugins.preUpdate(); - this.stage.preUpdate(); - - this.stage.update(); - this.tweens.update(); - this.sound.update(); - this.input.update(); - this.state.update(); - this.plugins.update(); - - this.stage.postUpdate(); - this.plugins.postUpdate(); - } - - if (this.renderType !== Phaser.HEADLESS) - { - this.renderer.render(this.stage); - this.plugins.render(); - this.state.render(); - - this.plugins.postRender(); - } - } - - }, - - /** - * Enable core game loop stepping. When enabled you must call game.step() directly (perhaps via a DOM button?) - * Calling step will advance the game loop by one frame. This is extremely useful to hard to track down errors! - * - * @method Phaser.Game#enableStep - */ - enableStep: function () { - - this.stepping = true; - this.pendingStep = false; - this.stepCount = 0; - - }, - - /** - * Disables core game loop stepping. - * - * @method Phaser.Game#disableStep - */ - disableStep: function () { - - this.stepping = false; - this.pendingStep = false; - - }, - - /** - * When stepping is enabled you must call this function directly (perhaps via a DOM button?) to advance the game loop by one frame. - * This is extremely useful to hard to track down errors! Use the internal stepCount property to monitor progress. - * - * @method Phaser.Game#step - */ - step: function () { - - this.pendingStep = false; - this.stepCount++; - - }, - - /** - * Nuke the entire game from orbit - * - * @method Phaser.Game#destroy - */ - destroy: function () { - - this.raf.stop(); - - this.input.destroy(); - - this.state.destroy(); - - this.state = null; - this.cache = null; - this.input = null; - this.load = null; - this.sound = null; - this.stage = null; - this.time = null; - this.world = null; - this.isBooted = false; - - }, - - /** - * Called by the Stage visibility handler. - * - * @method Phaser.Game#gamePaused - */ - gamePaused: function (time) { - - // If the game is already paused it was done via game code, so don't re-pause it - if (!this._paused) - { - this._paused = true; - this.time.gamePaused(time); - this.sound.setMute(); - this.onPause.dispatch(this); - } - - }, - - /** - * Called by the Stage visibility handler. - * - * @method Phaser.Game#gameResumed - */ - gameResumed: function (time) { - - // Game is paused, but wasn't paused via code, so resume it - if (this._paused && !this._codePaused) - { - this._paused = false; - this.time.gameResumed(time); - this.input.reset(); - this.sound.unsetMute(); - this.onResume.dispatch(this); - } - - } - -}; - -Phaser.Game.prototype.constructor = Phaser.Game; - -/** -* The paused state of the Game. A paused game doesn't update any of its subsystems. -* When a game is paused the onPause event is dispatched. When it is resumed the onResume event is dispatched. -* @name Phaser.Game#paused -* @property {boolean} paused - Gets and sets the paused state of the Game. -*/ -Object.defineProperty(Phaser.Game.prototype, "paused", { - - get: function () { - return this._paused; - }, - - set: function (value) { - - if (value === true) - { - if (this._paused === false) - { - this._paused = true; - this._codePaused = true; - this.sound.mute = true; - this.time.gamePaused(); - this.onPause.dispatch(this); - } - } - else - { - if (this._paused) - { - this._paused = false; - this._codePaused = false; - this.input.reset(); - this.sound.mute = false; - this.time.gameResumed(); - this.onResume.dispatch(this); - } - } - - } - -}); - -/** -* "Deleted code is debugged code." - Jeff Sickel -*/ diff --git a/src/core/StateManager.js b/src/core/StateManager.js index bffda116..2abbcd9b 100644 --- a/src/core/StateManager.js +++ b/src/core/StateManager.js @@ -286,10 +286,7 @@ Phaser.StateManager.prototype = { this.game.world.destroy(); - if (this.game.physics) - { - this.game.physics.clear(); - } + this.game.physics.clear(); if (this._clearCache === true) { @@ -388,11 +385,7 @@ Phaser.StateManager.prototype = { this.states[key].world = this.game.world; this.states[key].particles = this.game.particles; this.states[key].rnd = this.game.rnd; - - if (this.game.physics) - { - this.states[key].physics = this.game.physics; - } + this.states[key].physics = this.game.physics; }, diff --git a/src/gameobjects/Image.js b/src/gameobjects/Image.js index a4e54fb4..b8582f5a 100644 --- a/src/gameobjects/Image.js +++ b/src/gameobjects/Image.js @@ -466,18 +466,11 @@ Phaser.Image.prototype.reset = function(x, y) { * @memberof Phaser.Image * @return {Phaser.Image} This instance. */ -Phaser.Image.prototype.bringToTop = function(child) { +Phaser.Image.prototype.bringToTop = function() { - if (typeof child === 'undefined') + if (this.parent) { - if (this.parent) - { - this.parent.bringToTop(this); - } - } - else - { - + this.parent.bringToTop(this); } return this; diff --git a/src/gameobjects/Sprite.js b/src/gameobjects/Sprite.js index 8dfc32e6..b7f75483 100644 --- a/src/gameobjects/Sprite.js +++ b/src/gameobjects/Sprite.js @@ -99,7 +99,7 @@ Phaser.Sprite = function (game, x, y, key, frame) { this.input = null; /** - * @property {Phaser.Physics.Body|null} body - The Sprites physics Body. Will be null unless physics has been enabled via `Sprite.physicsEnabled = true`. + * @property {Phaser.Physics.Arcade.Body|Phaser.Physics.P2.Body|null} body - The Sprites physics Body. Will be null unless physics has been enabled via `Sprite.physicsEnabled = true`. */ this.body = null; @@ -253,6 +253,11 @@ Phaser.Sprite.prototype.preUpdate = function() { this.animations.update(); + if (this.exists && this.body) + { + this.body.preUpdate(); + } + // Update any Children for (var i = 0, len = this.children.length; i < len; i++) { @@ -287,12 +292,9 @@ Phaser.Sprite.prototype.postUpdate = function() { this.key.render(); } - if (this.exists) + if (this.exists && this.body) { - if (this.body) - { - this.body.postUpdate(); - } + this.body.postUpdate(); } // Fixed to Camera? @@ -624,18 +626,11 @@ Phaser.Sprite.prototype.reset = function(x, y, health) { * @memberof Phaser.Sprite * @return (Phaser.Sprite) This instance. */ -Phaser.Sprite.prototype.bringToTop = function(child) { +Phaser.Sprite.prototype.bringToTop = function() { - if (typeof child === 'undefined') + if (this.parent) { - if (this.parent) - { - this.parent.bringToTop(this); - } - } - else - { - + this.parent.bringToTop(this); } return this; @@ -856,16 +851,15 @@ Object.defineProperty(Phaser.Sprite.prototype, "inputEnabled", { }); /** -* By default Sprites won't add themselves to the physics world. By setting physicsEnabled to true a Rectangle physics body is +* By default Sprites won't add themselves to the physics simulation. By setting physicsEnabled to true a Rectangle physics body is * attached to this Sprite matching its placement and dimensions, and will then start to process physics world updates. * You can access all physics related properties via Sprite.body. * -* Important: Enabling a Sprite for physics will automatically set `Sprite.anchor` to 0.5 s0 the physics body is centered on the Sprite. +* Important: Enabling a Sprite for physics will automatically set `Sprite.anchor` to 0.5 so the physics body is centered on the Sprite. * If you need a different result then adjust or re-create the Body shape offsets manually, and/or reset the anchor after enabling physics. * * @name Phaser.Sprite#physicsEnabled * @property {boolean} physicsEnabled - Set to true to add this Sprite to the physics world. Set to false to destroy the body and remove it from the physics world. -*/ Object.defineProperty(Phaser.Sprite.prototype, "physicsEnabled", { get: function () { @@ -894,6 +888,7 @@ Object.defineProperty(Phaser.Sprite.prototype, "physicsEnabled", { } }); +*/ /** * Sprite.exists controls if the core game loop and physics update this Sprite or not. diff --git a/src/geom/Circle.js b/src/geom/Circle.js index c755f013..60511440 100644 --- a/src/geom/Circle.js +++ b/src/geom/Circle.js @@ -482,7 +482,7 @@ Phaser.Circle.circumferencePoint = function (a, angle, asDegrees, out) { if (asDegrees === true) { - angle = Phaser.Math.radToDeg(angle); + angle = Phaser.Math.degToRad(angle); } out.x = a.x + a.radius * Math.cos(angle); diff --git a/src/physics/Physics.js b/src/physics/Physics.js new file mode 100644 index 00000000..d275a52a --- /dev/null +++ b/src/physics/Physics.js @@ -0,0 +1,145 @@ +/** +* @author Richard Davey +* @copyright 2014 Photon Storm Ltd. +* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} +*/ + +/** +* The Physics manager. +* +* @class Phaser.Physics +* +* @classdesc todo +* +* @constructor +* @param {Phaser.Game} game - A reference to the currently running game. +* @param {object} [physicsConfig=null] - A physics configuration object to pass to the Physics world on creation. +*/ +Phaser.Physics = function (game, config) { + + /** + * @property {Phaser.Game} game - Local reference to game. + */ + this.game = game; + + this.config = config; + + this.arcade = new Phaser.Physics.Arcade(game); + + this.p2 = null; + + this.box2d = null; + + this.chipmunk = null; + +}; + +/** +* @const +* @type {number} +*/ +Phaser.Physics.ARCADE = 0; + +/** +* @const +* @type {number} +*/ +Phaser.Physics.P2 = 1; + +/** +* @const +* @type {number} +*/ +Phaser.Physics.BOX2D = 2; + +/** +* @const +* @type {number} +*/ +Phaser.Physics.CHIPMUNK = 3; + +Phaser.Physics.prototype = { + + startSystem: function (system) { + + if (system === Phaser.Physics.ARCADE) + { + this.arcade = new Phaser.Physics.Arcade(this.game); + } + else if (system === Phaser.Physics.P2) + { + this.p2 = new Phaser.Physics.P2(this.game, this.config); + } + else if (system === Phaser.Physics.BOX2D) + { + // Coming soon + } + else if (system === Phaser.Physics.CHIPMUNK) + { + // Coming soon + } + + }, + + // Enables a sprites physics body + enable: function (object, system) { + + if (typeof system === 'undefined') { system = Phaser.Physics.ARCADE; } + + var i = 1; + + if (Array.isArray(object)) + { + // Add to Group + i = object.length; + } + else + { + object = [object]; + } + + while (i--) + { + if (object[i].body === null) + { + if (system === Phaser.Physics.ARCADE) + { + object[i].body = new Phaser.Physics.Arcade.Body(object[i]); + } + else if (system === Phaser.Physics.P2) + { + object[i].body = new Phaser.Physics.P2.Body(this.game, object[i], object[i].x, object[i].y, 1); + object[i].anchor.set(0.5); + } + } + } + + }, + + update: function () { + + // ArcadePhysics doesn't have a core to update + + if (this.p2) + { + this.p2.update(); + } + + }, + + setBoundsToWorld: function () { + + }, + + clear: function () { + + if (this.p2) + { + this.p2.clear(); + } + + } + +}; + +Phaser.Physics.prototype.constructor = Phaser.Physics; diff --git a/src/physics/arcade/Body.js b/src/physics/arcade/Body.js new file mode 100644 index 00000000..8ca528fa --- /dev/null +++ b/src/physics/arcade/Body.js @@ -0,0 +1,635 @@ +/** +* @author Richard Davey +* @copyright 2013 Photon Storm Ltd. +* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} +*/ + +/** +* The Physics Body is linked to a single Sprite. All physics operations should be performed against the body rather than +* the Sprite itself. For example you can set the velocity, acceleration, bounce values etc all on the Body. +* +* @class Phaser.Physics.Arcade.Body +* @classdesc Arcade Physics Body Constructor +* @constructor +* @param {Phaser.Sprite} sprite - The Sprite object this physics body belongs to. +*/ +Phaser.Physics.Arcade.Body = function (sprite) { + + /** + * @property {Phaser.Sprite} sprite - Reference to the parent Sprite. + */ + this.sprite = sprite; + + /** + * @property {Phaser.Game} game - Local reference to game. + */ + this.game = sprite.game; + + /** + * @property {Phaser.Point} offset - The offset of the Physics Body from the Sprite x/y position. + */ + this.offset = new Phaser.Point(); + + /** + * @property {number} x - The x position of the physics body. + * @readonly + */ + this.x = sprite.x; + + /** + * @property {number} y - The y position of the physics body. + * @readonly + */ + this.y = sprite.y; + + /** + * @property {number} preX - The previous x position of the physics body. + * @readonly + */ + this.preX = sprite.x; + + /** + * @property {number} preY - The previous y position of the physics body. + * @readonly + */ + this.preY = sprite.y; + + /** + * @property {number} preRotation - The previous rotation of the physics body. + * @readonly + */ + this.preRotation = sprite.angle; + + /** + * @property {number} screenX - The x position of the physics body translated to screen space. + * @readonly + */ + this.screenX = sprite.x; + + /** + * @property {number} screenY - The y position of the physics body translated to screen space. + * @readonly + */ + this.screenY = sprite.y; + + /** + * @property {number} sourceWidth - The un-scaled original size. + * @readonly + */ + this.sourceWidth = sprite.texture.frame.width; + + /** + * @property {number} sourceHeight - The un-scaled original size. + * @readonly + */ + this.sourceHeight = sprite.texture.frame.height; + + /** + * @property {number} width - The calculated width of the physics body. + */ + this.width = sprite.width; + + /** + * @property .numInternal ID cache + */ + this.height = sprite.height; + + /** + * @property {number} halfWidth - The calculated width / 2 of the physics body. + */ + this.halfWidth = Math.floor(sprite.width / 2); + + /** + * @property {number} halfHeight - The calculated height / 2 of the physics body. + */ + this.halfHeight = Math.floor(sprite.height / 2); + + /** + * @property {Phaser.Point} center - The center coordinate of the Physics Body. + */ + this.center = new Phaser.Point(this.x + this.halfWidth, this.y + this.halfHeight); + + /** + * @property {number} _sx - Internal cache var. + * @private + */ + this._sx = sprite.scale.x; + + /** + * @property {number} _sy - Internal cache var. + * @private + */ + this._sy = sprite.scale.y; + + /** + * @property {Phaser.Point} velocity - The velocity in pixels per second sq. of the Body. + */ + this.velocity = new Phaser.Point(); + + /** + * @property {Phaser.Point} acceleration - The velocity in pixels per second sq. of the Body. + */ + this.acceleration = new Phaser.Point(); + + /** + * @property {Phaser.Point} drag - The drag applied to the motion of the Body. + */ + this.drag = new Phaser.Point(); + + /** + * @property {Phaser.Point} gravity - A private Gravity setting for the Body. + */ + this.gravity = new Phaser.Point(); + + /** + * @property {Phaser.Point} bounce - The elasticitiy of the Body when colliding. bounce.x/y = 1 means full rebound, bounce.x/y = 0.5 means 50% rebound velocity. + */ + this.bounce = new Phaser.Point(); + + /** + * @property {Phaser.Point} maxVelocity - The maximum velocity in pixels per second sq. that the Body can reach. + * @default + */ + this.maxVelocity = new Phaser.Point(10000, 10000); + + /** + * @property {number} angularVelocity - The angular velocity in pixels per second sq. of the Body. + * @default + */ + this.angularVelocity = 0; + + /** + * @property {number} angularAcceleration - The angular acceleration in pixels per second sq. of the Body. + * @default + */ + this.angularAcceleration = 0; + + /** + * @property {number} angularDrag - The angular drag applied to the rotation of the Body. + * @default + */ + this.angularDrag = 0; + + /** + * @property {number} maxAngular - The maximum angular velocity in pixels per second sq. that the Body can reach. + * @default + */ + this.maxAngular = 1000; + + /** + * @property {number} mass - The mass of the Body. + * @default + */ + this.mass = 1; + + /** + * @property {boolean} skipQuadTree - If the Body is an irregular shape you can set this to true to avoid it being added to any QuadTrees. + * @default + */ + this.skipQuadTree = false; + + // Allow collision + + /** + * Set the allowCollision properties to control which directions collision is processed for this Body. + * For example allowCollision.up = false means it won't collide when the collision happened while moving up. + * @property {object} allowCollision - An object containing allowed collision. + */ + // This would be faster as an array + this.allowCollision = { none: false, any: true, up: true, down: true, left: true, right: true }; + + /** + * This object is populated with boolean values when the Body collides with another. + * touching.up = true means the collision happened to the top of this Body for example. + * @property {object} touching - An object containing touching results. + */ + // This would be faster as an array + this.touching = { none: true, up: false, down: false, left: false, right: false }; + + /** + * This object is populated with previous touching values from the bodies previous collision. + * @property {object} wasTouching - An object containing previous touching results. + */ + // This would be faster as an array + this.wasTouching = { none: true, up: false, down: false, left: false, right: false }; + + /** + * @property {number} facing - A const reference to the direction the Body is traveling or facing. + * @default + */ + this.facing = Phaser.NONE; + + /** + * @property {boolean} immovable - An immovable Body will not receive any impacts from other bodies. + * @default + */ + this.immovable = false; + + /** + * @property {boolean} moves - Set to true to allow the Physics system to move this Body, other false to move it manually. + * @default + */ + this.moves = true; + + /** + * @property {number} rotation - The amount the Body is rotated. + * @default + */ + this.rotation = 0; + + /** + * @property {boolean} allowRotation - Allow this Body to be rotated? (via angularVelocity, etc) + * @default + */ + this.allowRotation = true; + + /** + * @property {boolean} allowGravity - Allow this Body to be influenced by the global Gravity? + * @default + */ + this.allowGravity = true; + + /** + * This flag allows you to disable the custom x separation that takes place by Physics.Arcade.separate. + * Used in combination with your own collision processHandler you can create whatever type of collision response you need. + * @property {boolean} customSeparateX - Use a custom separation system or the built-in one? + * @default + */ + this.customSeparateX = false; + + /** + * This flag allows you to disable the custom y separation that takes place by Physics.Arcade.separate. + * Used in combination with your own collision processHandler you can create whatever type of collision response you need. + * @property {boolean} customSeparateY - Use a custom separation system or the built-in one? + * @default + */ + this.customSeparateY = false; + + /** + * When this body collides with another, the amount of overlap is stored here. + * @property {number} overlapX - The amount of horizontal overlap during the collision. + */ + this.overlapX = 0; + + /** + * When this body collides with another, the amount of overlap is stored here. + * @property {number} overlapY - The amount of vertical overlap during the collision. + */ + this.overlapY = 0; + + this.hull = new Phaser.Rectangle(); + + /** + * @property {Phaser.Rectangle} hullX - The dynamically calculated hull used during collision. + */ + this.hullX = new Phaser.Rectangle(); + + /** + * @property {Phaser.Rectangle} hullY - The dynamically calculated hull used during collision. + */ + this.hullY = new Phaser.Rectangle(); + + /** + * If a body is overlapping with another body, but neither of them are moving (maybe they spawned on-top of each other?) this is set to true. + * @property {boolean} embedded - Body embed value. + */ + this.embedded = false; + + /** + * A Body can be set to collide against the World bounds automatically and rebound back into the World if this is set to true. Otherwise it will leave the World. + * @property {boolean} collideWorldBounds - Should the Body collide with the World bounds? + */ + this.collideWorldBounds = false; + + this.blocked = { up: false, down: false, left: false, right: false }; + +}; + +Phaser.Physics.Arcade.Body.prototype = { + + /** + * Internal method. + * + * @method Phaser.Physics.Arcade#updateBounds + * @protected + */ + updateBounds: function (centerX, centerY, scaleX, scaleY) { + + if (scaleX != this._sx || scaleY != this._sy) + { + this.width = this.sourceWidth * scaleX; + this.height = this.sourceHeight * scaleY; + this.halfWidth = Math.floor(this.width / 2); + this.halfHeight = Math.floor(this.height / 2); + this._sx = scaleX; + this._sy = scaleY; + this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); + } + + }, + + /** + * Internal method. + * + * @method Phaser.Physics.Arcade#preUpdate + * @protected + */ + preUpdate: function () { + + // Store and reset collision flags + this.wasTouching.none = this.touching.none; + this.wasTouching.up = this.touching.up; + this.wasTouching.down = this.touching.down; + this.wasTouching.left = this.touching.left; + this.wasTouching.right = this.touching.right; + + this.touching.none = true; + this.touching.up = false; + this.touching.down = false; + this.touching.left = false; + this.touching.right = false; + + this.embedded = false; + + this.screenX = (this.sprite.worldTransform[2] - (this.sprite.anchor.x * this.width)) + this.offset.x; + this.screenY = (this.sprite.worldTransform[5] - (this.sprite.anchor.y * this.height)) + this.offset.y; + + this.preX = (this.sprite.world.x - (this.sprite.anchor.x * this.width)) + this.offset.x; + this.preY = (this.sprite.world.y - (this.sprite.anchor.y * this.height)) + this.offset.y; + + this.preRotation = this.sprite.angle; + + this.x = this.preX; + this.y = this.preY; + this.rotation = this.preRotation; + + // this.overlapX = 0; + // this.overlapY = 0; + + this.blocked.up = false; + this.blocked.down = false; + this.blocked.left = false; + this.blocked.right = false; + + if (this.moves) + { + this.game.physics.arcade.updateMotion(this); + + if (this.collideWorldBounds) + { + this.checkWorldBounds(); + } + } + + }, + + /** + * Internal method. + * + * @method Phaser.Physics.Arcade#postUpdate + * @protected + */ + postUpdate: function () { + + // if (this.overlapX !== 0) + // { + // this.x -= this.overlapX; + // } + + // if (this.overlapY !== 0) + // { + // this.y -= this.overlapY; + // } + + if (this.deltaX() < 0 && this.blocked.left === false) + { + this.facing = Phaser.LEFT; + this.sprite.x += this.deltaX(); + } + else if (this.deltaX() > 0 && this.blocked.right === false) + { + this.facing = Phaser.RIGHT; + this.sprite.x += this.deltaX(); + } + + if (this.deltaY() < 0 && this.blocked.up === false) + { + this.facing = Phaser.UP; + this.sprite.y += this.deltaY(); + } + else if (this.deltaY() > 0 && this.blocked.down === false) + { + this.facing = Phaser.DOWN; + this.sprite.y += this.deltaY(); + } + + this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); + + if (this.allowRotation) + { + this.sprite.angle += this.deltaZ(); + } + + }, + + /** + * Internal method. + * + * @method Phaser.Physics.Arcade#checkWorldBounds + * @protected + */ + checkWorldBounds: function () { + + if (this.x < this.game.world.bounds.x) + { + this.x = this.game.world.bounds.x; + this.velocity.x *= -this.bounce.x; + } + else if (this.right > this.game.world.bounds.right) + { + this.x = this.game.world.bounds.right - this.width; + this.velocity.x *= -this.bounce.x; + } + + if (this.y < this.game.world.bounds.y) + { + this.y = this.game.world.bounds.y; + this.velocity.y *= -this.bounce.y; + } + else if (this.bottom > this.game.world.bounds.bottom) + { + this.y = this.game.world.bounds.bottom - this.height; + this.velocity.y *= -this.bounce.y; + } + + }, + + /** + * You can modify the size of the physics Body to be any dimension you need. + * So it could be smaller or larger than the parent Sprite. You can also control the x and y offset, which + * is the position of the Body relative to the top-left of the Sprite. + * + * @method Phaser.Physics.Arcade#setSize + * @param {number} width - The width of the Body. + * @param {number} height - The height of the Body. + * @param {number} offsetX - The X offset of the Body from the Sprite position. + * @param {number} offsetY - The Y offset of the Body from the Sprite position. + */ + setSize: function (width, height, offsetX, offsetY) { + + offsetX = offsetX || this.offset.x; + offsetY = offsetY || this.offset.y; + + this.sourceWidth = width; + this.sourceHeight = height; + this.width = this.sourceWidth * this._sx; + this.height = this.sourceHeight * this._sy; + this.halfWidth = Math.floor(this.width / 2); + this.halfHeight = Math.floor(this.height / 2); + this.offset.setTo(offsetX, offsetY); + + this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); + + }, + + /** + * Resets all Body values (velocity, acceleration, rotation, etc) + * + * @method Phaser.Physics.Arcade#reset + */ + reset: function () { + + this.velocity.setTo(0, 0); + this.acceleration.setTo(0, 0); + + this.angularVelocity = 0; + this.angularAcceleration = 0; + this.preX = (this.sprite.world.x - (this.sprite.anchor.x * this.width)) + this.offset.x; + this.preY = (this.sprite.world.y - (this.sprite.anchor.y * this.height)) + this.offset.y; + this.preRotation = this.sprite.angle; + + this.x = this.preX; + this.y = this.preY; + this.rotation = this.preRotation; + + this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); + + }, + + /** + * Returns the absolute delta x value. + * + * @method Phaser.Physics.Arcade.Body#deltaAbsX + * @return {number} The absolute delta value. + */ + deltaAbsX: function () { + return (this.deltaX() > 0 ? this.deltaX() : -this.deltaX()); + }, + + /** + * Returns the absolute delta y value. + * + * @method Phaser.Physics.Arcade.Body#deltaAbsY + * @return {number} The absolute delta value. + */ + deltaAbsY: function () { + return (this.deltaY() > 0 ? this.deltaY() : -this.deltaY()); + }, + + /** + * Returns the delta x value. The difference between Body.x now and in the previous step. + * + * @method Phaser.Physics.Arcade.Body#deltaX + * @return {number} The delta value. Positive if the motion was to the right, negative if to the left. + */ + deltaX: function () { + return this.x - this.preX; + }, + + /** + * Returns the delta y value. The difference between Body.y now and in the previous step. + * + * @method Phaser.Physics.Arcade.Body#deltaY + * @return {number} The delta value. Positive if the motion was downwards, negative if upwards. + */ + deltaY: function () { + return this.y - this.preY; + }, + + deltaZ: function () { + return this.rotation - this.preRotation; + } + +}; + +/** +* @name Phaser.Physics.Arcade.Body#bottom +* @property {number} bottom - The bottom value of this Body (same as Body.y + Body.height) +*/ +Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "bottom", { + + /** + * The sum of the y and height properties. Changing the bottom property of a Rectangle object has no effect on the x, y and width properties, but does change the height property. + * @method bottom + * @return {number} + */ + get: function () { + return Math.floor(this.y + this.height); + }, + + /** + * The sum of the y and height properties. Changing the bottom property of a Rectangle object has no effect on the x, y and width properties, but does change the height property. + * @method bottom + * @param {number} value + */ + set: function (value) { + + if (value <= this.y) + { + this.height = 0; + } + else + { + this.height = (this.y - value); + } + + } + +}); + +/** +* @name Phaser.Physics.Arcade.Body#right +* @property {number} right - The right value of this Body (same as Body.x + Body.width) +*/ +Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "right", { + + /** + * The sum of the x and width properties. Changing the right property of a Rectangle object has no effect on the x, y and height properties. + * However it does affect the width property. + * @method right + * @return {number} + */ + get: function () { + return Math.floor(this.x + this.width); + }, + + /** + * The sum of the x and width properties. Changing the right property of a Rectangle object has no effect on the x, y and height properties. + * However it does affect the width property. + * @method right + * @param {number} value + */ + set: function (value) { + + if (value <= this.x) + { + this.width = 0; + } + else + { + this.width = this.x + value; + } + + } + +}); diff --git a/src/physics/arcade/ArcadePhysics.js b/src/physics/arcade/BrokenArcadePhysics.js similarity index 100% rename from src/physics/arcade/ArcadePhysics.js rename to src/physics/arcade/BrokenArcadePhysics.js diff --git a/src/physics/arcade/QuadTree.js b/src/physics/arcade/QuadTree.js new file mode 100644 index 00000000..661b7326 --- /dev/null +++ b/src/physics/arcade/QuadTree.js @@ -0,0 +1,265 @@ +/** +* @author Richard Davey +* @copyright 2013 Photon Storm Ltd. +* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} +*/ + +/** + * Javascript QuadTree + * @version 1.0 + * @author Timo Hausmann + * + * @version 1.2, September 4th 2013 + * @author Richard Davey + * The original code was a conversion of the Java code posted to GameDevTuts. However I've tweaked + * it massively to add node indexing, removed lots of temp. var creation and significantly + * increased performance as a result. + * + * Original version at https://github.com/timohausmann/quadtree-js/ + */ + +/** +* @copyright © 2012 Timo Hausmann +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/** + * QuadTree Constructor + * + * @class Phaser.Physics.Arcade.QuadTree + * @classdesc A QuadTree implementation. The original code was a conversion of the Java code posted to GameDevTuts. However I've tweaked + * it massively to add node indexing, removed lots of temp. var creation and significantly increased performance as a result. Original version at https://github.com/timohausmann/quadtree-js/ + * @constructor + * @param {Description} physicsManager - Description. + * @param {Description} x - Description. + * @param {Description} y - Description. + * @param {number} width - The width of your game in game pixels. + * @param {number} height - The height of your game in game pixels. + * @param {number} maxObjects - Description. + * @param {number} maxLevels - Description. + * @param {number} level - Description. + */ +Phaser.Physics.Arcade.QuadTree = function (physicsManager, x, y, width, height, maxObjects, maxLevels, level) { + + this.physicsManager = physicsManager; + this.ID = physicsManager.quadTreeID; + physicsManager.quadTreeID++; + + this.maxObjects = maxObjects || 10; + this.maxLevels = maxLevels || 4; + this.level = level || 0; + + this.bounds = { + x: Math.round(x), + y: Math.round(y), + width: width, + height: height, + subWidth: Math.floor(width / 2), + subHeight: Math.floor(height / 2), + right: Math.round(x) + Math.floor(width / 2), + bottom: Math.round(y) + Math.floor(height / 2) + }; + + this.objects = []; + this.nodes = []; + +}; + +Phaser.Physics.Arcade.QuadTree.prototype = { + + /* + * Split the node into 4 subnodes + * + * @method Phaser.Physics.Arcade.QuadTree#split + */ + split: function() { + + this.level++; + + // top right node + this.nodes[0] = new Phaser.Physics.Arcade.QuadTree(this.physicsManager, this.bounds.right, this.bounds.y, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level); + + // top left node + this.nodes[1] = new Phaser.Physics.Arcade.QuadTree(this.physicsManager, this.bounds.x, this.bounds.y, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level); + + // bottom left node + this.nodes[2] = new Phaser.Physics.Arcade.QuadTree(this.physicsManager, this.bounds.x, this.bounds.bottom, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level); + + // bottom right node + this.nodes[3] = new Phaser.Physics.Arcade.QuadTree(this.physicsManager, this.bounds.right, this.bounds.bottom, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level); + + }, + + /* + * Insert the object into the node. If the node + * exceeds the capacity, it will split and add all + * objects to their corresponding subnodes. + * + * @method Phaser.Physics.Arcade.QuadTree#insert + * @param {object} body - Description. + */ + insert: function (body) { + + var i = 0; + var index; + + // if we have subnodes ... + if (this.nodes[0] != null) + { + index = this.getIndex(body); + + if (index !== -1) + { + this.nodes[index].insert(body); + return; + } + } + + this.objects.push(body); + + if (this.objects.length > this.maxObjects && this.level < this.maxLevels) + { + // Split if we don't already have subnodes + if (this.nodes[0] == null) + { + this.split(); + } + + // Add objects to subnodes + while (i < this.objects.length) + { + index = this.getIndex(this.objects[i]); + + if (index !== -1) + { + // this is expensive - see what we can do about it + this.nodes[index].insert(this.objects.splice(i, 1)[0]); + } + else + { + i++; + } + } + } + + }, + + /* + * Determine which node the object belongs to. + * + * @method Phaser.Physics.Arcade.QuadTree#getIndex + * @param {object} rect - Description. + * @return {number} index - Index of the subnode (0-3), or -1 if rect cannot completely fit within a subnode and is part of the parent node. + */ + getIndex: function (rect) { + + // default is that rect doesn't fit, i.e. it straddles the internal quadrants + var index = -1; + + if (rect.x < this.bounds.right && rect.right < this.bounds.right) + { + if ((rect.y < this.bounds.bottom && rect.bottom < this.bounds.bottom)) + { + // rect fits within the top-left quadrant of this quadtree + index = 1; + } + else if ((rect.y > this.bounds.bottom)) + { + // rect fits within the bottom-left quadrant of this quadtree + index = 2; + } + } + else if (rect.x > this.bounds.right) + { + // rect can completely fit within the right quadrants + if ((rect.y < this.bounds.bottom && rect.bottom < this.bounds.bottom)) + { + // rect fits within the top-right quadrant of this quadtree + index = 0; + } + else if ((rect.y > this.bounds.bottom)) + { + // rect fits within the bottom-right quadrant of this quadtree + index = 3; + } + } + + return index; + + }, + + /* + * Return all objects that could collide with the given object. + * + * @method Phaser.Physics.Arcade.QuadTree#retrieve + * @param {object} rect - Description. + * @Return {array} - Array with all detected objects. + */ + retrieve: function (sprite) { + + var returnObjects = this.objects; + + sprite.body.quadTreeIndex = this.getIndex(sprite.body); + + // Temp store for the node IDs this sprite is in, we can use this for fast elimination later + sprite.body.quadTreeIDs.push(this.ID); + + if (this.nodes[0]) + { + // if rect fits into a subnode .. + if (sprite.body.quadTreeIndex !== -1) + { + returnObjects = returnObjects.concat(this.nodes[sprite.body.quadTreeIndex].retrieve(sprite)); + } + else + { + // if rect does not fit into a subnode, check it against all subnodes (unrolled for speed) + returnObjects = returnObjects.concat(this.nodes[0].retrieve(sprite)); + returnObjects = returnObjects.concat(this.nodes[1].retrieve(sprite)); + returnObjects = returnObjects.concat(this.nodes[2].retrieve(sprite)); + returnObjects = returnObjects.concat(this.nodes[3].retrieve(sprite)); + } + } + + return returnObjects; + + }, + + /* + * Clear the quadtree. + * @method Phaser.Physics.Arcade.QuadTree#clear + */ + clear: function () { + + this.objects = []; + + for (var i = 0, len = this.nodes.length; i < len; i++) + { + // if (typeof this.nodes[i] !== 'undefined') + if (this.nodes[i]) + { + this.nodes[i].clear(); + delete this.nodes[i]; + } + } + } + +}; diff --git a/src/physics/arcade/TempSprite.js b/src/physics/arcade/TempSprite.js new file mode 100644 index 00000000..de08e4c2 --- /dev/null +++ b/src/physics/arcade/TempSprite.js @@ -0,0 +1,1126 @@ +/** +* @author Richard Davey +* @copyright 2013 Photon Storm Ltd. +* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} +*/ + +/** +* @class Phaser.Sprite +* +* @classdesc Create a new `Sprite` object. Sprites are the lifeblood of your game, used for nearly everything visual. +* +* At its most basic a Sprite consists of a set of coordinates and a texture that is rendered to the canvas. +* They also contain additional properties allowing for physics motion (via Sprite.body), input handling (via Sprite.input), +* events (via Sprite.events), animation (via Sprite.animations), camera culling and more. Please see the Examples for use cases. +* +* @constructor +* @param {Phaser.Game} game - A reference to the currently running game. +* @param {number} x - The x coordinate (in world space) to position the Sprite at. +* @param {number} y - The y coordinate (in world space) to position the Sprite at. +* @param {string|Phaser.RenderTexture|Phaser.BitmapData|PIXI.Texture} key - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache entry, or an instance of a RenderTexture or PIXI.Texture. +* @param {string|number} frame - If this Sprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index. +*/ +Phaser.Sprite = function (game, x, y, key, frame) { + + x = x || 0; + y = y || 0; + key = key || null; + frame = frame || null; + + /** + * @property {Phaser.Game} game - A reference to the currently running Game. + */ + this.game = game; + + /** + * @property {boolean} exists - If exists = false then the Sprite isn't updated by the core game loop or physics subsystem at all. + * @default + */ + this.exists = true; + + /** + * @property {boolean} alive - This is a handy little var your game can use to determine if a sprite is alive or not, it doesn't effect rendering. + * @default + */ + this.alive = true; + + /** + * @property {Phaser.Group} group - The parent Group of this Sprite. This is usually set after Sprite instantiation by the parent. + */ + this.group = null; + + /** + * @property {string} name - The user defined name given to this Sprite. + * @default + */ + this.name = ''; + + /** + * @property {number} type - The const type of this object. + * @readonly + */ + this.type = Phaser.SPRITE; + + /** + * @property {number} renderOrderID - Used by the Renderer and Input Manager to control picking order. + * @default + */ + this.renderOrderID = -1; + + /** + * If you would like the Sprite to have a lifespan once 'born' you can set this to a positive value. Handy for particles, bullets, etc. + * The lifespan is decremented by game.time.elapsed each update, once it reaches zero the kill() function is called. + * @property {number} lifespan - The lifespan of the Sprite (in ms) before it will be killed. + * @default + */ + this.lifespan = 0; + + /** + * @property {Phaser.Events} events - The Events you can subscribe to that are dispatched when certain things happen on this Sprite or its components. + */ + this.events = new Phaser.Events(this); + + /** + * @property {Phaser.AnimationManager} animations - This manages animations of the sprite. You can modify animations through it (see Phaser.AnimationManager) + */ + this.animations = new Phaser.AnimationManager(this); + + /** + * @property {Phaser.InputHandler} input - The Input Handler Component. + */ + this.input = new Phaser.InputHandler(this); + + /** + * @property {string|Phaser.RenderTexture|Phaser.BitmapData|PIXI.Texture} key - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache entry, or an instance of a RenderTexture, BitmapData or PIXI.Texture. + */ + this.key = key; + + /** + * @property {Phaser.Frame} currentFrame - A reference to the currently displayed frame. + */ + this.currentFrame = null; + + if (key instanceof Phaser.RenderTexture) + { + PIXI.Sprite.call(this, key); + + this.currentFrame = this.game.cache.getTextureFrame(key.name); + } + else if (key instanceof Phaser.BitmapData) + { + PIXI.Sprite.call(this, key.texture, key.textureFrame); + + this.currentFrame = key.textureFrame; + } + else if (key instanceof PIXI.Texture) + { + PIXI.Sprite.call(this, key); + + this.currentFrame = frame; + } + else + { + if (key === null || typeof key === 'undefined') + { + key = '__default'; + this.key = key; + } + else if (typeof key === 'string' && this.game.cache.checkImageKey(key) === false) + { + key = '__missing'; + this.key = key; + } + + PIXI.Sprite.call(this, PIXI.TextureCache[key]); + + if (this.game.cache.isSpriteSheet(key)) + { + this.animations.loadFrameData(this.game.cache.getFrameData(key)); + + if (frame !== null) + { + if (typeof frame === 'string') + { + this.frameName = frame; + } + else + { + this.frame = frame; + } + } + } + else + { + this.currentFrame = this.game.cache.getFrame(key); + } + } + + /** + * The rectangular area from the texture that will be rendered. + * @property {Phaser.Rectangle} textureRegion + */ + this.textureRegion = new Phaser.Rectangle(this.texture.frame.x, this.texture.frame.y, this.texture.frame.width, this.texture.frame.height); + + /** + * The anchor sets the origin point of the texture. + * The default is 0,0 this means the textures origin is the top left + * Setting than anchor to 0.5,0.5 means the textures origin is centered + * Setting the anchor to 1,1 would mean the textures origin points will be the bottom right + * + * @property {Phaser.Point} anchor - The anchor around which rotation and scaling takes place. + */ + this.anchor = new Phaser.Point(); + + /** + * @property {number} x - The x coordinate in world space of this Sprite. + */ + this.x = x; + + /** + * @property {number} y - The y coordinate in world space of this Sprite. + */ + this.y = y; + + this.position.x = x; + this.position.y = y; + + /** + * @property {Phaser.Point} world - The world coordinates of this Sprite. This differs from the x/y coordinates which are relative to the Sprites container. + */ + this.world = new Phaser.Point(x, y); + + /** + * Should this Sprite be automatically culled if out of range of the camera? + * A culled sprite has its renderable property set to 'false'. + * + * @property {boolean} autoCull - A flag indicating if the Sprite should be automatically camera culled or not. + * @default + */ + this.autoCull = false; + + /** + * @property {Phaser.Point} scale - The scale of the Sprite when rendered. By default it's set to 1 (no scale). You can modify it via scale.x or scale.y or scale.setTo(x, y). A value of 1 means no change to the scale, 0.5 means "half the size", 2 means "twice the size", etc. + */ + this.scale = new Phaser.Point(1, 1); + + /** + * @property {object} _cache - A mini cache for storing all of the calculated values. + * @private + */ + this._cache = { + + dirty: false, + + // Transform cache + a00: -1, + a01: -1, + a02: -1, + a10: -1, + a11: -1, + a12: -1, + id: -1, + + // Input specific transform cache + i01: -1, + i10: -1, + idi: -1, + + // Bounds check + left: null, + right: null, + top: null, + bottom: null, + + // delta cache + prevX: x, + prevY: y, + + // The previous calculated position + x: -1, + y: -1, + + // The actual scale values based on the worldTransform + scaleX: 1, + scaleY: 1, + + // The width/height of the image, based on the un-modified frame size multiplied by the final calculated scale size + width: this.currentFrame.sourceSizeW, + height: this.currentFrame.sourceSizeH, + + // The actual width/height of the image if from a trimmed atlas, multiplied by the final calculated scale size + halfWidth: Math.floor(this.currentFrame.sourceSizeW / 2), + halfHeight: Math.floor(this.currentFrame.sourceSizeH / 2), + + // The width/height of the image, based on the un-modified frame size multiplied by the final calculated scale size + calcWidth: -1, + calcHeight: -1, + + // The current frame details + // frameID: this.currentFrame.uuid, frameWidth: this.currentFrame.width, frameHeight: this.currentFrame.height, + frameID: -1, + frameWidth: this.currentFrame.width, + frameHeight: this.currentFrame.height, + + // If this sprite visible to the camera (regardless of being set to visible or not) + cameraVisible: true, + + // Crop cache + cropX: 0, + cropY: 0, + cropWidth: this.currentFrame.sourceSizeW, + cropHeight: this.currentFrame.sourceSizeH + + }; + + /** + * @property {Phaser.Point} offset - Corner point defaults. Should not typically be modified. + */ + this.offset = new Phaser.Point(); + + /** + * @property {Phaser.Point} center - A Point containing the center coordinate of the Sprite. Takes rotation and scale into account. + */ + this.center = new Phaser.Point(x + Math.floor(this._cache.width / 2), y + Math.floor(this._cache.height / 2)); + + /** + * @property {Phaser.Point} topLeft - A Point containing the top left coordinate of the Sprite. Takes rotation and scale into account. + */ + this.topLeft = new Phaser.Point(x, y); + + /** + * @property {Phaser.Point} topRight - A Point containing the top right coordinate of the Sprite. Takes rotation and scale into account. + */ + this.topRight = new Phaser.Point(x + this._cache.width, y); + + /** + * @property {Phaser.Point} bottomRight - A Point containing the bottom right coordinate of the Sprite. Takes rotation and scale into account. + */ + this.bottomRight = new Phaser.Point(x + this._cache.width, y + this._cache.height); + + /** + * @property {Phaser.Point} bottomLeft - A Point containing the bottom left coordinate of the Sprite. Takes rotation and scale into account. + */ + this.bottomLeft = new Phaser.Point(x, y + this._cache.height); + + /** + * This Rectangle object fully encompasses the Sprite and is updated in real-time. + * The bounds is the full bounding area after rotation and scale have been taken into account. It should not be modified directly. + * It's used for Camera culling and physics body alignment. + * @property {Phaser.Rectangle} bounds + */ + this.bounds = new Phaser.Rectangle(x, y, this._cache.width, this._cache.height); + + /** + * @property {Phaser.Physics.Arcade.Body} body - By default Sprites have a Phaser.Physics Body attached to them. You can operate physics actions via this property, or null it to skip all physics updates. + */ + this.body = new Phaser.Physics.Arcade.Body(this); + + /** + * @property {number} health - Health value. Used in combination with damage() to allow for quick killing of Sprites. + */ + this.health = 1; + + /** + * @property {boolean} inWorld - This value is set to true if the Sprite is positioned within the World, otherwise false. + */ + this.inWorld = Phaser.Rectangle.intersects(this.bounds, this.game.world.bounds); + + /** + * @property {number} inWorldThreshold - A threshold value applied to the inWorld check. If you don't want a Sprite to be considered "out of the world" until at least 100px away for example then set it to 100. + * @default + */ + this.inWorldThreshold = 0; + + /** + * @property {boolean} outOfBoundsKill - If true the Sprite is killed as soon as Sprite.inWorld is false. + * @default + */ + this.outOfBoundsKill = false; + + /** + * @property {boolean} _outOfBoundsFired - Internal flag. + * @private + * @default + */ + this._outOfBoundsFired = false; + + /** + * A Sprite that is fixed to the camera ignores the position of any ancestors in the display list and uses its x/y coordinates as offsets from the top left of the camera. + * @property {boolean} fixedToCamera - Fixes this Sprite to the Camera. + * @default + */ + this.fixedToCamera = false; + + /** + * @property {Phaser.Point} cameraOffset - If this Sprite is fixed to the camera then use this Point to specify how far away from the Camera x/y it's rendered. + */ + this.cameraOffset = new Phaser.Point(); + + /** + * You can crop the Sprites texture by modifying the crop properties. For example crop.width = 50 would set the Sprite to only render 50px wide. + * The crop is only applied if you have set Sprite.cropEnabled to true. + * @property {Phaser.Rectangle} crop - The crop Rectangle applied to the Sprite texture before rendering. + * @default + */ + this.crop = new Phaser.Rectangle(0, 0, this._cache.width, this._cache.height); + + /** + * @property {boolean} cropEnabled - If true the Sprite.crop property is used to crop the texture before render. Set to false to disable. + * @default + */ + this.cropEnabled = false; + + this.updateCache(); + this.updateBounds(); + +}; + +// Needed to keep the PIXI.Sprite constructor in the prototype chain (as the core pixi renderer uses an instanceof check sadly) +Phaser.Sprite.prototype = Object.create(PIXI.Sprite.prototype); +Phaser.Sprite.prototype.constructor = Phaser.Sprite; + +/** +* Automatically called by World.preUpdate. Handles cache updates, lifespan checks, animation updates and physics updates. +* +* @method Phaser.Sprite#preUpdate +* @memberof Phaser.Sprite +*/ +Phaser.Sprite.prototype.preUpdate = function() { + + if (!this.exists || (this.group && !this.group.exists)) + { + this.renderOrderID = -1; + + // Skip children if not exists + return false; + } + + if (this.lifespan > 0) + { + this.lifespan -= this.game.time.elapsed; + + if (this.lifespan <= 0) + { + this.kill(); + return false; + } + } + + this._cache.dirty = false; + + if (this.visible) + { + this.renderOrderID = this.game.world.currentRenderOrderID++; + } + + this.updateCache(); + + this.updateAnimation(); + + this.updateCrop(); + + // Re-run the camera visibility check + if (this._cache.dirty || this.world.x !== this._cache.prevX || this.world.y !== this._cache.prevY) + { + this.updateBounds(); + } + + if (this.body) + { + this.body.preUpdate(); + } + + return true; + +}; + +/** +* Internal function called by preUpdate. +* +* @method Phaser.Sprite#updateCache +* @memberof Phaser.Sprite +*/ +Phaser.Sprite.prototype.updateCache = function() { + + this._cache.prevX = this.world.x; + this._cache.prevY = this.world.y; + + if (this.fixedToCamera) + { + this.x = this.game.camera.view.x + this.cameraOffset.x; + this.y = this.game.camera.view.y + this.cameraOffset.y; + } + + this.world.setTo(this.game.camera.x + this.worldTransform[2], this.game.camera.y + this.worldTransform[5]); + + if (this.worldTransform[1] != this._cache.i01 || this.worldTransform[3] != this._cache.i10 || this.worldTransform[0] != this._cache.a00 || this.worldTransform[41] != this._cache.a11) + { + this._cache.a00 = this.worldTransform[0]; // scaleX a |a c tx| + this._cache.a01 = this.worldTransform[1]; // skewY c |b d ty| + this._cache.a10 = this.worldTransform[3]; // skewX b |0 0 1| + this._cache.a11 = this.worldTransform[4]; // scaleY d + + this._cache.i01 = this.worldTransform[1]; // skewY c (remains non-modified for input checks) + this._cache.i10 = this.worldTransform[3]; // skewX b (remains non-modified for input checks) + + this._cache.scaleX = Math.sqrt((this._cache.a00 * this._cache.a00) + (this._cache.a01 * this._cache.a01)); // round this off a bit? + this._cache.scaleY = Math.sqrt((this._cache.a10 * this._cache.a10) + (this._cache.a11 * this._cache.a11)); // round this off a bit? + + this._cache.a01 *= -1; + this._cache.a10 *= -1; + + this._cache.id = 1 / (this._cache.a00 * this._cache.a11 + this._cache.a01 * -this._cache.a10); + this._cache.idi = 1 / (this._cache.a00 * this._cache.a11 + this._cache.i01 * -this._cache.i10); + + this._cache.dirty = true; + } + + this._cache.a02 = this.worldTransform[2]; // translateX tx + this._cache.a12 = this.worldTransform[5]; // translateY ty + +}; + +/** +* Internal function called by preUpdate. +* +* @method Phaser.Sprite#updateAnimation +* @memberof Phaser.Sprite +*/ +Phaser.Sprite.prototype.updateAnimation = function() { + + if (this.animations.update() || (this.currentFrame && this.currentFrame.uuid != this._cache.frameID)) + { + this._cache.frameID = this.currentFrame.uuid; + + this._cache.frameWidth = this.texture.frame.width; + this._cache.frameHeight = this.texture.frame.height; + + this._cache.width = this.currentFrame.width; + this._cache.height = this.currentFrame.height; + + this._cache.halfWidth = Math.floor(this._cache.width / 2); + this._cache.halfHeight = Math.floor(this._cache.height / 2); + + this._cache.dirty = true; + + } + +}; + +/** +* Internal function called by preUpdate. +* +* @method Phaser.Sprite#updateCrop +* @memberof Phaser.Sprite +*/ +Phaser.Sprite.prototype.updateCrop = function() { + + // This only runs if crop is enabled + if (this.cropEnabled && (this.crop.width != this._cache.cropWidth || this.crop.height != this._cache.cropHeight || this.crop.x != this._cache.cropX || this.crop.y != this._cache.cropY)) + { + this.crop.floorAll(); + + this._cache.cropX = this.crop.x; + this._cache.cropY = this.crop.y; + this._cache.cropWidth = this.crop.width; + this._cache.cropHeight = this.crop.height; + + this.texture.frame = this.crop; + this.texture.width = this.crop.width; + this.texture.height = this.crop.height; + + this.texture.updateFrame = true; + + PIXI.Texture.frameUpdates.push(this.texture); + } + +}; + +/** +* Internal function called by preUpdate. +* +* @method Phaser.Sprite#updateBounds +* @memberof Phaser.Sprite +*/ +Phaser.Sprite.prototype.updateBounds = function() { + + this.offset.setTo(this._cache.a02 - (this.anchor.x * this.width), this._cache.a12 - (this.anchor.y * this.height)); + + this.getLocalPosition(this.center, this.offset.x + (this.width / 2), this.offset.y + (this.height / 2)); + this.getLocalPosition(this.topLeft, this.offset.x, this.offset.y); + this.getLocalPosition(this.topRight, this.offset.x + this.width, this.offset.y); + this.getLocalPosition(this.bottomLeft, this.offset.x, this.offset.y + this.height); + this.getLocalPosition(this.bottomRight, this.offset.x + this.width, this.offset.y + this.height); + + this._cache.left = Phaser.Math.min(this.topLeft.x, this.topRight.x, this.bottomLeft.x, this.bottomRight.x); + this._cache.right = Phaser.Math.max(this.topLeft.x, this.topRight.x, this.bottomLeft.x, this.bottomRight.x); + this._cache.top = Phaser.Math.min(this.topLeft.y, this.topRight.y, this.bottomLeft.y, this.bottomRight.y); + this._cache.bottom = Phaser.Math.max(this.topLeft.y, this.topRight.y, this.bottomLeft.y, this.bottomRight.y); + + this.bounds.setTo(this._cache.left, this._cache.top, this._cache.right - this._cache.left, this._cache.bottom - this._cache.top); + + this.updateFrame = true; + + if (this.inWorld === false) + { + // Sprite WAS out of the screen, is it still? + this.inWorld = Phaser.Rectangle.intersects(this.bounds, this.game.world.bounds, this.inWorldThreshold); + + if (this.inWorld) + { + // It's back again, reset the OOB check + this._outOfBoundsFired = false; + } + } + else + { + // Sprite WAS in the screen, has it now left? + this.inWorld = Phaser.Rectangle.intersects(this.bounds, this.game.world.bounds, this.inWorldThreshold); + + if (this.inWorld === false) + { + this.events.onOutOfBounds.dispatch(this); + this._outOfBoundsFired = true; + + if (this.outOfBoundsKill) + { + this.kill(); + } + } + } + + this._cache.cameraVisible = Phaser.Rectangle.intersects(this.game.world.camera.screenView, this.bounds, 0); + + if (this.autoCull) + { + // Won't get rendered but will still get its transform updated + this.renderable = this._cache.cameraVisible; + } + + // Update our physics bounds + if (this.body) + { + this.body.updateBounds(this.center.x, this.center.y, this._cache.scaleX, this._cache.scaleY); + } + +}; + +/** +* Gets the local position of a coordinate relative to the Sprite, factoring in rotation and scale. +* Mostly only used internally. +* +* @method Phaser.Sprite#getLocalPosition +* @memberof Phaser.Sprite +* @param {Phaser.Point} p - The Point object to store the results in. +* @param {number} x - x coordinate within the Sprite to translate. +* @param {number} y - x coordinate within the Sprite to translate. +* @param {number} sx - Scale factor to be applied. +* @param {number} sy - Scale factor to be applied. +* @return {Phaser.Point} The translated point. +*/ +Phaser.Sprite.prototype.getLocalPosition = function(p, x, y) { + + p.x = ((this._cache.a11 * this._cache.id * x + -this._cache.a01 * this._cache.id * y + (this._cache.a12 * this._cache.a01 - this._cache.a02 * this._cache.a11) * this._cache.id) * this.scale.x) + this._cache.a02; + p.y = ((this._cache.a00 * this._cache.id * y + -this._cache.a10 * this._cache.id * x + (-this._cache.a12 * this._cache.a00 + this._cache.a02 * this._cache.a10) * this._cache.id) * this.scale.y) + this._cache.a12; + + return p; + +}; + +/** +* Gets the local unmodified position of a coordinate relative to the Sprite, factoring in rotation and scale. +* Mostly only used internally by the Input Manager, but also useful for custom hit detection. +* +* @method Phaser.Sprite#getLocalUnmodifiedPosition +* @memberof Phaser.Sprite +* @param {Phaser.Point} p - The Point object to store the results in. +* @param {number} x - x coordinate within the Sprite to translate. +* @param {number} y - x coordinate within the Sprite to translate. +* @return {Phaser.Point} The translated point. +*/ +Phaser.Sprite.prototype.getLocalUnmodifiedPosition = function(p, gx, gy) { + + p.x = (this._cache.a11 * this._cache.idi * gx + -this._cache.i01 * this._cache.idi * gy + (this._cache.a12 * this._cache.i01 - this._cache.a02 * this._cache.a11) * this._cache.idi) + (this.anchor.x * this._cache.width); + p.y = (this._cache.a00 * this._cache.idi * gy + -this._cache.i10 * this._cache.idi * gx + (-this._cache.a12 * this._cache.a00 + this._cache.a02 * this._cache.i10) * this._cache.idi) + (this.anchor.y * this._cache.height); + + return p; + +}; + +/** +* Resets the Sprite.crop value back to the frame dimensions. +* +* @method Phaser.Sprite#resetCrop +* @memberof Phaser.Sprite +*/ +Phaser.Sprite.prototype.resetCrop = function() { + + this.crop = new Phaser.Rectangle(0, 0, this._cache.width, this._cache.height); + this.texture.setFrame(this.crop); + this.cropEnabled = false; + +}; + +/** +* Internal function called by the World postUpdate cycle. +* +* @method Phaser.Sprite#postUpdate +* @memberof Phaser.Sprite +*/ +Phaser.Sprite.prototype.postUpdate = function() { + + if (this.key instanceof Phaser.BitmapData && this.key._dirty) + { + this.key.render(); + } + + if (this.exists) + { + // The sprite is positioned in this call, after taking into consideration motion updates and collision + if (this.body) + { + this.body.postUpdate(); + } + + if (this.fixedToCamera) + { + this._cache.x = this.game.camera.view.x + this.cameraOffset.x; + this._cache.y = this.game.camera.view.y + this.cameraOffset.y; + } + else + { + this._cache.x = this.x; + this._cache.y = this.y; + } + + this.world.setTo(this.game.camera.x + this.worldTransform[2], this.game.camera.y + this.worldTransform[5]); + + this.position.x = this._cache.x; + this.position.y = this._cache.y; + } + +}; + +/** +* Changes the Texture the Sprite is using entirely. The old texture is removed and the new one is referenced or fetched from the Cache. +* This causes a WebGL texture update, so use sparingly or in low-intensity portions of your game. +* +* @method Phaser.Sprite#loadTexture +* @memberof Phaser.Sprite +* @param {string|Phaser.RenderTexture|Phaser.BitmapData|PIXI.Texture} key - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache entry, or an instance of a RenderTexture, BitmapData or PIXI.Texture. +* @param {string|number} frame - If this Sprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index. +*/ +Phaser.Sprite.prototype.loadTexture = function (key, frame) { + + this.key = key; + + if (key instanceof Phaser.RenderTexture) + { + this.currentFrame = this.game.cache.getTextureFrame(key.name); + } + else if (key instanceof Phaser.BitmapData) + { + this.setTexture(key.texture); + this.currentFrame = key.textureFrame; + } + else if (key instanceof PIXI.Texture) + { + this.currentFrame = frame; + } + else + { + if (typeof key === 'undefined' || this.game.cache.checkImageKey(key) === false) + { + key = '__default'; + this.key = key; + } + + if (this.game.cache.isSpriteSheet(key)) + { + this.animations.loadFrameData(this.game.cache.getFrameData(key)); + + if (typeof frame !== 'undefined') + { + if (typeof frame === 'string') + { + this.frameName = frame; + } + else + { + this.frame = frame; + } + } + } + else + { + this.currentFrame = this.game.cache.getFrame(key); + this.setTexture(PIXI.TextureCache[key]); + } + } + +}; + +/** +* Moves the sprite so its center is located on the given x and y coordinates. +* Doesn't change the anchor point of the sprite. +* +* @method Phaser.Sprite#centerOn +* @memberof Phaser.Sprite +* @param {number} x - The x coordinate (in world space) to position the Sprite at. +* @param {number} y - The y coordinate (in world space) to position the Sprite at. +* @return (Phaser.Sprite) This instance. +*/ +Phaser.Sprite.prototype.centerOn = function(x, y) { + + this.x = x + (this.x - this.center.x); + this.y = y + (this.y - this.center.y); + return this; + +}; + +/** +* Brings a 'dead' Sprite back to life, optionally giving it the health value specified. +* A resurrected Sprite has its alive, exists and visible properties all set to true. +* It will dispatch the onRevived event, you can listen to Sprite.events.onRevived for the signal. +* +* @method Phaser.Sprite#revive +* @memberof Phaser.Sprite +* @param {number} [health=1] - The health to give the Sprite. +* @return (Phaser.Sprite) This instance. +*/ +Phaser.Sprite.prototype.revive = function(health) { + + if (typeof health === 'undefined') { health = 1; } + + this.alive = true; + this.exists = true; + this.visible = true; + this.health = health; + + if (this.events) + { + this.events.onRevived.dispatch(this); + } + + return this; + +}; + +/** +* Kills a Sprite. A killed Sprite has its alive, exists and visible properties all set to false. +* It will dispatch the onKilled event, you can listen to Sprite.events.onKilled for the signal. +* Note that killing a Sprite is a way for you to quickly recycle it in a Sprite pool, it doesn't free it up from memory. +* If you don't need this Sprite any more you should call Sprite.destroy instead. +* +* @method Phaser.Sprite#kill +* @memberof Phaser.Sprite +* @return (Phaser.Sprite) This instance. +*/ +Phaser.Sprite.prototype.kill = function() { + + this.alive = false; + this.exists = false; + this.visible = false; + + if (this.events) + { + this.events.onKilled.dispatch(this); + } + + return this; + +}; + +/** +* Destroys the Sprite. This removes it from its parent group, destroys the input, event and animation handlers if present +* and nulls its reference to game, freeing it up for garbage collection. +* +* @method Phaser.Sprite#destroy +* @memberof Phaser.Sprite +*/ +Phaser.Sprite.prototype.destroy = function() { + + if (this.filters) + { + this.filters = null; + } + + if (this.group) + { + this.group.remove(this); + } + + if (this.input) + { + this.input.destroy(); + } + + if (this.events) + { + this.events.destroy(); + } + + if (this.animations) + { + this.animations.destroy(); + } + + this.alive = false; + this.exists = false; + this.visible = false; + + this.game = null; + +}; + +/** +* Damages the Sprite, this removes the given amount from the Sprites health property. +* If health is then taken below zero Sprite.kill is called. +* +* @method Phaser.Sprite#damage +* @memberof Phaser.Sprite +* @param {number} amount - The amount to subtract from the Sprite.health value. +* @return (Phaser.Sprite) This instance. +*/ +Phaser.Sprite.prototype.damage = function(amount) { + + if (this.alive) + { + this.health -= amount; + + if (this.health < 0) + { + this.kill(); + } + } + + return this; + +}; + +/** +* Resets the Sprite. This places the Sprite at the given x/y world coordinates and then +* sets alive, exists, visible and renderable all to true. Also resets the outOfBounds state and health values. +* If the Sprite has a physics body that too is reset. +* +* @method Phaser.Sprite#reset +* @memberof Phaser.Sprite +* @param {number} x - The x coordinate (in world space) to position the Sprite at. +* @param {number} y - The y coordinate (in world space) to position the Sprite at. +* @param {number} [health=1] - The health to give the Sprite. +* @return (Phaser.Sprite) This instance. +*/ +Phaser.Sprite.prototype.reset = function(x, y, health) { + + if (typeof health === 'undefined') { health = 1; } + + this.x = x; + this.y = y; + this.position.x = this.x; + this.position.y = this.y; + this.alive = true; + this.exists = true; + this.visible = true; + this.renderable = true; + this._outOfBoundsFired = false; + + this.health = health; + + if (this.body) + { + this.body.reset(); + } + + return this; + +}; + +/** +* Brings the Sprite to the top of the display list it is a child of. Sprites that are members of a Phaser.Group are only +* bought to the top of that Group, not the entire display list. +* +* @method Phaser.Sprite#bringToTop +* @memberof Phaser.Sprite +* @return (Phaser.Sprite) This instance. +*/ +Phaser.Sprite.prototype.bringToTop = function() { + + if (this.group) + { + this.group.bringToTop(this); + } + else + { + this.game.world.bringToTop(this); + } + + return this; + +}; + +/** +* Play an animation based on the given key. The animation should previously have been added via sprite.animations.add() +* If the requested animation is already playing this request will be ignored. If you need to reset an already running animation do so directly on the Animation object itself. +* +* @method Phaser.Sprite#play +* @memberof Phaser.Sprite +* @param {string} name - The name of the animation to be played, e.g. "fire", "walk", "jump". +* @param {number} [frameRate=null] - The framerate to play the animation at. The speed is given in frames per second. If not provided the previously set frameRate of the Animation is used. +* @param {boolean} [loop=false] - Should the animation be looped after playback. If not provided the previously set loop value of the Animation is used. +* @param {boolean} [killOnComplete=false] - If set to true when the animation completes (only happens if loop=false) the parent Sprite will be killed. +* @return {Phaser.Animation} A reference to playing Animation instance. +*/ +Phaser.Sprite.prototype.play = function (name, frameRate, loop, killOnComplete) { + + if (this.animations) + { + return this.animations.play(name, frameRate, loop, killOnComplete); + } + +}; + +/** +* Indicates the rotation of the Sprite, in degrees, from its original orientation. Values from 0 to 180 represent clockwise rotation; values from 0 to -180 represent counterclockwise rotation. +* Values outside this range are added to or subtracted from 360 to obtain a value within the range. For example, the statement player.angle = 450 is the same as player.angle = 90. +* If you wish to work in radians instead of degrees use the property Sprite.rotation instead. +* @name Phaser.Sprite#angle +* @property {number} angle - Gets or sets the Sprites angle of rotation in degrees. +*/ +Object.defineProperty(Phaser.Sprite.prototype, 'angle', { + + get: function() { + return Phaser.Math.wrapAngle(Phaser.Math.radToDeg(this.rotation)); + }, + + set: function(value) { + this.rotation = Phaser.Math.degToRad(Phaser.Math.wrapAngle(value)); + } + +}); + +/** +* @name Phaser.Sprite#frame +* @property {number} frame - Gets or sets the current frame index and updates the Texture Cache for display. +*/ +Object.defineProperty(Phaser.Sprite.prototype, "frame", { + + get: function () { + return this.animations.frame; + }, + + set: function (value) { + this.animations.frame = value; + } + +}); + +/** +* @name Phaser.Sprite#frameName +* @property {string} frameName - Gets or sets the current frame name and updates the Texture Cache for display. +*/ +Object.defineProperty(Phaser.Sprite.prototype, "frameName", { + + get: function () { + return this.animations.frameName; + }, + + set: function (value) { + this.animations.frameName = value; + } + +}); + +/** +* @name Phaser.Sprite#inCamera +* @property {boolean} inCamera - Is this sprite visible to the camera or not? +* @readonly +*/ +Object.defineProperty(Phaser.Sprite.prototype, "inCamera", { + + get: function () { + return this._cache.cameraVisible; + } + +}); + +/** +* The width of the sprite in pixels, setting this will actually modify the scale to acheive the value desired. +* If you wish to crop the Sprite instead see the Sprite.crop value. +* +* @name Phaser.Sprite#width +* @property {number} width - The width of the Sprite in pixels. +*/ +Object.defineProperty(Phaser.Sprite.prototype, 'width', { + + get: function() { + return this.scale.x * this.currentFrame.width; + }, + + set: function(value) { + + this.scale.x = value / this.currentFrame.width; + this._cache.scaleX = value / this.currentFrame.width; + this._width = value; + + } + +}); + +/** +* The height of the sprite in pixels, setting this will actually modify the scale to acheive the value desired. +* If you wish to crop the Sprite instead see the Sprite.crop value. +* +* @name Phaser.Sprite#height +* @property {number} height - The height of the Sprite in pixels. +*/ +Object.defineProperty(Phaser.Sprite.prototype, 'height', { + + get: function() { + return this.scale.y * this.currentFrame.height; + }, + + set: function(value) { + + this.scale.y = value / this.currentFrame.height; + this._cache.scaleY = value / this.currentFrame.height; + this._height = value; + + } + +}); + +/** +* By default a Sprite won't process any input events at all. By setting inputEnabled to true the Phaser.InputHandler is +* activated for this Sprite instance and it will then start to process click/touch events and more. +* +* @name Phaser.Sprite#inputEnabled +* @property {boolean} inputEnabled - Set to true to allow this Sprite to receive input events, otherwise false. +*/ +Object.defineProperty(Phaser.Sprite.prototype, "inputEnabled", { + + get: function () { + + return (this.input.enabled); + + }, + + set: function (value) { + + if (value) + { + if (this.input.enabled === false) + { + this.input.start(); + } + } + else + { + if (this.input.enabled) + { + this.input.stop(); + } + } + + } + +}); diff --git a/src/physics/arcade/World.js b/src/physics/arcade/World.js new file mode 100644 index 00000000..576f7ae3 --- /dev/null +++ b/src/physics/arcade/World.js @@ -0,0 +1,1611 @@ +/** +* @author Richard Davey +* @copyright 2013 Photon Storm Ltd. +* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} +*/ + +/** +* Arcade Physics constructor. +* +* @class Phaser.Physics.Arcade +* @classdesc Arcade Physics Constructor +* @constructor +* @param {Phaser.Game} game reference to the current game instance. +*/ +Phaser.Physics.Arcade = function (game) { + + /** + * @property {Phaser.Game} game - Local reference to game. + */ + this.game = game; + + /** + * @property {Phaser.Point} gravity - The World gravity setting. Defaults to x: 0, y: 0, or no gravity. + */ + this.gravity = new Phaser.Point(); + + /** + * @property {Phaser.Rectangle} bounds - The bounds inside of which the physics world exists. Defaults to match the world bounds. + */ + this.bounds = new Phaser.Rectangle(0, 0, game.world.width, game.world.height); + + /** + * @property {number} maxObjects - Used by the QuadTree to set the maximum number of objects per quad. + */ + this.maxObjects = 10; + + /** + * @property {number} maxLevels - Used by the QuadTree to set the maximum number of iteration levels. + */ + this.maxLevels = 4; + + /** + * @property {number} OVERLAP_BIAS - A value added to the delta values during collision checks. + */ + this.OVERLAP_BIAS = 4; + + /** + * @property {Phaser.QuadTree} quadTree - The world QuadTree. + */ + this.quadTree = new Phaser.Physics.Arcade.QuadTree(this, this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height, this.maxObjects, this.maxLevels); + + /** + * @property {number} quadTreeID - The QuadTree ID. + */ + this.quadTreeID = 0; + + // Avoid gc spikes by caching these values for re-use + + /** + * @property {Phaser.Rectangle} _bounds1 - Internal cache var. + * @private + */ + this._bounds1 = new Phaser.Rectangle(); + + /** + * @property {Phaser.Rectangle} _bounds2 - Internal cache var. + * @private + */ + this._bounds2 = new Phaser.Rectangle(); + + /** + * @property {number} _overlap - Internal cache var. + * @private + */ + this._overlap = 0; + + /** + * @property {number} _maxOverlap - Internal cache var. + * @private + */ + this._maxOverlap = 0; + + /** + * @property {number} _velocity1 - Internal cache var. + * @private + */ + this._velocity1 = 0; + + /** + * @property {number} _velocity2 - Internal cache var. + * @private + */ + this._velocity2 = 0; + + /** + * @property {number} _newVelocity1 - Internal cache var. + * @private + */ + this._newVelocity1 = 0; + + /** + * @property {number} _newVelocity2 - Internal cache var. + * @private + */ + this._newVelocity2 = 0; + + /** + * @property {number} _average - Internal cache var. + * @private + */ + this._average = 0; + + /** + * @property {Array} _mapData - Internal cache var. + * @private + */ + this._mapData = []; + + /** + * @property {number} _mapTiles - Internal cache var. + * @private + */ + this._mapTiles = 0; + + /** + * @property {boolean} _result - Internal cache var. + * @private + */ + this._result = false; + + /** + * @property {number} _total - Internal cache var. + * @private + */ + this._total = 0; + + /** + * @property {number} _angle - Internal cache var. + * @private + */ + this._angle = 0; + + /** + * @property {number} _dx - Internal cache var. + * @private + */ + this._dx = 0; + + /** + * @property {number} _dy - Internal cache var. + * @private + */ + this._dy = 0; + +}; + +Phaser.Physics.Arcade.prototype = { + + /** + * Called automatically by a Physics body, it updates all motion related values on the Body. + * + * @method Phaser.Physics.Arcade#updateMotion + * @param {Phaser.Physics.Arcade.Body} The Body object to be updated. + */ + updateMotion: function (body) { + + // If you're wondering why the velocity is halved and applied twice, read this: http://www.niksula.hut.fi/~hkankaan/Homepages/gravity.html + + // Rotation + this._velocityDelta = (this.computeVelocity(body, body.angularVelocity, body.angularAcceleration, body.angularDrag, body.maxAngular, 0) - body.angularVelocity) * 0.5; + body.angularVelocity += this._velocityDelta; + body.rotation += (body.angularVelocity * this.game.time.physicsElapsed); + body.angularVelocity += this._velocityDelta; + + if(body.allowGravity) + { + // Gravity was previously applied without taking physicsElapsed into account + // so it needs to be multiplied by 60 (fps) for compatibility with existing games + this._gravityX = (this.gravity.x + body.gravity.x) * 60; + this._gravityY = (this.gravity.y + body.gravity.y) * 60; + } else { + this._gravityX = this._gravityY = 0; + } + + // Horizontal + this._velocityDelta = (this.computeVelocity(body, body.velocity.x, body.acceleration.x, body.drag.x, body.maxVelocity.x, this._gravityX) - body.velocity.x) * 0.5; + body.velocity.x += this._velocityDelta; + body.x += (body.velocity.x * this.game.time.physicsElapsed); + body.velocity.x += this._velocityDelta; + + // Vertical + this._velocityDelta = (this.computeVelocity(body, body.velocity.y, body.acceleration.y, body.drag.y, body.maxVelocity.y, this._gravityY) - body.velocity.y) * 0.5; + body.velocity.y += this._velocityDelta; + body.y += (body.velocity.y * this.game.time.physicsElapsed); + body.velocity.y += this._velocityDelta; + + }, + + /** + * A tween-like function that takes a starting velocity and some other factors and returns an altered velocity. + * + * @method Phaser.Physics.Arcade#computeVelocity + * @param {Phaser.Physics.Arcade.Body} body - The Body object to be updated. + * @param {number} velocity - Any component of velocity (e.g. 20). + * @param {number} acceleration - Rate at which the velocity is changing. + * @param {number} drag - Really kind of a deceleration, this is how much the velocity changes if Acceleration is not set. + * @param {number} [max=10000] - An absolute value cap for the velocity. + * @param {number} gravity - The acceleration due to gravity. Gravity will not induce drag. + * @return {number} The altered Velocity value. + */ + computeVelocity: function (body, velocity, acceleration, drag, max, gravity) { + + max = max || 10000; + + velocity += (acceleration + gravity) * this.game.time.physicsElapsed; + + if (acceleration === 0 && drag !== 0) + { + this._drag = drag * this.game.time.physicsElapsed; + + if (velocity - this._drag > 0) + { + velocity -= this._drag; + } + else if (velocity + this._drag < 0) + { + velocity += this._drag; + } + else + { + velocity = 0; + } + } + + if (velocity > max) + { + velocity = max; + } + else if (velocity < -max) + { + velocity = -max; + } + + return velocity; + + }, + + /** + * Called automatically by the core game loop. + * + * @method Phaser.Physics.Arcade#preUpdate + * @protected + */ + preUpdate: function () { + + // Clear the tree + this.quadTree.clear(); + + // Create our tree which all of the Physics bodies will add themselves to + this.quadTreeID = 0; + this.quadTree = new Phaser.QuadTree(this, this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height, this.maxObjects, this.maxLevels); + + }, + + /** + * Called automatically by the core game loop. + * + * @method Phaser.Physics.Arcade#postUpdate + * @protected + */ + postUpdate: function () { + + // Clear the tree ready for the next update + this.quadTree.clear(); + + }, + + /** + * Checks for overlaps between two game objects. The objects can be Sprites, Groups or Emitters. + * You can perform Sprite vs. Sprite, Sprite vs. Group and Group vs. Group overlap checks. + * Unlike collide the objects are NOT automatically separated or have any physics applied, they merely test for overlap results. + * + * @method Phaser.Physics.Arcade#overlap + * @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter} object1 - The first object to check. Can be an instance of Phaser.Sprite, Phaser.Group or Phaser.Particles.Emitter. + * @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter} object2 - The second object to check. Can be an instance of Phaser.Sprite, Phaser.Group or Phaser.Particles.Emitter. + * @param {function} [overlapCallback=null] - An optional callback function that is called if the objects overlap. The two objects will be passed to this function in the same order in which you specified them. + * @param {function} [processCallback=null] - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then overlapCallback will only be called if processCallback returns true. + * @param {object} [callbackContext] - The context in which to run the callbacks. + * @returns {boolean} True if an overlap occured otherwise false. + */ + overlap: function (object1, object2, overlapCallback, processCallback, callbackContext) { + + overlapCallback = overlapCallback || null; + processCallback = processCallback || null; + callbackContext = callbackContext || overlapCallback; + + this._result = false; + this._total = 0; + + // Only test valid objects + if (object1 && object2 && object1.exists && object2.exists) + { + // SPRITES + if (object1.type == Phaser.SPRITE || object1.type == Phaser.TILESPRITE) + { + if (object2.type == Phaser.SPRITE || object2.type == Phaser.TILESPRITE) + { + this.overlapSpriteVsSprite(object1, object2, overlapCallback, processCallback, callbackContext); + } + else if (object2.type == Phaser.GROUP || object2.type == Phaser.EMITTER) + { + this.overlapSpriteVsGroup(object1, object2, overlapCallback, processCallback, callbackContext); + } + } + // GROUPS + else if (object1.type == Phaser.GROUP) + { + if (object2.type == Phaser.SPRITE || object2.type == Phaser.TILESPRITE) + { + this.overlapSpriteVsGroup(object2, object1, overlapCallback, processCallback, callbackContext); + } + else if (object2.type == Phaser.GROUP || object2.type == Phaser.EMITTER) + { + this.overlapGroupVsGroup(object1, object2, overlapCallback, processCallback, callbackContext); + } + } + // EMITTER + else if (object1.type == Phaser.EMITTER) + { + if (object2.type == Phaser.SPRITE || object2.type == Phaser.TILESPRITE) + { + this.overlapSpriteVsGroup(object2, object1, overlapCallback, processCallback, callbackContext); + } + else if (object2.type == Phaser.GROUP || object2.type == Phaser.EMITTER) + { + this.overlapGroupVsGroup(object1, object2, overlapCallback, processCallback, callbackContext); + } + } + } + + return (this._total > 0); + + }, + + /** + * An internal function. Use Phaser.Physics.Arcade.overlap instead. + * + * @method Phaser.Physics.Arcade#overlapSpriteVsSprite + * @private + */ + overlapSpriteVsSprite: function (sprite1, sprite2, overlapCallback, processCallback, callbackContext) { + + this._result = Phaser.Rectangle.intersects(sprite1.body, sprite2.body); + + if (this._result) + { + // They collided, is there a custom process callback? + if (processCallback) + { + if (processCallback.call(callbackContext, sprite1, sprite2)) + { + this._total++; + + if (overlapCallback) + { + overlapCallback.call(callbackContext, sprite1, sprite2); + } + } + } + else + { + this._total++; + + if (overlapCallback) + { + overlapCallback.call(callbackContext, sprite1, sprite2); + } + } + } + + }, + + /** + * An internal function. Use Phaser.Physics.Arcade.overlap instead. + * + * @method Phaser.Physics.Arcade#overlapSpriteVsGroup + * @private + */ + overlapSpriteVsGroup: function (sprite, group, overlapCallback, processCallback, callbackContext) { + + if (group.length === 0) + { + return; + } + + // What is the sprite colliding with in the quadtree? + this._potentials = this.quadTree.retrieve(sprite); + + for (var i = 0, len = this._potentials.length; i < len; i++) + { + // We have our potential suspects, are they in this group? + if (this._potentials[i].sprite.group == group) + { + this._result = Phaser.Rectangle.intersects(sprite.body, this._potentials[i]); + + if (this._result && processCallback) + { + this._result = processCallback.call(callbackContext, sprite, this._potentials[i].sprite); + } + + if (this._result) + { + this._total++; + + if (overlapCallback) + { + overlapCallback.call(callbackContext, sprite, this._potentials[i].sprite); + } + } + } + } + + }, + + /** + * An internal function. Use Phaser.Physics.Arcade.overlap instead. + * + * @method Phaser.Physics.Arcade#overlapGroupVsGroup + * @private + */ + overlapGroupVsGroup: function (group1, group2, overlapCallback, processCallback, callbackContext) { + + if (group1.length === 0 || group2.length === 0) + { + return; + } + + if (group1._container.first._iNext) + { + var currentNode = group1._container.first._iNext; + + do + { + if (currentNode.exists) + { + this.overlapSpriteVsGroup(currentNode, group2, overlapCallback, processCallback, callbackContext); + } + currentNode = currentNode._iNext; + } + while (currentNode != group1._container.last._iNext); + } + + }, + + /** + * Checks for collision between two game objects. The objects can be Sprites, Groups, Emitters or Tilemap Layers. + * You can perform Sprite vs. Sprite, Sprite vs. Group, Group vs. Group, Sprite vs. Tilemap Layer or Group vs. Tilemap Layer collisions. + * The objects are also automatically separated. + * + * @method Phaser.Physics.Arcade#collide + * @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|Phaser.Tilemap} object1 - The first object to check. Can be an instance of Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter, or Phaser.Tilemap + * @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|Phaser.Tilemap} object2 - The second object to check. Can be an instance of Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter or Phaser.Tilemap + * @param {function} [collideCallback=null] - An optional callback function that is called if the objects overlap. The two objects will be passed to this function in the same order in which you specified them. + * @param {function} [processCallback=null] - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then collideCallback will only be called if processCallback returns true. + * @param {object} [callbackContext] - The context in which to run the callbacks. + * @returns {boolean} True if a collision occured otherwise false. + */ + collide: function (object1, object2, collideCallback, processCallback, callbackContext) { + + collideCallback = collideCallback || null; + processCallback = processCallback || null; + callbackContext = callbackContext || collideCallback; + + this._result = false; + this._total = 0; + + // Only collide valid objects + if (object1 && object2 && object1.exists && object2.exists) + { + // SPRITES + if (object1.type == Phaser.SPRITE || object1.type == Phaser.TILESPRITE) + { + if (object2.type == Phaser.SPRITE || object2.type == Phaser.TILESPRITE) + { + this.collideSpriteVsSprite(object1, object2, collideCallback, processCallback, callbackContext); + } + else if (object2.type == Phaser.GROUP || object2.type == Phaser.EMITTER) + { + this.collideSpriteVsGroup(object1, object2, collideCallback, processCallback, callbackContext); + } + else if (object2.type == Phaser.TILEMAPLAYER) + { + this.collideSpriteVsTilemapLayer(object1, object2, collideCallback, processCallback, callbackContext); + } + } + // GROUPS + else if (object1.type == Phaser.GROUP) + { + if (object2.type == Phaser.SPRITE || object2.type == Phaser.TILESPRITE) + { + this.collideSpriteVsGroup(object2, object1, collideCallback, processCallback, callbackContext); + } + else if (object2.type == Phaser.GROUP || object2.type == Phaser.EMITTER) + { + this.collideGroupVsGroup(object1, object2, collideCallback, processCallback, callbackContext); + } + else if (object2.type == Phaser.TILEMAPLAYER) + { + this.collideGroupVsTilemapLayer(object1, object2, collideCallback, processCallback, callbackContext); + } + } + // TILEMAP LAYERS + else if (object1.type == Phaser.TILEMAPLAYER) + { + if (object2.type == Phaser.SPRITE || object2.type == Phaser.TILESPRITE) + { + this.collideSpriteVsTilemapLayer(object2, object1, collideCallback, processCallback, callbackContext); + } + else if (object2.type == Phaser.GROUP || object2.type == Phaser.EMITTER) + { + this.collideGroupVsTilemapLayer(object2, object1, collideCallback, processCallback, callbackContext); + } + } + // EMITTER + else if (object1.type == Phaser.EMITTER) + { + if (object2.type == Phaser.SPRITE || object2.type == Phaser.TILESPRITE) + { + this.collideSpriteVsGroup(object2, object1, collideCallback, processCallback, callbackContext); + } + else if (object2.type == Phaser.GROUP || object2.type == Phaser.EMITTER) + { + this.collideGroupVsGroup(object1, object2, collideCallback, processCallback, callbackContext); + } + else if (object2.type == Phaser.TILEMAPLAYER) + { + this.collideGroupVsTilemapLayer(object1, object2, collideCallback, processCallback, callbackContext); + } + } + } + + return (this._total > 0); + + }, + + /** + * An internal function. Use Phaser.Physics.Arcade.collide instead. + * + * @method Phaser.Physics.Arcade#collideSpriteVsTilemapLayer + * @private + */ + collideSpriteVsTilemapLayer: function (sprite, tilemapLayer, collideCallback, processCallback, callbackContext) { + + this._mapData = tilemapLayer.getTiles(sprite.body.x, sprite.body.y, sprite.body.width, sprite.body.height, true); + + if (this._mapData.length === 0) + { + return; + } + + if (this._mapData.length > 1) + { + // console.log(' multi sep ---------------------------------------------------------------------------------------------'); + this.separateTiles(sprite.body, this._mapData); + } + else + { + var i = 0; + if (this.separateTile(sprite.body, this._mapData[i])) + { + // They collided, is there a custom process callback? + if (processCallback) + { + if (processCallback.call(callbackContext, sprite, this._mapData[i])) + { + this._total++; + + if (collideCallback) + { + collideCallback.call(callbackContext, sprite, this._mapData[i]); + } + } + } + else + { + this._total++; + + if (collideCallback) + { + collideCallback.call(callbackContext, sprite, this._mapData[i]); + } + } + } + } + + }, + + /** + * An internal function. Use Phaser.Physics.Arcade.collide instead. + * + * @method Phaser.Physics.Arcade#collideGroupVsTilemapLayer + * @private + */ + collideGroupVsTilemapLayer: function (group, tilemapLayer, collideCallback, processCallback, callbackContext) { + + if (group.length === 0) + { + return; + } + + if (group._container.first._iNext) + { + var currentNode = group._container.first._iNext; + + do + { + if (currentNode.exists) + { + this.collideSpriteVsTilemapLayer(currentNode, tilemapLayer, collideCallback, processCallback, callbackContext); + } + currentNode = currentNode._iNext; + } + while (currentNode != group._container.last._iNext); + } + + }, + + /** + * An internal function. Use Phaser.Physics.Arcade.collide instead. + * + * @method Phaser.Physics.Arcade#collideSpriteVsSprite + * @private + */ + collideSpriteVsSprite: function (sprite1, sprite2, collideCallback, processCallback, callbackContext) { + + this.separate(sprite1.body, sprite2.body); + + if (this._result) + { + // They collided, is there a custom process callback? + if (processCallback) + { + if (processCallback.call(callbackContext, sprite1, sprite2)) + { + this._total++; + + if (collideCallback) + { + collideCallback.call(callbackContext, sprite1, sprite2); + } + } + } + else + { + this._total++; + + if (collideCallback) + { + collideCallback.call(callbackContext, sprite1, sprite2); + } + } + } + + }, + + /** + * An internal function. Use Phaser.Physics.Arcade.collide instead. + * + * @method Phaser.Physics.Arcade#collideSpriteVsGroup + * @private + */ + collideSpriteVsGroup: function (sprite, group, collideCallback, processCallback, callbackContext) { + + if (group.length === 0) + { + return; + } + + // What is the sprite colliding with in the quadtree? + this._potentials = this.quadTree.retrieve(sprite); + + for (var i = 0, len = this._potentials.length; i < len; i++) + { + // We have our potential suspects, are they in this group? + if (this._potentials[i].sprite.group == group) + { + this.separate(sprite.body, this._potentials[i]); + + if (this._result && processCallback) + { + this._result = processCallback.call(callbackContext, sprite, this._potentials[i].sprite); + } + + if (this._result) + { + this._total++; + + if (collideCallback) + { + collideCallback.call(callbackContext, sprite, this._potentials[i].sprite); + } + } + } + } + + }, + + /** + * An internal function. Use Phaser.Physics.Arcade.collide instead. + * + * @method Phaser.Physics.Arcade#collideGroupVsGroup + * @private + */ + collideGroupVsGroup: function (group1, group2, collideCallback, processCallback, callbackContext) { + + if (group1.length === 0 || group2.length === 0) + { + return; + } + + if (group1._container.first._iNext) + { + var currentNode = group1._container.first._iNext; + + do + { + if (currentNode.exists) + { + this.collideSpriteVsGroup(currentNode, group2, collideCallback, processCallback, callbackContext); + } + currentNode = currentNode._iNext; + } + while (currentNode != group1._container.last._iNext); + } + + }, + + /** + * The core separation function to separate two physics bodies. + * @method Phaser.Physics.Arcade#separate + * @param {Phaser.Physics.Arcade.Body} body1 - The Body object to separate. + * @param {Phaser.Physics.Arcade.Body} body2 - The Body object to separate. + * @returns {boolean} Returns true if the bodies were separated, otherwise false. + */ + separate: function (body1, body2) { + + this._result = (this.separateX(body1, body2) || this.separateY(body1, body2)); + + }, + + /** + * The core separation function to separate two physics bodies on the x axis. + * @method Phaser.Physics.Arcade#separateX + * @param {Phaser.Physics.Arcade.Body} body1 - The Body object to separate. + * @param {Phaser.Physics.Arcade.Body} body2 - The Body object to separate. + * @returns {boolean} Returns true if the bodies were separated, otherwise false. + */ + separateX: function (body1, body2) { + + // Can't separate two immovable bodies + if (body1.immovable && body2.immovable) + { + return false; + } + + this._overlap = 0; + + // Check if the hulls actually overlap + if (Phaser.Rectangle.intersects(body1, body2)) + { + this._maxOverlap = body1.deltaAbsX() + body2.deltaAbsX() + this.OVERLAP_BIAS; + + if (body1.deltaX() === 0 && body2.deltaX() === 0) + { + // They overlap but neither of them are moving + body1.embedded = true; + body2.embedded = true; + } + else if (body1.deltaX() > body2.deltaX()) + { + // Body1 is moving right and/or Body2 is moving left + this._overlap = body1.x + body1.width - body2.x; + + if ((this._overlap > this._maxOverlap) || body1.allowCollision.right === false || body2.allowCollision.left === false) + { + this._overlap = 0; + } + else + { + body1.touching.right = true; + body2.touching.left = true; + } + } + else if (body1.deltaX() < body2.deltaX()) + { + // Body1 is moving left and/or Body2 is moving right + this._overlap = body1.x - body2.width - body2.x; + + if ((-this._overlap > this._maxOverlap) || body1.allowCollision.left === false || body2.allowCollision.right === false) + { + this._overlap = 0; + } + else + { + body1.touching.left = true; + body2.touching.right = true; + } + } + + // Then adjust their positions and velocities accordingly (if there was any overlap) + if (this._overlap !== 0) + { + body1.overlapX = this._overlap; + body2.overlapX = this._overlap; + + if (body1.customSeparateX || body2.customSeparateX) + { + return true; + } + + this._velocity1 = body1.velocity.x; + this._velocity2 = body2.velocity.x; + + if (!body1.immovable && !body2.immovable) + { + this._overlap *= 0.5; + + body1.x = body1.x - this._overlap; + body2.x += this._overlap; + + this._newVelocity1 = Math.sqrt((this._velocity2 * this._velocity2 * body2.mass) / body1.mass) * ((this._velocity2 > 0) ? 1 : -1); + this._newVelocity2 = Math.sqrt((this._velocity1 * this._velocity1 * body1.mass) / body2.mass) * ((this._velocity1 > 0) ? 1 : -1); + this._average = (this._newVelocity1 + this._newVelocity2) * 0.5; + this._newVelocity1 -= this._average; + this._newVelocity2 -= this._average; + + body1.velocity.x = this._average + this._newVelocity1 * body1.bounce.x; + body2.velocity.x = this._average + this._newVelocity2 * body2.bounce.x; + } + else if (!body1.immovable) + { + body1.x = body1.x - this._overlap; + body1.velocity.x = this._velocity2 - this._velocity1 * body1.bounce.x; + } + else if (!body2.immovable) + { + body2.x += this._overlap; + body2.velocity.x = this._velocity1 - this._velocity2 * body2.bounce.x; + } + + return true; + } + } + + return false; + + }, + + /** + * The core separation function to separate two physics bodies on the y axis. + * @method Phaser.Physics.Arcade#separateY + * @param {Phaser.Physics.Arcade.Body} body1 - The Body object to separate. + * @param {Phaser.Physics.Arcade.Body} body2 - The Body object to separate. + * @returns {boolean} Returns true if the bodies were separated, otherwise false. + */ + separateY: function (body1, body2) { + + // Can't separate two immovable or non-existing bodys + if (body1.immovable && body2.immovable) + { + return false; + } + + this._overlap = 0; + + // Check if the hulls actually overlap + if (Phaser.Rectangle.intersects(body1, body2)) + { + this._maxOverlap = body1.deltaAbsY() + body2.deltaAbsY() + this.OVERLAP_BIAS; + + if (body1.deltaY() === 0 && body2.deltaY() === 0) + { + // They overlap but neither of them are moving + body1.embedded = true; + body2.embedded = true; + } + else if (body1.deltaY() > body2.deltaY()) + { + // Body1 is moving down and/or Body2 is moving up + this._overlap = body1.y + body1.height - body2.y; + + if ((this._overlap > this._maxOverlap) || body1.allowCollision.down === false || body2.allowCollision.up === false) + { + this._overlap = 0; + } + else + { + body1.touching.down = true; + body2.touching.up = true; + } + } + else if (body1.deltaY() < body2.deltaY()) + { + // Body1 is moving up and/or Body2 is moving down + this._overlap = body1.y - body2.height - body2.y; + + if ((-this._overlap > this._maxOverlap) || body1.allowCollision.up === false || body2.allowCollision.down === false) + { + this._overlap = 0; + } + else + { + body1.touching.up = true; + body2.touching.down = true; + } + } + + // Then adjust their positions and velocities accordingly (if there was any overlap) + if (this._overlap !== 0) + { + body1.overlapY = this._overlap; + body2.overlapY = this._overlap; + + if (body1.customSeparateY || body2.customSeparateY) + { + return true; + } + + this._velocity1 = body1.velocity.y; + this._velocity2 = body2.velocity.y; + + if (!body1.immovable && !body2.immovable) + { + this._overlap *= 0.5; + + body1.y = body1.y - this._overlap; + body2.y += this._overlap; + + this._newVelocity1 = Math.sqrt((this._velocity2 * this._velocity2 * body2.mass) / body1.mass) * ((this._velocity2 > 0) ? 1 : -1); + this._newVelocity2 = Math.sqrt((this._velocity1 * this._velocity1 * body1.mass) / body2.mass) * ((this._velocity1 > 0) ? 1 : -1); + this._average = (this._newVelocity1 + this._newVelocity2) * 0.5; + this._newVelocity1 -= this._average; + this._newVelocity2 -= this._average; + + body1.velocity.y = this._average + this._newVelocity1 * body1.bounce.y; + body2.velocity.y = this._average + this._newVelocity2 * body2.bounce.y; + } + else if (!body1.immovable) + { + body1.y = body1.y - this._overlap; + body1.velocity.y = this._velocity2 - this._velocity1 * body1.bounce.y; + + // This is special case code that handles things like horizontal moving platforms you can ride + if (body2.moves) + { + body1.x += body2.x - body2.preX; + } + } + else if (!body2.immovable) + { + body2.y += this._overlap; + body2.velocity.y = this._velocity1 - this._velocity2 * body2.bounce.y; + + // This is special case code that handles things like horizontal moving platforms you can ride + if (body1.moves) + { + body2.x += body1.x - body1.preX; + } + } + + return true; + } + + } + + return false; + + }, + + /** + * The core separation function to separate a physics body and an array of tiles. + * @method Phaser.Physics.Arcade#separateTiles + * @param {Phaser.Physics.Arcade.Body} body1 - The Body object to separate. + * @param {Phaser.Tile} tile - The tile to collide against. + * @returns {boolean} Returns true if the bodies were separated, otherwise false. + */ + separateTiles: function (body, tiles) { + + // Can't separate two immovable objects (tiles are always immovable) + if (body.immovable) + { + return false; + } + + body.overlapX = 0; + body.overlapY = 0; + + var tile; + var localOverlapX = 0; + var localOverlapY = 0; + + for (var i = 0; i < tiles.length; i++) + { + tile = tiles[i]; + + if (Phaser.Rectangle.intersects(body, tile)) + { + if (body.deltaX() < 0 && body.allowCollision.left && tile.tile.faceRight) + { + // LEFT + localOverlapX = body.x - tile.right; + + if (localOverlapX >= body.deltaX()) + { + // console.log('m left overlapX', localOverlapX, body.deltaX()); + // use touching instead of blocked? + body.blocked.left = true; + body.touching.left = true; + body.touching.none = false; + } + } + else if (body.deltaX() > 0 && body.allowCollision.right && tile.tile.faceLeft) + { + // RIGHT + localOverlapX = body.right - tile.x; + + // Distance check + if (localOverlapX <= body.deltaX()) + { + // console.log('m right overlapX', localOverlapX, body.deltaX()); + body.blocked.right = true; + body.touching.right = true; + body.touching.none = false; + } + } + + if (body.deltaY() < 0 && body.allowCollision.up && tile.tile.faceBottom) + { + // UP + localOverlapY = body.y - tile.bottom; + + // Distance check + if (localOverlapY >= body.deltaY()) + { + // console.log('m up overlapY', localOverlapY, body.deltaY()); + body.blocked.up = true; + body.touching.up = true; + body.touching.none = false; + } + } + else if (body.deltaY() > 0 && body.allowCollision.down && tile.tile.faceTop) + { + // DOWN + localOverlapY = body.bottom - tile.y; + + if (localOverlapY <= body.deltaY()) + { + // console.log('m down overlapY', localOverlapY, body.deltaY()); + body.blocked.down = true; + body.touching.down = true; + body.touching.none = false; + } + } + } + } + + if (localOverlapX !== 0) + { + body.overlapX = localOverlapX; + } + + if (localOverlapY !== 0) + { + body.overlapY = localOverlapY; + } + + if (body.touching.none) + { + return false; + } + + // if (body.overlapX !== 0) + if (body.touching.left || body.touching.right) + { + body.x -= body.overlapX; + body.preX -= body.overlapX; + + if (body.bounce.x === 0) + { + body.velocity.x = 0; + } + else + { + body.velocity.x = -body.velocity.x * body.bounce.x; + } + } + + // if (body.overlapY !== 0) + if (body.touching.up || body.touching.down) + { + body.y -= body.overlapY; + body.preY -= body.overlapY; + + if (body.bounce.y === 0) + { + body.velocity.y = 0; + } + else + { + body.velocity.y = -body.velocity.y * body.bounce.y; + } + } + + return true; + + }, + + /** + * The core separation function to separate a physics body and a tile. + * @method Phaser.Physics.Arcade#separateTile + * @param {Phaser.Physics.Arcade.Body} body1 - The Body object to separate. + * @param {Phaser.Tile} tile - The tile to collide against. + * @returns {boolean} Returns true if the bodies were separated, otherwise false. + */ + separateTile: function (body, tile) { + + // Can't separate two immovable objects (tiles are always immovable) + if (body.immovable || Phaser.Rectangle.intersects(body, tile) === false) + { + // console.log('no intersects'); + // console.log('tx', tile.x, 'ty', tile.y, 'tw', tile.width, 'th', tile.height, 'tr', tile.right, 'tb', tile.bottom); + // console.log('bx', body.x, 'by', body.y, 'bw', body.width, 'bh', body.height, 'br', body.right, 'bb', body.bottom); + return false; + } + + // use body var instead + body.overlapX = 0; + body.overlapY = 0; + + // Remember - this happens AFTER the body has been moved by the motion update, so it needs moving back again + // console.log('---------------------------------------------------------------------------------------------'); + // console.log('tx', tile.x, 'ty', tile.y, 'tw', tile.width, 'th', tile.height, 'tr', tile.right, 'tb', tile.bottom); + // console.log('bx', body.x, 'by', body.y, 'bw', body.width, 'bh', body.height, 'br', body.right, 'bb', body.bottom); + // console.log(Phaser.Rectangle.intersects(body, tile)); + // console.log('dx', body.deltaX(), 'dy', body.deltaY(), 'dax', body.deltaAbsX(), 'day', body.deltaAbsY(), 'cax', Math.ceil(body.deltaAbsX()), 'cay', Math.ceil(body.deltaAbsY())); + + if (body.deltaX() < 0 && body.allowCollision.left && tile.tile.faceRight) + { + // LEFT + body.overlapX = body.x - tile.right; + + if (body.overlapX >= body.deltaX()) + { + // console.log('left overlapX', body.overlapX, body.deltaX()); + // use touching instead of blocked? + body.blocked.left = true; + body.touching.left = true; + body.touching.none = false; + } + } + else if (body.deltaX() > 0 && body.allowCollision.right && tile.tile.faceLeft) + { + // RIGHT + body.overlapX = body.right - tile.x; + + // Distance check + if (body.overlapX <= body.deltaX()) + { + // console.log('right overlapX', body.overlapX, body.deltaX()); + body.blocked.right = true; + body.touching.right = true; + body.touching.none = false; + } + } + + if (body.deltaY() < 0 && body.allowCollision.up && tile.tile.faceBottom) + { + // UP + body.overlapY = body.y - tile.bottom; + + // Distance check + if (body.overlapY >= body.deltaY()) + { + // console.log('up overlapY', body.overlapY, body.deltaY()); + body.blocked.up = true; + body.touching.up = true; + body.touching.none = false; + } + } + else if (body.deltaY() > 0 && body.allowCollision.down && tile.tile.faceTop) + { + // DOWN + body.overlapY = body.bottom - tile.y; + + if (body.overlapY <= body.deltaY()) + { + // console.log('down overlapY', body.overlapY, body.deltaY()); + body.blocked.down = true; + body.touching.down = true; + body.touching.none = false; + } + } + + // Separate in a single sweep + + if (body.touching.none) + { + return false; + } + + // if (body.overlapX !== 0) + if (body.touching.left || body.touching.right) + { + body.x -= body.overlapX; + body.preX -= body.overlapX; + + if (body.bounce.x === 0) + { + body.velocity.x = 0; + } + else + { + body.velocity.x = -body.velocity.x * body.bounce.x; + } + } + + // if (body.overlapY !== 0) + if (body.touching.up || body.touching.down) + { + body.y -= body.overlapY; + body.preY -= body.overlapY; + + if (body.bounce.y === 0) + { + body.velocity.y = 0; + } + else + { + body.velocity.y = -body.velocity.y * body.bounce.y; + } + } + + return true; + + }, + + /** + * Move the given display object towards the destination object at a steady velocity. + * If you specify a maxTime then it will adjust the speed (overwriting what you set) so it arrives at the destination in that number of seconds. + * Timings are approximate due to the way browser timers work. Allow for a variance of +- 50ms. + * Note: The display object does not continuously track the target. If the target changes location during transit the display object will not modify its course. + * Note: The display object doesn't stop moving once it reaches the destination coordinates. + * Note: Doesn't take into account acceleration, maxVelocity or drag (if you've set drag or acceleration too high this object may not move at all) + * + * @method Phaser.Physics.Arcade#moveToObject + * @param {any} displayObject - The display object to move. + * @param {any} destination - The display object to move towards. Can be any object but must have visible x/y properties. + * @param {number} [speed=60] - The speed it will move, in pixels per second (default is 60 pixels/sec) + * @param {number} [maxTime=0] - Time given in milliseconds (1000 = 1 sec). If set the speed is adjusted so the object will arrive at destination in the given number of ms. + * @return {number} The angle (in radians) that the object should be visually set to in order to match its new velocity. + */ + moveToObject: function (displayObject, destination, speed, maxTime) { + + if (typeof speed === 'undefined') { speed = 60; } + if (typeof maxTime === 'undefined') { maxTime = 0; } + + this._angle = Math.atan2(destination.y - displayObject.y, destination.x - displayObject.x); + + if (maxTime > 0) + { + // We know how many pixels we need to move, but how fast? + speed = this.distanceBetween(displayObject, destination) / (maxTime / 1000); + } + + displayObject.body.velocity.x = Math.cos(this._angle) * speed; + displayObject.body.velocity.y = Math.sin(this._angle) * speed; + + return this._angle; + + }, + + /** + * Move the given display object towards the pointer at a steady velocity. If no pointer is given it will use Phaser.Input.activePointer. + * If you specify a maxTime then it will adjust the speed (over-writing what you set) so it arrives at the destination in that number of seconds. + * Timings are approximate due to the way browser timers work. Allow for a variance of +- 50ms. + * Note: The display object does not continuously track the target. If the target changes location during transit the display object will not modify its course. + * Note: The display object doesn't stop moving once it reaches the destination coordinates. + * + * @method Phaser.Physics.Arcade#moveToPointer + * @param {any} displayObject - The display object to move. + * @param {number} [speed=60] - The speed it will move, in pixels per second (default is 60 pixels/sec) + * @param {Phaser.Pointer} [pointer] - The pointer to move towards. Defaults to Phaser.Input.activePointer. + * @param {number} [maxTime=0] - Time given in milliseconds (1000 = 1 sec). If set the speed is adjusted so the object will arrive at destination in the given number of ms. + * @return {number} The angle (in radians) that the object should be visually set to in order to match its new velocity. + */ + moveToPointer: function (displayObject, speed, pointer, maxTime) { + + if (typeof speed === 'undefined') { speed = 60; } + pointer = pointer || this.game.input.activePointer; + if (typeof maxTime === 'undefined') { maxTime = 0; } + + this._angle = this.angleToPointer(displayObject, pointer); + + if (maxTime > 0) + { + // We know how many pixels we need to move, but how fast? + speed = this.distanceToPointer(displayObject, pointer) / (maxTime / 1000); + } + + displayObject.body.velocity.x = Math.cos(this._angle) * speed; + displayObject.body.velocity.y = Math.sin(this._angle) * speed; + + return this._angle; + + }, + + /** + * Move the given display object towards the x/y coordinates at a steady velocity. + * If you specify a maxTime then it will adjust the speed (over-writing what you set) so it arrives at the destination in that number of seconds. + * Timings are approximate due to the way browser timers work. Allow for a variance of +- 50ms. + * Note: The display object does not continuously track the target. If the target changes location during transit the display object will not modify its course. + * Note: The display object doesn't stop moving once it reaches the destination coordinates. + * Note: Doesn't take into account acceleration, maxVelocity or drag (if you've set drag or acceleration too high this object may not move at all) + * + * @method Phaser.Physics.Arcade#moveToXY + * @param {any} displayObject - The display object to move. + * @param {number} x - The x coordinate to move towards. + * @param {number} y - The y coordinate to move towards. + * @param {number} [speed=60] - The speed it will move, in pixels per second (default is 60 pixels/sec) + * @param {number} [maxTime=0] - Time given in milliseconds (1000 = 1 sec). If set the speed is adjusted so the object will arrive at destination in the given number of ms. + * @return {number} The angle (in radians) that the object should be visually set to in order to match its new velocity. + */ + moveToXY: function (displayObject, x, y, speed, maxTime) { + + if (typeof speed === 'undefined') { speed = 60; } + if (typeof maxTime === 'undefined') { maxTime = 0; } + + this._angle = Math.atan2(y - displayObject.y, x - displayObject.x); + + if (maxTime > 0) + { + // We know how many pixels we need to move, but how fast? + speed = this.distanceToXY(displayObject, x, y) / (maxTime / 1000); + } + + displayObject.body.velocity.x = Math.cos(this._angle) * speed; + displayObject.body.velocity.y = Math.sin(this._angle) * speed; + + return this._angle; + + }, + + /** + * Given the angle (in degrees) and speed calculate the velocity and return it as a Point object, or set it to the given point object. + * One way to use this is: velocityFromAngle(angle, 200, sprite.velocity) which will set the values directly to the sprites velocity and not create a new Point object. + * + * @method Phaser.Physics.Arcade#velocityFromAngle + * @param {number} angle - The angle in degrees calculated in clockwise positive direction (down = 90 degrees positive, right = 0 degrees positive, up = 90 degrees negative) + * @param {number} [speed=60] - The speed it will move, in pixels per second sq. + * @param {Phaser.Point|object} [point] - The Point object in which the x and y properties will be set to the calculated velocity. + * @return {Phaser.Point} - A Point where point.x contains the velocity x value and point.y contains the velocity y value. + */ + velocityFromAngle: function (angle, speed, point) { + + if (typeof speed === 'undefined') { speed = 60; } + point = point || new Phaser.Point(); + + return point.setTo((Math.cos(this.game.math.degToRad(angle)) * speed), (Math.sin(this.game.math.degToRad(angle)) * speed)); + + }, + + /** + * Given the rotation (in radians) and speed calculate the velocity and return it as a Point object, or set it to the given point object. + * One way to use this is: velocityFromRotation(rotation, 200, sprite.velocity) which will set the values directly to the sprites velocity and not create a new Point object. + * + * @method Phaser.Physics.Arcade#velocityFromRotation + * @param {number} rotation - The angle in radians. + * @param {number} [speed=60] - The speed it will move, in pixels per second sq. + * @param {Phaser.Point|object} [point] - The Point object in which the x and y properties will be set to the calculated velocity. + * @return {Phaser.Point} - A Point where point.x contains the velocity x value and point.y contains the velocity y value. + */ + velocityFromRotation: function (rotation, speed, point) { + + if (typeof speed === 'undefined') { speed = 60; } + point = point || new Phaser.Point(); + + return point.setTo((Math.cos(rotation) * speed), (Math.sin(rotation) * speed)); + + }, + + /** + * Given the rotation (in radians) and speed calculate the acceleration and return it as a Point object, or set it to the given point object. + * One way to use this is: accelerationFromRotation(rotation, 200, sprite.acceleration) which will set the values directly to the sprites acceleration and not create a new Point object. + * + * @method Phaser.Physics.Arcade#accelerationFromRotation + * @param {number} rotation - The angle in radians. + * @param {number} [speed=60] - The speed it will move, in pixels per second sq. + * @param {Phaser.Point|object} [point] - The Point object in which the x and y properties will be set to the calculated acceleration. + * @return {Phaser.Point} - A Point where point.x contains the acceleration x value and point.y contains the acceleration y value. + */ + accelerationFromRotation: function (rotation, speed, point) { + + if (typeof speed === 'undefined') { speed = 60; } + point = point || new Phaser.Point(); + + return point.setTo((Math.cos(rotation) * speed), (Math.sin(rotation) * speed)); + + }, + + /** + * Sets the acceleration.x/y property on the display object so it will move towards the target at the given speed (in pixels per second sq.) + * You must give a maximum speed value, beyond which the display object won't go any faster. + * Note: The display object does not continuously track the target. If the target changes location during transit the display object will not modify its course. + * Note: The display object doesn't stop moving once it reaches the destination coordinates. + * + * @method Phaser.Physics.Arcade#accelerateToObject + * @param {any} displayObject - The display object to move. + * @param {any} destination - The display object to move towards. Can be any object but must have visible x/y properties. + * @param {number} [speed=60] - The speed it will accelerate in pixels per second. + * @param {number} [xSpeedMax=500] - The maximum x velocity the display object can reach. + * @param {number} [ySpeedMax=500] - The maximum y velocity the display object can reach. + * @return {number} The angle (in radians) that the object should be visually set to in order to match its new trajectory. + */ + accelerateToObject: function (displayObject, destination, speed, xSpeedMax, ySpeedMax) { + + if (typeof speed === 'undefined') { speed = 60; } + if (typeof xSpeedMax === 'undefined') { xSpeedMax = 1000; } + if (typeof ySpeedMax === 'undefined') { ySpeedMax = 1000; } + + this._angle = this.angleBetween(displayObject, destination); + + displayObject.body.acceleration.setTo(Math.cos(this._angle) * speed, Math.sin(this._angle) * speed); + displayObject.body.maxVelocity.setTo(xSpeedMax, ySpeedMax); + + return this._angle; + + }, + + /** + * Sets the acceleration.x/y property on the display object so it will move towards the target at the given speed (in pixels per second sq.) + * You must give a maximum speed value, beyond which the display object won't go any faster. + * Note: The display object does not continuously track the target. If the target changes location during transit the display object will not modify its course. + * Note: The display object doesn't stop moving once it reaches the destination coordinates. + * + * @method Phaser.Physics.Arcade#accelerateToPointer + * @param {any} displayObject - The display object to move. + * @param {Phaser.Pointer} [pointer] - The pointer to move towards. Defaults to Phaser.Input.activePointer. + * @param {number} [speed=60] - The speed it will accelerate in pixels per second. + * @param {number} [xSpeedMax=500] - The maximum x velocity the display object can reach. + * @param {number} [ySpeedMax=500] - The maximum y velocity the display object can reach. + * @return {number} The angle (in radians) that the object should be visually set to in order to match its new trajectory. + */ + accelerateToPointer: function (displayObject, pointer, speed, xSpeedMax, ySpeedMax) { + + if (typeof speed === 'undefined') { speed = 60; } + if (typeof pointer === 'undefined') { pointer = this.game.input.activePointer; } + if (typeof xSpeedMax === 'undefined') { xSpeedMax = 1000; } + if (typeof ySpeedMax === 'undefined') { ySpeedMax = 1000; } + + this._angle = this.angleToPointer(displayObject, pointer); + + displayObject.body.acceleration.setTo(Math.cos(this._angle) * speed, Math.sin(this._angle) * speed); + displayObject.body.maxVelocity.setTo(xSpeedMax, ySpeedMax); + + return this._angle; + + }, + + /** + * Sets the acceleration.x/y property on the display object so it will move towards the x/y coordinates at the given speed (in pixels per second sq.) + * You must give a maximum speed value, beyond which the display object won't go any faster. + * Note: The display object does not continuously track the target. If the target changes location during transit the display object will not modify its course. + * Note: The display object doesn't stop moving once it reaches the destination coordinates. + * + * @method Phaser.Physics.Arcade#accelerateToXY + * @param {any} displayObject - The display object to move. + * @param {number} x - The x coordinate to accelerate towards. + * @param {number} y - The y coordinate to accelerate towards. + * @param {number} [speed=60] - The speed it will accelerate in pixels per second. + * @param {number} [xSpeedMax=500] - The maximum x velocity the display object can reach. + * @param {number} [ySpeedMax=500] - The maximum y velocity the display object can reach. + * @return {number} The angle (in radians) that the object should be visually set to in order to match its new trajectory. + */ + accelerateToXY: function (displayObject, x, y, speed, xSpeedMax, ySpeedMax) { + + if (typeof speed === 'undefined') { speed = 60; } + if (typeof xSpeedMax === 'undefined') { xSpeedMax = 1000; } + if (typeof ySpeedMax === 'undefined') { ySpeedMax = 1000; } + + this._angle = this.angleToXY(displayObject, x, y); + + displayObject.body.acceleration.setTo(Math.cos(this._angle) * speed, Math.sin(this._angle) * speed); + displayObject.body.maxVelocity.setTo(xSpeedMax, ySpeedMax); + + return this._angle; + + }, + + /** + * Find the distance between two display objects (like Sprites). + * + * @method Phaser.Physics.Arcade#distanceBetween + * @param {any} source - The Display Object to test from. + * @param {any} target - The Display Object to test to. + * @return {number} The distance between the source and target objects. + */ + distanceBetween: function (source, target) { + + this._dx = source.x - target.x; + this._dy = source.y - target.y; + + return Math.sqrt(this._dx * this._dx + this._dy * this._dy); + + }, + + /** + * Find the distance between a display object (like a Sprite) and the given x/y coordinates. + * The calculation is made from the display objects x/y coordinate. This may be the top-left if its anchor hasn't been changed. + * If you need to calculate from the center of a display object instead use the method distanceBetweenCenters() + * + * @method Phaser.Physics.Arcade#distanceToXY + * @param {any} displayObject - The Display Object to test from. + * @param {number} x - The x coordinate to move towards. + * @param {number} y - The y coordinate to move towards. + * @return {number} The distance between the object and the x/y coordinates. + */ + distanceToXY: function (displayObject, x, y) { + + this._dx = displayObject.x - x; + this._dy = displayObject.y - y; + + return Math.sqrt(this._dx * this._dx + this._dy * this._dy); + + }, + + /** + * Find the distance between a display object (like a Sprite) and a Pointer. If no Pointer is given the Input.activePointer is used. + * The calculation is made from the display objects x/y coordinate. This may be the top-left if its anchor hasn't been changed. + * If you need to calculate from the center of a display object instead use the method distanceBetweenCenters() + * + * @method Phaser.Physics.Arcade#distanceToPointer + * @param {any} displayObject - The Display Object to test from. + * @param {Phaser.Pointer} [pointer] - The Phaser.Pointer to test to. If none is given then Input.activePointer is used. + * @return {number} The distance between the object and the Pointer. + */ + distanceToPointer: function (displayObject, pointer) { + + pointer = pointer || this.game.input.activePointer; + + this._dx = displayObject.x - pointer.x; + this._dy = displayObject.y - pointer.y; + + return Math.sqrt(this._dx * this._dx + this._dy * this._dy); + + }, + + /** + * Find the angle in radians between two display objects (like Sprites). + * + * @method Phaser.Physics.Arcade#angleBetween + * @param {any} source - The Display Object to test from. + * @param {any} target - The Display Object to test to. + * @return {number} The angle in radians between the source and target display objects. + */ + angleBetween: function (source, target) { + + this._dx = target.x - source.x; + this._dy = target.y - source.y; + + return Math.atan2(this._dy, this._dx); + + }, + + /** + * Find the angle in radians between a display object (like a Sprite) and the given x/y coordinate. + * + * @method Phaser.Physics.Arcade#angleToXY + * @param {any} displayObject - The Display Object to test from. + * @param {number} x - The x coordinate to get the angle to. + * @param {number} y - The y coordinate to get the angle to. + * @return {number} The angle in radians between displayObject.x/y to Pointer.x/y + */ + angleToXY: function (displayObject, x, y) { + + this._dx = x - displayObject.x; + this._dy = y - displayObject.y; + + return Math.atan2(this._dy, this._dx); + + }, + + /** + * Find the angle in radians between a display object (like a Sprite) and a Pointer, taking their x/y and center into account. + * + * @method Phaser.Physics.Arcade#angleToPointer + * @param {any} displayObject - The Display Object to test from. + * @param {Phaser.Pointer} [pointer] - The Phaser.Pointer to test to. If none is given then Input.activePointer is used. + * @return {number} The angle in radians between displayObject.x/y to Pointer.x/y + */ + angleToPointer: function (displayObject, pointer) { + + pointer = pointer || this.game.input.activePointer; + + this._dx = pointer.worldX - displayObject.x; + this._dy = pointer.worldY - displayObject.y; + + return Math.atan2(this._dy, this._dx); + + } + +}; diff --git a/src/physics/Body.js b/src/physics/p2/Body.js similarity index 100% rename from src/physics/Body.js rename to src/physics/p2/Body.js diff --git a/src/physics/CollisionGroup.js b/src/physics/p2/CollisionGroup.js similarity index 80% rename from src/physics/CollisionGroup.js rename to src/physics/p2/CollisionGroup.js index 5f27ea57..f4270d3c 100644 --- a/src/physics/CollisionGroup.js +++ b/src/physics/p2/CollisionGroup.js @@ -7,11 +7,11 @@ /** * Collision Group * -* @class Phaser.Physics.CollisionGroup +* @class Phaser.Physics.P2.CollisionGroup * @classdesc Physics Collision Group Constructor * @constructor */ -Phaser.Physics.CollisionGroup = function (bitmask) { +Phaser.Physics.P2.CollisionGroup = function (bitmask) { /** * @property {number} mask - The CollisionGroup bitmask. diff --git a/src/physics/ContactMaterial.js b/src/physics/p2/ContactMaterial.js similarity index 69% rename from src/physics/ContactMaterial.js rename to src/physics/p2/ContactMaterial.js index 486f8558..4f1328e7 100644 --- a/src/physics/ContactMaterial.js +++ b/src/physics/p2/ContactMaterial.js @@ -7,25 +7,25 @@ /** * Defines a physics material * -* @class Phaser.Physics.ContactMaterial +* @class Phaser.Physics.P2.ContactMaterial * @classdesc Physics ContactMaterial Constructor * @constructor -* @param {Phaser.Physics.Material} materialA -* @param {Phaser.Physics.Material} materialB +* @param {Phaser.Physics.P2.Material} materialA +* @param {Phaser.Physics.P2.Material} materialB * @param {object} [options] */ -Phaser.Physics.ContactMaterial = function (materialA, materialB, options) { +Phaser.Physics.P2.ContactMaterial = function (materialA, materialB, options) { /** * @property {number} id - The contact material identifier. */ /** - * @property {Phaser.Physics.Material} materialA - First material participating in the contact material. + * @property {Phaser.Physics.P2.Material} materialA - First material participating in the contact material. */ /** - * @property {Phaser.Physics.Material} materialB - First second participating in the contact material. + * @property {Phaser.Physics.P2.Material} materialB - First second participating in the contact material. */ /** @@ -60,5 +60,5 @@ Phaser.Physics.ContactMaterial = function (materialA, materialB, options) { } -Phaser.Physics.ContactMaterial.prototype = Object.create(p2.ContactMaterial.prototype); -Phaser.Physics.ContactMaterial.prototype.constructor = Phaser.Physics.ContactMaterial; +Phaser.Physics.P2.ContactMaterial.prototype = Object.create(p2.ContactMaterial.prototype); +Phaser.Physics.P2.ContactMaterial.prototype.constructor = Phaser.Physics.P2.ContactMaterial; diff --git a/src/physics/InversePointProxy.js b/src/physics/p2/InversePointProxy.js similarity index 70% rename from src/physics/InversePointProxy.js rename to src/physics/p2/InversePointProxy.js index c00d9af7..b2ccee2c 100644 --- a/src/physics/InversePointProxy.js +++ b/src/physics/p2/InversePointProxy.js @@ -7,26 +7,26 @@ /** * A InversePointProxy is an internal class that allows for direct getter/setter style property access to Arrays and TypedArrays but inverses the values on set. * -* @class Phaser.Physics.InversePointProxy +* @class Phaser.Physics.P2.InversePointProxy * @classdesc InversePointProxy * @constructor * @param {Phaser.Game} game - A reference to the Phaser.Game instance. * @param {any} destination - The object to bind to. */ -Phaser.Physics.InversePointProxy = function (game, destination) { +Phaser.Physics.P2.InversePointProxy = function (game, destination) { this.game = game; this.destination = destination; }; -Phaser.Physics.InversePointProxy.prototype.constructor = Phaser.Physics.InversePointProxy; +Phaser.Physics.P2.InversePointProxy.prototype.constructor = Phaser.Physics.P2.InversePointProxy; /** -* @name Phaser.Physics.InversePointProxy#x +* @name Phaser.Physics.P2.InversePointProxy#x * @property {number} x - The x property of this InversePointProxy. */ -Object.defineProperty(Phaser.Physics.InversePointProxy.prototype, "x", { +Object.defineProperty(Phaser.Physics.P2.InversePointProxy.prototype, "x", { get: function () { @@ -43,10 +43,10 @@ Object.defineProperty(Phaser.Physics.InversePointProxy.prototype, "x", { }); /** -* @name Phaser.Physics.InversePointProxy#y +* @name Phaser.Physics.P2.InversePointProxy#y * @property {number} y - The y property of this InversePointProxy. */ -Object.defineProperty(Phaser.Physics.InversePointProxy.prototype, "y", { +Object.defineProperty(Phaser.Physics.P2.InversePointProxy.prototype, "y", { get: function () { diff --git a/src/physics/Material.js b/src/physics/p2/Material.js similarity index 66% rename from src/physics/Material.js rename to src/physics/p2/Material.js index 884ac525..08209361 100644 --- a/src/physics/Material.js +++ b/src/physics/p2/Material.js @@ -7,11 +7,11 @@ /** * \o/ ~ "Because I'm a Material girl" * -* @class Phaser.Physics.Material +* @class Phaser.Physics.P2.Material * @classdesc Physics Material Constructor * @constructor */ -Phaser.Physics.Material = function (name) { +Phaser.Physics.P2.Material = function (name) { /** * @property {string} name - The user defined name given to this Material. @@ -23,5 +23,5 @@ Phaser.Physics.Material = function (name) { } -Phaser.Physics.Material.prototype = Object.create(p2.Material.prototype); -Phaser.Physics.Material.prototype.constructor = Phaser.Physics.Material; +Phaser.Physics.P2.Material.prototype = Object.create(p2.Material.prototype); +Phaser.Physics.P2.Material.prototype.constructor = Phaser.Physics.P2.Material; diff --git a/src/physics/PointProxy.js b/src/physics/p2/PointProxy.js similarity index 72% rename from src/physics/PointProxy.js rename to src/physics/p2/PointProxy.js index 409ef782..1f2004a2 100644 --- a/src/physics/PointProxy.js +++ b/src/physics/p2/PointProxy.js @@ -7,26 +7,26 @@ /** * A PointProxy is an internal class that allows for direct getter/setter style property access to Arrays and TypedArrays. * -* @class Phaser.Physics.PointProxy +* @class Phaser.Physics.P2.PointProxy * @classdesc PointProxy * @constructor * @param {Phaser.Game} game - A reference to the Phaser.Game instance. * @param {any} destination - The object to bind to. */ -Phaser.Physics.PointProxy = function (game, destination) { +Phaser.Physics.P2.PointProxy = function (game, destination) { this.game = game; this.destination = destination; }; -Phaser.Physics.PointProxy.prototype.constructor = Phaser.Physics.PointProxy; +Phaser.Physics.P2.PointProxy.prototype.constructor = Phaser.Physics.P2.PointProxy; /** -* @name Phaser.Physics.PointProxy#x +* @name Phaser.Physics.P2.PointProxy#x * @property {number} x - The x property of this PointProxy. */ -Object.defineProperty(Phaser.Physics.PointProxy.prototype, "x", { +Object.defineProperty(Phaser.Physics.P2.PointProxy.prototype, "x", { get: function () { @@ -43,10 +43,10 @@ Object.defineProperty(Phaser.Physics.PointProxy.prototype, "x", { }); /** -* @name Phaser.Physics.PointProxy#y +* @name Phaser.Physics.P2.PointProxy#y * @property {number} y - The y property of this PointProxy. */ -Object.defineProperty(Phaser.Physics.PointProxy.prototype, "y", { +Object.defineProperty(Phaser.Physics.P2.PointProxy.prototype, "y", { get: function () { diff --git a/src/physics/Spring.js b/src/physics/p2/Spring.js similarity index 87% rename from src/physics/Spring.js rename to src/physics/p2/Spring.js index 417f6923..58a6bb3a 100644 --- a/src/physics/Spring.js +++ b/src/physics/p2/Spring.js @@ -7,7 +7,7 @@ /** * Creates a spring, connecting two bodies. * -* @class Phaser.Physics.Spring +* @class Phaser.Physics.P2.Spring * @classdesc Physics Spring Constructor * @constructor * @param {Phaser.Game} game - A reference to the current game. @@ -21,7 +21,7 @@ * @param {Array} [localA] - Where to hook the spring to body A, in local body coordinates. * @param {Array} [localB] - Where to hook the spring to body B, in local body coordinates. */ -Phaser.Physics.Spring = function (game, bodyA, bodyB, restLength, stiffness, damping, worldA, worldB, localA, localB) { +Phaser.Physics.P2.Spring = function (game, bodyA, bodyB, restLength, stiffness, damping, worldA, worldB, localA, localB) { /** * @property {Phaser.Game} game - Local reference to game. @@ -62,5 +62,5 @@ Phaser.Physics.Spring = function (game, bodyA, bodyB, restLength, stiffness, dam } -Phaser.Physics.Spring.prototype = Object.create(p2.Spring.prototype); -Phaser.Physics.Spring.prototype.constructor = Phaser.Physics.Spring; +Phaser.Physics.P2.Spring.prototype = Object.create(p2.Spring.prototype); +Phaser.Physics.P2.Spring.prototype.constructor = Phaser.Physics.P2.Spring; diff --git a/src/physics/World.js b/src/physics/p2/World.js similarity index 81% rename from src/physics/World.js rename to src/physics/p2/World.js index 4f8143dc..21e8ef87 100644 --- a/src/physics/World.js +++ b/src/physics/p2/World.js @@ -4,29 +4,24 @@ * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ -/** -* @class Phaser.Physics -*/ -Phaser.Physics = {}; - /** * @const * @type {number} */ -Phaser.Physics.LIME_CORONA_JSON = 0; +Phaser.Physics.P2.LIME_CORONA_JSON = 0; // Add an extra properties to p2 that we need p2.Body.prototype.parent = null; p2.Spring.prototype.parent = null; /** -* @class Phaser.Physics.World +* @class Phaser.Physics.P2 * @classdesc Physics World Constructor * @constructor * @param {Phaser.Game} game - Reference to the current game instance. * @param {object} [config] - Physics configuration object passed in from the game constructor. */ -Phaser.Physics.World = function (game, config) { +Phaser.Physics.P2 = function (game, config) { /** * @property {Phaser.Game} game - Local reference to game. @@ -45,7 +40,7 @@ Phaser.Physics.World = function (game, config) { this.world = new p2.World(config); /** - * @property {array} materials - A local array of all created Materials. + * @property {array} materials - A local array of all created Materials. * @protected */ this.materials = []; @@ -53,7 +48,7 @@ Phaser.Physics.World = function (game, config) { /** * @property {Phaser.InversePointProxy} gravity - The gravity applied to all bodies each step. */ - this.gravity = new Phaser.Physics.InversePointProxy(game, this.world.gravity); + this.gravity = new Phaser.Physics.P2.InversePointProxy(game, this.world.gravity); /** * @property {p2.Body} bounds - The bounds body contains the 4 walls that border the World. Define or disable with setBounds. @@ -149,9 +144,9 @@ Phaser.Physics.World = function (game, config) { */ this._collisionGroupID = 2; - this.nothingCollisionGroup = new Phaser.Physics.CollisionGroup(1); - this.boundsCollisionGroup = new Phaser.Physics.CollisionGroup(2); - this.everythingCollisionGroup = new Phaser.Physics.CollisionGroup(2147483648); + this.nothingCollisionGroup = new Phaser.Physics.P2.CollisionGroup(1); + this.boundsCollisionGroup = new Phaser.Physics.P2.CollisionGroup(2); + this.everythingCollisionGroup = new Phaser.Physics.P2.CollisionGroup(2147483648); this.boundsCollidesWith = []; @@ -162,12 +157,12 @@ Phaser.Physics.World = function (game, config) { }; -Phaser.Physics.World.prototype = { +Phaser.Physics.P2.prototype = { /** * Handles a p2 postStep event. * - * @method Phaser.Physics.World#postStepHandler + * @method Phaser.Physics.P2#postStepHandler * @private * @param {object} event - The event data. */ @@ -179,7 +174,7 @@ Phaser.Physics.World.prototype = { * Fired after the Broadphase has collected collision pairs in the world. * Inside the event handler, you can modify the pairs array as you like, to prevent collisions between objects that you don't want. * - * @method Phaser.Physics.World#postBroadphaseHandler + * @method Phaser.Physics.P2#postBroadphaseHandler * @private * @param {object} event - The event data. */ @@ -203,7 +198,7 @@ Phaser.Physics.World.prototype = { /** * Handles a p2 impact event. * - * @method Phaser.Physics.World#impactHandler + * @method Phaser.Physics.P2#impactHandler * @private * @param {object} event - The event data. */ @@ -242,7 +237,7 @@ Phaser.Physics.World.prototype = { /** * Handles a p2 begin contact event. * - * @method Phaser.Physics.World#beginContactHandler + * @method Phaser.Physics.P2#beginContactHandler * @private * @param {object} event - The event data. */ @@ -263,7 +258,7 @@ Phaser.Physics.World.prototype = { /** * Handles a p2 end contact event. * - * @method Phaser.Physics.World#endContactHandler + * @method Phaser.Physics.P2#endContactHandler * @private * @param {object} event - The event data. */ @@ -302,7 +297,7 @@ Phaser.Physics.World.prototype = { * Sets the given material against the 4 bounds of this World. * * @method Phaser.Physics#setWorldMaterial - * @param {Phaser.Physics.Material} material - The material to set. + * @param {Phaser.Physics.P2.Material} material - The material to set. * @param {boolean} [left=true] - If true will set the material on the left bounds wall. * @param {boolean} [right=true] - If true will set the material on the right bounds wall. * @param {boolean} [top=true] - If true will set the material on the top bounds wall. @@ -341,7 +336,7 @@ Phaser.Physics.World.prototype = { * Sets the bounds of the Physics world to match the given world pixel dimensions. * You can optionally set which 'walls' to create: left, right, top or bottom. * - * @method Phaser.Physics.World#setBounds + * @method Phaser.Physics.P2#setBounds * @param {number} x - The x coordinate of the top-left corner of the bounds. * @param {number} y - The y coordinate of the top-left corner of the bounds. * @param {number} width - The width of the bounds. @@ -449,7 +444,7 @@ Phaser.Physics.World.prototype = { }, /** - * @method Phaser.Physics.World#update + * @method Phaser.Physics.P2#update */ update: function () { @@ -460,7 +455,7 @@ Phaser.Physics.World.prototype = { /** * Clears all bodies from the simulation. * - * @method Phaser.Physics.World#clear + * @method Phaser.Physics.P2#clear */ clear: function () { @@ -471,7 +466,7 @@ Phaser.Physics.World.prototype = { /** * Clears all bodies from the simulation and unlinks World from Game. Should only be called on game shutdown. Call `clear` on a State change. * - * @method Phaser.Physics.World#destroy + * @method Phaser.Physics.P2#destroy */ destroy: function () { @@ -484,8 +479,8 @@ Phaser.Physics.World.prototype = { /** * Add a body to the world. * - * @method Phaser.Physics.World#addBody - * @param {Phaser.Physics.Body} body - The Body to add to the World. + * @method Phaser.Physics.P2#addBody + * @param {Phaser.Physics.P2.Body} body - The Body to add to the World. * @return {boolean} True if the Body was added successfully, otherwise false. */ addBody: function (body) { @@ -508,9 +503,9 @@ Phaser.Physics.World.prototype = { /** * Removes a body from the world. * - * @method Phaser.Physics.World#removeBody - * @param {Phaser.Physics.Body} body - The Body to remove from the World. - * @return {Phaser.Physics.Body} The Body that was removed. + * @method Phaser.Physics.P2#removeBody + * @param {Phaser.Physics.P2.Body} body - The Body to remove from the World. + * @return {Phaser.Physics.P2.Body} The Body that was removed. */ removeBody: function (body) { @@ -525,9 +520,9 @@ Phaser.Physics.World.prototype = { /** * Adds a Spring to the world. * - * @method Phaser.Physics.World#addSpring - * @param {Phaser.Physics.Spring} spring - The Spring to add to the World. - * @return {Phaser.Physics.Spring} The Spring that was added. + * @method Phaser.Physics.P2#addSpring + * @param {Phaser.Physics.P2.Spring} spring - The Spring to add to the World. + * @return {Phaser.Physics.P2.Spring} The Spring that was added. */ addSpring: function (spring) { @@ -542,9 +537,9 @@ Phaser.Physics.World.prototype = { /** * Removes a Spring from the world. * - * @method Phaser.Physics.World#removeSpring - * @param {Phaser.Physics.Spring} spring - The Spring to remove from the World. - * @return {Phaser.Physics.Spring} The Spring that was removed. + * @method Phaser.Physics.P2#removeSpring + * @param {Phaser.Physics.P2.Spring} spring - The Spring to remove from the World. + * @return {Phaser.Physics.P2.Spring} The Spring that was removed. */ removeSpring: function (spring) { @@ -559,9 +554,9 @@ Phaser.Physics.World.prototype = { /** * Adds a Constraint to the world. * - * @method Phaser.Physics.World#addConstraint - * @param {Phaser.Physics.Constraint} constraint - The Constraint to add to the World. - * @return {Phaser.Physics.Constraint} The Constraint that was added. + * @method Phaser.Physics.P2#addConstraint + * @param {Phaser.Physics.P2.Constraint} constraint - The Constraint to add to the World. + * @return {Phaser.Physics.P2.Constraint} The Constraint that was added. */ addConstraint: function (constraint) { @@ -576,9 +571,9 @@ Phaser.Physics.World.prototype = { /** * Removes a Constraint from the world. * - * @method Phaser.Physics.World#removeConstraint - * @param {Phaser.Physics.Constraint} constraint - The Constraint to be removed from the World. - * @return {Phaser.Physics.Constraint} The Constraint that was removed. + * @method Phaser.Physics.P2#removeConstraint + * @param {Phaser.Physics.P2.Constraint} constraint - The Constraint to be removed from the World. + * @return {Phaser.Physics.P2.Constraint} The Constraint that was removed. */ removeConstraint: function (constraint) { @@ -593,9 +588,9 @@ Phaser.Physics.World.prototype = { /** * Adds a Contact Material to the world. * - * @method Phaser.Physics.World#addContactMaterial - * @param {Phaser.Physics.ContactMaterial} material - The Contact Material to be added to the World. - * @return {Phaser.Physics.ContactMaterial} The Contact Material that was added. + * @method Phaser.Physics.P2#addContactMaterial + * @param {Phaser.Physics.P2.ContactMaterial} material - The Contact Material to be added to the World. + * @return {Phaser.Physics.P2.ContactMaterial} The Contact Material that was added. */ addContactMaterial: function (material) { @@ -610,9 +605,9 @@ Phaser.Physics.World.prototype = { /** * Removes a Contact Material from the world. * - * @method Phaser.Physics.World#removeContactMaterial - * @param {Phaser.Physics.ContactMaterial} material - The Contact Material to be removed from the World. - * @return {Phaser.Physics.ContactMaterial} The Contact Material that was removed. + * @method Phaser.Physics.P2#removeContactMaterial + * @param {Phaser.Physics.P2.ContactMaterial} material - The Contact Material to be removed from the World. + * @return {Phaser.Physics.P2.ContactMaterial} The Contact Material that was removed. */ removeContactMaterial: function (material) { @@ -627,10 +622,10 @@ Phaser.Physics.World.prototype = { /** * Gets a Contact Material based on the two given Materials. * - * @method Phaser.Physics.World#getContactMaterial - * @param {Phaser.Physics.Material} materialA - The first Material to search for. - * @param {Phaser.Physics.Material} materialB - The second Material to search for. - * @return {Phaser.Physics.ContactMaterial|boolean} The Contact Material or false if none was found matching the Materials given. + * @method Phaser.Physics.P2#getContactMaterial + * @param {Phaser.Physics.P2.Material} materialA - The first Material to search for. + * @param {Phaser.Physics.P2.Material} materialB - The second Material to search for. + * @return {Phaser.Physics.P2.ContactMaterial|boolean} The Contact Material or false if none was found matching the Materials given. */ getContactMaterial: function (materialA, materialB) { @@ -641,9 +636,9 @@ Phaser.Physics.World.prototype = { /** * Sets the given Material against all Shapes owned by all the Bodies in the given array. * - * @method Phaser.Physics.World#setMaterial - * @param {Phaser.Physics.Material} material - The Material to be applied to the given Bodies. - * @param {array} bodies - An Array of Body objects that the given Material will be set on. + * @method Phaser.Physics.P2#setMaterial + * @param {Phaser.Physics.P2.Material} material - The Material to be applied to the given Bodies. + * @param {array} bodies - An Array of Body objects that the given Material will be set on. */ setMaterial: function (material, bodies) { @@ -661,16 +656,16 @@ Phaser.Physics.World.prototype = { * Materials are a way to control what happens when Shapes collide. Combine unique Materials together to create Contact Materials. * Contact Materials have properties such as friction and restitution that allow for fine-grained collision control between different Materials. * - * @method Phaser.Physics.World#createMaterial + * @method Phaser.Physics.P2#createMaterial * @param {string} [name] - Optional name of the Material. Each Material has a unique ID but string names are handy for debugging. - * @param {Phaser.Physics.Body} [body] - Optional Body. If given it will assign the newly created Material to the Body shapes. - * @return {Phaser.Physics.Material} The Material that was created. This is also stored in Phaser.Physics.World.materials. + * @param {Phaser.Physics.P2.Body} [body] - Optional Body. If given it will assign the newly created Material to the Body shapes. + * @return {Phaser.Physics.P2.Material} The Material that was created. This is also stored in Phaser.Physics.P2.materials. */ createMaterial: function (name, body) { name = name || ''; - var material = new Phaser.Physics.Material(name); + var material = new Phaser.Physics.P2.Material(name); this.materials.push(material); @@ -686,18 +681,18 @@ Phaser.Physics.World.prototype = { /** * Creates a Contact Material from the two given Materials. You can then edit the properties of the Contact Material directly. * - * @method Phaser.Physics.World#createContactMaterial - * @param {Phaser.Physics.Material} [materialA] - The first Material to create the ContactMaterial from. If undefined it will create a new Material object first. - * @param {Phaser.Physics.Material} [materialB] - The second Material to create the ContactMaterial from. If undefined it will create a new Material object first. + * @method Phaser.Physics.P2#createContactMaterial + * @param {Phaser.Physics.P2.Material} [materialA] - The first Material to create the ContactMaterial from. If undefined it will create a new Material object first. + * @param {Phaser.Physics.P2.Material} [materialB] - The second Material to create the ContactMaterial from. If undefined it will create a new Material object first. * @param {object} [options] - Material options object. - * @return {Phaser.Physics.ContactMaterial} The Contact Material that was created. + * @return {Phaser.Physics.P2.ContactMaterial} The Contact Material that was created. */ createContactMaterial: function (materialA, materialB, options) { if (typeof materialA === 'undefined') { materialA = this.createMaterial(); } if (typeof materialB === 'undefined') { materialB = this.createMaterial(); } - var contact = new Phaser.Physics.ContactMaterial(materialA, materialB, options); + var contact = new Phaser.Physics.P2.ContactMaterial(materialA, materialB, options); return this.addContactMaterial(contact); @@ -706,8 +701,8 @@ Phaser.Physics.World.prototype = { /** * Populates and returns an array of all current Bodies in the world. * - * @method Phaser.Physics.World#getBodies - * @return {array} An array containing all current Bodies in the world. + * @method Phaser.Physics.P2#getBodies + * @return {array} An array containing all current Bodies in the world. */ getBodies: function () { @@ -726,8 +721,8 @@ Phaser.Physics.World.prototype = { /** * Populates and returns an array of all current Springs in the world. * - * @method Phaser.Physics.World#getSprings - * @return {array} An array containing all current Springs in the world. + * @method Phaser.Physics.P2#getSprings + * @return {array} An array containing all current Springs in the world. */ getSprings: function () { @@ -746,8 +741,8 @@ Phaser.Physics.World.prototype = { /** * Populates and returns an array of all current Constraints in the world. * - * @method Phaser.Physics.World#getConstraints - * @return {array} An array containing all current Constraints in the world. + * @method Phaser.Physics.P2#getConstraints + * @return {array} An array containing all current Constraints in the world. */ getConstraints: function () { @@ -766,7 +761,7 @@ Phaser.Physics.World.prototype = { /** * Test if a world point overlaps bodies. * - * @method Phaser.Physics.World#hitTest + * @method Phaser.Physics.P2#hitTest * @param {Phaser.Point} worldPoint - Point to use for intersection tests. * @param {Array} bodies - A list of objects to check for intersection. * @param {number} precision - Used for matching against particles and lines. Adds some margin to these infinitesimal objects. @@ -779,7 +774,7 @@ Phaser.Physics.World.prototype = { /** * Converts the current world into a JSON object. * - * @method Phaser.Physics.World#toJSON + * @method Phaser.Physics.P2#toJSON * @return {object} A JSON representation of the world. */ toJSON: function () { @@ -814,7 +809,7 @@ Phaser.Physics.World.prototype = { this._collisionGroupID++; - var group = new Phaser.Physics.CollisionGroup(bitmask); + var group = new Phaser.Physics.P2.CollisionGroup(bitmask); this.collisionGroups.push(group); @@ -823,7 +818,7 @@ Phaser.Physics.World.prototype = { }, /** - * @method Phaser.Physics.World.prototype.createBody + * @method Phaser.Physics.P2.prototype.createBody * @param {number} x - The x coordinate of Body. * @param {number} y - The y coordinate of Body. * @param {number} mass - The mass of the Body. A mass of 0 means a 'static' Body is created. @@ -840,7 +835,7 @@ Phaser.Physics.World.prototype = { if (typeof addToWorld === 'undefined') { addToWorld = false; } - var body = new Phaser.Physics.Body(this.game, null, x, y, mass); + var body = new Phaser.Physics.P2.Body(this.game, null, x, y, mass); if (data) { @@ -862,7 +857,7 @@ Phaser.Physics.World.prototype = { }, /** - * @method Phaser.Physics.World.prototype.createBody + * @method Phaser.Physics.P2.prototype.createBody * @param {number} x - The x coordinate of Body. * @param {number} y - The y coordinate of Body. * @param {number} mass - The mass of the Body. A mass of 0 means a 'static' Body is created. @@ -879,7 +874,7 @@ Phaser.Physics.World.prototype = { if (typeof addToWorld === 'undefined') { addToWorld = false; } - var body = new Phaser.Physics.Body(this.game, null, x, y, mass); + var body = new Phaser.Physics.P2.Body(this.game, null, x, y, mass); if (data) { @@ -905,10 +900,10 @@ Phaser.Physics.World.prototype = { }; /** -* @name Phaser.Physics.World#friction +* @name Phaser.Physics.P2#friction * @property {number} friction - Friction between colliding bodies. This value is used if no matching ContactMaterial is found for a Material pair. */ -Object.defineProperty(Phaser.Physics.World.prototype, "friction", { +Object.defineProperty(Phaser.Physics.P2.prototype, "friction", { get: function () { @@ -925,10 +920,10 @@ Object.defineProperty(Phaser.Physics.World.prototype, "friction", { }); /** -* @name Phaser.Physics.World#restituion +* @name Phaser.Physics.P2#restituion * @property {number} restitution - Default coefficient of restitution between colliding bodies. This value is used if no matching ContactMaterial is found for a Material pair. */ -Object.defineProperty(Phaser.Physics.World.prototype, "restituion", { +Object.defineProperty(Phaser.Physics.P2.prototype, "restituion", { get: function () { @@ -945,10 +940,10 @@ Object.defineProperty(Phaser.Physics.World.prototype, "restituion", { }); /** -* @name Phaser.Physics.World#applySpringForces +* @name Phaser.Physics.P2#applySpringForces * @property {boolean} applySpringForces - Enable to automatically apply spring forces each step. */ -Object.defineProperty(Phaser.Physics.World.prototype, "applySpringForces", { +Object.defineProperty(Phaser.Physics.P2.prototype, "applySpringForces", { get: function () { @@ -965,10 +960,10 @@ Object.defineProperty(Phaser.Physics.World.prototype, "applySpringForces", { }); /** -* @name Phaser.Physics.World#applyDamping +* @name Phaser.Physics.P2#applyDamping * @property {boolean} applyDamping - Enable to automatically apply body damping each step. */ -Object.defineProperty(Phaser.Physics.World.prototype, "applyDamping", { +Object.defineProperty(Phaser.Physics.P2.prototype, "applyDamping", { get: function () { @@ -985,10 +980,10 @@ Object.defineProperty(Phaser.Physics.World.prototype, "applyDamping", { }); /** -* @name Phaser.Physics.World#applyGravity +* @name Phaser.Physics.P2#applyGravity * @property {boolean} applyGravity - Enable to automatically apply gravity each step. */ -Object.defineProperty(Phaser.Physics.World.prototype, "applyGravity", { +Object.defineProperty(Phaser.Physics.P2.prototype, "applyGravity", { get: function () { @@ -1005,10 +1000,10 @@ Object.defineProperty(Phaser.Physics.World.prototype, "applyGravity", { }); /** -* @name Phaser.Physics.World#solveConstraints +* @name Phaser.Physics.P2#solveConstraints * @property {boolean} solveConstraints - Enable/disable constraint solving in each step. */ -Object.defineProperty(Phaser.Physics.World.prototype, "solveConstraints", { +Object.defineProperty(Phaser.Physics.P2.prototype, "solveConstraints", { get: function () { @@ -1025,11 +1020,11 @@ Object.defineProperty(Phaser.Physics.World.prototype, "solveConstraints", { }); /** -* @name Phaser.Physics.World#time +* @name Phaser.Physics.P2#time * @property {boolean} time - The World time. * @readonly */ -Object.defineProperty(Phaser.Physics.World.prototype, "time", { +Object.defineProperty(Phaser.Physics.P2.prototype, "time", { get: function () { @@ -1040,10 +1035,10 @@ Object.defineProperty(Phaser.Physics.World.prototype, "time", { }); /** -* @name Phaser.Physics.World#emitImpactEvent +* @name Phaser.Physics.P2#emitImpactEvent * @property {boolean} emitImpactEvent - Set to true if you want to the world to emit the "impact" event. Turning this off could improve performance. */ -Object.defineProperty(Phaser.Physics.World.prototype, "emitImpactEvent", { +Object.defineProperty(Phaser.Physics.P2.prototype, "emitImpactEvent", { get: function () { @@ -1060,10 +1055,10 @@ Object.defineProperty(Phaser.Physics.World.prototype, "emitImpactEvent", { }); /** -* @name Phaser.Physics.World#enableBodySleeping +* @name Phaser.Physics.P2#enableBodySleeping * @property {boolean} enableBodySleeping - Enable / disable automatic body sleeping. */ -Object.defineProperty(Phaser.Physics.World.prototype, "enableBodySleeping", { +Object.defineProperty(Phaser.Physics.P2.prototype, "enableBodySleeping", { get: function () { diff --git a/src/utils/Debug.js b/src/utils/Debug.js index 949d2381..d1971365 100644 --- a/src/utils/Debug.js +++ b/src/utils/Debug.js @@ -117,7 +117,7 @@ Phaser.Utils.Debug.prototype = { this.context = this.canvas.getContext('2d'); this.baseTexture = new PIXI.BaseTexture(this.canvas); this.texture = new PIXI.Texture(this.baseTexture); - this.textureFrame = new Phaser.Frame(0, 0, 0, this.game.width, this.game.height, 'debug', game.rnd.uuid()); + this.textureFrame = new Phaser.Frame(0, 0, 0, this.game.width, this.game.height, 'debug', this.game.rnd.uuid()); this.sprite = this.game.make.image(0, 0, this.texture, this.textureFrame); this.game.stage.addChild(this.sprite); }