Sprite.crop (and Image.crop) has been completely overhauled. You can now crop animated sprites (sprite sheet and texture atlas), you can define the x/y crop offset and the crop rectangle is exposed in the Sprite.cropRect property.

Sprite.updateCrop is available if you wish to update an externally referenced crop rectangle.
Sprites and Images now have their own textures objects, they are no longer references to those stored in the global Pixi.TextureCache. This allows you to redefine the texture frame dynamically without messing up any other Sprites in your game, such as via cropping. They still share global Base Textures, so image references are kept to a minimum.
Sprite.resetFrame will revert the Sprites texture frame back to its defaults dimensions. This is called when you call Sprite.crop with no rectangle, to reset the crop effect, but can be userful in other situations so we've left it as a public method.
This commit is contained in:
photonstorm 2014-06-10 23:37:33 +01:00
parent 6d10be6baa
commit 7c7d9153e6
9 changed files with 401 additions and 324 deletions

View file

@ -16,6 +16,7 @@ By Richard Davey, [Photon Storm](http://www.photonstorm.com)
* Read the [documentation online](http://docs.phaser.io)
* Join our [#phaserio IRC channel](http://www.html5gamedevs.com/topic/4470-official-phaserio-irc-channel-phaserio-on-freenode/) on freenode
* Subscribe to the [Phaser Newsletter](https://confirmsubscription.com/h/r/369DE48E3E86AF1E) and we'll email you when new versions are released.
* Please help support our work via [Gittip](https://www.gittip.com/photonstorm/)
![div](http://phaser.io/images/div4.png)
@ -66,6 +67,8 @@ Version 2.0.6 - "Jornhill" - -in development-
* Emitter.start has a new parameter: forceQuantity which will force the quantity of a flow of particles to be the given value (request #853)
* Sound.pause will no longer fire a Sound.onStop signal, and the pause values are set before the onPause signal is dispatched (thanks @AnderbergE, fix #868)
* Swapped to using escaped Unicode characters for the console output.
* Frame.setTrim no longer modifies the Frame width and height values.
* AnimationParser doesn't populate the Pixi.TextureCache for every frame any longer. Each display object has its own texture property instead.
### CocoonJS Specific Updates
@ -93,6 +96,10 @@ Version 2.0.6 - "Jornhill" - -in development-
* Loader.totalLoadedPacks returns the number of Asset Packs already loaded.
* Emitter.explode is a new short-cut for exploding a fixed quantity of particles at once.
* Emitter.flow is a new short-cut for creating a flow of particles based on the given frequency.
* Sprite.crop (and Image.crop) has been completely overhauled. You can now crop animated sprites (sprite sheet and texture atlas), you can define the x/y crop offset and the crop rectangle is exposed in the Sprite.cropRect property.
* Sprite.updateCrop is available if you wish to update an externally referenced crop rectangle.
* Sprites and Images now have their own textures objects, they are no longer references to those stored in the global Pixi.TextureCache. This allows you to redefine the texture frame dynamically without messing up any other Sprites in your game, such as via cropping. They still share global Base Textures, so image references are kept to a minimum.
* Sprite.resetFrame will revert the Sprites texture frame back to its defaults dimensions. This is called when you call Sprite.crop with no rectangle, to reset the crop effect, but can be userful in other situations so we've left it as a public method.
### Bug Fixes
@ -284,14 +291,18 @@ Here are some of the features planned for future releases:
### Version 2.1 ("Shienar")
* Scene Manager - json scene parser.
* Comprehensive testing across Firefox OS devices, CocoonJS and Ejecta.
* Ability to control DOM elements from the core game and layer them into the game.
* Touch Gestures.
* Optimised global Animation manager to cut down on object creation.
* Swapping to using a RenderTexture for the Tilemaps and implementing Tilemap slicing.
* Enhance the State Management, so you can perform non-destructive State swaps and persistence.
* Support for parallel asset loading.
### Version 2.2 ("Tarabon")
* Enhance the State Management, so you can perform non-destructive State swaps and persistence.
* Support for parallel asset loading.
* Look carefully at the internal structure of Phaser to avoid method repetition (such as Sprite.crop and Image.crop), investigate using mixins to help reduce overall codebase size.
* Flash CC HTML5 export integration.
* Massively enhance the audio side of Phaser. Take more advantage of Web Audio: echo effects, positional sound, etc.

13
build/phaser.d.ts vendored
View file

@ -2240,6 +2240,7 @@ declare module Phaser {
anchor: Phaser.Point;
autoCull: boolean;
cameraOffset: Phaser.Point;
cropRect: Phaser.Rectangle;
deltaX: number;
deltaY: number;
deltaZ: number;
@ -2264,16 +2265,18 @@ declare module Phaser {
z: number;
bringToTop(): Phaser.Image;
crop(rect: Phaser.Rectangle): void;
crop(rect: Object): void;
crop(rect: Phaser.Rectangle, copy: boolean): void;
destroy(destroyChildren?: boolean): void;
kill(): Phaser.Image;
loadTexture(key: any, frame: any): void;
postUpdate(): void;
preUpdate(): void;
reset(x: number, y: number): Phaser.Image;
resetFrame(): void;
revive(): Phaser.Image;
setFrame(frame: Phaser.Frame): void;
update(): void;
updateCrop(): void;
}
@ -4295,6 +4298,7 @@ declare module Phaser {
body: any;
cameraOffset: Phaser.Point;
checkWorldBounds: boolean;
cropRect: Phaser.Rectangle;
debug: boolean;
deltaX: number;
deltaY: number;
@ -4327,7 +4331,7 @@ declare module Phaser {
z: number;
bringToTop(): Phaser.Sprite;
crop(rect: Phaser.Rectangle): void;
crop(rect: Phaser.Rectangle, copy: boolean): void;
damage(amount: number): Phaser.Sprite;
destroy(destroyChildren?: boolean): void;
drawPolygon(): void;
@ -4338,8 +4342,11 @@ declare module Phaser {
postUpdate(): void;
preUpdate(): void;
reset(x: number, y: number, health?: number): Phaser.Sprite;
resetFrame(): void;
revive(health?: number): Phaser.Sprite;
setFrame(frame: Phaser.Frame): void;
update(): void;
updateCrop(): void;
}

View file

@ -185,9 +185,7 @@ Phaser.Animation.prototype = {
this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]);
this._parent.setFrame(this.currentFrame.x, this.currentFrame.y, this.currentFrame.width, this.currentFrame.height);
// this._parent.setTexture(PIXI.TextureCache[this.currentFrame.uuid]);
this._parent.setFrame(this.currentFrame);
// TODO: Double check if required
if (this._parent.__tilePattern)
@ -197,6 +195,7 @@ Phaser.Animation.prototype = {
}
this._parent.events.onAnimationStart.dispatch(this._parent, this);
this.onStart.dispatch(this._parent, this);
return this;
@ -222,6 +221,8 @@ Phaser.Animation.prototype = {
this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]);
this._parent.setFrame(this.currentFrame);
this.onStart.dispatch(this._parent, this);
},
@ -304,6 +305,7 @@ Phaser.Animation.prototype = {
if (resetFrame)
{
this.currentFrame = this._frameData.getFrame(this._frames[0]);
this._parent.setFrame(this.currentFrame);
}
if (dispatchComplete)
@ -367,7 +369,6 @@ Phaser.Animation.prototype = {
{
// We need to skip a frame, work out how many
this._frameSkip = Math.floor(this._frameDiff / this.delay);
this._frameDiff -= (this._frameSkip * this.delay);
}
@ -382,21 +383,7 @@ Phaser.Animation.prototype = {
{
this._frameIndex %= this._frames.length;
this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]);
// if (this.currentFrame)
// {
// this._parent.setTexture(PIXI.TextureCache[this.currentFrame.uuid]);
// this._parent.setFrame(this.currentFrame.x, this.currentFrame.y, this.currentFrame.width, this.currentFrame.height);
// if (this._parent.__tilePattern)
// {
// this._parent.__tilePattern = false;
// this._parent.tilingTexture = false;
// }
// }
this.loopCount++;
// console.log('loop', this.loopCount);
this._parent.events.onAnimationLoop.dispatch(this._parent, this);
this.onLoop.dispatch(this._parent, this);
}
@ -405,20 +392,13 @@ Phaser.Animation.prototype = {
this.complete();
}
}
// else
// {
// }
this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]);
if (this.currentFrame)
{
// this._parent.setTexture(PIXI.TextureCache[this.currentFrame.uuid]);
// this._parent.setFrame(this.currentFrame.x, this.currentFrame.y, this.currentFrame.width, this.currentFrame.height);
this._parent.setFrame(this.currentFrame);
// console.log('a1', this._parent.texture.frame, PIXI.TextureCache[this.currentFrame.uuid].frame);
if (this._parent.__tilePattern)
{
this._parent.__tilePattern = false;
@ -556,9 +536,7 @@ Object.defineProperty(Phaser.Animation.prototype, 'frame', {
if (this.currentFrame !== null)
{
this._frameIndex = value;
// this._parent.setTexture(PIXI.TextureCache[this.currentFrame.uuid]);
this._parent.setFrame(this.currentFrame);
// this._parent.setFrame(this.currentFrame.x, this.currentFrame.y, this.currentFrame.width, this.currentFrame.height);
}
}

View file

@ -160,8 +160,6 @@ Phaser.AnimationManager.prototype = {
this.currentFrame = this.currentAnim.currentFrame;
this.sprite.setFrame(this.currentFrame);
// this.sprite.setFrame(this.currentFrame.x, this.currentFrame.y, this.currentFrame.width, this.currentFrame.height);
// this.sprite.setTexture(PIXI.TextureCache[this.currentFrame.uuid]);
if (this.sprite.__tilePattern)
{
@ -447,8 +445,6 @@ Object.defineProperty(Phaser.AnimationManager.prototype, 'frame', {
this._frameIndex = value;
this.sprite.setFrame(this.currentFrame);
// this.sprite.setFrame(this.currentFrame.x, this.currentFrame.y, this.currentFrame.width, this.currentFrame.height);
// this.sprite.setTexture(PIXI.TextureCache[this.currentFrame.uuid]);
if (this.sprite.__tilePattern)
{
@ -486,9 +482,8 @@ Object.defineProperty(Phaser.AnimationManager.prototype, 'frameName', {
if (this.currentFrame)
{
this._frameIndex = this.currentFrame.index;
this.sprite.setFrame(this.currentFrame);
// this.sprite.setFrame(this.currentFrame.x, this.currentFrame.y, this.currentFrame.width, this.currentFrame.height);
// this.sprite.setTexture(PIXI.TextureCache[this.currentFrame.uuid]);
if (this.sprite.__tilePattern)
{

View file

@ -75,13 +75,6 @@ Phaser.AnimationParser = {
// uuid needed?
data.addFrame(new Phaser.Frame(i, x, y, frameWidth, frameHeight, '', uuid));
// PIXI.TextureCache[uuid] = new PIXI.Texture(PIXI.BaseTextureCache[key], {
// x: x,
// y: y,
// width: frameWidth,
// height: frameHeight
// });
x += frameWidth + spacing;
if (x + frameWidth > width)
@ -135,27 +128,8 @@ Phaser.AnimationParser = {
uuid
));
// PIXI.TextureCache[uuid] = new PIXI.Texture(PIXI.BaseTextureCache[cacheKey], {
// x: frames[i].frame.x,
// y: frames[i].frame.y,
// width: frames[i].frame.w,
// height: frames[i].frame.h
// });
/*
"filename": "octopus0000",
"frame": {"x":888,"y":1399,"w":82,"h":88},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":82,"h":95},
"sourceSize": {"w":82,"h":95}
*/
if (frames[i].trimmed)
{
// setTrim: function (trimmed, actualWidth, actualHeight, destX, destY, destWidth, destHeight) {
newFrame.setTrim(
frames[i].trimmed,
frames[i].sourceSize.w,
@ -165,11 +139,7 @@ Phaser.AnimationParser = {
frames[i].spriteSourceSize.w,
frames[i].spriteSourceSize.h
);
// PIXI.TextureCache[uuid].trim = new Phaser.Rectangle(frames[i].spriteSourceSize.x, frames[i].spriteSourceSize.y, frames[i].sourceSize.w, frames[i].sourceSize.h);
}
}
return data;
@ -217,13 +187,6 @@ Phaser.AnimationParser = {
uuid
));
PIXI.TextureCache[uuid] = new PIXI.Texture(PIXI.BaseTextureCache[cacheKey], {
x: frames[key].frame.x,
y: frames[key].frame.y,
width: frames[key].frame.w,
height: frames[key].frame.h
});
if (frames[key].trimmed)
{
newFrame.setTrim(
@ -235,8 +198,6 @@ Phaser.AnimationParser = {
frames[key].spriteSourceSize.w,
frames[key].spriteSourceSize.h
);
PIXI.TextureCache[uuid].trim = new Phaser.Rectangle(frames[key].spriteSourceSize.x, frames[key].spriteSourceSize.y, frames[key].sourceSize.w, frames[key].sourceSize.h);
}
i++;
@ -306,19 +267,10 @@ Phaser.AnimationParser = {
newFrame = data.addFrame(new Phaser.Frame(i, x, y, width, height, name, uuid));
PIXI.TextureCache[uuid] = new PIXI.Texture(PIXI.BaseTextureCache[cacheKey], {
x: x,
y: y,
width: width,
height: height
});
// Trimmed?
if (frameX !== null || frameY !== null)
{
newFrame.setTrim(true, width, height, frameX, frameY, frameWidth, frameHeight);
PIXI.TextureCache[uuid].trim = new Phaser.Rectangle(frameX, frameY, width, height);
}
}

View file

@ -143,8 +143,6 @@ Phaser.Frame.prototype = {
if (trimmed)
{
// this.width = actualWidth;
// this.height = actualHeight;
this.sourceSizeW = actualWidth;
this.sourceSizeH = actualHeight;
this.centerX = Math.floor(actualWidth / 2);

View file

@ -62,22 +62,8 @@ Phaser.Image = function (game, x, y, key, frame) {
*/
this.key = key;
/**
* @property {number} _frame - Internal cache var.
* @private
*/
this._frame = 0;
/**
* @property {string} _frameName - Internal cache var.
* @private
*/
this._frameName = '';
PIXI.Sprite.call(this, PIXI.TextureCache['__default']);
this.loadTexture(key, frame);
this.position.set(x, y);
/**
@ -105,8 +91,15 @@ Phaser.Image = function (game, x, y, key, frame) {
*/
this.cameraOffset = new Phaser.Point();
/**
* @property {Phaser.Rectangle} cropRect - The Rectangle used to crop the texture. Set this via Sprite.crop. Any time you modify this property directly you must call Sprite.updateCrop.
* @default
*/
this.cropRect = null;
/**
* A small internal cache:
*
* 0 = previous position.x
* 1 = previous position.y
* 2 = previous rotation
@ -116,10 +109,38 @@ Phaser.Image = function (game, x, y, key, frame) {
* 6 = exists (0 = no, 1 = yes)
* 7 = fixed to camera (0 = no, 1 = yes)
* 8 = destroy phase? (0 = no, 1 = yes)
* 9 = texture x
* 10 = texture y
* 11 = texture width
* 12 = texture height
* 13 = texture spriteSourceSizeX
* 14 = texture spriteSourceSizeY
* 15 = trim x
* 16 = trim y
* @property {Array} _cache
* @private
*/
this._cache = [ 0, 0, 0, 0, 1, 0, 1, 0, 0 ];
this._cache = [ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
/**
* @property {Phaser.Rectangle} _bounds - Internal cache var.
* @private
*/
this._bounds = new Phaser.Rectangle();
/**
* @property {number} _frame - Internal cache var.
* @private
*/
this._frame = 0;
/**
* @property {string} _frameName - Internal cache var.
* @private
*/
this._frameName = '';
this.loadTexture(key, frame);
};
@ -217,24 +238,24 @@ Phaser.Image.prototype.postUpdate = function() {
Phaser.Image.prototype.loadTexture = function (key, frame) {
frame = frame || 0;
this.key = key;
this._frame = 0;
this._frameName = '';
if (key instanceof Phaser.RenderTexture)
{
this.key = key.key;
this.setTexture(key);
return;
}
else if (key instanceof Phaser.BitmapData)
{
this.key = key;
this.setTexture(key.texture);
return;
}
else if (key instanceof PIXI.Texture)
{
this.key = key;
this.setTexture(key);
return;
}
else
{
@ -242,92 +263,212 @@ Phaser.Image.prototype.loadTexture = function (key, frame) {
{
this.key = '__default';
this.setTexture(PIXI.TextureCache[this.key]);
return;
}
else if (typeof key === 'string' && !this.game.cache.checkImageKey(key))
{
this.key = '__missing';
this.setTexture(PIXI.TextureCache[this.key]);
return;
}
if (this.game.cache.isSpriteSheet(key))
{
this.key = key;
var frameData = this.game.cache.getFrameData(key);
if (typeof frame === 'string')
{
this._frame = 0;
this._frameName = frame;
this.setTexture(PIXI.TextureCache[frameData.getFrameByName(frame).uuid]);
return;
}
else
{
this._frame = frame;
this._frameName = '';
this.setTexture(PIXI.TextureCache[frameData.getFrame(frame).uuid]);
return;
}
}
else
{
this.key = key;
this.setTexture(PIXI.TextureCache[key]);
return;
this.setTexture(new PIXI.Texture(PIXI.BaseTextureCache[this.key]));
var frameData = this.game.cache.getFrameData(this.key);
if (frameData)
{
if (typeof frame === 'string')
{
this._frameName = frame;
this.setFrame(frameData.getFrameByName(frame));
}
else
{
this._frame = frame;
this.setFrame(frameData.getFrame(frame));
}
}
}
}
};
/**
* Crop allows you to crop the texture used to display this Image.
* Cropping takes place from the top-left of the Image and can be modified in real-time by providing an updated rectangle object.
* The rectangle object given to this method can be either a Phaser.Rectangle or any object so long as it has public x, y, width and height properties.
* Please note that the rectangle object given is not duplicated by this method, but rather the Image uses a reference to the rectangle.
* Keep this in mind if assigning a rectangle in a for-loop, or when cleaning up for garbage collection.
* Resets the Texture frame dimensions that the Image uses for rendering.
*
* @method Phaser.Image#crop
* @method Phaser.Image#resetFrame
* @memberof Phaser.Image
* @param {Phaser.Rectangle|object} rect - The Rectangle to crop the Image to. Pass null or no parameters to clear a previously set crop rectangle.
*/
Phaser.Image.prototype.crop = function(rect) {
Phaser.Image.prototype.resetFrame = function() {
if (typeof rect === 'undefined' || rect === null)
this.texture.frame.x = this._cache[9];
this.texture.frame.y = this._cache[10];
this.texture.frame.width = this._cache[11];
this.texture.frame.height = this._cache[12];
if (this.texture.trim)
{
// Clear any crop that may be set
if (this.texture.hasOwnProperty('sourceWidth'))
this.texture.trim.x = this._cache[13];
this.texture.trim.y = this._cache[14];
this.texture.trim.width = this.texture.frame.width;
this.texture.trim.height = this.texture.frame.height;
}
if (this.game.renderType === Phaser.WEBGL)
{
PIXI.WebGLRenderer.updateTextureFrame(this.texture);
}
};
/**
* Sets the Texture frame the Image uses for rendering.
* This is primarily an internal method used by Image.loadTexture, although you may call it directly.
*
* @method Phaser.Image#setFrame
* @memberof Phaser.Image
* @param {Phaser.Frame} frame - The Frame to be used by the Image texture.
*/
Phaser.Image.prototype.setFrame = function(frame) {
this._cache[9] = frame.x;
this._cache[10] = frame.y;
this._cache[11] = frame.width;
this._cache[12] = frame.height;
this._cache[13] = frame.spriteSourceSizeX;
this._cache[14] = frame.spriteSourceSizeY;
this.texture.frame.x = frame.x;
this.texture.frame.y = frame.y;
this.texture.frame.width = frame.width;
this.texture.frame.height = frame.height;
if (frame.trimmed)
{
this.texture.trim = { x: frame.spriteSourceSizeX, y: frame.spriteSourceSizeY, width: frame.width, height: frame.height };
}
if (this.game.renderType === Phaser.WEBGL)
{
PIXI.WebGLRenderer.updateTextureFrame(this.texture);
}
if (this.cropRect)
{
this.updateCrop();
}
};
/**
* If you have set a crop rectangle on this Image via Image.crop and since modified the Image.cropRect property (or the rectangle it references)
* then you need to update the crop frame by calling this method.
*
* @method Phaser.Image#updateCrop
* @memberof Phaser.Image
*/
Phaser.Image.prototype.updateCrop = function() {
if (!this.cropRect)
{
return;
}
if (this.texture.trim)
{
this._cache[15] = this._cache[9] + this.cropRect.x - this._cache[13];
if (this._cache[15] < this._cache[9])
{
this.texture.setFrame(new Phaser.Rectangle(0, 0, this.texture.sourceWidth, this.texture.sourceHeight));
this._cache[15] = this._cache[9];
}
this._cache[16] = this._cache[10] + this.cropRect.y - this._cache[14];
if (this._cache[16] < this._cache[10])
{
this._cache[16] = this._cache[10];
}
this.texture.frame.x = this._cache[15];
this.texture.frame.y = this._cache[16];
this._cache[15] = 0;
this._cache[16] = 0;
if (this.cropRect.x === 0)
{
this._cache[15] = this._cache[13];
}
if (this.cropRect.y === 0)
{
this._cache[16] = this._cache[14];
}
this.texture.frame.width = this.cropRect.width - this._cache[15];
this.texture.frame.height = this.cropRect.height - this._cache[16];
this.texture.trim.x = this._cache[15];
this.texture.trim.y = this._cache[16];
this.texture.trim.width = this.cropRect.width;
this.texture.trim.height = this.cropRect.height;
}
else
{
// Do we need to clone the PIXI.Texture object?
if (this.texture instanceof PIXI.Texture)
this.texture.frame.x = this._cache[9] + this.cropRect.x;
this.texture.frame.y = this._cache[10] + this.cropRect.y;
this.texture.frame.width = this.cropRect.width;
this.texture.frame.height = this.cropRect.height;
}
if (this.game.renderType === Phaser.WEBGL)
{
PIXI.WebGLRenderer.updateTextureFrame(this.texture);
}
};
/**
* Crop allows you to crop the texture used to display this Image.
* This modifies the core Image texture frame, so the Image width/height properties will adjust accordingly.
*
* Cropping takes place from the top-left of the Image and can be modified in real-time by either providing an updated rectangle object to Image.crop,
* or by modifying Image.cropRect (or a reference to it) and then calling Image.updateCrop.
*
* The rectangle object given to this method can be either a Phaser.Rectangle or any object so long as it has public x, y, width and height properties.
* A reference to the rectangle is stored in Image.cropRect unless the `copy` parameter is `true` in which case the values are duplicated to a local object.
*
* @method Phaser.Image#crop
* @memberof Phaser.Image
* @param {Phaser.Rectangle} rect - The Rectangle used during cropping. Pass null or no parameters to clear a previously set crop rectangle.
* @param {boolean} [copy=false] - If false Image.cropRect will be a reference to the given rect. If true it will copy the rect values into a local Image.cropRect object.
*/
Phaser.Image.prototype.crop = function(rect, copy) {
if (typeof copy === 'undefined') { copy = false; }
if (rect)
{
if (copy && this.cropRect !== null)
{
// Yup, let's rock it ...
var local = {};
Phaser.Utils.extend(true, local, this.texture);
local.sourceWidth = local.width;
local.sourceHeight = local.height;
local.frame = rect;
local.width = rect.width;
local.height = rect.height;
this.texture = local;
this.texture.updateFrame = true;
PIXI.Texture.frameUpdates.push(this.texture);
this.cropRect.setTo(rect.x, rect.y, rect.width, rect.height);
}
else if (copy && this.cropRect === null)
{
this.cropRect = new Phaser.Rectangle(rect.x, rect.y, rect.width, rect.height);
}
else
{
this.texture.setFrame(rect);
this.cropRect = rect;
}
this.updateCrop();
}
else
{
this.cropRect = null;
this.resetFrame();
}
};
@ -619,8 +760,8 @@ Object.defineProperty(Phaser.Image.prototype, "frame", {
if (frameData && value < frameData.total && frameData.getFrame(value))
{
this.setTexture(PIXI.TextureCache[frameData.getFrame(value).uuid]);
this._frame = value;
this.setFrame(frameData.getFrame(value));
}
}
@ -648,8 +789,8 @@ Object.defineProperty(Phaser.Image.prototype, "frameName", {
if (frameData && frameData.getFrameByName(value))
{
this.setTexture(PIXI.TextureCache[frameData.getFrameByName(value).uuid]);
this._frameName = value;
this.setFrame(frameData.getFrameByName(value));
}
}

View file

@ -65,22 +65,8 @@ Phaser.Sprite = function (game, x, y, key, frame) {
*/
this.key = key;
/**
* @property {number} _frame - Internal cache var.
* @private
*/
this._frame = 0;
/**
* @property {string} _frameName - Internal cache var.
* @private
*/
this._frameName = '';
PIXI.Sprite.call(this, PIXI.TextureCache['__default']);
this.loadTexture(key, frame);
this.position.set(x, y);
/**
@ -161,8 +147,15 @@ Phaser.Sprite = function (game, x, y, key, frame) {
*/
this.cameraOffset = new Phaser.Point();
/**
* @property {Phaser.Rectangle} cropRect - The Rectangle used to crop the texture. Set this via Sprite.crop. Any time you modify this property directly you must call Sprite.updateCrop.
* @default
*/
this.cropRect = null;
/**
* A small internal cache:
*
* 0 = previous position.x
* 1 = previous position.y
* 2 = previous rotation
@ -172,10 +165,18 @@ Phaser.Sprite = function (game, x, y, key, frame) {
* 6 = exists (0 = no, 1 = yes)
* 7 = fixed to camera (0 = no, 1 = yes)
* 8 = destroy phase? (0 = no, 1 = yes)
* 9 = texture x
* 10 = texture y
* 11 = texture width
* 12 = texture height
* 13 = texture spriteSourceSizeX
* 14 = texture spriteSourceSizeY
* 15 = trim x
* 16 = trim y
* @property {Array} _cache
* @private
*/
this._cache = [ 0, 0, 0, 0, 1, 0, 1, 0, 0 ];
this._cache = [ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
/**
* @property {Phaser.Rectangle} _bounds - Internal cache var.
@ -183,17 +184,7 @@ Phaser.Sprite = function (game, x, y, key, frame) {
*/
this._bounds = new Phaser.Rectangle();
/**
* @property {Phaser.Rectangle} _crop - Internal cache var.
* @private
*/
this._crop = null;
/**
* @property {Phaser.Rectangle} _frame - Internal cache var.
* @private
*/
this._frame = null;
this.loadTexture(key, frame);
};
@ -359,29 +350,26 @@ Phaser.Sprite.prototype.postUpdate = function() {
* @method Phaser.Sprite#loadTexture
* @memberof Phaser.Sprite
* @param {string|Phaser.RenderTexture|Phaser.BitmapData|PIXI.Texture} key - This is the image or texture used by the Sprite during rendering. It can be a string which is a reference to the Cache entry, or an instance of a RenderTexture, BitmapData or PIXI.Texture.
* @param {string|number} frame - If this Sprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
* @param {string|number} [frame] - If this Sprite is using part of a sprite sheet or texture atlas you can specify the exact frame to use by giving a string or numeric index.
*/
Phaser.Sprite.prototype.loadTexture = function (key, frame) {
frame = frame || 0;
this.key = key;
if (key instanceof Phaser.RenderTexture)
{
this.key = key.key;
this.setTexture(key);
return;
}
else if (key instanceof Phaser.BitmapData)
{
this.key = key;
this.setTexture(key.texture);
return;
}
else if (key instanceof PIXI.Texture)
{
this.key = key;
this.setTexture(key);
return;
}
else
{
@ -389,114 +377,40 @@ Phaser.Sprite.prototype.loadTexture = function (key, frame) {
{
this.key = '__default';
this.setTexture(PIXI.TextureCache[this.key]);
return;
}
else if (typeof key === 'string' && !this.game.cache.checkImageKey(key))
{
this.key = '__missing';
this.setTexture(PIXI.TextureCache[this.key]);
return;
}
if (this.game.cache.isSpriteSheet(key))
{
this.key = key;
this.setTexture(new PIXI.Texture(PIXI.BaseTextureCache[key]));
this.animations.loadFrameData(this.game.cache.getFrameData(key));
this.textureChange = true;
if (typeof frame === 'string')
{
this.frameName = frame;
}
else
{
this.frame = frame;
}
}
else
{
this.key = key;
this.setTexture(new PIXI.Texture(PIXI.BaseTextureCache[key]));
this.animations.loadFrameData(null);
return;
this.animations.loadFrameData(this.game.cache.getFrameData(key), frame);
}
}
};
/**
* Resets the Texture frame dimensions that the Sprite uses for rendering.
*
* @method Phaser.Sprite#resetFrame
* @memberof Phaser.Sprite
*/
Phaser.Sprite.prototype.resetFrame = function() {
Phaser.Sprite.prototype.setFrame = function(frame) {
this.texture.frame.x = this._cache[9];
this.texture.frame.y = this._cache[10];
this.texture.frame.width = this._cache[11];
this.texture.frame.height = this._cache[12];
if (frame.trimmed)
if (this.texture.trim)
{
if (this._crop)
{
// Works but doesn't take crop x/y into account
// this.texture.frame.x = frame.x;
// this.texture.frame.y = frame.y;
// this.texture.frame.width = this._crop.width - frame.spriteSourceSizeX;
// this.texture.frame.height = this._crop.height - frame.spriteSourceSizeY;
// this.texture.trim = new Phaser.Rectangle(frame.spriteSourceSizeX, frame.spriteSourceSizeY, frame.width, frame.height);
var fx = frame.x + this._crop.x - frame.spriteSourceSizeX;
if (fx < frame.x)
{
fx = frame.x;
}
var fy = frame.y + this._crop.y - frame.spriteSourceSizeY;
if (fy < frame.y)
{
fy = frame.y;
}
this.texture.frame.x = fx;
this.texture.frame.y = fy;
var tx = 0;
var ty = 0;
if (this._crop.x === 0)
{
tx = frame.spriteSourceSizeX;
}
if (this._crop.y === 0)
{
ty = frame.spriteSourceSizeY;
}
this.texture.frame.width = this._crop.width - tx;
this.texture.frame.height = this._crop.height - ty;
this.texture.trim = new Phaser.Rectangle(tx, ty, this._crop.width, this._crop.height);
}
else
{
this.texture.frame.x = frame.x;
this.texture.frame.y = frame.y;
this.texture.frame.width = frame.width;
this.texture.frame.height = frame.height;
this.texture.trim = new Phaser.Rectangle(frame.spriteSourceSizeX, frame.spriteSourceSizeY, frame.width, frame.height);
}
}
else
{
this.texture.frame.x = frame.x;
this.texture.frame.y = frame.y;
this.texture.frame.width = frame.width;
this.texture.frame.height = frame.height;
if (this._crop)
{
this.texture.frame.x += this._crop.x;
this.texture.frame.y += this._crop.y;
this.texture.frame.width = this._crop.width;
this.texture.frame.height = this._crop.height;
}
this.texture.trim.x = this._cache[13];
this.texture.trim.y = this._cache[14];
this.texture.trim.width = this.texture.frame.width;
this.texture.trim.height = this.texture.frame.height;
}
if (this.game.renderType === Phaser.WEBGL)
@ -506,28 +420,106 @@ Phaser.Sprite.prototype.setFrame = function(frame) {
};
/**
* Sets the Texture frame the Sprite uses for rendering.
* This is primarily an internal method used by Sprite.loadTexture, although you may call it directly.
*
* @method Phaser.Sprite#setFrame
* @memberof Phaser.Sprite
* @param {Phaser.Frame} frame - The Frame to be used by the Sprite texture.
*/
Phaser.Sprite.prototype.setFrame = function(frame) {
Phaser.Sprite.prototype.XsetFrame = function(x, y, width, height) {
this._cache[9] = frame.x;
this._cache[10] = frame.y;
this._cache[11] = frame.width;
this._cache[12] = frame.height;
this._cache[13] = frame.spriteSourceSizeX;
this._cache[14] = frame.spriteSourceSizeY;
// console.log('setFrame', this.key, x, y);
this.texture.frame.x = frame.x;
this.texture.frame.y = frame.y;
this.texture.frame.width = frame.width;
this.texture.frame.height = frame.height;
this.texture.frame.x = x;
this.texture.frame.y = y;
this.texture.frame.width = width;
this.texture.frame.height = height;
// Apply crop?
if (this._crop)
if (frame.trimmed)
{
this.texture.frame.x += this._crop.x;
this.texture.frame.y += this._crop.y;
this.texture.frame.width = this._crop.width;
this.texture.frame.height = this._crop.height;
this.texture.trim = { x: frame.spriteSourceSizeX, y: frame.spriteSourceSizeY, width: frame.width, height: frame.height };
}
// Needed?
// this.updateFrame = true;
if (this.game.renderType === Phaser.WEBGL)
{
PIXI.WebGLRenderer.updateTextureFrame(this.texture);
}
if (this.cropRect)
{
this.updateCrop();
}
};
/**
* If you have set a crop rectangle on this Sprite via Sprite.crop and since modified the Sprite.cropRect property (or the rectangle it references)
* then you need to update the crop frame by calling this method.
*
* @method Phaser.Sprite#updateCrop
* @memberof Phaser.Sprite
*/
Phaser.Sprite.prototype.updateCrop = function() {
if (!this.cropRect)
{
return;
}
if (this.texture.trim)
{
this._cache[15] = this._cache[9] + this.cropRect.x - this._cache[13];
if (this._cache[15] < this._cache[9])
{
this._cache[15] = this._cache[9];
}
this._cache[16] = this._cache[10] + this.cropRect.y - this._cache[14];
if (this._cache[16] < this._cache[10])
{
this._cache[16] = this._cache[10];
}
this.texture.frame.x = this._cache[15];
this.texture.frame.y = this._cache[16];
this._cache[15] = 0;
this._cache[16] = 0;
if (this.cropRect.x === 0)
{
this._cache[15] = this._cache[13];
}
if (this.cropRect.y === 0)
{
this._cache[16] = this._cache[14];
}
this.texture.frame.width = this.cropRect.width - this._cache[15];
this.texture.frame.height = this.cropRect.height - this._cache[16];
this.texture.trim.x = this._cache[15];
this.texture.trim.y = this._cache[16];
this.texture.trim.width = this.cropRect.width;
this.texture.trim.height = this.cropRect.height;
}
else
{
this.texture.frame.x = this._cache[9] + this.cropRect.x;
this.texture.frame.y = this._cache[10] + this.cropRect.y;
this.texture.frame.width = this.cropRect.width;
this.texture.frame.height = this.cropRect.height;
}
if (this.game.renderType === Phaser.WEBGL)
{
@ -538,38 +530,44 @@ Phaser.Sprite.prototype.XsetFrame = function(x, y, width, height) {
/**
* Crop allows you to crop the texture used to display this Sprite.
* Cropping takes place from the top-left of the Sprite and can be modified in real-time by providing an updated rectangle object.
* Note that cropping a Sprite will reset its animation to the first frame. You cannot currently crop an animated Sprite.
* This modifies the core Sprite texture frame, so the Sprite width/height properties will adjust accordingly.
*
* Cropping takes place from the top-left of the Sprite and can be modified in real-time by either providing an updated rectangle object to Sprite.crop,
* or by modifying Sprite.cropRect (or a reference to it) and then calling Sprite.updateCrop.
*
* The rectangle object given to this method can be either a Phaser.Rectangle or any object so long as it has public x, y, width and height properties.
* Please note that the rectangle object given is not duplicated by this method, but rather the Image uses a reference to the rectangle.
* Keep this in mind if assigning a rectangle in a for-loop, or when cleaning up for garbage collection.
* A reference to the rectangle is stored in Sprite.cropRect unless the `copy` parameter is `true` in which case the values are duplicated to a local object.
*
* @method Phaser.Sprite#crop
* @memberof Phaser.Sprite
* @param {Phaser.Rectangle} rect - The Rectangle to crop the Sprite to. Pass null or no parameters to clear a previously set crop rectangle.
* @param {boolean} [copy=false] - Should the Sprite store a local copy of the Rectangle object?
* @param {Phaser.Rectangle} rect - The Rectangle used during cropping. Pass null or no parameters to clear a previously set crop rectangle.
* @param {boolean} [copy=false] - If false Sprite.cropRect will be a reference to the given rect. If true it will copy the rect values into a local Sprite.cropRect object.
*/
Phaser.Sprite.prototype.crop = function(rect, copy) {
if (typeof copy === 'undefined') { copy = false; }
if (rect)
{
if (copy)
if (copy && this.cropRect !== null)
{
this._crop = new Phaser.Rectangle(rect.x, rect.y, rect.width, rect.height);
this.cropRect.setTo(rect.x, rect.y, rect.width, rect.height);
}
else if (copy && this.cropRect === null)
{
this.cropRect = new Phaser.Rectangle(rect.x, rect.y, rect.width, rect.height);
}
else
{
this._crop = rect;
this.cropRect = rect;
}
// this.setFrame(this.texture.frame.x, this.texture.frame.y, this.texture.frame.width, this.texture.frame.height);
this.setFrame(this.texture);
this.updateCrop();
}
else
{
this._crop = null;
// How to reset the frame
// this.setFrame(this.texture.frame.x, this.texture.frame.y, this.texture.frame.width, this.texture.frame.height);
this.cropRect = null;
this.resetFrame();
}
};

View file

@ -256,7 +256,6 @@ Phaser.Cache.prototype = {
this._images[key] = { url: url, data: data, spriteSheet: true, frameWidth: frameWidth, frameHeight: frameHeight, margin: margin, spacing: spacing };
PIXI.BaseTextureCache[key] = new PIXI.BaseTexture(data);
// PIXI.TextureCache[key] = new PIXI.Texture(PIXI.BaseTextureCache[key]);
this._images[key].frameData = Phaser.AnimationParser.spriteSheet(this.game, key, frameWidth, frameHeight, frameMax, margin, spacing);
@ -292,7 +291,6 @@ Phaser.Cache.prototype = {
this._images[key] = { url: url, data: data, spriteSheet: true };
PIXI.BaseTextureCache[key] = new PIXI.BaseTexture(data);
PIXI.TextureCache[key] = new PIXI.Texture(PIXI.BaseTextureCache[key]);
if (format == Phaser.Loader.TEXTURE_ATLAS_JSON_ARRAY)
{
@ -325,7 +323,7 @@ Phaser.Cache.prototype = {
this._images[key] = { url: url, data: data, spriteSheet: true };
PIXI.BaseTextureCache[key] = new PIXI.BaseTexture(data);
PIXI.TextureCache[key] = new PIXI.Texture(PIXI.BaseTextureCache[key]);
// PIXI.TextureCache[key] = new PIXI.Texture(PIXI.BaseTextureCache[key]);
Phaser.LoaderParser.bitmapFont(this.game, xmlData, key, xSpacing, ySpacing);
@ -427,7 +425,6 @@ Phaser.Cache.prototype = {
this._images[key].frame = new Phaser.Frame(0, 0, 0, data.width, data.height, key, this.game.rnd.uuid());
PIXI.BaseTextureCache[key] = new PIXI.BaseTexture(data);
// PIXI.TextureCache[key] = new PIXI.Texture(PIXI.BaseTextureCache[key]);
},