From a415e779d12f5ed214c9b97b6015083eab4d89fc Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 20 Sep 2013 13:55:33 +0100 Subject: [PATCH] Final 1.0.5 release. --- README.md | 13 +- examples/assets/sprites/breakout.json | 236 -------------------------- examples/assets/sprites/breakout.png | Bin 2423 -> 0 bytes examples/collision/bounding box.php | 7 +- examples/games/breakout.php | 148 ++++++++++++++-- examples/games/invaders.php | 140 +++++++++++++++ examples/tile sprites/tilesprite2.php | 4 +- src/core/Group.js | 75 +++----- src/gameobjects/Sprite.js | 142 +++++++++------- src/gameobjects/Text.js | 40 +++++ src/physics/arcade/Body.js | 18 +- src/utils/Debug.js | 50 +++++- 12 files changed, 494 insertions(+), 379 deletions(-) delete mode 100644 examples/assets/sprites/breakout.json delete mode 100644 examples/assets/sprites/breakout.png create mode 100644 examples/games/invaders.php diff --git a/README.md b/README.md index 55172603a..850dab1d4 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Phaser 1.0 Phaser is a fast, free and fun open source game framework for making desktop and mobile browser HTML5 games. It uses [Pixi.js](https://github.com/GoodBoyDigital/pixi.js/) internally for fast 2D Canvas and WebGL rendering. -Version: 1.0.4 - Released: September 18th 2013 +Version: 1.0.5 - Released: September 20th 2013 By Richard Davey, [Photon Storm](http://www.photonstorm.com) @@ -35,7 +35,7 @@ Phaser is everything we ever wanted from an HTML5 game framework. It will power Change Log ---------- -Version 1.0.5 (In progress) +Version 1.0.5 (September 20th 2013) * Fixed issue in FrameData.getFrameIndexes where the input array was being ignored. * Added Math.numberArray - Returns an Array containing the numbers from min to max (inclusive), useful for animation frame construction. @@ -44,6 +44,15 @@ Version 1.0.5 (In progress) * Added Group.length property. * Added explicit x/y attributes to Phaser.Text to make it work with the camera system (thanks cocoademon). * Fixed issue stopping multiple animations from playing, only the most recent would play (frames array was being overwritten, thanks Legrandk) +* Updated Debug.renderSpriteBounds() so it doesn't use the deprecated Sprite.worldView any more (thanks MikeMnD) +* Added 2 new properties to the Text object: Text.text and Text.style, both are getter/setters and don't flag dirty unless changed, so safe for core loop use. +* Removed the exists check from Group.callAll, it now runs on all children (as the name implies) +* Added Group.callAllExists - you can now call a function on all children who have exists = the provided boolean. +* Finished off the Breakout example game - now fully playable, proper rebound, scoring, lives, etc. +* Removed Group.sort dummy entry until it's working. +* Removed ArcadePhysics.postUpdate. +* Updated Sprite.update to set renderable to false when the object goes out of Camera, not 'visible' false, otherwise it stops the transform being updated by Pixi. +* BUG: There is a known issue where the wrong rect coordinates are given to the QuadTree if the Sprite is a child of a Group or another Sprite which has an x/y offset. Version 1.0.4 (September 18th 2013) diff --git a/examples/assets/sprites/breakout.json b/examples/assets/sprites/breakout.json deleted file mode 100644 index a21b339d6..000000000 --- a/examples/assets/sprites/breakout.json +++ /dev/null @@ -1,236 +0,0 @@ -{"frames": [ - -{ - "filename": "ball_1.png", - "frame": {"x":218,"y":38,"w":16,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":16,"h":16}, - "sourceSize": {"w":16,"h":16} -}, -{ - "filename": "ball_2.png", - "frame": {"x":218,"y":20,"w":16,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":16,"h":16}, - "sourceSize": {"w":16,"h":16} -}, -{ - "filename": "ball_3.png", - "frame": {"x":218,"y":2,"w":16,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":16,"h":16}, - "sourceSize": {"w":16,"h":16} -}, -{ - "filename": "ball_4.png", - "frame": {"x":200,"y":38,"w":16,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":16,"h":16}, - "sourceSize": {"w":16,"h":16} -}, -{ - "filename": "ball_5.png", - "frame": {"x":200,"y":20,"w":16,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":16,"h":16}, - "sourceSize": {"w":16,"h":16} -}, -{ - "filename": "brick_1_1.png", - "frame": {"x":98,"y":21,"w":32,"h":17}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":32,"h":17}, - "sourceSize": {"w":32,"h":17} -}, -{ - "filename": "brick_1_2.png", - "frame": {"x":98,"y":2,"w":32,"h":17}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":32,"h":17}, - "sourceSize": {"w":32,"h":17} -}, -{ - "filename": "brick_1_3.png", - "frame": {"x":270,"y":17,"w":30,"h":13}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":1,"y":1,"w":30,"h":13}, - "sourceSize": {"w":32,"h":17} -}, -{ - "filename": "brick_1_4.png", - "frame": {"x":54,"y":52,"w":24,"h":9}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":4,"y":4,"w":24,"h":9}, - "sourceSize": {"w":32,"h":17} -}, -{ - "filename": "brick_2_1.png", - "frame": {"x":236,"y":19,"w":32,"h":15}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":32,"h":15}, - "sourceSize": {"w":32,"h":15} -}, -{ - "filename": "brick_2_2.png", - "frame": {"x":236,"y":2,"w":32,"h":15}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":32,"h":15}, - "sourceSize": {"w":32,"h":15} -}, -{ - "filename": "brick_2_3.png", - "frame": {"x":270,"y":2,"w":30,"h":13}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":1,"y":0,"w":30,"h":13}, - "sourceSize": {"w":32,"h":15} -}, -{ - "filename": "brick_2_4.png", - "frame": {"x":236,"y":50,"w":24,"h":11}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":4,"y":3,"w":24,"h":11}, - "sourceSize": {"w":32,"h":15} -}, -{ - "filename": "brick_3_1.png", - "frame": {"x":166,"y":20,"w":32,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":32,"h":16}, - "sourceSize": {"w":32,"h":16} -}, -{ - "filename": "brick_3_2.png", - "frame": {"x":166,"y":2,"w":32,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":32,"h":16}, - "sourceSize": {"w":32,"h":16} -}, -{ - "filename": "brick_3_3.png", - "frame": {"x":236,"y":36,"w":30,"h":12}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":1,"y":2,"w":30,"h":12}, - "sourceSize": {"w":32,"h":16} -}, -{ - "filename": "brick_3_4.png", - "frame": {"x":28,"y":52,"w":24,"h":10}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":4,"y":3,"w":24,"h":10}, - "sourceSize": {"w":32,"h":16} -}, -{ - "filename": "one.png", - "frame": {"x":66,"y":2,"w":30,"h":48}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":1,"y":16,"w":30,"h":48}, - "sourceSize": {"w":32,"h":64} -}, -{ - "filename": "paddle_big.png", - "frame": {"x":98,"y":40,"w":48,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":48,"h":16}, - "sourceSize": {"w":48,"h":16} -}, -{ - "filename": "paddle_small.png", - "frame": {"x":148,"y":38,"w":32,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":32,"h":16}, - "sourceSize": {"w":32,"h":16} -}, -{ - "filename": "power_down.png", - "frame": {"x":200,"y":2,"w":16,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":16,"h":16}, - "sourceSize": {"w":16,"h":16} -}, -{ - "filename": "power_up.png", - "frame": {"x":182,"y":38,"w":16,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":16,"h":16}, - "sourceSize": {"w":16,"h":16} -}, -{ - "filename": "brick_4_1.png", - "frame": {"x":132,"y":20,"w":32,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":32,"h":16}, - "sourceSize": {"w":32,"h":16} -}, -{ - "filename": "brick_4_2.png", - "frame": {"x":132,"y":2,"w":32,"h":16}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":32,"h":16}, - "sourceSize": {"w":32,"h":16} -}, -{ - "filename": "brick_4_3.png", - "frame": {"x":270,"y":32,"w":30,"h":12}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":1,"y":2,"w":30,"h":12}, - "sourceSize": {"w":32,"h":16} -}, -{ - "filename": "brick_4_4.png", - "frame": {"x":2,"y":52,"w":24,"h":10}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":4,"y":3,"w":24,"h":10}, - "sourceSize": {"w":32,"h":16} -}, -{ - "filename": "three.png", - "frame": {"x":34,"y":2,"w":30,"h":48}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":1,"y":0,"w":30,"h":48}, - "sourceSize": {"w":32,"h":48} -}, -{ - "filename": "two.png", - "frame": {"x":2,"y":2,"w":30,"h":48}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":1,"y":16,"w":30,"h":48}, - "sourceSize": {"w":32,"h":64} -}], -"meta": { - "app": "http://www.texturepacker.com", - "version": "1.0", - "image": "breakout.png", - "format": "RGBA8888", - "size": {"w":302,"h":64}, - "scale": "1", - "smartupdate": "$TexturePacker:SmartUpdate:c510ff2f709e8d175b059cd1cbe64773$" -} -} diff --git a/examples/assets/sprites/breakout.png b/examples/assets/sprites/breakout.png deleted file mode 100644 index 85f75c82f5a72b37c55f734d54966f902571fc1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2423 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 diff --git a/examples/collision/bounding box.php b/examples/collision/bounding box.php index 3ae50f31c..f42acaf5b 100644 --- a/examples/collision/bounding box.php +++ b/examples/collision/bounding box.php @@ -55,8 +55,11 @@ function render() { - game.debug.renderRectangle(sprite1.body); - game.debug.renderRectangle(sprite2.body); + game.debug.renderSpriteInfo(sprite1, 32, 32); + game.debug.renderSpriteCollision(sprite1, 32, 400); + + game.debug.renderSpriteBody(sprite1); + game.debug.renderSpriteBody(sprite2); } diff --git a/examples/games/breakout.php b/examples/games/breakout.php index d1a1df8e8..be67307e0 100644 --- a/examples/games/breakout.php +++ b/examples/games/breakout.php @@ -7,21 +7,37 @@ (function () { - var game = new Phaser.Game(800, 600, Phaser.CANVAS, '', { preload: preload, create: create, update: update, render: render }); + var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: preload, create: create, update: update }); function preload() { - game.load.atlas('breakout', 'assets/sprites/breakout.png', 'assets/sprites/breakout.json'); + game.load.atlas('breakout', 'assets/games/breakout/breakout.png', 'assets/games/breakout/breakout.json'); + game.load.image('starfield', 'assets/misc/starfield.jpg'); } var ball; var paddle; var bricks; + var ballOnPaddle = true; + var lives = 3; + var score = 0; + + var scoreText; + var livesText; + var introText; + + var s; + function create() { + // We do this so the ball can still rebound with the world bounds, but it will look like it has gone off the bottom of the screen + game.world.height = 620; + + s = game.add.tileSprite(0, 0, 800, 600, 'starfield'); + var brick; bricks = game.add.group(); @@ -35,15 +51,22 @@ } } - ball = game.add.sprite(game.world.centerX, 534, 'breakout', 'ball_1.png'); + paddle = game.add.sprite(game.world.centerX, 500, 'breakout', 'paddle_big.png'); + paddle.anchor.setTo(0.5, 0.5); + paddle.body.collideWorldBounds = true; + paddle.body.bounce.setTo(1, 1); + paddle.body.immovable = true; + + ball = game.add.sprite(game.world.centerX, paddle.y - 16, 'breakout', 'ball_1.png'); + ball.anchor.setTo(0.5, 0.5); ball.body.collideWorldBounds = true; ball.body.bounce.setTo(1, 1); ball.animations.add('spin', [ 'ball_1.png', 'ball_2.png', 'ball_3.png', 'ball_4.png', 'ball_5.png' ], 50, true, false); - paddle = game.add.sprite(game.world.centerX, 550, 'breakout', 'paddle_big.png'); - paddle.body.collideWorldBounds = true; - paddle.body.bounce.setTo(1, 1); - paddle.body.immovable = true; + scoreText = game.add.text(32, 550, 'score: 0', { font: "20px Arial", fill: "#ffffff", align: "left" }); + livesText = game.add.text(680, 550, 'lives: 3', { font: "20px Arial", fill: "#ffffff", align: "left" }); + introText = game.add.text(game.world.centerX, 400, '- click to start -', { font: "40px Arial", fill: "#ffffff", align: "center" }); + introText.anchor.setTo(0.5, 0.5); game.input.onDown.add(releaseBall, this); @@ -51,36 +74,133 @@ function update () { + // Fun, but a little sea-sick inducing :) Uncomment if you like! + // s.tilePosition.x += (game.input.speed.x / 2); + paddle.x = game.input.x; + if (paddle.x < 24) + { + paddle.x = 24; + } + else if (paddle.x > game.width - 24) + { + paddle.x = game.width - 24; + } + if (ballOnPaddle) { - ball.x = paddle.x + 16; + ball.x = paddle.x; } else { - game.physics.collide(paddle, ball); + game.physics.collide(ball, paddle, ballHitPaddle, null, this); game.physics.collide(ball, bricks, ballHitBrick, null, this); } + // Out? + if (ball.y > 600 && ballOnPaddle == false) + { + ballLost(); + } + } function releaseBall () { - ballOnPaddle = false; - ball.body.velocity.y = -300; - ball.body.velocity.x = -75; - ball.animations.play('spin'); + if (ballOnPaddle) + { + ballOnPaddle = false; + ball.body.velocity.y = -300; + ball.body.velocity.x = -75; + ball.animations.play('spin'); + introText.visible = false; + } } + function ballLost () { + + lives--; + + if (lives == 0) + { + gameOver(); + } + else + { + livesText.text = 'lives: ' + lives; + ballOnPaddle = true; + ball.body.velocity.setTo(0, 0); + ball.x = paddle.x + 16; + ball.y = paddle.y - 16; + ball.animations.stop(); + } + + } + + function gameOver () { + + ball.body.velocity.setTo(0, 0); + + introText.text = "Game Over!"; + introText.visible = true; + + } + + function ballHitBrick (_ball, _brick) { _brick.kill(); + score += 10; + + scoreText.text = 'score: ' + score; + + // Are they any bricks left? + if (bricks.countLiving() == 0) + { + // New level starts + score += 1000; + scoreText.text = 'score: ' + score; + introText = '- Next Level -'; + + // Let's move the ball back to the paddle + ballOnPaddle = true; + ball.body.velocity.setTo(0, 0); + ball.x = paddle.x + 16; + ball.y = paddle.y - 16; + ball.animations.stop(); + + // And bring the bricks back from the dead :) + bricks.callAll('revive', this); + } + } - function render () { + function ballHitPaddle (_ball, _paddle) { + + var diff = 0; + + if (_ball.x < _paddle.x) + { + // Ball is on the left-hand side of the paddle + diff = _paddle.x - _ball.x; + _ball.body.velocity.x = (-10 * diff); + } + else if (_ball.x > _paddle.x) + { + // Ball is on the right-hand side of the paddle + diff = _ball.x -_paddle.x; + _ball.body.velocity.x = (10 * diff); + } + else + { + // Ball is perfectly in the middle + // Add a little random X to stop it bouncing straight up! + _ball.body.velocity.x = 2 + Math.random() * 8; + } + } })(); diff --git a/examples/games/invaders.php b/examples/games/invaders.php new file mode 100644 index 000000000..0499acffe --- /dev/null +++ b/examples/games/invaders.php @@ -0,0 +1,140 @@ + + + + + diff --git a/examples/tile sprites/tilesprite2.php b/examples/tile sprites/tilesprite2.php index 61153cbaa..5b90b0fe4 100644 --- a/examples/tile sprites/tilesprite2.php +++ b/examples/tile sprites/tilesprite2.php @@ -12,11 +12,11 @@ var s; function preload() { - game.load.image('disk', 'assets/misc/starfield.jpg'); + game.load.image('starfield', 'assets/misc/starfield.jpg'); } function create() { - s = game.add.tileSprite(0, 0, 800, 600, 'disk'); + s = game.add.tileSprite(0, 0, 800, 600, 'starfield'); } function update() { diff --git a/src/core/Group.js b/src/core/Group.js index f8b0ca359..8b1dfcee3 100644 --- a/src/core/Group.js +++ b/src/core/Group.js @@ -273,54 +273,6 @@ Phaser.Group.prototype = { }, - /** - * Call this function to sort the group according to a particular value and order. - * For example, to sort game objects for Zelda-style overlaps you might call - * myGroup.sort("y",Group.ASCENDING) at the bottom of your - * State.update() override. To sort all existing objects after - * a big explosion or bomb attack, you might call myGroup.sort("exists",Group.DESCENDING). - * - * @param {string} index The string name of the member variable you want to sort on. Default value is "z". - * @param {number} order A Group constant that defines the sort order. Possible values are Group.ASCENDING and Group.DESCENDING. Default value is Group.ASCENDING. - */ - - // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.c - - sort: function (index, order) { - // if (typeof index === "undefined") { index = 'z'; } - // if (typeof order === "undefined") { order = Phaser.Types.SORT_ASCENDING; } - // var _this = this; - // this._sortIndex = index; - // this._sortOrder = order; - // this.members.sort(function (a, b) { - // return _this.sortHandler(a, b); - // }); - }, - - /** - * Helper function for the sort process. - * - * @param {Basic} Obj1 The first object being sorted. - * @param {Basic} Obj2 The second object being sorted. - * - * @return {number} An integer value: -1 (Obj1 before Obj2), 0 (same), or 1 (Obj1 after Obj2). - */ - sortHandler: function (obj1, obj2) { - - /* - if (!obj1 || !obj2) { - //console.log('null objects in sort', obj1, obj2); - return 0; - } - if (obj1[this._sortIndex] < obj2[this._sortIndex]) { - return this._sortOrder; - } else if (obj1[this._sortIndex] > obj2[this._sortIndex]) { - return -this._sortOrder; - } - return 0; - */ - }, - // key is an ARRAY of values. setProperty: function (child, key, value, operation) { @@ -424,8 +376,31 @@ Phaser.Group.prototype = { }, + callAllExists: function (callback, callbackContext, existsValue) { + + var args = Array.prototype.splice.call(arguments, 3); + + if (this._container.children.length > 0 && this._container.first._iNext) + { + var currentNode = this._container.first._iNext; + + do + { + if (currentNode.exists == existsValue && currentNode[callback]) + { + currentNode[callback].apply(currentNode, args); + } + + currentNode = currentNode._iNext; + } + while (currentNode != this._container.last._iNext) + + } + + }, + /** - * Calls a function on all of the active children (children with exists=true). + * Calls a function on all of the children regardless if they are dead or alive (see callAllExists if you need control over that) * You must pass the context in which the callback is applied. * After the context you can add as many parameters as you like, which will all be passed to the child. */ @@ -439,7 +414,7 @@ Phaser.Group.prototype = { do { - if (currentNode.exists && currentNode[callback]) + if (currentNode[callback]) { currentNode[callback].apply(currentNode, args); } diff --git a/src/gameobjects/Sprite.js b/src/gameobjects/Sprite.js index 55e6aa759..d3fdb6dff 100644 --- a/src/gameobjects/Sprite.js +++ b/src/gameobjects/Sprite.js @@ -214,6 +214,7 @@ Phaser.Sprite.prototype.preUpdate = function() { this._cache.y = this.y - (this.game.world.camera.y * this.scrollFactor.y); // If this sprite or the camera have moved then let's update everything + // Note: The actual position shouldn't be changed if this item is inside a Group? if (this.position.x != this._cache.x || this.position.y != this._cache.y) { this.position.x = this._cache.x; @@ -224,76 +225,77 @@ Phaser.Sprite.prototype.preUpdate = function() { if (this.visible) { this.renderOrderID = this.game.world.currentRenderOrderID++; - - // |a c tx| - // |b d ty| - // |0 0 1| - - // Only update the values we need - if (this.worldTransform[0] != this._cache.a00 || this.worldTransform[1] != this._cache.a01) - { - this._cache.a00 = this.worldTransform[0]; // scaleX a - this._cache.a01 = this.worldTransform[1]; // skewY c - this._cache.i01 = this.worldTransform[1]; // skewY c - this._cache.scaleX = Math.sqrt((this._cache.a00 * this._cache.a00) + (this._cache.a01 * this._cache.a01)); // round this off a bit? - this._cache.a01 *= -1; - this._cache.dirty = true; - } - - // Need to test, but probably highly unlikely that a scaleX would happen without effecting the Y skew - if (this.worldTransform[3] != this._cache.a10 || this.worldTransform[4] != this._cache.a11) - { - this._cache.a10 = this.worldTransform[3]; // skewX b - this._cache.i10 = this.worldTransform[3]; // skewX b - this._cache.a11 = this.worldTransform[4]; // scaleY d - this._cache.scaleY = Math.sqrt((this._cache.a10 * this._cache.a10) + (this._cache.a11 * this._cache.a11)); // round this off a bit? - this._cache.a10 *= -1; - 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; - } - - // Frame updated? - if (this.currentFrame.uuid != this._cache.frameID) - { - 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._cache.width = Math.floor(this.currentFrame.sourceSizeW * this._cache.scaleX); - this._cache.height = Math.floor(this.currentFrame.sourceSizeH * this._cache.scaleY); - 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.updateBounds(); - } } - else + + // |a c tx| + // |b d ty| + // |0 0 1| + + // Only update the values we need + if (this.worldTransform[0] != this._cache.a00 || this.worldTransform[1] != this._cache.a01) { + this._cache.a00 = this.worldTransform[0]; // scaleX a + this._cache.a01 = this.worldTransform[1]; // skewY c + this._cache.i01 = this.worldTransform[1]; // skewY c + this._cache.scaleX = Math.sqrt((this._cache.a00 * this._cache.a00) + (this._cache.a01 * this._cache.a01)); // round this off a bit? + this._cache.a01 *= -1; + this._cache.dirty = true; + } + + // Need to test, but probably highly unlikely that a scaleX would happen without effecting the Y skew + if (this.worldTransform[3] != this._cache.a10 || this.worldTransform[4] != this._cache.a11) + { + this._cache.a10 = this.worldTransform[3]; // skewX b + this._cache.i10 = this.worldTransform[3]; // skewX b + this._cache.a11 = this.worldTransform[4]; // scaleY d + this._cache.scaleY = Math.sqrt((this._cache.a10 * this._cache.a10) + (this._cache.a11 * this._cache.a11)); // round this off a bit? + this._cache.a10 *= -1; + 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; + } + + // Frame updated? + if (this.currentFrame.uuid != this._cache.frameID) + { + 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._cache.width = Math.floor(this.currentFrame.sourceSizeW * this._cache.scaleX); + this._cache.height = Math.floor(this.currentFrame.sourceSizeH * this._cache.scaleY); + 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.updateBounds(); + } + // } + // else + // { // We still need to work out the bounds in case the camera has moved // but we can't use the local or worldTransform to do it, as Pixi resets that if a Sprite is invisible. // So we'll compare against the cached state + new position. - if (this._cache.dirty && this.visible == false) - { - this.bounds.x -= this._cache.boundsX - this._cache.x; - this._cache.boundsX = this._cache.x; + // if (this._cache.dirty && this.visible == false) + // { + // this.bounds.x -= this._cache.boundsX - this._cache.x; + // this._cache.boundsX = this._cache.x; - this.bounds.y -= this._cache.boundsY - this._cache.y; - this._cache.boundsY = this._cache.y; - } - } + // this.bounds.y -= this._cache.boundsY - this._cache.y; + // this._cache.boundsY = this._cache.y; + // } + // } // Re-run the camera visibility check if (this._cache.dirty) @@ -302,7 +304,8 @@ Phaser.Sprite.prototype.preUpdate = function() { if (this.autoCull == true) { - this.visible = this._cache.cameraVisible; + // Won't get rendered but will still get its transform updated + this.renderable = this._cache.cameraVisible; } // Update our physics bounds @@ -313,6 +316,15 @@ Phaser.Sprite.prototype.preUpdate = function() { } +Phaser.Sprite.prototype.postUpdate = function() { + + if (this.exists) + { + this.body.postUpdate(); + } + +} + /** * Moves the sprite so its center is located on the given x and y coordinates. * Doesn't change the origin of the sprite. diff --git a/src/gameobjects/Text.js b/src/gameobjects/Text.js index 8c195b2f4..092143eb1 100644 --- a/src/gameobjects/Text.js +++ b/src/gameobjects/Text.js @@ -17,6 +17,9 @@ Phaser.Text = function (game, x, y, text, style) { this.game = game; + this._text = text; + this._style = style; + PIXI.Text.call(this, text, style); this.type = Phaser.TEXT; @@ -91,3 +94,40 @@ Object.defineProperty(Phaser.Text.prototype, 'angle', { }); +Object.defineProperty(Phaser.Text.prototype, 'text', { + + get: function() { + return this._text; + }, + + set: function(value) { + + // Let's not update unless needed, this way we can safely update the text in a core loop without constant re-draws + if (value !== this._text) + { + this._text = value; + this.dirty = true; + } + + } + +}); + +Object.defineProperty(Phaser.Text.prototype, 'style', { + + get: function() { + return this._style; + }, + + set: function(value) { + + // Let's not update unless needed, this way we can safely update the text in a core loop without constant re-draws + if (value !== this._style) + { + this._style = value; + this.dirty = true; + } + + } + +}); diff --git a/src/physics/arcade/Body.js b/src/physics/arcade/Body.js index c46d7d75a..d961946e6 100644 --- a/src/physics/arcade/Body.js +++ b/src/physics/arcade/Body.js @@ -7,6 +7,8 @@ Phaser.Physics.Arcade.Body = function (sprite) { this.x = sprite.x; this.y = sprite.y; + this.lastX = sprite.x; + this.lastY = sprite.y; // un-scaled original size this.sourceWidth = sprite.currentFrame.sourceSizeW; @@ -62,9 +64,6 @@ Phaser.Physics.Arcade.Body = function (sprite) { this.collideWorldBounds = false; - this.lastX = sprite.x; - this.lastY = sprite.y; - }; Phaser.Physics.Arcade.Body.prototype = { @@ -102,8 +101,11 @@ Phaser.Physics.Arcade.Body.prototype = { this.lastY = this.y; this.rotation = this.sprite.angle; + // There is a bug here in that the worldTransform values are what should be used, otherwise the quadTree gets the wrong rect given to it this.x = (this.sprite.x - (this.sprite.anchor.x * this.width)) + this.offset.x; this.y = (this.sprite.y - (this.sprite.anchor.y * this.height)) + this.offset.y; + // this.x = (this.sprite.worldTransform[2] - (this.sprite.anchor.x * this.width)) + this.offset.x; + // this.y = (this.sprite.worldTransform[5] - (this.sprite.anchor.y * this.height)) + this.offset.y; if (this.moves) { @@ -122,6 +124,16 @@ Phaser.Physics.Arcade.Body.prototype = { this.game.physics.quadTree.insert(this); } + if (this.deltaX() != 0) + { + this.sprite.x -= this.deltaX(); + } + + if (this.deltaY() != 0) + { + this.sprite.y -= this.deltaY(); + } + // Adjust the sprite based on all of the above, so the x/y coords will be correct going into the State update this.sprite.x = this.x - this.offset.x + (this.sprite.anchor.x * this.width); this.sprite.y = this.y - this.offset.y + (this.sprite.anchor.y * this.height); diff --git a/src/utils/Debug.js b/src/utils/Debug.js index 5b5bc9e4d..b197927e9 100644 --- a/src/utils/Debug.js +++ b/src/utils/Debug.js @@ -119,6 +119,14 @@ Phaser.Utils.Debug.prototype = { this.context.strokeStyle = color; this.context.strokeRect(bounds.x, bounds.y, bounds.width, bounds.height); this.renderText(quadtree.ID + ' / ' + quadtree.objects.length, bounds.x + 4, bounds.y + 16, 'rgb(0,200,0)', '12px Courier'); + + this.context.strokeStyle = 'rgb(0,255,0)'; + + // children + for (var i = 0; i < quadtree.objects.length; i++) + { + this.context.strokeRect(quadtree.objects[i].x, quadtree.objects[i].y, quadtree.objects[i].width, quadtree.objects[i].height); + } } else { @@ -374,6 +382,7 @@ Phaser.Utils.Debug.prototype = { this.line('x: ' + sprite.x.toFixed(1) + ' y: ' + sprite.y.toFixed(1) + ' rotation: ' + sprite.rotation.toFixed(1)); this.line('visible: ' + sprite.visible); this.line('in camera: ' + sprite.inCamera); + this.line('body x: ' + sprite.body.x.toFixed(1) + ' y: ' + sprite.body.y.toFixed(1)); // 0 = scaleX // 1 = skewY @@ -382,7 +391,6 @@ Phaser.Utils.Debug.prototype = { // 4 = scaleY // 5 = translateY - // this.line('id: ' + sprite._id); // this.line('scale x: ' + sprite.worldTransform[0]); // this.line('scale y: ' + sprite.worldTransform[4]); @@ -390,6 +398,8 @@ Phaser.Utils.Debug.prototype = { // this.line('ty: ' + sprite.worldTransform[5]); // this.line('skew x: ' + sprite.worldTransform[3]); // this.line('skew y: ' + sprite.worldTransform[1]); + // this.line('dx: ' + sprite.body.deltaX()); + // this.line('dy: ' + sprite.body.deltaY()); // this.line('inCamera: ' + this.game.renderer.spriteRenderer.inCamera(this.game.camera, sprite)); @@ -454,18 +464,48 @@ Phaser.Utils.Debug.prototype = { }, - renderSpriteBounds: function (sprite, color) { + renderSpriteBody: function (sprite, color) { if (this.context == null) { return; } - color = color || 'rgba(0, 255, 0, 0.2)'; + color = color || 'rgba(255,0,255, 0.3)'; + + this.start(0, 0, color); - this.start(); this.context.fillStyle = color; - this.context.fillRect(sprite.worldView.x, sprite.worldView.y, sprite.worldView.width, sprite.worldView.height); + // this.context.fillRect(sprite.body.x - sprite.body.deltaX(), sprite.body.y - sprite.body.deltaY(), sprite.body.width, sprite.body.height); + this.context.fillRect(sprite.body.x, sprite.body.y, sprite.body.width, sprite.body.height); + + this.stop(); + + }, + + renderSpriteBounds: function (sprite, color, fill) { + + if (this.context == null) + { + return; + } + + color = color || 'rgb(255,0,255)'; + + this.start(0, 0, color); + + if (fill) + { + this.context.fillStyle = color; + this.context.fillRect(sprite.bounds.x, sprite.bounds.y, sprite.bounds.width, sprite.bounds.height); + } + else + { + this.context.strokeStyle = color; + this.context.strokeRect(sprite.bounds.x, sprite.bounds.y, sprite.bounds.width, sprite.bounds.height); + this.context.stroke(); + } + this.stop(); },