diff --git a/Phaser/components/animation/AnimationManager.ts b/Phaser/components/animation/AnimationManager.ts index e2e46477..17a09cce 100644 --- a/Phaser/components/animation/AnimationManager.ts +++ b/Phaser/components/animation/AnimationManager.ts @@ -12,7 +12,7 @@ * sprite specific animations. */ -module Phaser { +module Phaser.Components { export class AnimationManager { @@ -22,10 +22,10 @@ module Phaser { * * @param parent {Sprite} Owner sprite of this manager. */ - constructor(game: Game, parent: Sprite) { + constructor(parent: Sprite) { - this._game = game; this._parent = parent; + this._game = parent.game; this._anims = {}; } diff --git a/Phaser/components/sprite/Texture.ts b/Phaser/components/sprite/Texture.ts index 0e48bc88..ff78d5f9 100644 --- a/Phaser/components/sprite/Texture.ts +++ b/Phaser/components/sprite/Texture.ts @@ -12,13 +12,13 @@ module Phaser.Components { export class Texture { - constructor(parent: Sprite, key?: string = '', canvas?: HTMLCanvasElement = null, context?: CanvasRenderingContext2D = null) { + constructor(parent: Sprite, key?: string = '') { this._game = parent.game; this._sprite = parent; - this.canvas = canvas; - this.context = context; + this.canvas = parent.game.stage.canvas; + this.context = parent.game.stage.context; this.alpha = 1; this.flippedX = false; this.flippedY = false; @@ -137,10 +137,10 @@ module Phaser.Components { */ public loadImage(key: string, clearAnimations: bool = true) { - //if (clearAnimations && sprite.animations.frameData !== null) - //{ - // sprite.animations.destroy(); - //} + if (clearAnimations && this._sprite.animations.frameData !== null) + { + this._sprite.animations.destroy(); + } if (this._game.cache.getImage(key) !== null) { @@ -148,16 +148,12 @@ module Phaser.Components { if (this._game.cache.isSpriteSheet(key)) { - //sprite.animations.loadFrameData(sprite._game.cache.getFrameData(key)); - //sprite.collisionMask.width = sprite.animations.currentFrame.width; - //sprite.collisionMask.height = sprite.animations.currentFrame.height; + this._sprite.animations.loadFrameData(this._sprite.game.cache.getFrameData(key)); } else { this._sprite.frameBounds.width = this.width; this._sprite.frameBounds.height = this.height; - //sprite.collisionMask.width = sprite._texture.width; - //sprite.collisionMask.height = sprite._texture.height; } } @@ -170,10 +166,10 @@ module Phaser.Components { */ public loadDynamicTexture(texture: DynamicTexture) { - //if (sprite.animations.frameData !== null) - //{ - // sprite.animations.destroy(); - //} + if (this._sprite.animations.frameData !== null) + { + this._sprite.animations.destroy(); + } this.setTo(null, texture); this._sprite.frameBounds.width = this.width; diff --git a/Phaser/core/Vec2.ts b/Phaser/core/Vec2.ts index f33eca21..ec290914 100644 --- a/Phaser/core/Vec2.ts +++ b/Phaser/core/Vec2.ts @@ -230,6 +230,15 @@ module Phaser { } + /** + * Check if both the x and y of this vector equal the given value. + * + * @return {Boolean} + */ + public equals(value): bool { + return (this.x == value && this.y == value); + } + /** * Returns a string representation of this object. * @method toString diff --git a/Phaser/gameobjects/Sprite.ts b/Phaser/gameobjects/Sprite.ts index e01eee54..afd1d245 100644 --- a/Phaser/gameobjects/Sprite.ts +++ b/Phaser/gameobjects/Sprite.ts @@ -1,4 +1,5 @@ /// +/// /// /// /// @@ -34,19 +35,23 @@ module Phaser { this.alive = true; this.frameBounds = new Rectangle(x, y, width, height); - this.origin = new Phaser.Vec2(0, 0); this.scrollFactor = new Phaser.Vec2(1, 1); - this.scale = new Phaser.Vec2(1, 1); this.x = x; this.y = y; - this.z = 0; + this.z = 0; // not used yet - this.texture = new Phaser.Components.Texture(this, key, game.stage.canvas, game.stage.context); + this.animations = new Phaser.Components.AnimationManager(this); + this.texture = new Phaser.Components.Texture(this, key); this.width = this.frameBounds.width; this.height = this.frameBounds.height; + // Transform related (if we add any more then move to a component) + this.origin = new Phaser.Vec2(this.width / 2, this.height / 2); + this.scale = new Phaser.Vec2(1, 1); + this.skew = new Phaser.Vec2(0, 0); + } /** @@ -99,6 +104,12 @@ module Phaser { */ public texture: Phaser.Components.Texture; + /** + * This manages animations of the sprite. You can modify animations though it. (see AnimationManager) + * @type AnimationManager + */ + public animations: Phaser.Components.AnimationManager; + /** * The frame boundary around this Sprite. * For non-animated sprites this matches the loaded texture dimensions. @@ -111,6 +122,16 @@ module Phaser { */ public scale: Phaser.Vec2; + /** + * Skew the Sprite along the x and y axis. A skew value of 0 is no skew. + */ + public skew: Phaser.Vec2; + + /** + * A boolean representing if the Sprite has been modified in any way via a scale, rotate, flip or skew. + */ + public modified: bool = false; + /** * The influence of camera movement upon the Sprite. */ @@ -159,6 +180,34 @@ module Phaser { this._rotation = this.game.math.wrap(value, 360, 0); } + /** + * Set the animation frame by frame number. + */ + public set frame(value: number) { + this.animations.frame = value; + } + + /** + * Get the animation frame number. + */ + public get frame(): number { + return this.animations.frame; + } + + /** + * Set the animation frame by frame name. + */ + public set frameName(value: string) { + this.animations.frameName = value; + } + + /** + * Get the animation frame name. + */ + public get frameName(): string { + return this.animations.frameName; + } + /** * Pre-update is called right before update() on each object in the game loop. */ @@ -169,6 +218,11 @@ module Phaser { //this.collisionMask.preUpdate(); + if (this.modified == false && (!this.scale.equals(1) || !this.skew.equals(0) || this.rotation != 0 || this.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) + { + this.modified = true; + } + } /** @@ -182,9 +236,9 @@ module Phaser { */ public postUpdate() { - /* this.animations.update(); + /* if (this.moves) { this.updateMotion(); @@ -232,6 +286,11 @@ module Phaser { this.touching = Collision.NONE; */ + if (this.modified == true && this.scale.equals(1) && this.skew.equals(0) && this.rotation == 0 && this.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) + { + this.modified = false; + } + } /** diff --git a/Phaser/renderers/CanvasRenderer.ts b/Phaser/renderers/CanvasRenderer.ts index cc6b9055..6825d27d 100644 --- a/Phaser/renderers/CanvasRenderer.ts +++ b/Phaser/renderers/CanvasRenderer.ts @@ -103,20 +103,20 @@ module Phaser { this._dw = sprite.frameBounds.width; this._dh = sprite.frameBounds.height; - /* - if (this._dynamicTexture == false && this.animations.currentFrame !== null) + if (sprite.animations.currentFrame !== null) { - this._sx = this.animations.currentFrame.x; - this._sy = this.animations.currentFrame.y; + this._sx = sprite.animations.currentFrame.x; + this._sy = sprite.animations.currentFrame.y; - if (this.animations.currentFrame.trimmed) + if (sprite.animations.currentFrame.trimmed) { - this._dx += this.animations.currentFrame.spriteSourceSizeX; - this._dy += this.animations.currentFrame.spriteSourceSizeY; + this._dx += sprite.animations.currentFrame.spriteSourceSizeX; + this._dy += sprite.animations.currentFrame.spriteSourceSizeY; } } // Apply camera difference - looks like this is already applied? + /* if (sprite.scrollFactor.x !== 1 || sprite.scrollFactor.y !== 1) { //this._dx -= (camera.worldView.x * this.scrollFactor.x); @@ -125,7 +125,7 @@ module Phaser { */ // Rotation and Flipped - if (sprite.scale.x != 1 || sprite.scale.y != 1 || sprite.rotation != 0 || sprite.rotationOffset != 0 || sprite.texture.flippedX || sprite.texture.flippedY) + if (sprite.modified) { if (sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.rotationOffset !== 0)) { @@ -142,15 +142,17 @@ module Phaser { // f = translate y sprite.texture.context.save(); - sprite.texture.context.setTransform(this._cos * this._fx, this._sin * this._fx, -this._sin * this._fy, this._cos * this._fy, this._dx, this._dy); + sprite.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + sprite.skew.x, -(this._sin * this._fy) + sprite.skew.y, this._cos * this._fy, this._dx, this._dy); this._dx = -sprite.origin.x; this._dy = -sprite.origin.y; } else { - this._dw = sprite.frameBounds.width * sprite.scale.x; - this._dh = sprite.frameBounds.height * sprite.scale.y; + this._dx -= sprite.origin.x; + this._dy -= sprite.origin.y; + //this._dw = sprite.frameBounds.width * sprite.scale.x; + //this._dh = sprite.frameBounds.height * sprite.scale.y; } this._sx = Math.round(this._sx); @@ -183,7 +185,7 @@ module Phaser { sprite.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); } - if (sprite.scale.x != 1 || sprite.scale.y != 1 || sprite.rotation != 0 || sprite.rotationOffset != 0 || sprite.texture.flippedX || sprite.texture.flippedY) + if (sprite.modified) { sprite.texture.context.restore(); } diff --git a/Phaser/tweens/Tween.ts b/Phaser/tweens/Tween.ts index 90edf048..f46d500a 100644 --- a/Phaser/tweens/Tween.ts +++ b/Phaser/tweens/Tween.ts @@ -82,6 +82,23 @@ module Phaser { private _delayTime = 0; private _startTime = null; + // Temp vars to avoid gc spikes + private _tempElapsed: number; + private _tempValue; + + /** + * Will this tween automatically restart when it completes? + * @type {boolean} + */ + private _loop: bool = false; + + /** + * A yoyo tween is one that plays once fully, then reverses back to the original tween values before completing. + * @type {boolean} + */ + private _yoyo: bool = false; + private _yoyoCount: number = 0; + /** * Easing function which actually updating this tween. * @type {function} @@ -120,9 +137,10 @@ module Phaser { * @param [ease] {any} Easing function. * @param [autoStart] {boolean} Whether this tween will start automatically or not. * @param [delay] {number} delay before this tween will start, defaults to 0 (no delay) + * @param [loop] {boolean} Should the tween automatically restart once complete? (ignores any chained tweens) * @return {Tween} Itself. */ - public to(properties, duration?: number = 1000, ease?: any = null, autoStart?: bool = false, delay?:number = 0) { + public to(properties, duration?: number = 1000, ease?: any = null, autoStart?: bool = false, delay?:number = 0, loop?:bool = false, yoyo?:bool = false): Tween { this._duration = duration; @@ -139,6 +157,10 @@ module Phaser { this._delayTime = delay; } + this._loop = loop; + this._yoyo = yoyo; + this._yoyoCount = 0; + if (autoStart === true) { return this.start(); @@ -150,19 +172,37 @@ module Phaser { } + public loop(value: bool): Tween { + + this._loop = value; + return this; + + } + + public yoyo(value: bool): Tween { + + this._yoyo = value; + this._yoyoCount = 0; + return this; + + } + /** * Start to tween. */ - public start() { + public start(looped: bool = false): Tween { if (this._game === null || this._object === null) { return; } - this._manager.add(this); + if (looped == false) + { + this._manager.add(this); - this.onStart.dispatch(this._object); + this.onStart.dispatch(this._object); + } this._startTime = this._game.time.now + this._delayTime; @@ -187,7 +227,10 @@ module Phaser { this._valuesEnd[property] = [this._object[property]].concat(this._valuesEnd[property]); } - this._valuesStart[property] = this._object[property]; + if (looped == false) + { + this._valuesStart[property] = this._object[property]; + } } @@ -195,7 +238,36 @@ module Phaser { } - public clear() { + public reverse() { + + var tempObj = {}; + + for (var property in this._valuesStart) + { + tempObj[property] = this._valuesStart[property]; + this._valuesStart[property] = this._valuesEnd[property]; + this._valuesEnd[property] = tempObj[property]; + } + + this._yoyoCount++; + + return this.start(true); + + } + + public reset(): Tween { + + // Reset the properties back to what they were before + for (var property in this._valuesStart) + { + this._object[property] = this._valuesStart[property]; + } + + return this.start(true); + + } + + public clear(): Tween { this._chainedTweens = []; @@ -210,7 +282,7 @@ module Phaser { /** * Stop tweening. */ - public stop() { + public stop(): Tween { if (this._manager !== null) { @@ -259,7 +331,7 @@ module Phaser { * @param tween {Phaser.Tween} Tween object you want to chain with this. * @return {Phaser.Tween} Itselfe. */ - public chain(tween:Phaser.Tween) { + public chain(tween:Phaser.Tween): Tween { this._chainedTweens.push(tween); @@ -267,11 +339,6 @@ module Phaser { } - /** - * Debug value? - */ - public debugValue; - /** * Update tweening. * @param time {number} Current time from game clock. @@ -301,36 +368,72 @@ module Phaser { return true; } - var elapsed = (time - this._startTime) / this._duration; - elapsed = elapsed > 1 ? 1 : elapsed; + this._tempElapsed = (time - this._startTime) / this._duration; + this._tempElapsed = this._tempElapsed > 1 ? 1 : this._tempElapsed; - var value = this._easingFunction(elapsed); + this._tempValue = this._easingFunction(this._tempElapsed); for (var property in this._valuesStart) { // Add checks for object, array, numeric up front if (this._valuesEnd[property] instanceof Array) { - this._object[property] = this._interpolationFunction(this._valuesEnd[property], value); + this._object[property] = this._interpolationFunction(this._valuesEnd[property], this._tempValue); } else { - this._object[property] = this._valuesStart[property] + (this._valuesEnd[property] - this._valuesStart[property]) * value; + this._object[property] = this._valuesStart[property] + (this._valuesEnd[property] - this._valuesStart[property]) * this._tempValue; } } - this.onUpdate.dispatch(this._object, value); + this.onUpdate.dispatch(this._object, this._tempValue); - if (elapsed == 1) + if (this._tempElapsed == 1) { - this.onComplete.dispatch(this._object); - - for (var i = 0; i < this._chainedTweens.length; i++) + // Yoyo? + if (this._yoyo) { - this._chainedTweens[i].start(); + if (this._yoyoCount == 0) + { + // Reverse the tween + this.reverse(); + return true; + } + else + { + // We've yoyo'd once already, quit? + if (this._loop == false) + { + this.onComplete.dispatch(this._object); + + for (var i = 0; i < this._chainedTweens.length; i++) + { + this._chainedTweens[i].start(); + } + + return false; + } + } } - return false; + // Loop? + if (this._loop) + { + this._yoyoCount = 0; + this.reset(); + return true; + } + else + { + this.onComplete.dispatch(this._object); + + for (var i = 0; i < this._chainedTweens.length; i++) + { + this._chainedTweens[i].start(); + } + + return false; + } } diff --git a/README.md b/README.md index ed679800..673d293f 100644 --- a/README.md +++ b/README.md @@ -24,13 +24,13 @@ TODO: * Dispatch world resize event * Removed ignoreGlobalUpdate because it checks exists etc in the Group update, so remove those checks from Sprite.update (same for render) - - +* Investigate why tweens don't restart after the game pauses +* Fix bug in Tween yoyo + loop combo V1.0.0 * Massive refactoring across the entire codebase. -* Removed Basic and GameObject and put Sprite on a diet. 127 properties and methods, now down to < 30. +* Removed Basic and GameObject and put Sprite on a diet. 127 properties and methods cut down to 32. * Added a new headless renderer for non-display related performance testing. * Added camera type to the CameraManager for future non-orthographic cameras. * Added Camera.destroy - now clears down the FX and unregisters itself from the CameraManager. @@ -40,7 +40,10 @@ V1.0.0 * Added Sprite.render which is a reference to IRenderer.renderSprite, but can be overridden for custom handling. * Refactored QuadTree so it no longer creates any temporary variables in any methods. * The Sprite Renderer now uses a single setTransform for scale, rotation and translation that respects the Sprite.origin value in all cases. - +* Sprite.modified is set to true if scale, rotation, skew or flip have been used. +* By default the Sprite.origin is set to the center of the sprite, but can be offset to anywhere. +* Added Tween.loop property so they can now re-run themselves indefinitely. +* Added Tween.yoyo property so they can reverse themselves after completing. V0.9.6 diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 9f898a47..0aad50da 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -53,13 +53,41 @@ false + + tween loop 1.ts + + + tween loop 2.ts + + + + + + animation 1.ts + + + + animation 2.ts + create sprite 1.ts - - - scale origin 1.ts + + sprite origin 1.ts + + sprite origin 2.ts + + + sprite origin 3.ts + + + sprite origin 4.ts + + + + + scale sprite 1.ts @@ -86,5 +114,6 @@ boot screen.ts + \ No newline at end of file diff --git a/Tests/phaser.js b/Tests/phaser.js index 3d982d13..962d81df 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -1986,6 +1986,14 @@ var Phaser; this.y = -this.y; return this; }; + Vec2.prototype.equals = /** + * Check if both the x and y of this vector equal the given value. + * + * @return {Boolean} + */ + function (value) { + return (this.x == value && this.y == value); + }; Vec2.prototype.toString = /** * Returns a string representation of this object. * @method toString @@ -2436,204 +2444,207 @@ var Phaser; })(); Phaser.FrameData = FrameData; })(Phaser || (Phaser = {})); -/// -/// -/// -/// -/// -/// -/** -* Phaser - AnimationManager -* -* Any Sprite that has animation contains an instance of the AnimationManager, which is used to add, play and update -* sprite specific animations. -*/ var Phaser; (function (Phaser) { - var AnimationManager = (function () { - /** - * AnimationManager constructor - * Create a new AnimationManager. - * - * @param parent {Sprite} Owner sprite of this manager. - */ - function AnimationManager(game, parent) { + /// + /// + /// + /// + /// + /// + /** + * Phaser - AnimationManager + * + * Any Sprite that has animation contains an instance of the AnimationManager, which is used to add, play and update + * sprite specific animations. + */ + (function (Components) { + var AnimationManager = (function () { /** - * Data contains animation frames. - * @type {FrameData} + * AnimationManager constructor + * Create a new AnimationManager. + * + * @param parent {Sprite} Owner sprite of this manager. */ - this._frameData = null; - /** - * Keeps track of the current frame of animation. - */ - this.currentFrame = null; - this._game = game; - this._parent = parent; - this._anims = { - }; - } - AnimationManager.prototype.loadFrameData = /** - * Load animation frame data. - * @param frameData Data to be loaded. - */ - function (frameData) { - this._frameData = frameData; - this.frame = 0; - }; - AnimationManager.prototype.add = /** - * Add a new animation. - * @param name {string} What this animation should be called (e.g. "run"). - * @param frames {any[]} An array of numbers/strings indicating what frames to play in what order (e.g. [1, 2, 3] or ['run0', 'run1', run2]). - * @param frameRate {number} The speed in frames per second that the animation should play at (e.g. 60 fps). - * @param loop {boolean} Whether or not the animation is looped or just plays once. - * @param useNumericIndex {boolean} Use number indexes instead of string indexes? - * @return {Animation} The Animation that was created - */ - function (name, frames, frameRate, loop, useNumericIndex) { - if (typeof frames === "undefined") { frames = null; } - if (typeof frameRate === "undefined") { frameRate = 60; } - if (typeof loop === "undefined") { loop = false; } - if (typeof useNumericIndex === "undefined") { useNumericIndex = true; } - if(this._frameData == null) { - return; + function AnimationManager(parent) { + /** + * Data contains animation frames. + * @type {FrameData} + */ + this._frameData = null; + /** + * Keeps track of the current frame of animation. + */ + this.currentFrame = null; + this._parent = parent; + this._game = parent.game; + this._anims = { + }; } - if(frames == null) { - frames = this._frameData.getFrameIndexes(); - } else { - if(this.validateFrames(frames, useNumericIndex) == false) { - throw Error('Invalid frames given to Animation ' + name); + AnimationManager.prototype.loadFrameData = /** + * Load animation frame data. + * @param frameData Data to be loaded. + */ + function (frameData) { + this._frameData = frameData; + this.frame = 0; + }; + AnimationManager.prototype.add = /** + * Add a new animation. + * @param name {string} What this animation should be called (e.g. "run"). + * @param frames {any[]} An array of numbers/strings indicating what frames to play in what order (e.g. [1, 2, 3] or ['run0', 'run1', run2]). + * @param frameRate {number} The speed in frames per second that the animation should play at (e.g. 60 fps). + * @param loop {boolean} Whether or not the animation is looped or just plays once. + * @param useNumericIndex {boolean} Use number indexes instead of string indexes? + * @return {Animation} The Animation that was created + */ + function (name, frames, frameRate, loop, useNumericIndex) { + if (typeof frames === "undefined") { frames = null; } + if (typeof frameRate === "undefined") { frameRate = 60; } + if (typeof loop === "undefined") { loop = false; } + if (typeof useNumericIndex === "undefined") { useNumericIndex = true; } + if(this._frameData == null) { return; } - } - if(useNumericIndex == false) { - frames = this._frameData.getFrameIndexesByName(frames); - } - this._anims[name] = new Phaser.Animation(this._game, this._parent, this._frameData, name, frames, frameRate, loop); - this.currentAnim = this._anims[name]; - this.currentFrame = this.currentAnim.currentFrame; - return this._anims[name]; - }; - AnimationManager.prototype.validateFrames = /** - * Check whether the frames is valid. - * @param frames {any[]} Frames to be validated. - * @param useNumericIndex {boolean} Does these frames use number indexes or string indexes? - * @return {boolean} True if they're valid, otherwise return false. - */ - function (frames, useNumericIndex) { - for(var i = 0; i < frames.length; i++) { - if(useNumericIndex == true) { - if(frames[i] > this._frameData.total) { - return false; - } + if(frames == null) { + frames = this._frameData.getFrameIndexes(); } else { - if(this._frameData.checkFrameName(frames[i]) == false) { - return false; + if(this.validateFrames(frames, useNumericIndex) == false) { + throw Error('Invalid frames given to Animation ' + name); + return; } } - } - return true; - }; - AnimationManager.prototype.play = /** - * Play animation with specific name. - * @param name {string} The string name of the animation you want to play. - * @param frameRate {number} FrameRate you want to specify instead of using default. - * @param loop {boolean} Whether or not the animation is looped or just plays once. - */ - function (name, frameRate, loop) { - if (typeof frameRate === "undefined") { frameRate = null; } - if(this._anims[name]) { - if(this.currentAnim == this._anims[name]) { - if(this.currentAnim.isPlaying == false) { + if(useNumericIndex == false) { + frames = this._frameData.getFrameIndexesByName(frames); + } + this._anims[name] = new Phaser.Animation(this._game, this._parent, this._frameData, name, frames, frameRate, loop); + this.currentAnim = this._anims[name]; + this.currentFrame = this.currentAnim.currentFrame; + return this._anims[name]; + }; + AnimationManager.prototype.validateFrames = /** + * Check whether the frames is valid. + * @param frames {any[]} Frames to be validated. + * @param useNumericIndex {boolean} Does these frames use number indexes or string indexes? + * @return {boolean} True if they're valid, otherwise return false. + */ + function (frames, useNumericIndex) { + for(var i = 0; i < frames.length; i++) { + if(useNumericIndex == true) { + if(frames[i] > this._frameData.total) { + return false; + } + } else { + if(this._frameData.checkFrameName(frames[i]) == false) { + return false; + } + } + } + return true; + }; + AnimationManager.prototype.play = /** + * Play animation with specific name. + * @param name {string} The string name of the animation you want to play. + * @param frameRate {number} FrameRate you want to specify instead of using default. + * @param loop {boolean} Whether or not the animation is looped or just plays once. + */ + function (name, frameRate, loop) { + if (typeof frameRate === "undefined") { frameRate = null; } + if(this._anims[name]) { + if(this.currentAnim == this._anims[name]) { + if(this.currentAnim.isPlaying == false) { + this.currentAnim.play(frameRate, loop); + } + } else { + this.currentAnim = this._anims[name]; this.currentAnim.play(frameRate, loop); } - } else { - this.currentAnim = this._anims[name]; - this.currentAnim.play(frameRate, loop); } - } - }; - AnimationManager.prototype.stop = /** - * Stop animation by name. - * Current animation will be automatically set to the stopped one. - */ - function (name) { - if(this._anims[name]) { - this.currentAnim = this._anims[name]; - this.currentAnim.stop(); - } - }; - AnimationManager.prototype.update = /** - * Update animation and parent sprite's bounds. - */ - function () { - if(this.currentAnim && this.currentAnim.update() == true) { - this.currentFrame = this.currentAnim.currentFrame; - this._parent.frameBounds.width = this.currentFrame.width; - this._parent.frameBounds.height = this.currentFrame.height; - } - }; - Object.defineProperty(AnimationManager.prototype, "frameData", { - get: function () { - return this._frameData; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(AnimationManager.prototype, "frameTotal", { - get: function () { - if(this._frameData) { - return this._frameData.total; - } else { - return -1; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(AnimationManager.prototype, "frame", { - get: function () { - return this._frameIndex; - }, - set: function (value) { - if(this._frameData.getFrame(value) !== null) { - this.currentFrame = this._frameData.getFrame(value); - this._parent.frameBounds.width = this.currentFrame.width; - this._parent.frameBounds.height = this.currentFrame.height; - this._frameIndex = value; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(AnimationManager.prototype, "frameName", { - get: function () { - return this.currentFrame.name; - }, - set: function (value) { - if(this._frameData.getFrameByName(value) !== null) { - this.currentFrame = this._frameData.getFrameByName(value); - this._parent.frameBounds.width = this.currentFrame.width; - this._parent.frameBounds.height = this.currentFrame.height; - this._frameIndex = this.currentFrame.index; - } - }, - enumerable: true, - configurable: true - }); - AnimationManager.prototype.destroy = /** - * Removes all related references - */ - function () { - this._anims = { }; - this._frameData = null; - this._frameIndex = 0; - this.currentAnim = null; - this.currentFrame = null; - }; - return AnimationManager; - })(); - Phaser.AnimationManager = AnimationManager; + AnimationManager.prototype.stop = /** + * Stop animation by name. + * Current animation will be automatically set to the stopped one. + */ + function (name) { + if(this._anims[name]) { + this.currentAnim = this._anims[name]; + this.currentAnim.stop(); + } + }; + AnimationManager.prototype.update = /** + * Update animation and parent sprite's bounds. + */ + function () { + if(this.currentAnim && this.currentAnim.update() == true) { + this.currentFrame = this.currentAnim.currentFrame; + this._parent.frameBounds.width = this.currentFrame.width; + this._parent.frameBounds.height = this.currentFrame.height; + } + }; + Object.defineProperty(AnimationManager.prototype, "frameData", { + get: function () { + return this._frameData; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(AnimationManager.prototype, "frameTotal", { + get: function () { + if(this._frameData) { + return this._frameData.total; + } else { + return -1; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(AnimationManager.prototype, "frame", { + get: function () { + return this._frameIndex; + }, + set: function (value) { + if(this._frameData.getFrame(value) !== null) { + this.currentFrame = this._frameData.getFrame(value); + this._parent.frameBounds.width = this.currentFrame.width; + this._parent.frameBounds.height = this.currentFrame.height; + this._frameIndex = value; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(AnimationManager.prototype, "frameName", { + get: function () { + return this.currentFrame.name; + }, + set: function (value) { + if(this._frameData.getFrameByName(value) !== null) { + this.currentFrame = this._frameData.getFrameByName(value); + this._parent.frameBounds.width = this.currentFrame.width; + this._parent.frameBounds.height = this.currentFrame.height; + this._frameIndex = this.currentFrame.index; + } + }, + enumerable: true, + configurable: true + }); + AnimationManager.prototype.destroy = /** + * Removes all related references + */ + function () { + this._anims = { + }; + this._frameData = null; + this._frameIndex = 0; + this.currentAnim = null; + this.currentFrame = null; + }; + return AnimationManager; + })(); + Components.AnimationManager = AnimationManager; + })(Phaser.Components || (Phaser.Components = {})); + var Components = Phaser.Components; })(Phaser || (Phaser = {})); /// /// @@ -3680,10 +3691,8 @@ var Phaser; */ (function (Components) { var Texture = (function () { - function Texture(parent, key, canvas, context) { + function Texture(parent, key) { if (typeof key === "undefined") { key = ''; } - if (typeof canvas === "undefined") { canvas = null; } - if (typeof context === "undefined") { context = null; } /** * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. */ @@ -3716,8 +3725,8 @@ var Phaser; this.flippedY = false; this._game = parent.game; this._sprite = parent; - this.canvas = canvas; - this.context = context; + this.canvas = parent.game.stage.canvas; + this.context = parent.game.stage.context; this.alpha = 1; this.flippedX = false; this.flippedY = false; @@ -3752,22 +3761,17 @@ var Phaser; */ function (key, clearAnimations) { if (typeof clearAnimations === "undefined") { clearAnimations = true; } - //if (clearAnimations && sprite.animations.frameData !== null) - //{ - // sprite.animations.destroy(); - //} + if(clearAnimations && this._sprite.animations.frameData !== null) { + this._sprite.animations.destroy(); + } if(this._game.cache.getImage(key) !== null) { this.setTo(this._game.cache.getImage(key), null); if(this._game.cache.isSpriteSheet(key)) { - //sprite.animations.loadFrameData(sprite._game.cache.getFrameData(key)); - //sprite.collisionMask.width = sprite.animations.currentFrame.width; - //sprite.collisionMask.height = sprite.animations.currentFrame.height; - } else { + this._sprite.animations.loadFrameData(this._sprite.game.cache.getFrameData(key)); + } else { this._sprite.frameBounds.width = this.width; this._sprite.frameBounds.height = this.height; - //sprite.collisionMask.width = sprite._texture.width; - //sprite.collisionMask.height = sprite._texture.height; - } + } } }; Texture.prototype.loadDynamicTexture = /** @@ -3776,10 +3780,9 @@ var Phaser; * @return {Sprite} Sprite instance itself. */ function (texture) { - //if (sprite.animations.frameData !== null) - //{ - // sprite.animations.destroy(); - //} + if(this._sprite.animations.frameData !== null) { + this._sprite.animations.destroy(); + } this.setTo(null, texture); this._sprite.frameBounds.width = this.width; this._sprite.frameBounds.height = this.height; @@ -3821,6 +3824,7 @@ var Phaser; var Components = Phaser.Components; })(Phaser || (Phaser = {})); /// +/// /// /// /// @@ -3853,6 +3857,10 @@ var Phaser; */ this._rotation = 0; /** + * A boolean representing if the Sprite has been modified in any way via a scale, rotate, flip or skew. + */ + this.modified = false; + /** * x value of the object. */ this.x = 0; @@ -3879,15 +3887,19 @@ var Phaser; this.visible = true; this.alive = true; this.frameBounds = new Phaser.Rectangle(x, y, width, height); - this.origin = new Phaser.Vec2(0, 0); this.scrollFactor = new Phaser.Vec2(1, 1); - this.scale = new Phaser.Vec2(1, 1); this.x = x; this.y = y; - this.z = 0; - this.texture = new Phaser.Components.Texture(this, key, game.stage.canvas, game.stage.context); + this.z = 0// not used yet + ; + this.animations = new Phaser.Components.AnimationManager(this); + this.texture = new Phaser.Components.Texture(this, key); this.width = this.frameBounds.width; this.height = this.frameBounds.height; + // Transform related (if we add any more then move to a component) + this.origin = new Phaser.Vec2(this.width / 2, this.height / 2); + this.scale = new Phaser.Vec2(1, 1); + this.skew = new Phaser.Vec2(0, 0); } Object.defineProperty(Sprite.prototype, "rotation", { get: /** @@ -3906,6 +3918,38 @@ var Phaser; enumerable: true, configurable: true }); + Object.defineProperty(Sprite.prototype, "frame", { + get: /** + * Get the animation frame number. + */ + function () { + return this.animations.frame; + }, + set: /** + * Set the animation frame by frame number. + */ + function (value) { + this.animations.frame = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Sprite.prototype, "frameName", { + get: /** + * Get the animation frame name. + */ + function () { + return this.animations.frameName; + }, + set: /** + * Set the animation frame by frame name. + */ + function (value) { + this.animations.frameName = value; + }, + enumerable: true, + configurable: true + }); Sprite.prototype.preUpdate = /** * Pre-update is called right before update() on each object in the game loop. */ @@ -3913,7 +3957,10 @@ var Phaser; //this.last.x = this.frameBounds.x; //this.last.y = this.frameBounds.y; //this.collisionMask.preUpdate(); - }; + if(this.modified == false && (!this.scale.equals(1) || !this.skew.equals(0) || this.rotation != 0 || this.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { + this.modified = true; + } + }; Sprite.prototype.update = /** * Override this function to update your class's position and appearance. */ @@ -3923,9 +3970,8 @@ var Phaser; * Automatically called after update() by the game loop. */ function () { - /* this.animations.update(); - + /* if (this.moves) { this.updateMotion(); @@ -3972,7 +4018,10 @@ var Phaser; this.wasTouching = this.touching; this.touching = Collision.NONE; */ - }; + if(this.modified == true && this.scale.equals(1) && this.skew.equals(0) && this.rotation == 0 && this.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { + this.modified = false; + } + }; Sprite.prototype.destroy = /** * Clean up memory. */ @@ -5077,6 +5126,17 @@ var Phaser; this._delayTime = 0; this._startTime = null; /** + * Will this tween automatically restart when it completes? + * @type {boolean} + */ + this._loop = false; + /** + * A yoyo tween is one that plays once fully, then reverses back to the original tween values before completing. + * @type {boolean} + */ + this._yoyo = false; + this._yoyoCount = 0; + /** * Contains chained tweens. * @type {Tweens[]} */ @@ -5098,13 +5158,16 @@ var Phaser; * @param [ease] {any} Easing function. * @param [autoStart] {boolean} Whether this tween will start automatically or not. * @param [delay] {number} delay before this tween will start, defaults to 0 (no delay) + * @param [loop] {boolean} Should the tween automatically restart once complete? (ignores any chained tweens) * @return {Tween} Itself. */ - function (properties, duration, ease, autoStart, delay) { + function (properties, duration, ease, autoStart, delay, loop, yoyo) { if (typeof duration === "undefined") { duration = 1000; } if (typeof ease === "undefined") { ease = null; } if (typeof autoStart === "undefined") { autoStart = false; } if (typeof delay === "undefined") { delay = 0; } + if (typeof loop === "undefined") { loop = false; } + if (typeof yoyo === "undefined") { yoyo = false; } this._duration = duration; // If properties isn't an object this will fail, sanity check it here somehow? this._valuesEnd = properties; @@ -5114,21 +5177,36 @@ var Phaser; if(delay > 0) { this._delayTime = delay; } + this._loop = loop; + this._yoyo = yoyo; + this._yoyoCount = 0; if(autoStart === true) { return this.start(); } else { return this; } }; + Tween.prototype.loop = function (value) { + this._loop = value; + return this; + }; + Tween.prototype.yoyo = function (value) { + this._yoyo = value; + this._yoyoCount = 0; + return this; + }; Tween.prototype.start = /** * Start to tween. */ - function () { + function (looped) { + if (typeof looped === "undefined") { looped = false; } if(this._game === null || this._object === null) { return; } - this._manager.add(this); - this.onStart.dispatch(this._object); + if(looped == false) { + this._manager.add(this); + this.onStart.dispatch(this._object); + } this._startTime = this._game.time.now + this._delayTime; for(var property in this._valuesEnd) { // This prevents the interpolation of null values or of non-existing properties @@ -5146,10 +5224,30 @@ var Phaser; this._object[property] ].concat(this._valuesEnd[property]); } - this._valuesStart[property] = this._object[property]; + if(looped == false) { + this._valuesStart[property] = this._object[property]; + } } return this; }; + Tween.prototype.reverse = function () { + var tempObj = { + }; + for(var property in this._valuesStart) { + tempObj[property] = this._valuesStart[property]; + this._valuesStart[property] = this._valuesEnd[property]; + this._valuesEnd[property] = tempObj[property]; + } + this._yoyoCount++; + return this.start(true); + }; + Tween.prototype.reset = function () { + // Reset the properties back to what they were before + for(var property in this._valuesStart) { + this._object[property] = this._valuesStart[property]; + } + return this.start(true); + }; Tween.prototype.clear = function () { this._chainedTweens = []; this.onStart.removeAll(); @@ -5234,24 +5332,48 @@ var Phaser; if(time < this._startTime) { return true; } - var elapsed = (time - this._startTime) / this._duration; - elapsed = elapsed > 1 ? 1 : elapsed; - var value = this._easingFunction(elapsed); + this._tempElapsed = (time - this._startTime) / this._duration; + this._tempElapsed = this._tempElapsed > 1 ? 1 : this._tempElapsed; + this._tempValue = this._easingFunction(this._tempElapsed); for(var property in this._valuesStart) { // Add checks for object, array, numeric up front if(this._valuesEnd[property] instanceof Array) { - this._object[property] = this._interpolationFunction(this._valuesEnd[property], value); + this._object[property] = this._interpolationFunction(this._valuesEnd[property], this._tempValue); } else { - this._object[property] = this._valuesStart[property] + (this._valuesEnd[property] - this._valuesStart[property]) * value; + this._object[property] = this._valuesStart[property] + (this._valuesEnd[property] - this._valuesStart[property]) * this._tempValue; } } - this.onUpdate.dispatch(this._object, value); - if(elapsed == 1) { - this.onComplete.dispatch(this._object); - for(var i = 0; i < this._chainedTweens.length; i++) { - this._chainedTweens[i].start(); + this.onUpdate.dispatch(this._object, this._tempValue); + if(this._tempElapsed == 1) { + // Yoyo? + if(this._yoyo) { + if(this._yoyoCount == 0) { + // Reverse the tween + this.reverse(); + return true; + } else { + // We've yoyo'd once already, quit? + if(this._loop == false) { + this.onComplete.dispatch(this._object); + for(var i = 0; i < this._chainedTweens.length; i++) { + this._chainedTweens[i].start(); + } + return false; + } + } + } + // Loop? + if(this._loop) { + this._yoyoCount = 0; + this.reset(); + return true; + } else { + this.onComplete.dispatch(this._object); + for(var i = 0; i < this._chainedTweens.length; i++) { + this._chainedTweens[i].start(); + } + return false; } - return false; } return true; }; @@ -10376,20 +10498,16 @@ var Phaser; this._dy = (camera.scaledY * sprite.scrollFactor.y) + sprite.frameBounds.y - (camera.worldView.y * sprite.scrollFactor.y); this._dw = sprite.frameBounds.width; this._dh = sprite.frameBounds.height; - /* - if (this._dynamicTexture == false && this.animations.currentFrame !== null) - { - this._sx = this.animations.currentFrame.x; - this._sy = this.animations.currentFrame.y; - - if (this.animations.currentFrame.trimmed) - { - this._dx += this.animations.currentFrame.spriteSourceSizeX; - this._dy += this.animations.currentFrame.spriteSourceSizeY; + if(sprite.animations.currentFrame !== null) { + this._sx = sprite.animations.currentFrame.x; + this._sy = sprite.animations.currentFrame.y; + if(sprite.animations.currentFrame.trimmed) { + this._dx += sprite.animations.currentFrame.spriteSourceSizeX; + this._dy += sprite.animations.currentFrame.spriteSourceSizeY; + } } - } - // Apply camera difference - looks like this is already applied? + /* if (sprite.scrollFactor.x !== 1 || sprite.scrollFactor.y !== 1) { //this._dx -= (camera.worldView.x * this.scrollFactor.x); @@ -10397,7 +10515,7 @@ var Phaser; } */ // Rotation and Flipped - if(sprite.scale.x != 1 || sprite.scale.y != 1 || sprite.rotation != 0 || sprite.rotationOffset != 0 || sprite.texture.flippedX || sprite.texture.flippedY) { + if(sprite.modified) { if(sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.rotationOffset !== 0)) { this._sin = Math.sin(sprite.game.math.degreesToRadians(sprite.rotationOffset + sprite.rotation)); this._cos = Math.cos(sprite.game.math.degreesToRadians(sprite.rotationOffset + sprite.rotation)); @@ -10410,13 +10528,15 @@ var Phaser; // e = translate x // f = translate y sprite.texture.context.save(); - sprite.texture.context.setTransform(this._cos * this._fx, this._sin * this._fx, -this._sin * this._fy, this._cos * this._fy, this._dx, this._dy); + sprite.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + sprite.skew.x, -(this._sin * this._fy) + sprite.skew.y, this._cos * this._fy, this._dx, this._dy); this._dx = -sprite.origin.x; this._dy = -sprite.origin.y; } else { - this._dw = sprite.frameBounds.width * sprite.scale.x; - this._dh = sprite.frameBounds.height * sprite.scale.y; - } + this._dx -= sprite.origin.x; + this._dy -= sprite.origin.y; + //this._dw = sprite.frameBounds.width * sprite.scale.x; + //this._dh = sprite.frameBounds.height * sprite.scale.y; + } this._sx = Math.round(this._sx); this._sy = Math.round(this._sy); this._sw = Math.round(this._sw); @@ -10441,7 +10561,7 @@ var Phaser; sprite.texture.context.fillStyle = 'rgb(255,255,255)'; sprite.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); } - if(sprite.scale.x != 1 || sprite.scale.y != 1 || sprite.rotation != 0 || sprite.rotationOffset != 0 || sprite.texture.flippedX || sprite.texture.flippedY) { + if(sprite.modified) { sprite.texture.context.restore(); } //if (this.renderDebug) diff --git a/Tests/sprites/animation 1.js b/Tests/sprites/animation 1.js new file mode 100644 index 00000000..b87914fd --- /dev/null +++ b/Tests/sprites/animation 1.js @@ -0,0 +1,23 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + function init() { + // Using Phasers asset loader we load up a PNG from the assets folder + // The sprite sheet is a standard frame-by-frame sheet, and each frame is 37 x 45 pixels in size. + // The final parameter (18) is the number of frames there are. You can omit this if your frames fill the entire sheet. + game.loader.addSpriteSheet('mummy', 'assets/sprites/metalslug_mummy37x45.png', 37, 45, 18); + game.loader.load(); + } + var mummy; + function create() { + mummy = game.add.sprite(game.stage.centerX, game.stage.centerY, 'mummy'); + // Here we add new animation called 'walk'. + // As it's the only animation in our sprite sheet we don't need to define the frames being used. + mummy.animations.add('walk'); + // This plays the animation at 20 frames per second on a loop (the 3rd parameter) + // Try changing the 20 value to something low to slow the speed down, or higher to make it play faster. + mummy.animations.play('walk', 20, true); + // This just scales the sprite up so you can see the animation better + mummy.scale.setTo(4, 4); + } +})(); diff --git a/Tests/sprites/animation 1.ts b/Tests/sprites/animation 1.ts new file mode 100644 index 00000000..4660abbd --- /dev/null +++ b/Tests/sprites/animation 1.ts @@ -0,0 +1,37 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + + function init() { + + // Using Phasers asset loader we load up a PNG from the assets folder + + // The sprite sheet is a standard frame-by-frame sheet, and each frame is 37 x 45 pixels in size. + // The final parameter (18) is the number of frames there are. You can omit this if your frames fill the entire sheet. + game.loader.addSpriteSheet('mummy', 'assets/sprites/metalslug_mummy37x45.png', 37, 45, 18); + game.loader.load(); + + } + + var mummy: Phaser.Sprite; + + function create() { + + mummy = game.add.sprite(game.stage.centerX, game.stage.centerY, 'mummy'); + + // Here we add new animation called 'walk'. + // As it's the only animation in our sprite sheet we don't need to define the frames being used. + mummy.animations.add('walk'); + + // This plays the animation at 20 frames per second on a loop (the 3rd parameter) + // Try changing the 20 value to something low to slow the speed down, or higher to make it play faster. + mummy.animations.play('walk', 20, true); + + // This just scales the sprite up so you can see the animation better + mummy.scale.setTo(4, 4); + + } + +})(); diff --git a/Tests/sprites/animation 2.js b/Tests/sprites/animation 2.js new file mode 100644 index 00000000..c9bb07a1 --- /dev/null +++ b/Tests/sprites/animation 2.js @@ -0,0 +1,22 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + function init() { + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addSpriteSheet('monster', 'assets/sprites/metalslug_monster39x40.png', 39, 40); + game.loader.load(); + } + var monster; + function create() { + game.stage.backgroundColor = 'rgb(50,10,10)'; + // Notice the use of 'stage.centerX' - this places the sprite in the middle of the stage without needing to do any extra math + monster = game.add.sprite(game.stage.centerX, game.stage.centerY, 'monster'); + // For this animation we pass 'null' for the frames, because we're going to use them all + // And we set the frame rate (30) and loop status (true) when we add the animation + // If the frame rate and looping is never going to change then it's easier to do it here + monster.animations.add('walk', null, 30, true); + // Then you can just call 'play' on its own with no other values to start things going + monster.animations.play('walk'); + monster.scale.setTo(2, 2); + } +})(); diff --git a/Tests/sprites/animation 2.ts b/Tests/sprites/animation 2.ts new file mode 100644 index 00000000..d41037c5 --- /dev/null +++ b/Tests/sprites/animation 2.ts @@ -0,0 +1,36 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + + function init() { + + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addSpriteSheet('monster', 'assets/sprites/metalslug_monster39x40.png', 39, 40); + game.loader.load(); + + } + + var monster: Phaser.Sprite; + + function create() { + + game.stage.backgroundColor = 'rgb(50,10,10)'; + + // Notice the use of 'stage.centerX' - this places the sprite in the middle of the stage without needing to do any extra math + monster = game.add.sprite(game.stage.centerX, game.stage.centerY, 'monster'); + + // For this animation we pass 'null' for the frames, because we're going to use them all + // And we set the frame rate (30) and loop status (true) when we add the animation + // If the frame rate and looping is never going to change then it's easier to do it here + monster.animations.add('walk', null, 30, true); + + // Then you can just call 'play' on its own with no other values to start things going + monster.animations.play('walk'); + + monster.scale.setTo(2, 2); + + } + +})(); diff --git a/Tests/sprites/scale origin 1.js b/Tests/sprites/scale origin 1.js deleted file mode 100644 index ee345abf..00000000 --- a/Tests/sprites/scale origin 1.js +++ /dev/null @@ -1,58 +0,0 @@ -/// -(function () { - var game = new Phaser.Game(this, 'game', 800, 600, init, create); - function init() { - // Using Phasers asset loader we load up a PNG from the assets folder - game.loader.addImageFile('fuji', 'assets/pics/atari_fujilogo.png'); - game.loader.load(); - } - var fuji; - var tween; - function create() { - game.stage.backgroundColor = 'rgb(0,0,100)'; - // Here we'll assign the new sprite to the local fuji variable - fuji = game.add.sprite(100, 200, 'fuji'); - // The sprite is 320 x 200 pixels in size - //fuji.origin.setTo(160, 0); - fuji.origin.setTo(160, 100); - //fuji.origin.setTo(320, 0); - //fuji.origin.setTo(320, 200); - //fuji.origin.setTo(260, 100); - fuji.scale.x = 2; - fuji.scale.y = 0.5; - //fuji.rotation = 45; - game.add.tween(fuji).to({ - rotation: 360 - }, 3000).start(); - // Create our tween - //tween = game.add.tween(fuji.scale); - //tween = game.add.tween(fuji.scale); - // Start it going - //scaleLeft(); - } - function rotate() { - tween.to({ - x: 0 - }, 1000); - tween.onComplete.add(scaleRight, this); - tween.start(); - } - function scaleLeft() { - tween.clear(); - tween.to({ - x: 0 - }, 1000); - tween.onComplete.add(scaleRight, this); - tween.start(); - } - function scaleRight() { - tween.clear(); - tween.to({ - x: 1 - }, 1000); - tween.onComplete.add(scaleLeft, this); - tween.start(); - // This line says "if the texture is flippedX then unflip it (set flippedX to false), otherwise set flippedX to true - (fuji.texture.flippedX) ? fuji.texture.flippedX = false : fuji.texture.flippedX = true; - } -})(); diff --git a/Tests/sprites/scale origin 1.ts b/Tests/sprites/scale origin 1.ts deleted file mode 100644 index 17a8695e..00000000 --- a/Tests/sprites/scale origin 1.ts +++ /dev/null @@ -1,75 +0,0 @@ -/// - -(function () { - - var game = new Phaser.Game(this, 'game', 800, 600, init, create); - - function init() { - - // Using Phasers asset loader we load up a PNG from the assets folder - game.loader.addImageFile('fuji', 'assets/pics/atari_fujilogo.png'); - game.loader.load(); - - } - - var fuji: Phaser.Sprite; - var tween: Phaser.Tween; - - function create() { - - game.stage.backgroundColor = 'rgb(0,0,100)'; - - // Here we'll assign the new sprite to the local fuji variable - fuji = game.add.sprite(100, 200, 'fuji'); - - // The sprite is 320 x 200 pixels in size - //fuji.origin.setTo(160, 0); - fuji.origin.setTo(160, 100); - //fuji.origin.setTo(320, 0); - //fuji.origin.setTo(320, 200); - - //fuji.origin.setTo(260, 100); - fuji.scale.x = 2; - fuji.scale.y = 0.5; - //fuji.rotation = 45; - game.add.tween(fuji).to({ rotation: 360 }, 3000).start(); - - // Create our tween - //tween = game.add.tween(fuji.scale); - //tween = game.add.tween(fuji.scale); - - // Start it going - //scaleLeft(); - - } - - function rotate() { - - tween.to({ x: 0 }, 1000); - tween.onComplete.add(scaleRight, this); - tween.start(); - - } - - function scaleLeft() { - - tween.clear(); - tween.to({ x: 0 }, 1000); - tween.onComplete.add(scaleRight, this); - tween.start(); - - } - - function scaleRight() { - - tween.clear(); - tween.to({ x: 1 }, 1000); - tween.onComplete.add(scaleLeft, this); - tween.start(); - - // This line says "if the texture is flippedX then unflip it (set flippedX to false), otherwise set flippedX to true - (fuji.texture.flippedX) ? fuji.texture.flippedX = false: fuji.texture.flippedX = true; - - } - -})(); diff --git a/Tests/sprites/scale sprite 5.ts b/Tests/sprites/scale sprite 5.ts index debd8c34..0f772dac 100644 --- a/Tests/sprites/scale sprite 5.ts +++ b/Tests/sprites/scale sprite 5.ts @@ -19,7 +19,6 @@ game.stage.backgroundColor = 'rgb(0,0,100)'; - // Here we'll assign the new sprite to the local fuji variable fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji'); diff --git a/Tests/sprites/sprite origin 1.js b/Tests/sprites/sprite origin 1.js new file mode 100644 index 00000000..fb3534cf --- /dev/null +++ b/Tests/sprites/sprite origin 1.js @@ -0,0 +1,29 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + function init() { + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addImageFile('fuji', 'assets/pics/atari_fujilogo.png'); + game.loader.load(); + } + var fuji; + var tween; + function create() { + game.stage.backgroundColor = 'rgb(0,0,100)'; + // Here we'll assign the new sprite to the local fuji variable + fuji = game.add.sprite(200, 200, 'fuji'); + // The sprite is 320 x 200 pixels in size + // If we don't set an origin then the sprite will rotate around 0,0 - the top left corner + tween = game.add.tween(fuji); + // Start it going + rotate(); + } + function rotate() { + tween.clear(); + tween.to({ + rotation: 360 + }, 2000); + tween.onComplete.add(rotate, this); + tween.start(); + } +})(); diff --git a/Tests/sprites/sprite origin 1.ts b/Tests/sprites/sprite origin 1.ts new file mode 100644 index 00000000..e1f53c14 --- /dev/null +++ b/Tests/sprites/sprite origin 1.ts @@ -0,0 +1,44 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + + function init() { + + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addImageFile('fuji', 'assets/pics/atari_fujilogo.png'); + game.loader.load(); + + } + + var fuji: Phaser.Sprite; + var tween: Phaser.Tween; + + function create() { + + game.stage.backgroundColor = 'rgb(0,0,100)'; + + // Here we'll assign the new sprite to the local fuji variable + fuji = game.add.sprite(200, 200, 'fuji'); + + // The sprite is 320 x 200 pixels in size + // If we don't set an origin then the sprite will rotate around 0,0 - the top left corner + + tween = game.add.tween(fuji); + + // Start it going + rotate(); + + } + + function rotate() { + + tween.clear(); + tween.to({ rotation: 360 }, 2000); + tween.onComplete.add(rotate, this); + tween.start(); + + } + +})(); diff --git a/Tests/sprites/sprite origin 2.js b/Tests/sprites/sprite origin 2.js new file mode 100644 index 00000000..9d1ac4c2 --- /dev/null +++ b/Tests/sprites/sprite origin 2.js @@ -0,0 +1,31 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + function init() { + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addImageFile('fuji', 'assets/pics/atari_fujilogo.png'); + game.loader.load(); + } + var fuji; + var tween; + function create() { + game.stage.backgroundColor = 'rgb(0,0,100)'; + // Here we'll assign the new sprite to the local fuji variable + fuji = game.add.sprite(200, 200, 'fuji'); + // The sprite is 320 x 200 pixels in size + // Here we set the origin to the center of the sprite (half of its width and height, so 160x100) + // This will cause it to rotate on its center + fuji.origin.setTo(160, 100); + tween = game.add.tween(fuji); + // Start it going + rotate(); + } + function rotate() { + tween.clear(); + tween.to({ + rotation: 360 + }, 2000); + tween.onComplete.add(rotate, this); + tween.start(); + } +})(); diff --git a/Tests/sprites/sprite origin 2.ts b/Tests/sprites/sprite origin 2.ts new file mode 100644 index 00000000..b4f469dc --- /dev/null +++ b/Tests/sprites/sprite origin 2.ts @@ -0,0 +1,46 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + + function init() { + + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addImageFile('fuji', 'assets/pics/atari_fujilogo.png'); + game.loader.load(); + + } + + var fuji: Phaser.Sprite; + var tween: Phaser.Tween; + + function create() { + + game.stage.backgroundColor = 'rgb(0,0,100)'; + + // Here we'll assign the new sprite to the local fuji variable + fuji = game.add.sprite(200, 200, 'fuji'); + + // The sprite is 320 x 200 pixels in size + // Here we set the origin to the center of the sprite (half of its width and height, so 160x100) + // This will cause it to rotate on its center + fuji.origin.setTo(160, 100); + + tween = game.add.tween(fuji); + + // Start it going + rotate(); + + } + + function rotate() { + + tween.clear(); + tween.to({ rotation: 360 }, 2000); + tween.onComplete.add(rotate, this); + tween.start(); + + } + +})(); diff --git a/Tests/sprites/sprite origin 3.js b/Tests/sprites/sprite origin 3.js new file mode 100644 index 00000000..8eeb9a24 --- /dev/null +++ b/Tests/sprites/sprite origin 3.js @@ -0,0 +1,30 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + function init() { + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addImageFile('fuji', 'assets/pics/atari_fujilogo.png'); + game.loader.load(); + } + var fuji; + var tween; + function create() { + game.stage.backgroundColor = 'rgb(0,0,100)'; + // Here we'll assign the new sprite to the local fuji variable + fuji = game.add.sprite(300, 300, 'fuji'); + // The sprite is 320 x 200 pixels in size + // Here we set the origin to be the bottom-right of the sprite + fuji.origin.setTo(320, 200); + tween = game.add.tween(fuji); + // Start it going + rotate(); + } + function rotate() { + tween.clear(); + tween.to({ + rotation: 360 + }, 2000); + tween.onComplete.add(rotate, this); + tween.start(); + } +})(); diff --git a/Tests/sprites/sprite origin 3.ts b/Tests/sprites/sprite origin 3.ts new file mode 100644 index 00000000..da3d79bf --- /dev/null +++ b/Tests/sprites/sprite origin 3.ts @@ -0,0 +1,45 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + + function init() { + + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addImageFile('fuji', 'assets/pics/atari_fujilogo.png'); + game.loader.load(); + + } + + var fuji: Phaser.Sprite; + var tween: Phaser.Tween; + + function create() { + + game.stage.backgroundColor = 'rgb(0,0,100)'; + + // Here we'll assign the new sprite to the local fuji variable + fuji = game.add.sprite(300, 300, 'fuji'); + + // The sprite is 320 x 200 pixels in size + // Here we set the origin to be the bottom-right of the sprite + fuji.origin.setTo(320, 200); + + tween = game.add.tween(fuji); + + // Start it going + rotate(); + + } + + function rotate() { + + tween.clear(); + tween.to({ rotation: 360 }, 2000); + tween.onComplete.add(rotate, this); + tween.start(); + + } + +})(); diff --git a/Tests/sprites/sprite origin 4.js b/Tests/sprites/sprite origin 4.js new file mode 100644 index 00000000..18dbeaeb --- /dev/null +++ b/Tests/sprites/sprite origin 4.js @@ -0,0 +1,51 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + function init() { + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addImageFile('fuji', 'assets/pics/atari_fujilogo.png'); + game.loader.load(); + } + var fuji; + var tweenRotate; + var tweenUp; + var tweenDown; + function create() { + game.stage.backgroundColor = 'rgb(0,0,100)'; + // Here we'll assign the new sprite to the local fuji variable + fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji'); + // The sprite is 320 x 200 pixels in size + // Here we set the origin to the center of the sprite again, so we can rotate and scale it at the same time + fuji.origin.setTo(160, 100); + tweenRotate = game.add.tween(fuji); + tweenUp = game.add.tween(fuji.scale); + tweenUp.onComplete.add(scaleDown, this); + tweenDown = game.add.tween(fuji.scale); + tweenDown.onComplete.add(scaleUp, this); + // Start it going + rotate(); + scaleUp(); + } + function rotate() { + tweenRotate.clear(); + tweenRotate.to({ + rotation: 360 + }, 2000); + tweenRotate.onComplete.add(rotate, this); + tweenRotate.start(); + } + function scaleUp() { + tweenUp.to({ + x: 2, + y: 2 + }, 1000, Phaser.Easing.Elastic.Out); + tweenUp.start(); + } + function scaleDown() { + tweenDown.to({ + x: 0.5, + y: 0.5 + }, 1000, Phaser.Easing.Elastic.Out); + tweenDown.start(); + } +})(); diff --git a/Tests/sprites/sprite origin 4.ts b/Tests/sprites/sprite origin 4.ts new file mode 100644 index 00000000..c9c0d521 --- /dev/null +++ b/Tests/sprites/sprite origin 4.ts @@ -0,0 +1,68 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + + function init() { + + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addImageFile('fuji', 'assets/pics/atari_fujilogo.png'); + game.loader.load(); + + } + + var fuji: Phaser.Sprite; + var tweenRotate: Phaser.Tween; + var tweenUp: Phaser.Tween; + var tweenDown: Phaser.Tween; + + function create() { + + game.stage.backgroundColor = 'rgb(0,0,100)'; + + // Here we'll assign the new sprite to the local fuji variable + fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji'); + + // The sprite is 320 x 200 pixels in size + // Here we set the origin to the center of the sprite again, so we can rotate and scale it at the same time + fuji.origin.setTo(160, 100); + + tweenRotate = game.add.tween(fuji); + + tweenUp = game.add.tween(fuji.scale); + tweenUp.onComplete.add(scaleDown, this); + + tweenDown = game.add.tween(fuji.scale); + tweenDown.onComplete.add(scaleUp, this); + + // Start it going + rotate(); + scaleUp(); + + } + + function rotate() { + + tweenRotate.clear(); + tweenRotate.to({ rotation: 360 }, 2000); + tweenRotate.onComplete.add(rotate, this); + tweenRotate.start(); + + } + + function scaleUp() { + + tweenUp.to({ x: 2, y: 2 }, 1000, Phaser.Easing.Elastic.Out); + tweenUp.start(); + + } + + function scaleDown() { + + tweenDown.to({ x: 0.5, y: 0.5 }, 1000, Phaser.Easing.Elastic.Out); + tweenDown.start(); + + } + +})(); diff --git a/Tests/tweens/tween loop 1.js b/Tests/tweens/tween loop 1.js new file mode 100644 index 00000000..f411e934 --- /dev/null +++ b/Tests/tweens/tween loop 1.js @@ -0,0 +1,20 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + function init() { + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addImageFile('swirl', 'assets/pics/color_wheel_swirl.png'); + game.loader.load(); + } + var swirl; + function create() { + // Here we'll assign the new sprite to the local swirl variable + swirl = game.add.sprite(game.stage.centerX, game.stage.centerY, 'swirl'); + // Increase the size of the sprite a little so it covers the edges of the stage + swirl.scale.setTo(1.4, 1.4); + // Create a tween that rotates a full 306 degrees and then repeats (loop set to true) + game.add.tween(swirl).to({ + rotation: 360 + }, 2000, Phaser.Easing.Linear.None, true, 0, true); + } +})(); diff --git a/Tests/tweens/tween loop 1.ts b/Tests/tweens/tween loop 1.ts new file mode 100644 index 00000000..61cc8e97 --- /dev/null +++ b/Tests/tweens/tween loop 1.ts @@ -0,0 +1,30 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + + function init() { + + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addImageFile('swirl', 'assets/pics/color_wheel_swirl.png'); + game.loader.load(); + + } + + var swirl: Phaser.Sprite; + + function create() { + + // Here we'll assign the new sprite to the local swirl variable + swirl = game.add.sprite(game.stage.centerX, game.stage.centerY, 'swirl'); + + // Increase the size of the sprite a little so it covers the edges of the stage + swirl.scale.setTo(1.4, 1.4); + + // Create a tween that rotates a full 306 degrees and then repeats (loop set to true) + game.add.tween(swirl).to({ rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); + + } + +})(); diff --git a/Tests/tweens/tween loop 2.js b/Tests/tweens/tween loop 2.js new file mode 100644 index 00000000..2cc240f0 --- /dev/null +++ b/Tests/tweens/tween loop 2.js @@ -0,0 +1,24 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + function init() { + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addImageFile('swirl', 'assets/pics/color_wheel_swirl.png'); + game.loader.load(); + } + var swirl; + function create() { + // Here we'll assign the new sprite to the local swirl variable + swirl = game.add.sprite(game.stage.centerX, game.stage.centerY, 'swirl'); + // Increase the size of the sprite a little so it covers the edges of the stage + swirl.scale.setTo(1.4, 1.4); + // Create a tween that rotates a full 306 degrees and then repeats (loop set to true) + game.add.tween(swirl).to({ + rotation: 360 + }, 2000, Phaser.Easing.Linear.None, true, 0, true); + game.add.tween(swirl.scale).to({ + x: 4, + y: 4 + }, 1000, Phaser.Easing.Linear.None, true, 0, true, true); + } +})(); diff --git a/Tests/tweens/tween loop 2.ts b/Tests/tweens/tween loop 2.ts new file mode 100644 index 00000000..c5b3be7b --- /dev/null +++ b/Tests/tweens/tween loop 2.ts @@ -0,0 +1,31 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + + function init() { + + // Using Phasers asset loader we load up a PNG from the assets folder + game.loader.addImageFile('swirl', 'assets/pics/color_wheel_swirl.png'); + game.loader.load(); + + } + + var swirl: Phaser.Sprite; + + function create() { + + // Here we'll assign the new sprite to the local swirl variable + swirl = game.add.sprite(game.stage.centerX, game.stage.centerY, 'swirl'); + + // Increase the size of the sprite a little so it covers the edges of the stage + swirl.scale.setTo(1.4, 1.4); + + // Create a tween that rotates a full 306 degrees and then repeats (loop set to true) + //game.add.tween(swirl).to({ rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); + game.add.tween(swirl.scale).to({ x: 4, y: 4 }, 1000, Phaser.Easing.Linear.None, true, 0, true, true); + + } + +})(); diff --git a/build/phaser.d.ts b/build/phaser.d.ts index ab0af752..274391d1 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -1080,6 +1080,12 @@ module Phaser { */ public reverse(): Vec2; /** + * Check if both the x and y of this vector equal the given value. + * + * @return {Boolean} + */ + public equals(value): bool; + /** * Returns a string representation of this object. * @method toString * @return {string} a string representation of the object. @@ -1415,7 +1421,7 @@ module Phaser { * Any Sprite that has animation contains an instance of the AnimationManager, which is used to add, play and update * sprite specific animations. */ -module Phaser { +module Phaser.Components { class AnimationManager { /** * AnimationManager constructor @@ -1423,7 +1429,7 @@ module Phaser { * * @param parent {Sprite} Owner sprite of this manager. */ - constructor(game: Game, parent: Sprite); + constructor(parent: Sprite); /** * Local private reference to game. */ @@ -2069,7 +2075,7 @@ module Phaser { */ module Phaser.Components { class Texture { - constructor(parent: Sprite, key?: string, canvas?: HTMLCanvasElement, context?: CanvasRenderingContext2D); + constructor(parent: Sprite, key?: string); /** * */ @@ -2219,6 +2225,11 @@ module Phaser { */ public texture: Components.Texture; /** + * This manages animations of the sprite. You can modify animations though it. (see AnimationManager) + * @type AnimationManager + */ + public animations: Components.AnimationManager; + /** * The frame boundary around this Sprite. * For non-animated sprites this matches the loaded texture dimensions. * For animated sprites it will be updated as part of the animation loop, changing to the dimensions of the current animation frame. @@ -2229,6 +2240,14 @@ module Phaser { */ public scale: Vec2; /** + * Skew the Sprite along the x and y axis. A skew value of 0 is no skew. + */ + public skew: Vec2; + /** + * A boolean representing if the Sprite has been modified in any way via a scale, rotate, flip or skew. + */ + public modified: bool; + /** * The influence of camera movement upon the Sprite. */ public scrollFactor: Vec2; @@ -2264,6 +2283,20 @@ module Phaser { */ public rotation : number; /** + * Get the animation frame number. + */ + /** + * Set the animation frame by frame number. + */ + public frame : number; + /** + * Get the animation frame name. + */ + /** + * Set the animation frame by frame name. + */ + public frameName : string; + /** * Pre-update is called right before update() on each object in the game loop. */ public preUpdate(): void; @@ -2818,6 +2851,19 @@ module Phaser { private _duration; private _delayTime; private _startTime; + private _tempElapsed; + private _tempValue; + /** + * Will this tween automatically restart when it completes? + * @type {boolean} + */ + private _loop; + /** + * A yoyo tween is one that plays once fully, then reverses back to the original tween values before completing. + * @type {boolean} + */ + private _yoyo; + private _yoyoCount; /** * Easing function which actually updating this tween. * @type {function} @@ -2851,13 +2897,18 @@ module Phaser { * @param [ease] {any} Easing function. * @param [autoStart] {boolean} Whether this tween will start automatically or not. * @param [delay] {number} delay before this tween will start, defaults to 0 (no delay) + * @param [loop] {boolean} Should the tween automatically restart once complete? (ignores any chained tweens) * @return {Tween} Itself. */ - public to(properties, duration?: number, ease?: any, autoStart?: bool, delay?: number): Tween; + public to(properties, duration?: number, ease?: any, autoStart?: bool, delay?: number, loop?: bool, yoyo?: bool): Tween; + public loop(value: bool): Tween; + public yoyo(value: bool): Tween; /** * Start to tween. */ - public start(): Tween; + public start(looped?: bool): Tween; + public reverse(): Tween; + public reset(): Tween; public clear(): Tween; /** * Stop tweening. @@ -2874,10 +2925,6 @@ module Phaser { */ public chain(tween: Tween): Tween; /** - * Debug value? - */ - public debugValue; - /** * Update tweening. * @param time {number} Current time from game clock. * @return {boolean} Return false if this completed and no need to update, otherwise return true. diff --git a/build/phaser.js b/build/phaser.js index 3d982d13..962d81df 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -1986,6 +1986,14 @@ var Phaser; this.y = -this.y; return this; }; + Vec2.prototype.equals = /** + * Check if both the x and y of this vector equal the given value. + * + * @return {Boolean} + */ + function (value) { + return (this.x == value && this.y == value); + }; Vec2.prototype.toString = /** * Returns a string representation of this object. * @method toString @@ -2436,204 +2444,207 @@ var Phaser; })(); Phaser.FrameData = FrameData; })(Phaser || (Phaser = {})); -/// -/// -/// -/// -/// -/// -/** -* Phaser - AnimationManager -* -* Any Sprite that has animation contains an instance of the AnimationManager, which is used to add, play and update -* sprite specific animations. -*/ var Phaser; (function (Phaser) { - var AnimationManager = (function () { - /** - * AnimationManager constructor - * Create a new AnimationManager. - * - * @param parent {Sprite} Owner sprite of this manager. - */ - function AnimationManager(game, parent) { + /// + /// + /// + /// + /// + /// + /** + * Phaser - AnimationManager + * + * Any Sprite that has animation contains an instance of the AnimationManager, which is used to add, play and update + * sprite specific animations. + */ + (function (Components) { + var AnimationManager = (function () { /** - * Data contains animation frames. - * @type {FrameData} + * AnimationManager constructor + * Create a new AnimationManager. + * + * @param parent {Sprite} Owner sprite of this manager. */ - this._frameData = null; - /** - * Keeps track of the current frame of animation. - */ - this.currentFrame = null; - this._game = game; - this._parent = parent; - this._anims = { - }; - } - AnimationManager.prototype.loadFrameData = /** - * Load animation frame data. - * @param frameData Data to be loaded. - */ - function (frameData) { - this._frameData = frameData; - this.frame = 0; - }; - AnimationManager.prototype.add = /** - * Add a new animation. - * @param name {string} What this animation should be called (e.g. "run"). - * @param frames {any[]} An array of numbers/strings indicating what frames to play in what order (e.g. [1, 2, 3] or ['run0', 'run1', run2]). - * @param frameRate {number} The speed in frames per second that the animation should play at (e.g. 60 fps). - * @param loop {boolean} Whether or not the animation is looped or just plays once. - * @param useNumericIndex {boolean} Use number indexes instead of string indexes? - * @return {Animation} The Animation that was created - */ - function (name, frames, frameRate, loop, useNumericIndex) { - if (typeof frames === "undefined") { frames = null; } - if (typeof frameRate === "undefined") { frameRate = 60; } - if (typeof loop === "undefined") { loop = false; } - if (typeof useNumericIndex === "undefined") { useNumericIndex = true; } - if(this._frameData == null) { - return; + function AnimationManager(parent) { + /** + * Data contains animation frames. + * @type {FrameData} + */ + this._frameData = null; + /** + * Keeps track of the current frame of animation. + */ + this.currentFrame = null; + this._parent = parent; + this._game = parent.game; + this._anims = { + }; } - if(frames == null) { - frames = this._frameData.getFrameIndexes(); - } else { - if(this.validateFrames(frames, useNumericIndex) == false) { - throw Error('Invalid frames given to Animation ' + name); + AnimationManager.prototype.loadFrameData = /** + * Load animation frame data. + * @param frameData Data to be loaded. + */ + function (frameData) { + this._frameData = frameData; + this.frame = 0; + }; + AnimationManager.prototype.add = /** + * Add a new animation. + * @param name {string} What this animation should be called (e.g. "run"). + * @param frames {any[]} An array of numbers/strings indicating what frames to play in what order (e.g. [1, 2, 3] or ['run0', 'run1', run2]). + * @param frameRate {number} The speed in frames per second that the animation should play at (e.g. 60 fps). + * @param loop {boolean} Whether or not the animation is looped or just plays once. + * @param useNumericIndex {boolean} Use number indexes instead of string indexes? + * @return {Animation} The Animation that was created + */ + function (name, frames, frameRate, loop, useNumericIndex) { + if (typeof frames === "undefined") { frames = null; } + if (typeof frameRate === "undefined") { frameRate = 60; } + if (typeof loop === "undefined") { loop = false; } + if (typeof useNumericIndex === "undefined") { useNumericIndex = true; } + if(this._frameData == null) { return; } - } - if(useNumericIndex == false) { - frames = this._frameData.getFrameIndexesByName(frames); - } - this._anims[name] = new Phaser.Animation(this._game, this._parent, this._frameData, name, frames, frameRate, loop); - this.currentAnim = this._anims[name]; - this.currentFrame = this.currentAnim.currentFrame; - return this._anims[name]; - }; - AnimationManager.prototype.validateFrames = /** - * Check whether the frames is valid. - * @param frames {any[]} Frames to be validated. - * @param useNumericIndex {boolean} Does these frames use number indexes or string indexes? - * @return {boolean} True if they're valid, otherwise return false. - */ - function (frames, useNumericIndex) { - for(var i = 0; i < frames.length; i++) { - if(useNumericIndex == true) { - if(frames[i] > this._frameData.total) { - return false; - } + if(frames == null) { + frames = this._frameData.getFrameIndexes(); } else { - if(this._frameData.checkFrameName(frames[i]) == false) { - return false; + if(this.validateFrames(frames, useNumericIndex) == false) { + throw Error('Invalid frames given to Animation ' + name); + return; } } - } - return true; - }; - AnimationManager.prototype.play = /** - * Play animation with specific name. - * @param name {string} The string name of the animation you want to play. - * @param frameRate {number} FrameRate you want to specify instead of using default. - * @param loop {boolean} Whether or not the animation is looped or just plays once. - */ - function (name, frameRate, loop) { - if (typeof frameRate === "undefined") { frameRate = null; } - if(this._anims[name]) { - if(this.currentAnim == this._anims[name]) { - if(this.currentAnim.isPlaying == false) { + if(useNumericIndex == false) { + frames = this._frameData.getFrameIndexesByName(frames); + } + this._anims[name] = new Phaser.Animation(this._game, this._parent, this._frameData, name, frames, frameRate, loop); + this.currentAnim = this._anims[name]; + this.currentFrame = this.currentAnim.currentFrame; + return this._anims[name]; + }; + AnimationManager.prototype.validateFrames = /** + * Check whether the frames is valid. + * @param frames {any[]} Frames to be validated. + * @param useNumericIndex {boolean} Does these frames use number indexes or string indexes? + * @return {boolean} True if they're valid, otherwise return false. + */ + function (frames, useNumericIndex) { + for(var i = 0; i < frames.length; i++) { + if(useNumericIndex == true) { + if(frames[i] > this._frameData.total) { + return false; + } + } else { + if(this._frameData.checkFrameName(frames[i]) == false) { + return false; + } + } + } + return true; + }; + AnimationManager.prototype.play = /** + * Play animation with specific name. + * @param name {string} The string name of the animation you want to play. + * @param frameRate {number} FrameRate you want to specify instead of using default. + * @param loop {boolean} Whether or not the animation is looped or just plays once. + */ + function (name, frameRate, loop) { + if (typeof frameRate === "undefined") { frameRate = null; } + if(this._anims[name]) { + if(this.currentAnim == this._anims[name]) { + if(this.currentAnim.isPlaying == false) { + this.currentAnim.play(frameRate, loop); + } + } else { + this.currentAnim = this._anims[name]; this.currentAnim.play(frameRate, loop); } - } else { - this.currentAnim = this._anims[name]; - this.currentAnim.play(frameRate, loop); } - } - }; - AnimationManager.prototype.stop = /** - * Stop animation by name. - * Current animation will be automatically set to the stopped one. - */ - function (name) { - if(this._anims[name]) { - this.currentAnim = this._anims[name]; - this.currentAnim.stop(); - } - }; - AnimationManager.prototype.update = /** - * Update animation and parent sprite's bounds. - */ - function () { - if(this.currentAnim && this.currentAnim.update() == true) { - this.currentFrame = this.currentAnim.currentFrame; - this._parent.frameBounds.width = this.currentFrame.width; - this._parent.frameBounds.height = this.currentFrame.height; - } - }; - Object.defineProperty(AnimationManager.prototype, "frameData", { - get: function () { - return this._frameData; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(AnimationManager.prototype, "frameTotal", { - get: function () { - if(this._frameData) { - return this._frameData.total; - } else { - return -1; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(AnimationManager.prototype, "frame", { - get: function () { - return this._frameIndex; - }, - set: function (value) { - if(this._frameData.getFrame(value) !== null) { - this.currentFrame = this._frameData.getFrame(value); - this._parent.frameBounds.width = this.currentFrame.width; - this._parent.frameBounds.height = this.currentFrame.height; - this._frameIndex = value; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(AnimationManager.prototype, "frameName", { - get: function () { - return this.currentFrame.name; - }, - set: function (value) { - if(this._frameData.getFrameByName(value) !== null) { - this.currentFrame = this._frameData.getFrameByName(value); - this._parent.frameBounds.width = this.currentFrame.width; - this._parent.frameBounds.height = this.currentFrame.height; - this._frameIndex = this.currentFrame.index; - } - }, - enumerable: true, - configurable: true - }); - AnimationManager.prototype.destroy = /** - * Removes all related references - */ - function () { - this._anims = { }; - this._frameData = null; - this._frameIndex = 0; - this.currentAnim = null; - this.currentFrame = null; - }; - return AnimationManager; - })(); - Phaser.AnimationManager = AnimationManager; + AnimationManager.prototype.stop = /** + * Stop animation by name. + * Current animation will be automatically set to the stopped one. + */ + function (name) { + if(this._anims[name]) { + this.currentAnim = this._anims[name]; + this.currentAnim.stop(); + } + }; + AnimationManager.prototype.update = /** + * Update animation and parent sprite's bounds. + */ + function () { + if(this.currentAnim && this.currentAnim.update() == true) { + this.currentFrame = this.currentAnim.currentFrame; + this._parent.frameBounds.width = this.currentFrame.width; + this._parent.frameBounds.height = this.currentFrame.height; + } + }; + Object.defineProperty(AnimationManager.prototype, "frameData", { + get: function () { + return this._frameData; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(AnimationManager.prototype, "frameTotal", { + get: function () { + if(this._frameData) { + return this._frameData.total; + } else { + return -1; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(AnimationManager.prototype, "frame", { + get: function () { + return this._frameIndex; + }, + set: function (value) { + if(this._frameData.getFrame(value) !== null) { + this.currentFrame = this._frameData.getFrame(value); + this._parent.frameBounds.width = this.currentFrame.width; + this._parent.frameBounds.height = this.currentFrame.height; + this._frameIndex = value; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(AnimationManager.prototype, "frameName", { + get: function () { + return this.currentFrame.name; + }, + set: function (value) { + if(this._frameData.getFrameByName(value) !== null) { + this.currentFrame = this._frameData.getFrameByName(value); + this._parent.frameBounds.width = this.currentFrame.width; + this._parent.frameBounds.height = this.currentFrame.height; + this._frameIndex = this.currentFrame.index; + } + }, + enumerable: true, + configurable: true + }); + AnimationManager.prototype.destroy = /** + * Removes all related references + */ + function () { + this._anims = { + }; + this._frameData = null; + this._frameIndex = 0; + this.currentAnim = null; + this.currentFrame = null; + }; + return AnimationManager; + })(); + Components.AnimationManager = AnimationManager; + })(Phaser.Components || (Phaser.Components = {})); + var Components = Phaser.Components; })(Phaser || (Phaser = {})); /// /// @@ -3680,10 +3691,8 @@ var Phaser; */ (function (Components) { var Texture = (function () { - function Texture(parent, key, canvas, context) { + function Texture(parent, key) { if (typeof key === "undefined") { key = ''; } - if (typeof canvas === "undefined") { canvas = null; } - if (typeof context === "undefined") { context = null; } /** * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. */ @@ -3716,8 +3725,8 @@ var Phaser; this.flippedY = false; this._game = parent.game; this._sprite = parent; - this.canvas = canvas; - this.context = context; + this.canvas = parent.game.stage.canvas; + this.context = parent.game.stage.context; this.alpha = 1; this.flippedX = false; this.flippedY = false; @@ -3752,22 +3761,17 @@ var Phaser; */ function (key, clearAnimations) { if (typeof clearAnimations === "undefined") { clearAnimations = true; } - //if (clearAnimations && sprite.animations.frameData !== null) - //{ - // sprite.animations.destroy(); - //} + if(clearAnimations && this._sprite.animations.frameData !== null) { + this._sprite.animations.destroy(); + } if(this._game.cache.getImage(key) !== null) { this.setTo(this._game.cache.getImage(key), null); if(this._game.cache.isSpriteSheet(key)) { - //sprite.animations.loadFrameData(sprite._game.cache.getFrameData(key)); - //sprite.collisionMask.width = sprite.animations.currentFrame.width; - //sprite.collisionMask.height = sprite.animations.currentFrame.height; - } else { + this._sprite.animations.loadFrameData(this._sprite.game.cache.getFrameData(key)); + } else { this._sprite.frameBounds.width = this.width; this._sprite.frameBounds.height = this.height; - //sprite.collisionMask.width = sprite._texture.width; - //sprite.collisionMask.height = sprite._texture.height; - } + } } }; Texture.prototype.loadDynamicTexture = /** @@ -3776,10 +3780,9 @@ var Phaser; * @return {Sprite} Sprite instance itself. */ function (texture) { - //if (sprite.animations.frameData !== null) - //{ - // sprite.animations.destroy(); - //} + if(this._sprite.animations.frameData !== null) { + this._sprite.animations.destroy(); + } this.setTo(null, texture); this._sprite.frameBounds.width = this.width; this._sprite.frameBounds.height = this.height; @@ -3821,6 +3824,7 @@ var Phaser; var Components = Phaser.Components; })(Phaser || (Phaser = {})); /// +/// /// /// /// @@ -3853,6 +3857,10 @@ var Phaser; */ this._rotation = 0; /** + * A boolean representing if the Sprite has been modified in any way via a scale, rotate, flip or skew. + */ + this.modified = false; + /** * x value of the object. */ this.x = 0; @@ -3879,15 +3887,19 @@ var Phaser; this.visible = true; this.alive = true; this.frameBounds = new Phaser.Rectangle(x, y, width, height); - this.origin = new Phaser.Vec2(0, 0); this.scrollFactor = new Phaser.Vec2(1, 1); - this.scale = new Phaser.Vec2(1, 1); this.x = x; this.y = y; - this.z = 0; - this.texture = new Phaser.Components.Texture(this, key, game.stage.canvas, game.stage.context); + this.z = 0// not used yet + ; + this.animations = new Phaser.Components.AnimationManager(this); + this.texture = new Phaser.Components.Texture(this, key); this.width = this.frameBounds.width; this.height = this.frameBounds.height; + // Transform related (if we add any more then move to a component) + this.origin = new Phaser.Vec2(this.width / 2, this.height / 2); + this.scale = new Phaser.Vec2(1, 1); + this.skew = new Phaser.Vec2(0, 0); } Object.defineProperty(Sprite.prototype, "rotation", { get: /** @@ -3906,6 +3918,38 @@ var Phaser; enumerable: true, configurable: true }); + Object.defineProperty(Sprite.prototype, "frame", { + get: /** + * Get the animation frame number. + */ + function () { + return this.animations.frame; + }, + set: /** + * Set the animation frame by frame number. + */ + function (value) { + this.animations.frame = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Sprite.prototype, "frameName", { + get: /** + * Get the animation frame name. + */ + function () { + return this.animations.frameName; + }, + set: /** + * Set the animation frame by frame name. + */ + function (value) { + this.animations.frameName = value; + }, + enumerable: true, + configurable: true + }); Sprite.prototype.preUpdate = /** * Pre-update is called right before update() on each object in the game loop. */ @@ -3913,7 +3957,10 @@ var Phaser; //this.last.x = this.frameBounds.x; //this.last.y = this.frameBounds.y; //this.collisionMask.preUpdate(); - }; + if(this.modified == false && (!this.scale.equals(1) || !this.skew.equals(0) || this.rotation != 0 || this.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { + this.modified = true; + } + }; Sprite.prototype.update = /** * Override this function to update your class's position and appearance. */ @@ -3923,9 +3970,8 @@ var Phaser; * Automatically called after update() by the game loop. */ function () { - /* this.animations.update(); - + /* if (this.moves) { this.updateMotion(); @@ -3972,7 +4018,10 @@ var Phaser; this.wasTouching = this.touching; this.touching = Collision.NONE; */ - }; + if(this.modified == true && this.scale.equals(1) && this.skew.equals(0) && this.rotation == 0 && this.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { + this.modified = false; + } + }; Sprite.prototype.destroy = /** * Clean up memory. */ @@ -5077,6 +5126,17 @@ var Phaser; this._delayTime = 0; this._startTime = null; /** + * Will this tween automatically restart when it completes? + * @type {boolean} + */ + this._loop = false; + /** + * A yoyo tween is one that plays once fully, then reverses back to the original tween values before completing. + * @type {boolean} + */ + this._yoyo = false; + this._yoyoCount = 0; + /** * Contains chained tweens. * @type {Tweens[]} */ @@ -5098,13 +5158,16 @@ var Phaser; * @param [ease] {any} Easing function. * @param [autoStart] {boolean} Whether this tween will start automatically or not. * @param [delay] {number} delay before this tween will start, defaults to 0 (no delay) + * @param [loop] {boolean} Should the tween automatically restart once complete? (ignores any chained tweens) * @return {Tween} Itself. */ - function (properties, duration, ease, autoStart, delay) { + function (properties, duration, ease, autoStart, delay, loop, yoyo) { if (typeof duration === "undefined") { duration = 1000; } if (typeof ease === "undefined") { ease = null; } if (typeof autoStart === "undefined") { autoStart = false; } if (typeof delay === "undefined") { delay = 0; } + if (typeof loop === "undefined") { loop = false; } + if (typeof yoyo === "undefined") { yoyo = false; } this._duration = duration; // If properties isn't an object this will fail, sanity check it here somehow? this._valuesEnd = properties; @@ -5114,21 +5177,36 @@ var Phaser; if(delay > 0) { this._delayTime = delay; } + this._loop = loop; + this._yoyo = yoyo; + this._yoyoCount = 0; if(autoStart === true) { return this.start(); } else { return this; } }; + Tween.prototype.loop = function (value) { + this._loop = value; + return this; + }; + Tween.prototype.yoyo = function (value) { + this._yoyo = value; + this._yoyoCount = 0; + return this; + }; Tween.prototype.start = /** * Start to tween. */ - function () { + function (looped) { + if (typeof looped === "undefined") { looped = false; } if(this._game === null || this._object === null) { return; } - this._manager.add(this); - this.onStart.dispatch(this._object); + if(looped == false) { + this._manager.add(this); + this.onStart.dispatch(this._object); + } this._startTime = this._game.time.now + this._delayTime; for(var property in this._valuesEnd) { // This prevents the interpolation of null values or of non-existing properties @@ -5146,10 +5224,30 @@ var Phaser; this._object[property] ].concat(this._valuesEnd[property]); } - this._valuesStart[property] = this._object[property]; + if(looped == false) { + this._valuesStart[property] = this._object[property]; + } } return this; }; + Tween.prototype.reverse = function () { + var tempObj = { + }; + for(var property in this._valuesStart) { + tempObj[property] = this._valuesStart[property]; + this._valuesStart[property] = this._valuesEnd[property]; + this._valuesEnd[property] = tempObj[property]; + } + this._yoyoCount++; + return this.start(true); + }; + Tween.prototype.reset = function () { + // Reset the properties back to what they were before + for(var property in this._valuesStart) { + this._object[property] = this._valuesStart[property]; + } + return this.start(true); + }; Tween.prototype.clear = function () { this._chainedTweens = []; this.onStart.removeAll(); @@ -5234,24 +5332,48 @@ var Phaser; if(time < this._startTime) { return true; } - var elapsed = (time - this._startTime) / this._duration; - elapsed = elapsed > 1 ? 1 : elapsed; - var value = this._easingFunction(elapsed); + this._tempElapsed = (time - this._startTime) / this._duration; + this._tempElapsed = this._tempElapsed > 1 ? 1 : this._tempElapsed; + this._tempValue = this._easingFunction(this._tempElapsed); for(var property in this._valuesStart) { // Add checks for object, array, numeric up front if(this._valuesEnd[property] instanceof Array) { - this._object[property] = this._interpolationFunction(this._valuesEnd[property], value); + this._object[property] = this._interpolationFunction(this._valuesEnd[property], this._tempValue); } else { - this._object[property] = this._valuesStart[property] + (this._valuesEnd[property] - this._valuesStart[property]) * value; + this._object[property] = this._valuesStart[property] + (this._valuesEnd[property] - this._valuesStart[property]) * this._tempValue; } } - this.onUpdate.dispatch(this._object, value); - if(elapsed == 1) { - this.onComplete.dispatch(this._object); - for(var i = 0; i < this._chainedTweens.length; i++) { - this._chainedTweens[i].start(); + this.onUpdate.dispatch(this._object, this._tempValue); + if(this._tempElapsed == 1) { + // Yoyo? + if(this._yoyo) { + if(this._yoyoCount == 0) { + // Reverse the tween + this.reverse(); + return true; + } else { + // We've yoyo'd once already, quit? + if(this._loop == false) { + this.onComplete.dispatch(this._object); + for(var i = 0; i < this._chainedTweens.length; i++) { + this._chainedTweens[i].start(); + } + return false; + } + } + } + // Loop? + if(this._loop) { + this._yoyoCount = 0; + this.reset(); + return true; + } else { + this.onComplete.dispatch(this._object); + for(var i = 0; i < this._chainedTweens.length; i++) { + this._chainedTweens[i].start(); + } + return false; } - return false; } return true; }; @@ -10376,20 +10498,16 @@ var Phaser; this._dy = (camera.scaledY * sprite.scrollFactor.y) + sprite.frameBounds.y - (camera.worldView.y * sprite.scrollFactor.y); this._dw = sprite.frameBounds.width; this._dh = sprite.frameBounds.height; - /* - if (this._dynamicTexture == false && this.animations.currentFrame !== null) - { - this._sx = this.animations.currentFrame.x; - this._sy = this.animations.currentFrame.y; - - if (this.animations.currentFrame.trimmed) - { - this._dx += this.animations.currentFrame.spriteSourceSizeX; - this._dy += this.animations.currentFrame.spriteSourceSizeY; + if(sprite.animations.currentFrame !== null) { + this._sx = sprite.animations.currentFrame.x; + this._sy = sprite.animations.currentFrame.y; + if(sprite.animations.currentFrame.trimmed) { + this._dx += sprite.animations.currentFrame.spriteSourceSizeX; + this._dy += sprite.animations.currentFrame.spriteSourceSizeY; + } } - } - // Apply camera difference - looks like this is already applied? + /* if (sprite.scrollFactor.x !== 1 || sprite.scrollFactor.y !== 1) { //this._dx -= (camera.worldView.x * this.scrollFactor.x); @@ -10397,7 +10515,7 @@ var Phaser; } */ // Rotation and Flipped - if(sprite.scale.x != 1 || sprite.scale.y != 1 || sprite.rotation != 0 || sprite.rotationOffset != 0 || sprite.texture.flippedX || sprite.texture.flippedY) { + if(sprite.modified) { if(sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.rotationOffset !== 0)) { this._sin = Math.sin(sprite.game.math.degreesToRadians(sprite.rotationOffset + sprite.rotation)); this._cos = Math.cos(sprite.game.math.degreesToRadians(sprite.rotationOffset + sprite.rotation)); @@ -10410,13 +10528,15 @@ var Phaser; // e = translate x // f = translate y sprite.texture.context.save(); - sprite.texture.context.setTransform(this._cos * this._fx, this._sin * this._fx, -this._sin * this._fy, this._cos * this._fy, this._dx, this._dy); + sprite.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + sprite.skew.x, -(this._sin * this._fy) + sprite.skew.y, this._cos * this._fy, this._dx, this._dy); this._dx = -sprite.origin.x; this._dy = -sprite.origin.y; } else { - this._dw = sprite.frameBounds.width * sprite.scale.x; - this._dh = sprite.frameBounds.height * sprite.scale.y; - } + this._dx -= sprite.origin.x; + this._dy -= sprite.origin.y; + //this._dw = sprite.frameBounds.width * sprite.scale.x; + //this._dh = sprite.frameBounds.height * sprite.scale.y; + } this._sx = Math.round(this._sx); this._sy = Math.round(this._sy); this._sw = Math.round(this._sw); @@ -10441,7 +10561,7 @@ var Phaser; sprite.texture.context.fillStyle = 'rgb(255,255,255)'; sprite.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); } - if(sprite.scale.x != 1 || sprite.scale.y != 1 || sprite.rotation != 0 || sprite.rotationOffset != 0 || sprite.texture.flippedX || sprite.texture.flippedY) { + if(sprite.modified) { sprite.texture.context.restore(); } //if (this.renderDebug)