diff --git a/examples/wip/p28.js b/examples/wip/p28.js new file mode 100644 index 00000000..12860ab2 --- /dev/null +++ b/examples/wip/p28.js @@ -0,0 +1,137 @@ + +var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.image('backdrop', 'assets/pics/remember-me.jpg'); + game.load.image('box', 'assets/sprites/block.png'); + +} + +var box; +var box2; +var cursors; + +function p2px(v) { + return v *= -20; +} + +function px2p(v) { + return v * -0.05; +} + +function create() { + + // game.world.setBounds(0, 0, 1920, 1200); + game.add.sprite(0, 0, 'backdrop'); + + game.physics.onBodyAdded.add(addedToWorld, this); + + box = game.add.sprite(200, 200, 'box'); + box.name = 'bob'; + box.anchor.set(0.5); + box.physicsEnabled = true; + + box2 = game.add.sprite(400, 200, 'box'); + box2.name = 'ben'; + box2.anchor.set(0.5); // if using physics you nearly always need to anchor from the center like this unless you don't need rotation + // box2.scale.set(2); // if you need to scale, do it BEFORE enabling physics. You can't do it at run-time. + box2.physicsEnabled = true; + + box2.body.setZeroDamping(); + box2.body.fixedRotation = true; + + game.camera.follow(box2); + + cursors = game.input.keyboard.createCursorKeys(); + + game.physics.defaultRestitution = 0.8; + +} + +function addedToWorld(body, world) { + + console.log('Body added for', body); + +} + +function update() { + + box2.body.setZeroVelocity(); + + if (cursors.left.isDown) + { + box2.body.moveLeft(400); + } + else if (cursors.right.isDown) + { + box2.body.moveRight(400); + } + + if (cursors.up.isDown) + { + box2.body.moveUp(400); + } + else if (cursors.down.isDown) + { + box2.body.moveDown(400); + } + +} + +function render() { + + game.debug.renderText('x: ' + box2.body.velocity.x, 32, 32); + game.debug.renderText('y: ' + box2.body.velocity.y, 32, 64); + + // game.debug.renderText('x: ' + p2px(boxBody.position[0]), 32, 32); + // game.debug.renderText('y: ' + p2px(boxBody.position[1]), 32, 64); + // game.debug.renderText('r: ' + boxBody.angle, 32, 96); + + // drawbox(); + +} + +function drawbox() { + + // var ctx = game.context; + +/* + ctx.save(); + ctx.translate(game.width/2, game.height/2); // Translate to the center + ctx.scale(50, -50); // Zoom in and flip y axis + + ctx.lineWidth = 0.05; + ctx.strokeStyle = 'rgb(255,255,255)'; + + + ctx.beginPath(); + var x = boxBody.position[0], + y = boxBody.position[1]; + ctx.save(); + ctx.translate(x, y); // Translate to the center of the box + ctx.rotate(boxBody.angle); // Rotate to the box body frame + ctx.rect(-boxShape.width/2, -boxShape.height/2, boxShape.width, boxShape.height); + ctx.stroke(); + ctx.closePath(); + // ctx.restore(); +*/ + + // ctx.save(); + // ctx.translate(game.width/2, game.height/2); // Translate to the center + // ctx.scale(20, -20); // Zoom in and flip y axis + + // ctx.lineWidth = 0.05; + // ctx.strokeStyle = 'rgb(255,255,255)'; + // ctx.beginPath(); + + // var y = planeBody.position[1]; + // ctx.rotate(0); // Rotate to the box body frame + // ctx.moveTo(-game.width, y); + // ctx.lineTo( game.width, y); + // ctx.stroke(); + + // ctx.closePath(); + // ctx.restore(); +} + diff --git a/src/core/Game.js b/src/core/Game.js index 69d17eec..a23c6c20 100644 --- a/src/core/Game.js +++ b/src/core/Game.js @@ -595,7 +595,7 @@ Phaser.Game.prototype = { if (this._paused) { - this.renderer.render(this.stage._stage); + this.renderer.render(this.stage); this.plugins.render(); this.state.render(); } @@ -627,7 +627,7 @@ Phaser.Game.prototype = { if (this.renderType !== Phaser.HEADLESS) { - this.renderer.render(this.stage._stage); + this.renderer.render(this.stage); this.plugins.render(); this.state.render(); diff --git a/src/core/Group.js b/src/core/Group.js index d135488c..ae8d7fd6 100644 --- a/src/core/Group.js +++ b/src/core/Group.js @@ -12,9 +12,9 @@ * @param {Phaser.Game} game - A reference to the currently running game. * @param {*} parent - The parent Group, DisplayObject or DisplayObjectContainer that this Group will be added to. If undefined or null it will use game.world. * @param {string} [name=group] - A name for this Group. Not used internally but useful for debugging. -* @param {boolean} [useStage=false] - Should this Group be added to the World (default, false) or direct to the Stage (true). +* @param {boolean} [addToStage=false] - If set to true this Group will be added directly to the Game.Stage instead of Game.World. */ -Phaser.Group = function (game, parent, name, useStage) { +Phaser.Group = function (game, parent, name, addToStage) { /** * @property {Phaser.Game} game - A reference to the currently running Game. @@ -33,7 +33,7 @@ Phaser.Group = function (game, parent, name, useStage) { PIXI.DisplayObjectContainer.call(this); - if (typeof useStage === 'undefined') + if (typeof addToStage === 'undefined') { if (parent) { @@ -41,12 +41,12 @@ Phaser.Group = function (game, parent, name, useStage) { } else { - this.game.stage._stage.addChild(this); + this.game.stage.addChild(this); } } else { - this.game.stage._stage.addChild(this); + this.game.stage.addChild(this); } /** diff --git a/src/core/Stage.js b/src/core/Stage.js index 3312f78b..2868575c 100644 --- a/src/core/Stage.js +++ b/src/core/Stage.js @@ -9,6 +9,7 @@ * focus handling, game resizing, scaling and the pause, boot and orientation screens. * * @class Phaser.Stage +* @extends PIXI.Stage * @constructor * @param {Phaser.Game} game - Game reference to the currently running game. * @param {number} width - Width of the canvas element. @@ -36,19 +37,25 @@ Phaser.Stage = function (game, width, height) { * @property {HTMLCanvasElement} canvas - Reference to the newly created `canvas` element. */ this.canvas = null; - + /** * @property {PIXI.Stage} _stage - The Pixi Stage which is hooked to the renderer. * @private */ - this._stage = new PIXI.Stage(0x000000, false); - this._stage.name = '_stage_root'; - this._stage.interactive = false; + // this._stage = new PIXI.Stage(0x000000, false); + // this._stage.name = '_stage_root'; + // this._stage.interactive = false; + + PIXI.Stage.call(this, 0x000000, false); + + this.name = '_stage_root'; + this.interactive = false; + /** * @property {PIXI.Stage} display - The Pixi Stage which is hooked to the renderer. */ - this.display = this._stage; + // this.display = this._stage; /** * @property {number} scaleMode - The current scaleMode. @@ -63,7 +70,7 @@ Phaser.Stage = function (game, width, height) { /** * @property {Phaser.StageScaleMode} scale - The scale of the current running game. */ - this.scale = new Phaser.StageScaleMode(this.game, width, height); + // this.scale = new Phaser.StageScaleMode(this.game, width, height); /** * @property {number} aspectRatio - Aspect ratio. @@ -100,143 +107,140 @@ Phaser.Stage = function (game, width, height) { }; -Phaser.Stage.prototype = { +Phaser.Stage.prototype = Object.create(PIXI.Stage.prototype); +Phaser.Stage.prototype.constructor = Phaser.Stage; - /** - * Parses a Game configuration object. - * - * @method Phaser.Stage#parseConfig - * @protected - */ - parseConfig: function (config) { +/** +* Parses a Game configuration object. +* +* @method Phaser.Stage#parseConfig +* @protected +*/ +Phaser.Stage.prototype.parseConfig = function (config) { - if (config['canvasID']) + if (config['canvasID']) + { + this.canvas = Phaser.Canvas.create(this.game.width, this.game.height, config['canvasID']); + } + else + { + this.canvas = Phaser.Canvas.create(this.game.width, this.game.height); + } + + if (config['canvasStyle']) + { + this.canvas.stlye = config['canvasStyle']; + } + else + { + this.canvas.style['-webkit-full-screen'] = 'width: 100%; height: 100%'; + } + + if (config['checkOffsetInterval']) + { + this.checkOffsetInterval = config['checkOffsetInterval']; + } + + if (config['disableVisibilityChange']) + { + this.disableVisibilityChange = config['disableVisibilityChange']; + } + + if (config['fullScreenScaleMode']) + { + this.fullScreenScaleMode = config['fullScreenScaleMode']; + } + + if (config['scaleMode']) + { + this.scaleMode = config['scaleMode']; + } + + if (config['backgroundColor']) + { + this.backgroundColor = config['backgroundColor']; + } + +} + +/** +* Initialises the stage and adds the event listeners. +* @method Phaser.Stage#boot +* @private +*/ +Phaser.Stage.prototype.boot = function () { + + Phaser.Canvas.getOffset(this.canvas, this.offset); + + this.bounds = new Phaser.Rectangle(this.offset.x, this.offset.y, this.game.width, this.game.height); + + var _this = this; + + this._onChange = function (event) { + return _this.visibilityChange(event); + } + + Phaser.Canvas.setUserSelect(this.canvas, 'none'); + Phaser.Canvas.setTouchAction(this.canvas, 'none'); + + // this.backgroundColor = '#000000'; + + document.addEventListener('visibilitychange', this._onChange, false); + document.addEventListener('webkitvisibilitychange', this._onChange, false); + document.addEventListener('pagehide', this._onChange, false); + document.addEventListener('pageshow', this._onChange, false); + + window.onblur = this._onChange; + window.onfocus = this._onChange; + +} + +/** +* Runs Stage processes that need periodic updates, such as the offset checks. +* @method Phaser.Stage#update +*/ +Phaser.Stage.prototype.update = function () { + + if (this.checkOffsetInterval !== false) + { + if (this.game.time.now > this._nextOffsetCheck) { - this.canvas = Phaser.Canvas.create(this.game.width, this.game.height, config['canvasID']); - } - else - { - this.canvas = Phaser.Canvas.create(this.game.width, this.game.height); - } - - if (config['canvasStyle']) - { - this.canvas.stlye = config['canvasStyle']; - } - else - { - this.canvas.style['-webkit-full-screen'] = 'width: 100%; height: 100%'; - } - - if (config['checkOffsetInterval']) - { - this.checkOffsetInterval = config['checkOffsetInterval']; - } - - if (config['disableVisibilityChange']) - { - this.disableVisibilityChange = config['disableVisibilityChange']; - } - - if (config['fullScreenScaleMode']) - { - this.fullScreenScaleMode = config['fullScreenScaleMode']; - } - - if (config['scaleMode']) - { - this.scaleMode = config['scaleMode']; - } - - if (config['backgroundColor']) - { - this.backgroundColor = config['backgroundColor']; - } - - }, - - /** - * Initialises the stage and adds the event listeners. - * @method Phaser.Stage#boot - * @private - */ - boot: function () { - - Phaser.Canvas.getOffset(this.canvas, this.offset); - - this.bounds = new Phaser.Rectangle(this.offset.x, this.offset.y, this.game.width, this.game.height); - - var _this = this; - - this._onChange = function (event) { - return _this.visibilityChange(event); - } - - Phaser.Canvas.setUserSelect(this.canvas, 'none'); - Phaser.Canvas.setTouchAction(this.canvas, 'none'); - - this.backgroundColor = '#000000'; - - document.addEventListener('visibilitychange', this._onChange, false); - document.addEventListener('webkitvisibilitychange', this._onChange, false); - document.addEventListener('pagehide', this._onChange, false); - document.addEventListener('pageshow', this._onChange, false); - - window.onblur = this._onChange; - window.onfocus = this._onChange; - - }, - - /** - * Runs Stage processes that need periodic updates, such as the offset checks. - * @method Phaser.Stage#update - */ - update: function () { - - if (this.checkOffsetInterval !== false) - { - if (this.game.time.now > this._nextOffsetCheck) - { - Phaser.Canvas.getOffset(this.canvas, this.offset); - this._nextOffsetCheck = this.game.time.now + this.checkOffsetInterval; - } - - } - - }, - - /** - * This method is called when the document visibility is changed. - * @method Phaser.Stage#visibilityChange - * @param {Event} event - Its type will be used to decide whether the game should be paused or not. - */ - visibilityChange: function (event) { - - if (this.disableVisibilityChange) - { - return; - } - - if (this.game.paused === false && (event.type == 'pagehide' || event.type == 'blur' || document['hidden'] === true || document['webkitHidden'] === true)) - { - this.game.paused = true; - } - else - { - this.game.paused = false; + Phaser.Canvas.getOffset(this.canvas, this.offset); + this._nextOffsetCheck = this.game.time.now + this.checkOffsetInterval; } } -}; +} -Phaser.Stage.prototype.constructor = Phaser.Stage; +/** +* This method is called when the document visibility is changed. +* @method Phaser.Stage#visibilityChange +* @param {Event} event - Its type will be used to decide whether the game should be paused or not. +*/ +Phaser.Stage.prototype.visibilityChange = function (event) { + + if (this.disableVisibilityChange) + { + return; + } + + if (this.game.paused === false && (event.type == 'pagehide' || event.type == 'blur' || document['hidden'] === true || document['webkitHidden'] === true)) + { + this.game.paused = true; + } + else + { + this.game.paused = false; + } + +} /** * @name Phaser.Stage#backgroundColor * @property {number|string} backgroundColor - Gets and sets the background color of the stage. The color can be given as a number: 0xff0000 or a hex string: '#ff0000' */ -Object.defineProperty(Phaser.Stage.prototype, "backgroundColor", { +Object.defineProperty(Phaser.Stage.prototype, "NEWbackgroundColor", { get: function () { return this._backgroundColor; @@ -253,7 +257,7 @@ Object.defineProperty(Phaser.Stage.prototype, "backgroundColor", { color = Phaser.Color.hexToRGB(color); } - this._stage.setBackgroundColor(color); + this.setBackgroundColor(color); } } diff --git a/src/core/World.js b/src/core/World.js index e6ec490c..a550b1df 100644 --- a/src/core/World.js +++ b/src/core/World.js @@ -58,7 +58,7 @@ Phaser.World.prototype.boot = function () { this.game.camera = this.camera; - this.game.stage._stage.addChild(this); + this.game.stage.addChild(this); } diff --git a/src/gameobjects/GameObjectFactory.js b/src/gameobjects/GameObjectFactory.js index 9a721045..7443842e 100644 --- a/src/gameobjects/GameObjectFactory.js +++ b/src/gameobjects/GameObjectFactory.js @@ -97,11 +97,15 @@ Phaser.GameObjectFactory.prototype = { * @method Phaser.GameObjectFactory#group * @param {any} parent - The parent Group or DisplayObjectContainer that will hold this group, if any. * @param {string} [name='group'] - A name for this Group. Not used internally but useful for debugging. + * @param {boolean} [addToStage=false] - If set to true this Group will be added directly to the Game.Stage instead of Game.World. * @return {Phaser.Group} The newly created group. */ - group: function (parent, name) { + group: function (parent, name, addToStage) { - return new Phaser.Group(this.game, parent, name); + if (typeof name === 'undefined') { name = 'group'; } + if (typeof addToStage === 'undefined') { addToStage = false; } + + return new Phaser.Group(this.game, parent, name, addToStage); }, diff --git a/src/gameobjects/Text.js b/src/gameobjects/Text.js index 3f0d181d..ad1b6928 100644 --- a/src/gameobjects/Text.js +++ b/src/gameobjects/Text.js @@ -109,7 +109,7 @@ Phaser.Text.prototype.constructor = Phaser.Text; * Automatically called by World.preUpdate. * @method Phaser.Text.prototype.preUpdate */ -Phaser.Text.prototype.preUpdate = function() { +Phaser.Text.prototype.preUpdate = function () { if (!this.exists || !this.parent.exists) { @@ -125,7 +125,7 @@ Phaser.Text.prototype.preUpdate = function() { * Automatically called by World.postUpdate. * @method Phaser.Text.prototype.postUpdate */ -Phaser.Text.prototype.postUpdate = function() { +Phaser.Text.prototype.postUpdate = function () { if (this.exists) { @@ -140,7 +140,7 @@ Phaser.Text.prototype.postUpdate = function() { /** * @method Phaser.Text.prototype.destroy */ -Phaser.Text.prototype.destroy = function() { +Phaser.Text.prototype.destroy = function () { if (this.filters) { @@ -178,7 +178,7 @@ Phaser.Text.prototype.destroy = function() { * @param {string} [color='rgba(0,0,0,0)'] - The color of the shadow, as given in CSS rgba format. Set the alpha component to 0 to disable the shadow. * @param {number} [blur=0] - The shadowBlur value. Make the shadow softer by applying a Gaussian blur to it. A number from 0 (no blur) up to approx. 10 (depending on scene). */ -Phaser.Text.prototype.setShadow = function(x, y, color, blur) { +Phaser.Text.prototype.setShadow = function (x, y, color, blur) { this.style.shadowOffsetX = x || 0; this.style.shadowOffsetY = y || 0; @@ -201,7 +201,7 @@ Phaser.Text.prototype.setShadow = function(x, y, color, blur) { * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap */ -Phaser.Text.prototype.setStyle = function(style) { +Phaser.Text.prototype.setStyle = function (style) { style = style || {}; style.font = style.font || 'bold 20pt Arial'; @@ -227,7 +227,7 @@ Phaser.Text.prototype.setStyle = function(style) { * @method Phaser.Text.prototype.updateText * @private */ -Phaser.Text.prototype.updateText = function() { +Phaser.Text.prototype.updateText = function () { this.context.font = this.style.font; @@ -307,7 +307,7 @@ Phaser.Text.prototype.updateText = function() { * @method Phaser.Text.prototype.runWordWrap * @private */ -Phaser.Text.prototype.runWordWrap = function(text) { +Phaser.Text.prototype.runWordWrap = function (text) { var result = ''; var lines = text.split('\n'); diff --git a/src/physics/Body.js b/src/physics/Body.js index 5932f530..7c0354a5 100644 --- a/src/physics/Body.js +++ b/src/physics/Body.js @@ -37,6 +37,7 @@ Phaser.Physics.Body = function (sprite) { * @protected */ this.data = new p2.Body({ position:[this.px2p(sprite.position.x), this.px2p(sprite.position.y)], mass: 1 }); + this.data.parent = this; /** * @property {Phaser.PointProxy} velocity - The velocity of the body. Set velocity.x to a negative value to move to the left, position to the right. velocity.y negative values move up, positive move down. @@ -48,15 +49,14 @@ Phaser.Physics.Body = function (sprite) { */ this.force = new Phaser.Physics.PointProxy(this.data.force); + // this.onAdded = new Phaser.Signal(); + // this.onRemoved = new Phaser.Signal(); + // Set-up the default shape this.setRectangleFromSprite(sprite); this.game.physics.addBody(this.data); - // Set-up contact events - // this.sprite.events.onBeginContact = new Phaser.Signal(); - // this.sprite.events.onEndContact = new Phaser.Signal(); - }; Phaser.Physics.Body.prototype = { diff --git a/src/physics/World.js b/src/physics/World.js index f48d8524..689e8cb7 100644 --- a/src/physics/World.js +++ b/src/physics/World.js @@ -9,6 +9,9 @@ */ Phaser.Physics = {}; +// Add an extra property to p2.Body +p2.Body.prototype.parent = null; + /** * @class Phaser.Physics.World * @classdesc Physics World Constructor @@ -22,10 +25,18 @@ Phaser.Physics.World = function (game) { */ this.game = game; + this.onBodyAdded = new Phaser.Signal(); + this.onBodyRemoved = new Phaser.Signal(); + this.bounds = null; p2.World.call(this, { gravity: [0, 0] }); + this.on("addBody", this.addBodyHandler); + this.on("removeBody", this.removeBodyHandler); + this.on("postStep", this.postStepHandler); + this.on("postBroadphase", this.postBroadphaseHandler); + this.setBoundsToWorld(true, true, true, true); }; @@ -33,6 +44,84 @@ Phaser.Physics.World = function (game) { Phaser.Physics.World.prototype = Object.create(p2.World.prototype); Phaser.Physics.World.prototype.constructor = Phaser.Physics.World; +/** +* Handles a p2 addBody event. +* +* @method Phaser.Physics.Arcade#addBodyHandler +* @private +* @param {object} event - The event data. +*/ +Phaser.Physics.World.prototype.addBodyHandler = function (event) { + + if (event.body.parent) + { + this.onBodyAdded.dispatch(event.body.parent, event.target); + } + +}; + +/** +* Handles a p2 removeBody event. +* +* @method Phaser.Physics.Arcade#removeBodyHandler +* @private +* @param {object} event - The event data. +*/ +Phaser.Physics.World.prototype.removeBodyHandler = function (event) { + + if (event.body.parent) + { + this.onBodyRemoved.dispatch(event.body.parent, event.target); + } + +}; + +/** +* Handles a p2 postStep event. +* +* @method Phaser.Physics.Arcade#postStepHandler +* @private +* @param {object} event - The event data. +*/ +Phaser.Physics.World.prototype.postStepHandler = function (event) { + + // console.log(event); + + // if (event.body.parent) + // { + // this.onBodyRemoved.dispatch(event.body.parent, event.target); + // } + +}; + +/** +* Handles a p2 postBroadphase event. +* +* @method Phaser.Physics.Arcade#postBroadphaseHandler +* @private +* @param {object} event - The event data. +*/ +Phaser.Physics.World.prototype.postBroadphaseHandler = function (event) { + + // Body.id 1 is always the World bounds object + + for (var i = 0; i < event.pairs.length; i++) + { + // console.log(i, event.pairs[i]); + + if (event.pairs[i].parent) + { + // console.log(event.pairs[i].parent.sprite.name); + } + } + + // if (event.body.parent) + // { + // this.onBodyRemoved.dispatch(event.body.parent, event.target); + // } + +}; + /** * Sets the bounds of the Physics world to match the Game.World dimensions. * You can optionally set which 'walls' to create: left, right, top or bottom. @@ -70,17 +159,25 @@ Phaser.Physics.World.prototype.setBounds = function (x, y, width, height, left, if (typeof top === 'undefined') { top = true; } if (typeof bottom === 'undefined') { bottom = true; } - if (this.bounds !== null) - { - this.removeBody(this.bounds); - } - var hw = (width / 2); var hh = (height / 2); var cx = hw + x; var cy = hh + y; - this.bounds = new p2.Body({ mass: 0, position:[this.game.math.px2p(cx), this.game.math.px2p(cy)] }); + if (this.bounds !== null) + { + this.removeBody(this.bounds); + + for (var i = this.bounds.shapes.length - 1; i >= 0; i--) + { + var shape = this.bounds.shapes[i]; + this.bounds.removeShape(shape); + } + } + else + { + this.bounds = new p2.Body({ mass: 0, position:[this.game.math.px2p(cx), this.game.math.px2p(cy)] }); + } if (left) { diff --git a/src/system/StageScaleMode.js b/src/system/StageScaleMode.js index fade08cd..9fe8b7be 100644 --- a/src/system/StageScaleMode.js +++ b/src/system/StageScaleMode.js @@ -388,7 +388,7 @@ Phaser.StageScaleMode.prototype = { this.game.world.visible = true; } - this.game.stage._stage.addChild(this.orientationSprite); + this.game.stage.addChild(this.orientationSprite); } },