diff --git a/README.md b/README.md index 6fe03710..ac6b7a73 100644 --- a/README.md +++ b/README.md @@ -40,13 +40,15 @@ Change Log Version 1.1.2 * New: You'll now find a complete Basic project Template in the resources/Project Templates folder. Will add more complex ones soon. +* New: Phaser.Button now has the ability to set over/out/up/down sound effects so they play automatically based on those events. +* Updated: Fixed a few final bugs in the Sprite body and bounds calculations, in turn this resolved the Tilemap collision issues in the 1.1 release. +* Updated: Finished documentation for the Phaser.Button class. * Fixed issue 135 - Added typeof checks into most ArcadePhysics functions to avoid errors with zero values. * Fixed issue 136 - distanceTo using worldX/Y instead of x/y. * Added init method to plugins, to be called as they are added to the PluginManager (thanks beeglebug) * If you pause an Animation, when you next play it it'll resume (un-pause itself). -* Started work on fixing the body / camera / tilemap issue - pretty much sorted now I think, more tests needed. - - +* New: Physics.Body now has a center property (issue 142, thanks MikeMnD) +* Updated: Fixed the Invaders game sample and enhanced it, also fixed lots of "cursor key moves the page" examples. Version 1.1.1 - October 26th 2013 diff --git a/examples/camera/basic follow.js b/examples/camera/basic follow.js index 417c07ac..bcb21bc7 100644 --- a/examples/camera/basic follow.js +++ b/examples/camera/basic follow.js @@ -67,6 +67,6 @@ function render() { game.debug.renderSpriteCoords(player, 32, 200); game.debug.renderSpriteCoords(fixed, 600, 200); - game.debug.renderSpriteCoords(game.world._container, 32, 400); + // game.debug.renderSpriteCoords(game.world._container, 32, 400); } diff --git a/examples/games/invaders.js b/examples/games/invaders.js index 82434b86..f7617693 100644 --- a/examples/games/invaders.js +++ b/examples/games/invaders.js @@ -7,6 +7,8 @@ function preload() { game.load.image('bullet', 'assets/misc/bullet0.png'); game.load.image('alien', 'assets/sprites/space-baddie.png'); game.load.image('ship', 'assets/sprites/shmup-ship.png'); + game.load.spritesheet('kaboom', 'assets/games/tanks/explosion.png', 64, 64, 23); + game.load.image('starfield', 'assets/misc/starfield.jpg'); } @@ -14,9 +16,14 @@ var player; var aliens; var bullets; var bulletTime = 0; +var cursors; +var fireButton; +var explosions; function create() { + s = game.add.tileSprite(0, 0, 800, 600, 'starfield'); + player = game.add.sprite(400, 500, 'ship'); player.anchor.setTo(0.5, 0.5); @@ -33,21 +40,29 @@ function create() { aliens.x = 100; aliens.y = 50; - bullets = game.add.group(null, 'bullets'); + // Our bullet group + bullets = game.add.group(); + bullets.createMultiple(30, 'bullet'); + bullets.setAll('anchor.x', 0.5); + bullets.setAll('anchor.y', 1); + bullets.setAll('outOfBoundsKill', true); + + // Explosion pool + explosions = game.add.group(); for (var i = 0; i < 10; i++) { - var b = bullets.create(0, 0, 'bullet'); - b.name = 'bullet' + i; - b.exists = false; - b.visible = false; - b.anchor.setTo(0.5, 1); - b.events.onOutOfBounds.add(resetBullet, this); + var explosionAnimation = explosions.create(0, 0, 'kaboom', [0], false); + explosionAnimation.anchor.setTo(0.5, 0.5); + explosionAnimation.animations.add('kaboom'); } var tween = game.add.tween(aliens).to({x: 200}, 3000, Phaser.Easing.Linear.None, true, 0, 1000, true); tween.onComplete.add(descend, this); + cursors = game.input.keyboard.createCursorKeys(); + fireButton = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR); + } @@ -60,16 +75,16 @@ function update() { player.body.velocity.x = 0; player.body.velocity.y = 0; - if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) + if (cursors.left.isDown) { player.body.velocity.x = -200; } - else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) + else if (cursors.right.isDown) { player.body.velocity.x = 200; } - if (game.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR)) + if (fireButton.isDown) { fireBullet(); } @@ -104,16 +119,11 @@ function collisionHandler (bullet, alien) { bullet.kill(); alien.kill(); + var explosionAnimation = explosions.getFirstDead(); + explosionAnimation.reset(alien.body.x, alien.body.y); + explosionAnimation.play('kaboom', 30, false, true); + } function render () { - - // aliens.forEach(renderBounds, this); - - game.debug.renderQuadTree(game.physics.quadTree); - -} - -function renderBounds(s) { - game.debug.renderSpriteBounds(s, 'rgba(0,0,255,0.4)', true); } diff --git a/resources/Project Templates/Basic/Boot.js b/resources/Project Templates/Basic/Boot.js index 131240a0..297cec2f 100644 --- a/resources/Project Templates/Basic/Boot.js +++ b/resources/Project Templates/Basic/Boot.js @@ -1,3 +1,4 @@ +BasicGame = {}; BasicGame.Boot = function (game) { diff --git a/resources/Project Templates/Basic/Game.js b/resources/Project Templates/Basic/Game.js index 1720d7f9..0339e7a8 100644 --- a/resources/Project Templates/Basic/Game.js +++ b/resources/Project Templates/Basic/Game.js @@ -1,3 +1,4 @@ + BasicGame.Game = function (game) { // Honestly, just about anything could go here. diff --git a/resources/Project Templates/Basic/MainMenu.js b/resources/Project Templates/Basic/MainMenu.js index bb94299a..968bca66 100644 --- a/resources/Project Templates/Basic/MainMenu.js +++ b/resources/Project Templates/Basic/MainMenu.js @@ -1,3 +1,4 @@ + BasicGame.MainMenu = function (game) { this.music = null; diff --git a/src/gameobjects/Button.js b/src/gameobjects/Button.js index 63bceb82..ea51a574 100644 --- a/src/gameobjects/Button.js +++ b/src/gameobjects/Button.js @@ -4,21 +4,26 @@ * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ - /** -* Create a new Button object. +* Create a new `Button` object. A Button is a special type of Sprite that is set-up to handle Pointer events automatically. The four states a Button responds to are: +* 'Over' - when the Pointer moves over the Button. This is also commonly known as 'hover'. +* 'Out' - when the Pointer that was previously over the Button moves out of it. +* 'Down' - when the Pointer is pressed down on the Button. I.e. touched on a touch enabled device or clicked with the mouse. +* 'Up' - when the Pointer that was pressed down on the Button is released again. +* You can set a unique texture frame and Sound for any of these states. +* * @class Phaser.Button * @constructor * * @param {Phaser.Game} game Current game instance. -* @param {number} [x] X position of the button. -* @param {number} [y] Y position of the button. -* @param {string} [key] The image key as defined in the Game.Cache to use as the texture for this button. -* @param {function} [callback] The function to call when this button is pressed -* @param {object} [callbackContext] The context in which the callback will be called (usually 'this') -* @param {string|number} [overFrame] This is the frame or frameName that will be set when this button is in an over state. Give either a number to use a frame ID or a string for a frame name. -* @param {string|number} [outFrame] This is the frame or frameName that will be set when this button is in an out state. Give either a number to use a frame ID or a string for a frame name. -* @param {string|number} [downFrame] This is the frame or frameName that will be set when this button is in a down state. Give either a number to use a frame ID or a string for a frame name. +* @param {number} [x] - X position of the Button. +* @param {number} [y] - Y position of the Button. +* @param {string} [key] - The image key as defined in the Game.Cache to use as the texture for this Button. +* @param {function} [callback] - The function to call when this Button is pressed. +* @param {object} [callbackContext] - The context in which the callback will be called (usually 'this'). +* @param {string|number} [overFrame] - This is the frame or frameName that will be set when this button is in an over state. Give either a number to use a frame ID or a string for a frame name. +* @param {string|number} [outFrame] - This is the frame or frameName that will be set when this button is in an out state. Give either a number to use a frame ID or a string for a frame name. +* @param {string|number} [downFrame] - This is the frame or frameName that will be set when this button is in a down state. Give either a number to use a frame ID or a string for a frame name. */ Phaser.Button = function (game, x, y, key, callback, callbackContext, overFrame, outFrame, downFrame) { @@ -31,87 +36,139 @@ Phaser.Button = function (game, x, y, key, callback, callbackContext, overFrame, Phaser.Sprite.call(this, game, x, y, key, outFrame); /** - * @property {Description} type - Description. + * @property {number} type - The Phaser Object Type. */ this.type = Phaser.BUTTON; /** - * @property {Description} _onOverFrameName - Description. + * @property {string} _onOverFrameName - Internal variable. * @private * @default */ this._onOverFrameName = null; /** - * @property {Description} _onOutFrameName - Description. + * @property {string} _onOutFrameName - Internal variable. * @private * @default */ this._onOutFrameName = null; /** - * @property {Description} _onDownFrameName - Description. + * @property {string} _onDownFrameName - Internal variable. * @private * @default */ this._onDownFrameName = null; /** - * @property {Description} _onUpFrameName - Description. + * @property {string} _onUpFrameName - Internal variable. * @private * @default */ this._onUpFrameName = null; /** - * @property {Description} _onOverFrameID - Description. + * @property {number} _onOverFrameID - Internal variable. * @private * @default */ this._onOverFrameID = null; /** - * @property {Description} _onOutFrameID - Description. + * @property {number} _onOutFrameID - Internal variable. * @private * @default */ this._onOutFrameID = null; /** - * @property {Description} _onDownFrameID - Description. + * @property {number} _onDownFrameID - Internal variable. * @private * @default */ this._onDownFrameID = null; /** - * @property {Description} _onUpFrameID - Description. + * @property {number} _onUpFrameID - Internal variable. * @private * @default */ this._onUpFrameID = null; - // These are the signals the game will subscribe to + /** + * @property {Phaser.Sound} onOverSound - The Sound to be played when this Buttons Over state is activated. + * @default + */ + this.onOverSound = null; + + /** + * @property {Phaser.Sound} onOutSound - The Sound to be played when this Buttons Out state is activated. + * @default + */ + this.onOutSound = null; + + /** + * @property {Phaser.Sound} onDownSound - The Sound to be played when this Buttons Down state is activated. + * @default + */ + this.onDownSound = null; + + /** + * @property {Phaser.Sound} onUpSound - The Sound to be played when this Buttons Up state is activated. + * @default + */ + this.onUpSound = null; + + /** + * @property {string} onOverSoundMarker - The Sound Marker used in conjunction with the onOverSound. + * @default + */ + this.onOverSoundMarker = ''; + + /** + * @property {string} onOutSoundMarker - The Sound Marker used in conjunction with the onOutSound. + * @default + */ + this.onOutSoundMarker = ''; + + /** + * @property {string} onDownSoundMarker - The Sound Marker used in conjunction with the onDownSound. + * @default + */ + this.onDownSoundMarker = ''; + + /** + * @property {string} onUpSoundMarker - The Sound Marker used in conjunction with the onUpSound. + * @default + */ + this.onUpSoundMarker = ''; + /** - * @property {Phaser.Signal} onInputOver - Description. + * @property {Phaser.Signal} onInputOver - The Signal (or event) dispatched when this Button is in an Over state. */ this.onInputOver = new Phaser.Signal; /** - * @property {Phaser.Signal} onInputOut - Description. + * @property {Phaser.Signal} onInputOut - The Signal (or event) dispatched when this Button is in an Out state. */ this.onInputOut = new Phaser.Signal; /** - * @property {Phaser.Signal} onInputDown - Description. + * @property {Phaser.Signal} onInputDown - The Signal (or event) dispatched when this Button is in an Down state. */ this.onInputDown = new Phaser.Signal; /** - * @property {Phaser.Signal} onInputUp - Description. + * @property {Phaser.Signal} onInputUp - The Signal (or event) dispatched when this Button is in an Up state. */ this.onInputUp = new Phaser.Signal; + /** + * @property {boolean} freezeFrames - When true the Button will cease to change texture frame on all events (over, out, up, down). + */ + this.freezeFrames = false; + this.setFrames(overFrame, outFrame, downFrame); if (callback !== null) @@ -119,8 +176,6 @@ Phaser.Button = function (game, x, y, key, callback, callbackContext, overFrame, this.onInputUp.add(callback, callbackContext); } - this.freezeFrames = false; - this.input.start(0, true); // Redirect the input events to here so we can handle animation updates, etc @@ -216,10 +271,131 @@ Phaser.Button.prototype.setFrames = function (overFrame, outFrame, downFrame) { }; /** -* Description. +* Sets the sounds to be played whenever this Button is interacted with. Sounds can be either full Sound objects, or markers pointing to a section of a Sound object. +* The most common forms of sounds are 'hover' effects and 'click' effects, which is why the order of the parameters is overSound then downSound. +* Call this function with no parameters at all to reset all sounds on this Button. * +* @method Phaser.Button.prototype.setSounds +* @param {Phaser.Sound} [overSound] - Over Button Sound. +* @param {string} [overMarker] - Over Button Sound Marker. +* @param {Phaser.Sound} [downSound] - Down Button Sound. +* @param {string} [downMarker] - Down Button Sound Marker. +* @param {Phaser.Sound} [outSound] - Out Button Sound. +* @param {string} [outMarker] - Out Button Sound Marker. +* @param {Phaser.Sound} [upSound] - Up Button Sound. +* @param {string} [upMarker] - Up Button Sound Marker. +*/ +Phaser.Button.prototype.setSounds = function (overSound, overMarker, downSound, downMarker, outSound, outMarker, upSound, upMarker) { + + this.setOverSound(overSound, overMarker); + this.setOutSound(outSound, outMarker); + this.setUpSound(upSound, upMarker); + this.setDownSound(downSound, downMarker); + +} + +/** +* The Sound to be played when a Pointer moves over this Button. +* +* @method Phaser.Button.prototype.setOverSound +* @param {Phaser.Sound} sound - The Sound that will be played. +* @param {string} [marker] - A Sound Marker that will be used in the playback. +*/ +Phaser.Button.prototype.setOverSound = function (sound, marker) { + + this.onOverSound = null; + this.onOverSoundMarker = ''; + + if (sound instanceof Phaser.Sound) + { + this.onOverSound = sound; + } + + if (typeof marker === 'string') + { + this.onOverSoundMarker = marker; + } + +} + +/** +* The Sound to be played when a Pointer moves out of this Button. +* +* @method Phaser.Button.prototype.setOutSound +* @param {Phaser.Sound} sound - The Sound that will be played. +* @param {string} [marker] - A Sound Marker that will be used in the playback. +*/ +Phaser.Button.prototype.setOutSound = function (sound, marker) { + + this.onOutSound = null; + this.onOutSoundMarker = ''; + + if (sound instanceof Phaser.Sound) + { + this.onOutSound = sound; + } + + if (typeof marker === 'string') + { + this.onOutSoundMarker = marker; + } + +} + +/** +* The Sound to be played when a Pointer clicks on this Button. +* +* @method Phaser.Button.prototype.setUpSound +* @param {Phaser.Sound} sound - The Sound that will be played. +* @param {string} [marker] - A Sound Marker that will be used in the playback. +*/ +Phaser.Button.prototype.setUpSound = function (sound, marker) { + + this.onUpSound = null; + this.onUpSoundMarker = ''; + + if (sound instanceof Phaser.Sound) + { + this.onUpSound = sound; + } + + if (typeof marker === 'string') + { + this.onUpSoundMarker = marker; + } + +} + +/** +* The Sound to be played when a Pointer clicks on this Button. +* +* @method Phaser.Button.prototype.setDownSound +* @param {Phaser.Sound} sound - The Sound that will be played. +* @param {string} [marker] - A Sound Marker that will be used in the playback. +*/ +Phaser.Button.prototype.setDownSound = function (sound, marker) { + + this.onDownSound = null; + this.onDownSoundMarker = ''; + + if (sound instanceof Phaser.Sound) + { + this.onDownSound = sound; + } + + if (typeof marker === 'string') + { + this.onDownSoundMarker = marker; + } + +} + +/** +* Internal function that handles input events. +* +* @protected * @method Phaser.Button.prototype.onInputOverHandler -* @param {Description} pointer - Description. +* @param {Phaser.Pointer} pointer - The Pointer that activated the Button. */ Phaser.Button.prototype.onInputOverHandler = function (pointer) { @@ -235,6 +411,11 @@ Phaser.Button.prototype.onInputOverHandler = function (pointer) { } } + if (this.onOverSound) + { + this.onOverSound.play(this.onOverSoundMarker); + } + if (this.onInputOver) { this.onInputOver.dispatch(this, pointer); @@ -242,10 +423,11 @@ Phaser.Button.prototype.onInputOverHandler = function (pointer) { }; /** -* Description. +* Internal function that handles input events. * -* @method Phaser.Button.prototype.onInputOutHandler -* @param {Description} pointer - Description. +* @protected +* @method Phaser.Button.prototype.onInputOverHandler +* @param {Phaser.Pointer} pointer - The Pointer that activated the Button. */ Phaser.Button.prototype.onInputOutHandler = function (pointer) { @@ -261,6 +443,11 @@ Phaser.Button.prototype.onInputOutHandler = function (pointer) { } } + if (this.onOutSound) + { + this.onOutSound.play(this.onOutSoundMarker); + } + if (this.onInputOut) { this.onInputOut.dispatch(this, pointer); @@ -268,10 +455,11 @@ Phaser.Button.prototype.onInputOutHandler = function (pointer) { }; /** -* Description. +* Internal function that handles input events. * -* @method Phaser.Button.prototype.onInputDownHandler -* @param {Description} pointer - Description. +* @protected +* @method Phaser.Button.prototype.onInputOverHandler +* @param {Phaser.Pointer} pointer - The Pointer that activated the Button. */ Phaser.Button.prototype.onInputDownHandler = function (pointer) { @@ -287,6 +475,11 @@ Phaser.Button.prototype.onInputDownHandler = function (pointer) { } } + if (this.onDownSound) + { + this.onDownSound.play(this.onDownSoundMarker); + } + if (this.onInputDown) { this.onInputDown.dispatch(this, pointer); @@ -294,10 +487,11 @@ Phaser.Button.prototype.onInputDownHandler = function (pointer) { }; /** -* Description. +* Internal function that handles input events. * -* @method Phaser.Button.prototype.onInputUpHandler -* @param {Description} pointer - Description. +* @protected +* @method Phaser.Button.prototype.onInputOverHandler +* @param {Phaser.Pointer} pointer - The Pointer that activated the Button. */ Phaser.Button.prototype.onInputUpHandler = function (pointer) { @@ -313,6 +507,11 @@ Phaser.Button.prototype.onInputUpHandler = function (pointer) { } } + if (this.onUpSound) + { + this.onUpSound.play(this.onUpSoundMarker); + } + if (this.onInputUp) { this.onInputUp.dispatch(this, pointer); diff --git a/src/gameobjects/Sprite.js b/src/gameobjects/Sprite.js index d9680ca0..35349736 100644 --- a/src/gameobjects/Sprite.js +++ b/src/gameobjects/Sprite.js @@ -202,9 +202,6 @@ Phaser.Sprite = function (game, x, y, key, frame) { // The actual scale values based on the worldTransform scaleX: 1, scaleY: 1, - // cache scale check - realScaleX: 1, realScaleY: 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, @@ -218,8 +215,6 @@ Phaser.Sprite = function (game, x, y, key, frame) { // frameID: this.currentFrame.uuid, frameWidth: this.currentFrame.width, frameHeight: this.currentFrame.height, frameID: -1, frameWidth: this.currentFrame.width, frameHeight: this.currentFrame.height, - boundsX: 0, boundsY: 0, - // If this sprite visible to the camera (regardless of being set to visible or not) cameraVisible: true, @@ -306,7 +301,15 @@ Phaser.Sprite = function (game, x, y, key, frame) { * @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; + + /** + * @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; /** @@ -323,6 +326,9 @@ Phaser.Sprite = function (game, x, y, key, frame) { */ 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) @@ -356,55 +362,21 @@ Phaser.Sprite.prototype.preUpdate = function() { this._cache.dirty = false; - if (this.animations.update()) - { - this._cache.dirty = true; - } - if (this.visible) { this.renderOrderID = this.game.world.currentRenderOrderID++; } - this.prevX = this.x; - this.prevY = this.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.prevX = this.game.camera.view.x + this.x; - // this.prevY = this.game.camera.view.y + this.y; - } - - this.world.setTo(this.game.camera.x + this.worldTransform[2], this.game.camera.y + this.worldTransform[5]); - this.updateCache(); + this.updateAnimation(); - if (this.cropEnabled) - { - this.updateCrop(); - } + this.updateCrop(); // Re-run the camera visibility check - if (this._cache.dirty) + if (this._cache.dirty || this.world.x !== this.prevX || this.world.y !== this.prevY) { this.updateBounds(); - - this._cache.cameraVisible = Phaser.Rectangle.intersects(this.game.world.camera.screenView, this.bounds, 0); - - if (this.autoCull == true) - { - // 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); - } } if (this.body) @@ -422,15 +394,22 @@ Phaser.Sprite.prototype.preUpdate = function() { */ Phaser.Sprite.prototype.updateCache = function() { - // |a c tx| - // |b d ty| - // |0 0 1| + this.prevX = this.world.x; + this.prevY = this.world.y; - if (this.worldTransform[1] != this._cache.i01 || this.worldTransform[3] != this._cache.i10) + if (this.fixedToCamera) { - this._cache.a00 = this.worldTransform[0]; // scaleX a - this._cache.a01 = this.worldTransform[1]; // skewY c - this._cache.a10 = this.worldTransform[3]; // skewX b + 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) @@ -442,15 +421,14 @@ Phaser.Sprite.prototype.updateCache = function() { 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; } - if (this.worldTransform[2] != this._cache.a02 || this.worldTransform[5] != this._cache.a12) - { - this._cache.a02 = this.worldTransform[2]; // translateX tx - this._cache.a12 = this.worldTransform[5]; // translateY ty - this._cache.dirty = true; - } + this._cache.a02 = this.worldTransform[2]; // translateX tx + this._cache.a12 = this.worldTransform[5]; // translateY ty } @@ -462,23 +440,50 @@ Phaser.Sprite.prototype.updateCache = function() { */ Phaser.Sprite.prototype.updateAnimation = function() { - if (this.currentFrame && this.currentFrame.uuid != this._cache.frameID) + 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.frameID = this.currentFrame.uuid; - this._cache.dirty = true; - } - if (this._cache.dirty && this.currentFrame) - { 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.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; + + } + +} + +/** +* 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); } } @@ -491,22 +496,13 @@ Phaser.Sprite.prototype.updateAnimation = function() { */ Phaser.Sprite.prototype.updateBounds = function() { - var sx = 1; - var sy = 1; - - if (this.worldTransform[3] !== 0 || this.worldTransform[1] !== 0) - { - sx = this.scale.x; - sy = this.scale.y; - } - 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), sx, sy); - this.getLocalPosition(this.topLeft, this.offset.x, this.offset.y, sx, sy); - this.getLocalPosition(this.topRight, this.offset.x + this.width, this.offset.y, sx, sy); - this.getLocalPosition(this.bottomLeft, this.offset.x, this.offset.y + this.height, sx, sy); - this.getLocalPosition(this.bottomRight, this.offset.x + this.width, this.offset.y + this.height, sx, sy); + 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); @@ -515,10 +511,6 @@ Phaser.Sprite.prototype.updateBounds = function() { this.bounds.setTo(this._cache.left, this._cache.top, this._cache.right - this._cache.left, this._cache.bottom - this._cache.top); - // This is the coordinate the Sprite was at when the last bounds was created - this._cache.boundsX = this._cache.x; - this._cache.boundsY = this._cache.y; - this.updateFrame = true; if (this.inWorld == false) @@ -549,6 +541,20 @@ Phaser.Sprite.prototype.updateBounds = function() { } } + 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); + } + } /** @@ -564,10 +570,10 @@ Phaser.Sprite.prototype.updateBounds = function() { * @param {number} sy - Scale factor to be applied. * @return {Phaser.Point} The translated point. */ -Phaser.Sprite.prototype.getLocalPosition = function(p, x, y, sx, sy) { +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) * sx) + 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) * sy) + this._cache.a12; + 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; @@ -586,47 +592,13 @@ Phaser.Sprite.prototype.getLocalPosition = function(p, x, y, sx, sy) { */ Phaser.Sprite.prototype.getLocalUnmodifiedPosition = function(p, gx, gy) { - var a00 = this.worldTransform[0], a01 = this.worldTransform[1], a02 = this.worldTransform[2], - a10 = this.worldTransform[3], a11 = this.worldTransform[4], a12 = this.worldTransform[5], - id = 1 / (a00 * a11 + a01 * -a10), - x = a11 * id * gx + -a01 * id * gy + (a12 * a01 - a02 * a11) * id, - y = a00 * id * gy + -a10 * id * gx + (-a12 * a00 + a02 * a10) * id; - - p.x = x + (this.anchor.x * this._cache.width); - p.y = y + (this.anchor.y * this._cache.height); + 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; } -/** -* 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.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); - } - -} /** * Resets the Sprite.crop value back to the frame dimensions. diff --git a/src/physics/arcade/Body.js b/src/physics/arcade/Body.js index e70bc705..10f81ffc 100644 --- a/src/physics/arcade/Body.js +++ b/src/physics/arcade/Body.js @@ -104,6 +104,11 @@ Phaser.Physics.Arcade.Body = function (sprite) { */ this.halfHeight = Math.floor(sprite.currentFrame.sourceSizeH / 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 @@ -323,6 +328,7 @@ Phaser.Physics.Arcade.Body.prototype = { this.halfHeight = Math.floor(this.height / 2); this._sx = scaleX; this._sy = scaleY; + this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); } }, @@ -353,9 +359,6 @@ Phaser.Physics.Arcade.Body.prototype = { 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.worldTransform[2] - (this.sprite.anchor.x * this.width)) + this.offset.x; - // this.preY = (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; @@ -374,7 +377,8 @@ Phaser.Physics.Arcade.Body.prototype = { this.checkWorldBounds(); } - this.updateHulls();Array } + this.updateHulls(); + } if (this.skipQuadTree == false && this.allowCollision.none == false && this.sprite.visible && this.sprite.alive) { @@ -393,16 +397,6 @@ Phaser.Physics.Arcade.Body.prototype = { */ postUpdate: function () { - // Calculate forward-facing edge - if (this.deltaX() == 0 && this.deltaY() == 0) - { - // Can't work it out from the Body, how about from x position? - if (this.sprite.deltaX() == 0 && this.sprite.deltaY() == 0) - { - // still as a statue - } - } - if (this.deltaX() < 0) { this.facing = Phaser.LEFT; @@ -421,8 +415,12 @@ Phaser.Physics.Arcade.Body.prototype = { this.facing = Phaser.DOWN; } - this.sprite.x += this.deltaX(); - this.sprite.y += this.deltaY(); + if (this.deltaX() !== 0 || this.deltaY() !== 0) + { + this.sprite.x += this.deltaX(); + this.sprite.y += this.deltaY(); + this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); + } if (this.allowRotation) { @@ -500,6 +498,8 @@ Phaser.Physics.Arcade.Body.prototype = { this.halfHeight = Math.floor(this.height / 2); this.offset.setTo(offsetX, offsetY); + this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); + }, /** @@ -514,8 +514,6 @@ Phaser.Physics.Arcade.Body.prototype = { this.angularVelocity = 0; this.angularAcceleration = 0; - // this.preX = (this.sprite.worldTransform[2] - (this.sprite.anchor.x * this.width)) + this.offset.x; - // this.preY = (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; @@ -523,6 +521,8 @@ Phaser.Physics.Arcade.Body.prototype = { this.x = this.preX; this.y = this.preY; this.rotation = this.preRotation; + + this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); },