From 18c695e9ddc4d62e47cf5c01824b30bce69daa7c Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 27 Sep 2013 09:57:08 +0100 Subject: [PATCH] PixiPatch and other 1.0.7 features --- README.md | 10 ++ examples/input/follow mouse.php | 53 ++++++++ src/PixiPatch.js | 230 ++++++++++++++++++++++++++++++++ src/animation/Animation.js | 102 ++++++++++++-- src/animation/Parser.js | 24 ++-- src/gameobjects/Button.js | 2 +- src/gameobjects/Sprite.js | 4 +- src/gameobjects/Text.js | 8 +- src/sound/Sound.js | 2 +- src/utils/Utils.js | 4 +- 10 files changed, 413 insertions(+), 26 deletions(-) create mode 100644 examples/input/follow mouse.php create mode 100644 src/PixiPatch.js diff --git a/README.md b/README.md index 57576c330..00c900a44 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,19 @@ Version 1.0.7 (in progress in the dev branch) * Updated ArcadePhysics.separateX/Y to use new body system - much better results now. * QuadTree bug found in 1.0.5 now fixed. The QuadTree is updated properly now using worldTransform values. * Fixed the Bounce.In and Bounce.InOut tweens (thanks XekeDeath) +* Renamed Phaser.Text.text to Phaser.Text.content to avoid conflict and overwrite from Pixi local var. +* Renamed Phaser.Text.style to Phaser.Text.font to avoid conflict and overwrite from Pixi local var. +* Phaser.Button now sets useHandCursor to true by default. +* Fixed an issue in Animation.update where if the game was paused it would get an insane delta timer throwing a uuid error. +* Added PixiPatch.js to patch in a few essential features until Pixi is updated. +* Fixed issue in Animation.play where the given frameRate and loop values wouldn't overwrite those set on construction. +* Added Animation.paused - can be set to true/false. +* New: Phaser.Animation.generateFrameNames - really useful when creating animation data from texture atlases using file names, not indexes. + * TODO: addMarker hh:mm:ss:ms * TODO: Direction constants +* TODO: Camera will adjust core DO. Means scrollFactor will need to be dropped sadly, but there are other ways to emulate its effect. Version 1.0.6 (September 24th 2013) diff --git a/examples/input/follow mouse.php b/examples/input/follow mouse.php new file mode 100644 index 000000000..67e480d08 --- /dev/null +++ b/examples/input/follow mouse.php @@ -0,0 +1,53 @@ + + + + + \ No newline at end of file diff --git a/src/PixiPatch.js b/src/PixiPatch.js new file mode 100644 index 000000000..c1bfe366e --- /dev/null +++ b/src/PixiPatch.js @@ -0,0 +1,230 @@ +/** + * We're replacing a couple of Pixi's methods here to fix or add some vital functionality: + * + * 1) Added support for Trimmed sprite sheets + * 2) Skip display objects with an alpha of zero + * + * Hopefully we can remove this once Pixi has been updated to support these things. + */ + +PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) +{ + // no loger recurrsive! + var transform; + var context = this.context; + + context.globalCompositeOperation = 'source-over'; + + // one the display object hits this. we can break the loop + var testObject = displayObject.last._iNext; + displayObject = displayObject.first; + + do + { + transform = displayObject.worldTransform; + + if(!displayObject.visible) + { + displayObject = displayObject.last._iNext; + continue; + } + + if(!displayObject.renderable || displayObject.alpha == 0) + { + displayObject = displayObject._iNext; + continue; + } + + if(displayObject instanceof PIXI.Sprite) + { + var frame = displayObject.texture.frame; + + if(frame) + { + context.globalAlpha = displayObject.worldAlpha; + + if (displayObject.texture.trimmed) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2] + displayObject.texture.trim.x, transform[5] + displayObject.texture.trim.y); + } + else + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); + } + + context.drawImage(displayObject.texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + (displayObject.anchor.x) * -frame.width, + (displayObject.anchor.y) * -frame.height, + frame.width, + frame.height); + } + } + else if(displayObject instanceof PIXI.Strip) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + this.renderStrip(displayObject); + } + else if(displayObject instanceof PIXI.TilingSprite) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + this.renderTilingSprite(displayObject); + } + else if(displayObject instanceof PIXI.CustomRenderable) + { + displayObject.renderCanvas(this); + } + else if(displayObject instanceof PIXI.Graphics) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + PIXI.CanvasGraphics.renderGraphics(displayObject, context); + } + else if(displayObject instanceof PIXI.FilterBlock) + { + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } + } + // count++ + displayObject = displayObject._iNext; + + + } + while(displayObject != testObject) + +} + +PIXI.WebGLBatch.prototype.update = function() +{ + var gl = this.gl; + var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, index2, index3 + + var a, b, c, d, tx, ty; + + var indexRun = 0; + + var displayObject = this.head; + + while(displayObject) + { + if(displayObject.vcount === PIXI.visibleCount) + { + width = displayObject.texture.frame.width; + height = displayObject.texture.frame.height; + + // TODO trim?? + aX = displayObject.anchor.x;// - displayObject.texture.trim.x + aY = displayObject.anchor.y; //- displayObject.texture.trim.y + w0 = width * (1-aX); + w1 = width * -aX; + + h0 = height * (1-aY); + h1 = height * -aY; + + index = indexRun * 8; + + worldTransform = displayObject.worldTransform; + + a = worldTransform[0]; + b = worldTransform[3]; + c = worldTransform[1]; + d = worldTransform[4]; + tx = worldTransform[2]; + ty = worldTransform[5]; + + if (displayObject.texture.trimmed) + { + tx += displayObject.texture.trim.x; + ty += displayObject.texture.trim.y; + } + + this.verticies[index + 0 ] = a * w1 + c * h1 + tx; + this.verticies[index + 1 ] = d * h1 + b * w1 + ty; + + this.verticies[index + 2 ] = a * w0 + c * h1 + tx; + this.verticies[index + 3 ] = d * h1 + b * w0 + ty; + + this.verticies[index + 4 ] = a * w0 + c * h0 + tx; + this.verticies[index + 5 ] = d * h0 + b * w0 + ty; + + this.verticies[index + 6] = a * w1 + c * h0 + tx; + this.verticies[index + 7] = d * h0 + b * w1 + ty; + + if(displayObject.updateFrame || displayObject.texture.updateFrame) + { + this.dirtyUVS = true; + + var texture = displayObject.texture; + + var frame = texture.frame; + var tw = texture.baseTexture.width; + var th = texture.baseTexture.height; + + this.uvs[index + 0] = frame.x / tw; + this.uvs[index +1] = frame.y / th; + + this.uvs[index +2] = (frame.x + frame.width) / tw; + this.uvs[index +3] = frame.y / th; + + this.uvs[index +4] = (frame.x + frame.width) / tw; + this.uvs[index +5] = (frame.y + frame.height) / th; + + this.uvs[index +6] = frame.x / tw; + this.uvs[index +7] = (frame.y + frame.height) / th; + + displayObject.updateFrame = false; + } + + // TODO this probably could do with some optimisation.... + if(displayObject.cacheAlpha != displayObject.worldAlpha) + { + displayObject.cacheAlpha = displayObject.worldAlpha; + + var colorIndex = indexRun * 4; + this.colors[colorIndex] = this.colors[colorIndex + 1] = this.colors[colorIndex + 2] = this.colors[colorIndex + 3] = displayObject.worldAlpha; + this.dirtyColors = true; + } + } + else + { + index = indexRun * 8; + + this.verticies[index + 0 ] = 0; + this.verticies[index + 1 ] = 0; + + this.verticies[index + 2 ] = 0; + this.verticies[index + 3 ] = 0; + + this.verticies[index + 4 ] = 0; + this.verticies[index + 5 ] = 0; + + this.verticies[index + 6] = 0; + this.verticies[index + 7] = 0; + } + + indexRun++; + displayObject = displayObject.__next; + } +} diff --git a/src/animation/Animation.js b/src/animation/Animation.js index a5e8d2713..4604a99a6 100644 --- a/src/animation/Animation.js +++ b/src/animation/Animation.js @@ -72,6 +72,19 @@ Phaser.Animation = function (game, parent, name, frameData, frames, delay, loope */ this.isPlaying = false; + /** + * @property {boolean} isPaused - The paused state of the Animation. + * @default + */ + this.isPaused = false; + + /** + * @property {boolean} _pauseStartTime - The time the animation paused. + * @private + * @default + */ + this._pauseStartTime = 0; + /** * @property {number} _frameIndex * @private @@ -101,18 +114,15 @@ Phaser.Animation.prototype = { */ play: function (frameRate, loop) { - frameRate = frameRate || null; - loop = loop || null; - - if (frameRate !== null) + if (typeof frameRate === 'number') { + // If they set a new frame rate then use it, otherwise use the one set on creation this.delay = 1000 / frameRate; - // this.delay = frameRate; } - if (loop !== null) + if (typeof loop === 'boolean') { - // If they set a new loop value then use it, otherwise use the default set on creation + // If they set a new loop value then use it, otherwise use the one set on creation this.looped = loop; } @@ -182,6 +192,11 @@ Phaser.Animation.prototype = { */ update: function () { + if (this.isPaused) + { + return false; + } + if (this.isPlaying == true && this.game.time.now >= this._timeNextFrame) { this._frameSkip = 1; @@ -210,7 +225,12 @@ Phaser.Animation.prototype = { { this._frameIndex = this._frameIndex - this._frames.length; this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); - this._parent.setTexture(PIXI.TextureCache[this.currentFrame.uuid]); + + if (this.currentFrame) + { + this._parent.setTexture(PIXI.TextureCache[this.currentFrame.uuid]); + } + this._parent.events.onAnimationLoop.dispatch(this._parent, this); } else @@ -266,6 +286,38 @@ Phaser.Animation.prototype = { }; +/** + */ +Object.defineProperty(Phaser.Animation.prototype, "paused", { + + get: function () { + + return this.isPaused; + + }, + + set: function (value) { + + this.isPaused = value; + + if (value) + { + // Paused + this._pauseStartTime = this.game.time.now; + } + else + { + // Un-paused + if (this.isPlaying) + { + this._timeNextFrame = this.game.time.now + this.delay; + } + } + + } + +}); + Object.defineProperty(Phaser.Animation.prototype, "frameTotal", { /** @@ -316,3 +368,37 @@ Object.defineProperty(Phaser.Animation.prototype, "frame", { } }); + +/* + * Really handy function for when you are creating arrays of animation data but it's using frame names and not numbers. + * For example imagine you've got 30 frames named: 'explosion_0001-large' to 'explosion_0030-large' + * You could use this function to generate those by doing: Phaser.Animation.generateFrameNames('explosion_', 1, 30, '-large', 4); + * The zeroPad value dictates how many zeroes to add in front of the numbers (if any) + */ +Phaser.Animation.generateFrameNames = function (prefix, min, max, suffix, zeroPad) { + + if (typeof suffix == 'undefined') { suffix = ''; } + + var output = []; + var frame = ''; + + for (var i = min; i <= max; i++) + { + if (typeof zeroPad == 'number') + { + // str, len, pad, dir + frame = Phaser.Utils.pad(i.toString(), zeroPad, '0', 1); + } + else + { + frame = i.toString(); + } + + frame = prefix + frame + suffix; + + output.push(frame); + } + + return output; + +} \ No newline at end of file diff --git a/src/animation/Parser.js b/src/animation/Parser.js index 0c420392e..46df1d6a8 100644 --- a/src/animation/Parser.js +++ b/src/animation/Parser.js @@ -146,9 +146,11 @@ Phaser.Animation.Parser = { frames[i].spriteSourceSize.h ); - PIXI.TextureCache[uuid].realSize = frames[i].spriteSourceSize; - // PIXI.TextureCache[uuid].realSize = frames[i].sourceSize; - PIXI.TextureCache[uuid].trim.x = 0; + // We had to hack Pixi to get this to work :( + PIXI.TextureCache[uuid].trimmed = true; + PIXI.TextureCache[uuid].trim.x = frames[i].spriteSourceSize.x; + PIXI.TextureCache[uuid].trim.y = frames[i].spriteSourceSize.y; + } } @@ -216,9 +218,11 @@ Phaser.Animation.Parser = { frames[key].spriteSourceSize.h ); - PIXI.TextureCache[uuid].realSize = frames[key].spriteSourceSize; - // PIXI.TextureCache[uuid].realSize = frames[key].sourceSize; - PIXI.TextureCache[uuid].trim.x = 0; + // We had to hack Pixi to get this to work :( + PIXI.TextureCache[uuid].trimmed = true; + PIXI.TextureCache[uuid].trim.x = frames[key].spriteSourceSize.x; + PIXI.TextureCache[uuid].trim.y = frames[key].spriteSourceSize.y; + } i++; @@ -275,7 +279,8 @@ Phaser.Animation.Parser = { }); // Trimmed? - if (frame.frameX.nodeValue != '-0' || frame.frameY.nodeValue != '-0') { + if (frame.frameX.nodeValue != '-0' || frame.frameY.nodeValue != '-0') + { newFrame.setTrim( true, frame.width.nodeValue, @@ -293,7 +298,10 @@ Phaser.Animation.Parser = { h: frame.frameHeight.nodeValue }; - PIXI.TextureCache[uuid].trim.x = 0; + // We had to hack Pixi to get this to work :( + PIXI.TextureCache[uuid].trimmed = true; + PIXI.TextureCache[uuid].trim.x = Math.abs(frame.frameX.nodeValue); + PIXI.TextureCache[uuid].trim.y = Math.abs(frame.frameY.nodeValue); } } diff --git a/src/gameobjects/Button.js b/src/gameobjects/Button.js index 325fee20b..171ed0864 100644 --- a/src/gameobjects/Button.js +++ b/src/gameobjects/Button.js @@ -55,7 +55,7 @@ Phaser.Button = function (game, x, y, key, callback, callbackContext, overFrame, this.onInputUp.add(callback, callbackContext); } - this.input.start(0, false, true); + this.input.start(0, true); // Redirect the input events to here so we can handle animation updates, etc this.events.onInputOver.add(this.onInputOverHandler, this); diff --git a/src/gameobjects/Sprite.js b/src/gameobjects/Sprite.js index 39b499fb7..d10f366a2 100644 --- a/src/gameobjects/Sprite.js +++ b/src/gameobjects/Sprite.js @@ -255,7 +255,7 @@ Phaser.Sprite.prototype.preUpdate = function() { } // Frame updated? - if (this.currentFrame.uuid != this._cache.frameID) + if (this.currentFrame && this.currentFrame.uuid != this._cache.frameID) { this._cache.frameWidth = this.texture.frame.width; this._cache.frameHeight = this.texture.frame.height; @@ -263,7 +263,7 @@ Phaser.Sprite.prototype.preUpdate = function() { this._cache.dirty = true; } - if (this._cache.dirty) + if (this._cache.dirty && this.currentFrame) { this._cache.width = Math.floor(this.currentFrame.sourceSizeW * this._cache.scaleX); this._cache.height = Math.floor(this.currentFrame.sourceSizeH * this._cache.scaleY); diff --git a/src/gameobjects/Text.js b/src/gameobjects/Text.js index 092143eb1..f3ba44729 100644 --- a/src/gameobjects/Text.js +++ b/src/gameobjects/Text.js @@ -94,7 +94,7 @@ Object.defineProperty(Phaser.Text.prototype, 'angle', { }); -Object.defineProperty(Phaser.Text.prototype, 'text', { +Object.defineProperty(Phaser.Text.prototype, 'content', { get: function() { return this._text; @@ -106,14 +106,14 @@ Object.defineProperty(Phaser.Text.prototype, 'text', { if (value !== this._text) { this._text = value; - this.dirty = true; + this.setText(value); } } }); -Object.defineProperty(Phaser.Text.prototype, 'style', { +Object.defineProperty(Phaser.Text.prototype, 'font', { get: function() { return this._style; @@ -125,7 +125,7 @@ Object.defineProperty(Phaser.Text.prototype, 'style', { if (value !== this._style) { this._style = value; - this.dirty = true; + this.setStyle(value); } } diff --git a/src/sound/Sound.js b/src/sound/Sound.js index c4cd3bea5..f466cbfbe 100644 --- a/src/sound/Sound.js +++ b/src/sound/Sound.js @@ -268,7 +268,7 @@ Phaser.Sound.prototype = { if (typeof loop == 'undefined') { loop = false; } if (typeof forceRestart == 'undefined') { forceRestart = false; } - console.log(this.name + ' play ' + marker + ' position ' + position + ' volume ' + volume + ' loop ' + loop); + // console.log(this.name + ' play ' + marker + ' position ' + position + ' volume ' + volume + ' loop ' + loop); if (this.isPlaying == true && forceRestart == false && this.override == false) { diff --git a/src/utils/Utils.js b/src/utils/Utils.js index ed08123ef..8be83b216 100644 --- a/src/utils/Utils.js +++ b/src/utils/Utils.js @@ -13,8 +13,8 @@ Phaser.Utils = { /** - * Javascript string pad - * http://www.webtoolkit.info/ + * Javascript string pad + * http://www.webtoolkit.info/ * pad = the string to pad it out with (defaults to a space) * dir = 1 (left), 2 (right), 3 (both) * @method pad