From 730594835ac0de94502e50f7a1d9cdd813f80dd6 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Jun 2013 02:47:08 +0100 Subject: [PATCH 1/8] New Texture and Transform components which are now used by Sprite, Group and Camera. --- Phaser/Motion.ts | 16 +- Phaser/Phaser.csproj | 12 +- Phaser/Stage.ts | 11 +- Phaser/Statics.ts | 2 +- Phaser/cameras/Camera.ts | 407 +- Phaser/cameras/CameraManager.ts | 69 + Phaser/components/{sprite => }/Texture.ts | 124 +- Phaser/components/TilemapLayer.ts | 8 +- Phaser/components/Transform.ts | 72 + Phaser/components/animation/Animation.ts | 4 +- .../components/animation/AnimationManager.ts | 34 +- Phaser/components/animation/Frame.ts | 19 +- Phaser/components/sprite/Events.ts | 8 +- Phaser/components/sprite/Input.ts | 106 +- Phaser/core/Group.ts | 104 +- Phaser/core/Rectangle.ts | 36 +- Phaser/gameobjects/DynamicTexture.ts | 14 +- Phaser/gameobjects/Emitter.ts | 4 +- Phaser/gameobjects/GameObjectFactory.ts | 5 +- Phaser/gameobjects/IGameObject.ts | 15 +- Phaser/gameobjects/Sprite.ts | 143 +- Phaser/input/Pointer.ts | 3 +- Phaser/loader/AnimationLoader.ts | 1 + Phaser/loader/Loader.ts | 2 +- Phaser/math/GameMath.ts | 16 +- Phaser/physics/Body.ts | 48 +- Phaser/physics/PhysicsManager.ts | 6 +- Phaser/renderers/CanvasRenderer.ts | 413 +- Phaser/renderers/HeadlessRenderer.ts | 12 + Phaser/renderers/IRenderer.ts | 6 +- Phaser/system/StageScaleMode.ts | 83 +- Phaser/utils/DebugUtils.ts | 4 +- Phaser/utils/PointUtils.ts | 4 +- Phaser/utils/RectangleUtils.ts | 8 +- Phaser/utils/SpriteUtils.ts | 30 +- README.md | 23 +- Tests/Tests.csproj | 40 +- Tests/assets/sprites/invaderpig.json | 28 + Tests/assets/sprites/invaderpig.png | Bin 0 -> 1956 bytes Tests/cameras/basic camera 1.js | 8 +- Tests/cameras/basic camera 1.ts | 8 +- Tests/cameras/scrollfactor 1.js | 10 +- Tests/cameras/scrollfactor 1.ts | 10 +- Tests/cameras/scrollfactor 2.js | 10 +- Tests/cameras/scrollfactor 2.ts | 10 +- Tests/input/drag sprite 1.js | 1 + Tests/input/world drag.js | 8 +- Tests/input/world drag.ts | 8 +- Tests/particles/mousetrail.js | 2 +- Tests/particles/mousetrail.ts | 2 +- Tests/phaser.js | 7562 +++++++++-------- Tests/scrollzones/blasteroids.js | 12 +- Tests/scrollzones/blasteroids.ts | 12 +- Tests/scrollzones/skewed scroller.js | 10 +- Tests/scrollzones/skewed scroller.ts | 10 +- Tests/sprites/animation 1.js | 2 +- Tests/sprites/animation 1.ts | 2 +- Tests/sprites/animation 2.js | 2 +- Tests/sprites/animation 2.ts | 2 +- Tests/sprites/atlas 1.js | 17 + Tests/sprites/atlas 1.ts | 29 + Tests/sprites/atlas 2.js | 19 + Tests/sprites/atlas 2.ts | 33 + Tests/sprites/create sprite 1.js | 8 +- Tests/sprites/create sprite 1.ts | 7 +- Tests/sprites/scale sprite 1.js | 8 +- Tests/sprites/scale sprite 1.ts | 8 +- Tests/sprites/scale sprite 2.js | 6 +- Tests/sprites/scale sprite 2.ts | 6 +- Tests/sprites/scale sprite 3.js | 2 +- Tests/sprites/scale sprite 3.ts | 2 +- Tests/sprites/scale sprite 4.js | 4 +- Tests/sprites/scale sprite 4.ts | 4 +- Tests/sprites/scale sprite 5.js | 4 +- Tests/sprites/scale sprite 5.ts | 4 +- Tests/sprites/sprite origin 1.js | 2 +- Tests/sprites/sprite origin 1.ts | 2 +- Tests/sprites/sprite origin 2.js | 4 +- Tests/sprites/sprite origin 2.ts | 4 +- Tests/sprites/sprite origin 3.js | 4 +- Tests/sprites/sprite origin 3.ts | 4 +- Tests/sprites/sprite origin 4.js | 8 +- Tests/sprites/sprite origin 4.ts | 8 +- Tests/tweens/tween loop 1.js | 6 +- Tests/tweens/tween loop 1.ts | 6 +- Tests/tweens/tween loop 2.js | 8 +- Tests/tweens/tween loop 2.ts | 8 +- build/phaser.d.ts | 3997 ++++----- build/phaser.js | 7562 +++++++++-------- 89 files changed, 11304 insertions(+), 10111 deletions(-) rename Phaser/components/{sprite => }/Texture.ts (55%) create mode 100644 Phaser/components/Transform.ts create mode 100644 Tests/assets/sprites/invaderpig.json create mode 100644 Tests/assets/sprites/invaderpig.png create mode 100644 Tests/sprites/atlas 1.js create mode 100644 Tests/sprites/atlas 1.ts create mode 100644 Tests/sprites/atlas 2.js create mode 100644 Tests/sprites/atlas 2.ts diff --git a/Phaser/Motion.ts b/Phaser/Motion.ts index 54098b6b..16e4a040 100644 --- a/Phaser/Motion.ts +++ b/Phaser/Motion.ts @@ -210,8 +210,8 @@ module Phaser { * @return {number} Distance (in pixels) */ public distanceToPoint(a: Sprite, target: Point): number { - var dx: number = (a.x + a.origin.x) - (target.x); - var dy: number = (a.y + a.origin.y) - (target.y); + var dx: number = (a.x + a.transform.origin.x) - (target.x); + var dy: number = (a.y + a.transform.origin.y) - (target.y); return this.game.math.vectorLength(dx, dy); } @@ -223,8 +223,8 @@ module Phaser { * @return {number} The distance between the given sprite and the mouse coordinates */ public distanceToMouse(a: Sprite): number { - var dx: number = (a.x + a.origin.x) - this.game.input.x; - var dy: number = (a.y + a.origin.y) - this.game.input.y; + var dx: number = (a.x + a.transform.origin.x) - this.game.input.x; + var dy: number = (a.y + a.transform.origin.y) - this.game.input.y; return this.game.math.vectorLength(dx, dy); } @@ -240,8 +240,8 @@ module Phaser { * @return {number} The angle (in radians unless asDegrees is true) */ public angleBetweenPoint(a: Sprite, target: Point, asDegrees: bool = false): number { - var dx: number = (target.x) - (a.x + a.origin.x); - var dy: number = (target.y) - (a.y + a.origin.y); + var dx: number = (target.x) - (a.x + a.transform.origin.x); + var dy: number = (target.y) - (a.y + a.transform.origin.y); if (asDegrees) { @@ -265,8 +265,8 @@ module Phaser { */ public angleBetween(a: Sprite, b: Sprite, asDegrees: bool = false): number { - var dx: number = (b.x + b.origin.x) - (a.x + a.origin.x); - var dy: number = (b.y + b.origin.y) - (a.y + a.origin.y); + var dx: number = (b.x + b.transform.origin.x) - (a.x + a.transform.origin.x); + var dy: number = (b.y + b.transform.origin.y) - (a.y + a.transform.origin.y); if (asDegrees) { diff --git a/Phaser/Phaser.csproj b/Phaser/Phaser.csproj index 098fdfbd..8028b489 100644 --- a/Phaser/Phaser.csproj +++ b/Phaser/Phaser.csproj @@ -74,22 +74,26 @@ Input.ts + + + Texture.ts + + + + Transform.ts + Game.ts - CameraFX.ts - - Texture.ts - Point.ts diff --git a/Phaser/Stage.ts b/Phaser/Stage.ts index 1dc5cdca..d147a03a 100644 --- a/Phaser/Stage.ts +++ b/Phaser/Stage.ts @@ -53,7 +53,7 @@ module Phaser { this.context = this.canvas.getContext('2d'); this.scaleMode = StageScaleMode.NO_SCALE; - this.scale = new StageScaleMode(this._game); + this.scale = new StageScaleMode(this._game, width, height); this.getOffset(this.canvas); this.bounds = new Rectangle(this.offset.x, this.offset.y, width, height); @@ -167,6 +167,8 @@ module Phaser { this.pauseScreen = new PauseScreen(this._game, this.width, this.height); this.orientationScreen = new OrientationScreen(this._game); + this.scale.setScreenSize(true); + } /** @@ -253,6 +255,13 @@ module Phaser { } + public setImageRenderingCrisp() { + this.canvas.style['image-rendering'] = 'crisp-edges'; + this.canvas.style['image-rendering'] = '-moz-crisp-edges'; + this.canvas.style['image-rendering'] = '-webkit-optimize-contrast'; + this.canvas.style['-ms-interpolation-mode'] = 'nearest-neighbor'; + } + public pauseGame() { if (this.disablePauseScreen == false && this.pauseScreen) diff --git a/Phaser/Statics.ts b/Phaser/Statics.ts index 1560d3fd..0c907992 100644 --- a/Phaser/Statics.ts +++ b/Phaser/Statics.ts @@ -20,7 +20,7 @@ module Phaser { static GEOM_POINT: number = 0; static GEOM_CIRCLE: number = 1; - static GEOM_RECTANGLE: number = 2; + static GEOM_Rectangle: number = 2; static GEOM_LINE: number = 3; static GEOM_POLYGON: number = 4; diff --git a/Phaser/cameras/Camera.ts b/Phaser/cameras/Camera.ts index 6d997fef..66a40c9b 100644 --- a/Phaser/cameras/Camera.ts +++ b/Phaser/cameras/Camera.ts @@ -1,9 +1,11 @@ +/// /// /// /// -/// -/// /// +/// +/// +/// /** * Phaser - Camera @@ -29,37 +31,45 @@ module Phaser { */ constructor(game: Game, id: number, x: number, y: number, width: number, height: number) { - this._game = game; + this.game = game; this.ID = id; - this._stageX = x; - this._stageY = y; - this.scaledX = x; - this.scaledY = y; - this.fx = new CameraFX(this._game, this); + this.z = id; - // The view into the world canvas we wish to render + // The view into the world we wish to render (by default the full game world size) + // The size of this Rect is the same as screenView, but the values are all in world coordinates instead of screen coordinates this.worldView = new Rectangle(0, 0, width, height); + // The rect of the area being rendered in stage/screen coordinates + this.screenView = new Rectangle(x, y, width, height); + + this.fx = new CameraFX(this.game, this); + + this.transform = new Phaser.Components.Transform(this); + this.texture = new Phaser.Components.Texture(this); + + this.texture.opaque = false; + this.checkClip(); } + private _target: Sprite = null; + /** * Local private reference to Game. */ - private _game: Game; + public game: Game; - private _clip: bool = false; - private _stageX: number; - private _stageY: number; - private _rotation: number = 0; - private _target: Sprite = null; - //private _sx: number = 0; - //private _sy: number = 0; + /** + * Optional texture used in the background of the Camera. + */ + public texture: Phaser.Components.Texture; - public scaledX: number; - public scaledY: number; + /** + * The transform component. + */ + public transform: Phaser.Components.Transform; /** * Camera "follow" style preset: camera has no deadzone, just tracks the focus object directly. @@ -91,31 +101,35 @@ module Phaser { public ID: number; /** - * Camera view rectangle in world coordinate. + * Controls if this camera is clipped or not when rendering. You shouldn't usually set this value directly. + */ + public clip: bool = false; + + /** + * Camera view Rectangle in world coordinate. * @type {Rectangle} */ public worldView: Rectangle; /** - * Scale factor of the camera. - * @type {Vec2} - */ - public scale: Vec2 = new Vec2(1, 1); - - /** - * Scrolling factor. - * @type {MicroPoint} - */ - public scroll: Vec2 = new Vec2(0, 0); - - /** - * Camera bounds. + * Visible / renderable area (changes if the camera resizes/moves around the stage) * @type {Rectangle} */ - public bounds: Rectangle = null; + public screenView: Rectangle; /** - * Sprite moving inside this rectangle will not cause camera moving. + * Camera worldBounds. + * @type {Rectangle} + */ + public worldBounds: Rectangle = null; + + /** + * A boolean representing if the Camera has been modified in any way via a scale, rotate, flip or skew. + */ + public modified: bool = false; + + /** + * Sprite moving inside this Rectangle will not cause camera moving. * @type {Rectangle} */ public deadzone: Rectangle = null; @@ -127,44 +141,15 @@ module Phaser { public disableClipping: bool = false; /** - * Whether the camera background is opaque or not. If set to true the Camera is filled with - * the value of Camera.backgroundColor every frame. Normally you wouldn't enable this if the - * Camera is the full Stage size, as the Stage.backgroundColor has the same effect. But for - * multiple or mini cameras it can be very useful. - * @type {boolean} - */ - public opaque: bool = false; - - /** - * The Background Color of the camera in css color string format, i.e. 'rgb(0,0,0)' or '#ff0000'. - * Not used if the Camera.opaque property is false. - * @type {string} - */ - public backgroundColor: string = 'rgb(0,0,0)'; - - /** - * Whether this camera visible or not. (default is true) + * Whether this camera is visible or not. (default is true) * @type {boolean} */ public visible: bool = true; /** - * Alpha of the camera. (everything rendered to this camera will be affected) - * @type {number} + * The z value of this Camera. Cameras are rendered in z-index order by the Renderer. */ - public alpha: number = 1; - - /** - * The x position of the current input event in world coordinates. - * @type {number} - */ - public inputX: number = 0; - - /** - * The y position of the current input event in world coordinates. - * @type {number} - */ - public inputY: number = 0; + public z: number = -1; /** * Effects manager. @@ -182,7 +167,7 @@ module Phaser { if (this.isHidden(object) == false) { - object['cameraBlacklist'].push(this.ID); + object.texture['cameraBlacklist'].push(this.ID); } } @@ -193,9 +178,7 @@ module Phaser { * @param object {Sprite/Group} The object to check. */ public isHidden(object): bool { - - return (object['cameraBlacklist'] && object['cameraBlacklist'].length > 0 && object['cameraBlacklist'].indexOf(this.ID) == -1); - + return (object.texture['cameraBlacklist'] && object.texture['cameraBlacklist'].length > 0 && object.texture['cameraBlacklist'].indexOf(this.ID) == -1); } /** @@ -208,7 +191,7 @@ module Phaser { if (this.isHidden(object) == true) { - object['cameraBlacklist'].slice(object['cameraBlacklist'].indexOf(this.ID), 1); + object.texture['cameraBlacklist'].slice(object.texture['cameraBlacklist'].indexOf(this.ID), 1); } } @@ -257,8 +240,8 @@ module Phaser { x += (x > 0) ? 0.0000001 : -0.0000001; y += (y > 0) ? 0.0000001 : -0.0000001; - this.scroll.x = Math.round(x - this.worldView.halfWidth); - this.scroll.y = Math.round(y - this.worldView.halfHeight); + this.worldView.x = Math.round(x - this.worldView.halfWidth); + this.worldView.y = Math.round(y - this.worldView.halfHeight); } @@ -271,8 +254,8 @@ module Phaser { point.x += (point.x > 0) ? 0.0000001 : -0.0000001; point.y += (point.y > 0) ? 0.0000001 : -0.0000001; - this.scroll.x = Math.round(point.x - this.worldView.halfWidth); - this.scroll.y = Math.round(point.y - this.worldView.halfHeight); + this.worldView.x = Math.round(point.x - this.worldView.halfWidth); + this.worldView.y = Math.round(point.y - this.worldView.halfHeight); } @@ -286,14 +269,15 @@ module Phaser { */ public setBounds(x: number = 0, y: number = 0, width: number = 0, height: number = 0) { - if (this.bounds == null) + if (this.worldBounds == null) { - this.bounds = new Rectangle(); + this.worldBounds = new Rectangle; } - this.bounds.setTo(x, y, width, height); + this.worldBounds.setTo(x, y, width, height); - this.scroll.setTo(0, 0); + this.worldView.x = x; + this.worldView.y = y; this.update(); } @@ -303,6 +287,15 @@ module Phaser { */ public update() { + if (this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) + { + this.modified = true; + } + else if (this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) + { + this.modified = false; + } + this.fx.preUpdate(); if (this._target !== null) @@ -319,206 +312,79 @@ module Phaser { edge = targetX - this.deadzone.x; - if (this.scroll.x > edge) + if (this.worldView.x > edge) { - this.scroll.x = edge; + this.worldView.x = edge; } edge = targetX + this._target.width - this.deadzone.x - this.deadzone.width; - if (this.scroll.x < edge) + if (this.worldView.x < edge) { - this.scroll.x = edge; + this.worldView.x = edge; } edge = targetY - this.deadzone.y; - if (this.scroll.y > edge) + if (this.worldView.y > edge) { - this.scroll.y = edge; + this.worldView.y = edge; } edge = targetY + this._target.height - this.deadzone.y - this.deadzone.height; - if (this.scroll.y < edge) + if (this.worldView.y < edge) { - this.scroll.y = edge; + this.worldView.y = edge; } } } - // Make sure we didn't go outside the cameras bounds - if (this.bounds !== null) + // Make sure we didn't go outside the cameras worldBounds + if (this.worldBounds !== null) { - if (this.scroll.x < this.bounds.left) + if (this.worldView.x < this.worldBounds.left) { - this.scroll.x = this.bounds.left; + this.worldView.x = this.worldBounds.left; } - if (this.scroll.x > this.bounds.right - this.width) + if (this.worldView.x > this.worldBounds.right - this.width) { - this.scroll.x = (this.bounds.right - this.width) + 1; + this.worldView.x = (this.worldBounds.right - this.width) + 1; } - if (this.scroll.y < this.bounds.top) + if (this.worldView.y < this.worldBounds.top) { - this.scroll.y = this.bounds.top; + this.worldView.y = this.worldBounds.top; } - if (this.scroll.y > this.bounds.bottom - this.height) + if (this.worldView.y > this.worldBounds.bottom - this.height) { - this.scroll.y = (this.bounds.bottom - this.height) + 1; + this.worldView.y = (this.worldBounds.bottom - this.height) + 1; } } - this.worldView.x = this.scroll.x; - this.worldView.y = this.scroll.y; - - // Input values - this.inputX = this.worldView.x + this._game.input.x; - this.inputY = this.worldView.y + this._game.input.y; - this.fx.postUpdate(); } /** - * Camera preRender - */ - public preRender() { - - if (this.visible === false || this.alpha < 0.1) - { - return; - } - - if (this._rotation !== 0 || this._clip || this.scale.x !== 1 || this.scale.y !== 1) - { - this._game.stage.context.save(); - } - - this.fx.preRender(this, this._stageX, this._stageY, this.worldView.width, this.worldView.height); - - if (this.alpha !== 1) - { - this._game.stage.context.globalAlpha = this.alpha; - } - - this.scaledX = this._stageX; - this.scaledY = this._stageY; - - // Scale on - if (this.scale.x !== 1 || this.scale.y !== 1) - { - this._game.stage.context.scale(this.scale.x, this.scale.y); - this.scaledX = this.scaledX / this.scale.x; - this.scaledY = this.scaledY / this.scale.y; - } - - // Rotation - translate to the mid-point of the camera - if (this._rotation !== 0) - { - this._game.stage.context.translate(this.scaledX + this.worldView.halfWidth, this.scaledY + this.worldView.halfHeight); - this._game.stage.context.rotate(this._rotation * (Math.PI / 180)); - - // now shift back to where that should actually render - this._game.stage.context.translate(-(this.scaledX + this.worldView.halfWidth), -(this.scaledY + this.worldView.halfHeight)); - } - - // Background - if (this.opaque) - { - this._game.stage.context.fillStyle = this.backgroundColor; - this._game.stage.context.fillRect(this.scaledX, this.scaledY, this.worldView.width, this.worldView.height); - } - - this.fx.render(this, this._stageX, this._stageY, this.worldView.width, this.worldView.height); - - // Clip the camera so we don't get sprites appearing outside the edges - if (this._clip == true && this.disableClipping == false) - { - this._game.stage.context.beginPath(); - this._game.stage.context.rect(this.scaledX, this.scaledY, this.worldView.width, this.worldView.height); - this._game.stage.context.closePath(); - this._game.stage.context.clip(); - } - - } - - /** - * Camera postRender - */ - public postRender() { - - // Scale off - if (this.scale.x !== 1 || this.scale.y !== 1) - { - this._game.stage.context.scale(1, 1); - } - - this.fx.postRender(this, this.scaledX, this.scaledY, this.worldView.width, this.worldView.height); - - if (this._rotation !== 0 || (this._clip && this.disableClipping == false)) - { - this._game.stage.context.translate(0, 0); - } - - if (this._rotation !== 0 || this._clip || this.scale.x !== 1 || this.scale.y !== 1) - { - this._game.stage.context.restore(); - } - - if (this.alpha !== 1) - { - this._game.stage.context.globalAlpha = 1; - } - - } - - /** - * Set position of this camera. - * @param x {number} X position. - * @param y {number} Y position. - */ - public setPosition(x: number, y: number) { - - this._stageX = x; - this._stageY = y; - - this.checkClip(); - - } - - /** - * Give this camera a new size. - * @param width {number} Width of new size. - * @param height {number} Height of new size. - */ - public setSize(width: number, height: number) { - - this.worldView.width = width; - this.worldView.height = height; - this.checkClip(); - - } - - /** - * Render debug infos. (including id, position, rotation, scrolling factor, bounds and some other properties) + * Render debug infos. (including id, position, rotation, scrolling factor, worldBounds and some other properties) * @param x {number} X position of the debug info to be rendered. * @param y {number} Y position of the debug info to be rendered. * @param [color] {number} color of the debug info to be rendered. (format is css color string) */ public renderDebugInfo(x: number, y: number, color?: string = 'rgb(255,255,255)') { - this._game.stage.context.fillStyle = color; - this._game.stage.context.fillText('Camera ID: ' + this.ID + ' (' + this.worldView.width + ' x ' + this.worldView.height + ')', x, y); - this._game.stage.context.fillText('X: ' + this._stageX + ' Y: ' + this._stageY + ' Rotation: ' + this._rotation, x, y + 14); - this._game.stage.context.fillText('World X: ' + this.scroll.x.toFixed(1) + ' World Y: ' + this.scroll.y.toFixed(1), x, y + 28); + this.game.stage.context.fillStyle = color; + this.game.stage.context.fillText('Camera ID: ' + this.ID + ' (' + this.screenView.width + ' x ' + this.screenView.height + ')', x, y); + this.game.stage.context.fillText('X: ' + this.screenView.x + ' Y: ' + this.screenView.y + ' rotation: ' + this.transform.rotation, x, y + 14); + this.game.stage.context.fillText('World X: ' + this.worldView.x.toFixed(1) + ' World Y: ' + this.worldView.y.toFixed(1), x, y + 28); - if (this.bounds) + if (this.worldBounds) { - this._game.stage.context.fillText('Bounds: ' + this.bounds.width + ' x ' + this.bounds.height, x, y + 42); + this.game.stage.context.fillText('Bounds: ' + this.worldBounds.width + ' x ' + this.worldBounds.height, x, y + 42); } } @@ -528,75 +394,82 @@ module Phaser { */ public destroy() { - this._game.world.cameras.removeCamera(this.ID); + this.game.world.cameras.removeCamera(this.ID); this.fx.destroy(); } public get x(): number { - return this._stageX; - } - - public set x(value: number) { - this._stageX = value; - this.checkClip(); + return this.worldView.x; } public get y(): number { - return this._stageY; + return this.worldView.y; + } + + public set x(value: number) { + this.worldView.x = value; } public set y(value: number) { - this._stageY = value; - this.checkClip(); + this.worldView.y = value; } public get width(): number { - return this.worldView.width; - } - - public set width(value: number) { - - if (value > this._game.stage.width) - { - value = this._game.stage.width; - } - - this.worldView.width = value; - this.checkClip(); + return this.screenView.width; } public get height(): number { - return this.worldView.height; + return this.screenView.height; + } + + public set width(value: number) { + this.screenView.width = value; + this.worldView.width = value; } public set height(value: number) { - - if (value > this._game.stage.height) - { - value = this._game.stage.height; - } - + this.screenView.height = value; this.worldView.height = value; + } + + public setPosition(x: number, y: number) { + this.screenView.x = x; + this.screenView.y = y; this.checkClip(); } - public get rotation(): number { - return this._rotation; + public setSize(width: number, height: number) { + this.screenView.width = width * this.transform.scale.x; + this.screenView.height = height * this.transform.scale.y; + this.worldView.width = width; + this.worldView.height = height; + this.checkClip(); } + /** + * The angle of the Camera in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + */ + public get rotation(): number { + return this.transform.rotation; + } + + /** + * Set the angle of the Camera in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + * The value is automatically wrapped to be between 0 and 360. + */ public set rotation(value: number) { - this._rotation = this._game.math.wrap(value, 360, 0); + this.transform.rotation = this.game.math.wrap(value, 360, 0); } private checkClip() { - if (this._stageX !== 0 || this._stageY !== 0 || this.worldView.width < this._game.stage.width || this.worldView.height < this._game.stage.height) + if (this.screenView.x != 0 || this.screenView.y != 0 || this.screenView.width < this.game.stage.width || this.screenView.height < this.game.stage.height) { - this._clip = true; + this.clip = true; } else { - this._clip = false; + this.clip = false; } } diff --git a/Phaser/cameras/CameraManager.ts b/Phaser/cameras/CameraManager.ts index 191dc335..c3bbc476 100644 --- a/Phaser/cameras/CameraManager.ts +++ b/Phaser/cameras/CameraManager.ts @@ -47,6 +47,16 @@ module Phaser { */ private _cameraInstance: number = 0; + /** + * Helper for sort. + */ + private _sortIndex: string = ''; + + /** + * Helper for sort. + */ + private _sortOrder: number; + public static CAMERA_TYPE_ORTHOGRAPHIC: number = 0; public static CAMERA_TYPE_ISOMETRIC: number = 1; @@ -124,6 +134,65 @@ module Phaser { } + public swap(camera1: Camera, camera2: Camera, sort?: bool = true): bool { + + if (camera1.ID == camera2.ID) + { + return false; + } + + var tempZ: number = camera1.z; + + camera1.z = camera2.z; + camera2.z = tempZ; + + if (sort) + { + this.sort(); + } + + return true; + + } + + /** + * Call this function to sort the Cameras according to a particular value and order (default is their Z value). + * The order in which they are sorted determines the render order. If sorted on z then Cameras with a lower z-index value render first. + * + * @param {string} index The string name of the Camera variable you want to sort on. Default value is "z". + * @param {number} order A Group constant that defines the sort order. Possible values are Group.ASCENDING and Group.DESCENDING. Default value is Group.ASCENDING. + */ + public sort(index: string = 'z', order: number = Group.ASCENDING) { + + this._sortIndex = index; + this._sortOrder = order; + this._cameras.sort((a, b) => this.sortHandler(a, b)); + + } + + /** + * Helper function for the sort process. + * + * @param {Basic} Obj1 The first object being sorted. + * @param {Basic} Obj2 The second object being sorted. + * + * @return {number} An integer value: -1 (Obj1 before Obj2), 0 (same), or 1 (Obj1 after Obj2). + */ + public sortHandler(obj1, obj2): number { + + if (obj1[this._sortIndex] < obj2[this._sortIndex]) + { + return this._sortOrder; + } + else if (obj1[this._sortIndex] > obj2[this._sortIndex]) + { + return -this._sortOrder; + } + + return 0; + + } + /** * Clean up memory. */ diff --git a/Phaser/components/sprite/Texture.ts b/Phaser/components/Texture.ts similarity index 55% rename from Phaser/components/sprite/Texture.ts rename to Phaser/components/Texture.ts index dcead1b3..49114745 100644 --- a/Phaser/components/sprite/Texture.ts +++ b/Phaser/components/Texture.ts @@ -1,11 +1,11 @@ -/// -/// -/// +/// +/// +/// /** * Phaser - Components - Texture * -* The Texture being used to render the Sprite. Either Image based on a DynamicTexture. +* The Texture being used to render the object (Sprite, Group background, etc). Either Image based on a DynamicTexture. */ module Phaser.Components { @@ -13,14 +13,14 @@ module Phaser.Components { export class Texture { /** - * Creates a new Sprite Texture component - * @param parent The Sprite using this Texture to render + * Creates a new Texture component + * @param parent The object using this Texture to render. * @param key An optional Game.Cache key to load an image from */ - constructor(parent: Sprite, key?: string = '') { + constructor(parent) { this.game = parent.game; - this._sprite = parent; + this.parent = parent; this.canvas = parent.game.stage.canvas; this.context = parent.game.stage.context; @@ -28,14 +28,22 @@ module Phaser.Components { this.flippedX = false; this.flippedY = false; - if (key !== null) - { - this.cacheKey = key; - this.loadImage(key); - } + this._width = 16; + this._height = 16; + + this.cameraBlacklist = []; } + /** + * Private _width - use the width getter/setter instead + */ + private _width: number; + + /** + * Private _height - use the height getter/setter instead + */ + private _height: number; /** * Reference to Phaser.Game @@ -43,9 +51,9 @@ module Phaser.Components { public game: Game; /** - * Reference to the parent Sprite + * Reference to the parent object (Sprite, Group, etc) */ - private _sprite: Sprite; + public parent; /** * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. @@ -65,11 +73,40 @@ module Phaser.Components { public loaded: bool = false; /** - * Opacity of the Sprite texture where 1 is opaque and 0 is fully transparent. + * An Array of Cameras to which this texture won't render + * @type {Array} + */ + public cameraBlacklist: number[]; + + /** + * Whether the Sprite background is opaque or not. If set to true the Sprite is filled with + * the value of Texture.backgroundColor every frame. Normally you wouldn't enable this but + * for some effects it can be handy. + * @type {boolean} + */ + public opaque: bool = false; + + /** + * Opacity of the Sprite texture where 1 is opaque (default) and 0 is fully transparent. * @type {number} */ public alpha: number; + /** + * The Background Color of the Sprite if Texture.opaque is set to true. + * Given in css color string format, i.e. 'rgb(0,0,0)' or '#ff0000'. + * @type {string} + */ + public backgroundColor: string = 'rgb(255,255,255)'; + + /** + * You can set a globalCompositeOperation that will be applied before the render method is called on this Sprite. + * This is useful if you wish to apply an effect like 'lighten'. + * If this value is set it will call a canvas context save and restore before and after the render pass, so use it sparingly. + * Set to null to disable. + */ + public globalCompositeOperation: string = null; + /** * A reference to the Canvas this Sprite renders to. * @type {HTMLCanvasElement} @@ -121,7 +158,7 @@ module Phaser.Components { * Updates the texture being used to render the Sprite. * Called automatically by SpriteUtils.loadTexture and SpriteUtils.loadDynamicTexture. */ - public setTo(image = null, dynamic?: DynamicTexture = null): Sprite { + public setTo(image = null, dynamic?: DynamicTexture = null) { if (dynamic) { @@ -134,11 +171,13 @@ module Phaser.Components { this.isDynamic = false; this.imageTexture = image; this.texture = this.imageTexture; + this._width = image.width; + this._height = image.height; } this.loaded = true; - return this._sprite; + return this.parent; } @@ -147,32 +186,31 @@ module Phaser.Components { * The graphic can be SpriteSheet or Texture Atlas. If you need to use a DynamicTexture see loadDynamicTexture. * @param key {string} Key of the graphic you want to load for this sprite. * @param clearAnimations {boolean} If this Sprite has a set of animation data already loaded you can choose to keep or clear it with this boolean + * @param updateBody {boolean} Update the physics body dimensions to match the newly loaded texture/frame? */ public loadImage(key: string, clearAnimations?: bool = true, updateBody?: bool = true) { - if (clearAnimations && this._sprite.animations.frameData !== null) + if (clearAnimations && this.parent['animations'] && this.parent['animations'].frameData !== null) { - this._sprite.animations.destroy(); + this.parent.animations.destroy(); } if (this.game.cache.getImage(key) !== null) { this.setTo(this.game.cache.getImage(key), null); + this.cacheKey = key; - if (this.game.cache.isSpriteSheet(key)) + if (this.game.cache.isSpriteSheet(key) && this.parent['animations']) { - this._sprite.animations.loadFrameData(this._sprite.game.cache.getFrameData(key)); + this.parent.animations.loadFrameData(this.parent.game.cache.getFrameData(key)); } else { - this._sprite.frameBounds.width = this.width; - this._sprite.frameBounds.height = this.height; - } - - if (updateBody) - { - this._sprite.body.bounds.width = this.width; - this._sprite.body.bounds.height = this.height; + if (updateBody && this.parent['body']) + { + this.parent.body.bounds.width = this.width; + this.parent.body.bounds.height = this.height; + } } } @@ -184,19 +222,28 @@ module Phaser.Components { */ public loadDynamicTexture(texture: DynamicTexture) { - if (this._sprite.animations.frameData !== null) + if (this.parent.animations.frameData !== null) { - this._sprite.animations.destroy(); + this.parent.animations.destroy(); } this.setTo(null, texture); - this._sprite.frameBounds.width = this.width; - this._sprite.frameBounds.height = this.height; + this.parent.texture.width = this.width; + this.parent.texture.height = this.height; } + public set width(value: number) { + this._width = value; + } + + public set height(value: number) { + this._height = value; + } + /** - * Getter only. The width of the texture. + * The width of the texture. If an animation it will be the frame width, not the width of the sprite sheet. + * If using a DynamicTexture it will be the width of the dynamic texture itself. * @type {number} */ public get width(): number { @@ -207,12 +254,13 @@ module Phaser.Components { } else { - return this.imageTexture.width; + return this._width; } } /** - * Getter only. The height of the texture. + * The height of the texture. If an animation it will be the frame height, not the height of the sprite sheet. + * If using a DynamicTexture it will be the height of the dynamic texture itself. * @type {number} */ public get height(): number { @@ -223,7 +271,7 @@ module Phaser.Components { } else { - return this.imageTexture.height; + return this._height; } } diff --git a/Phaser/components/TilemapLayer.ts b/Phaser/components/TilemapLayer.ts index 3183cda7..b26b26bf 100644 --- a/Phaser/components/TilemapLayer.ts +++ b/Phaser/components/TilemapLayer.ts @@ -219,10 +219,10 @@ module Phaser { * Swap tiles with 2 kinds of indexes. * @param tileA {number} First tile index. * @param tileB {number} Second tile index. - * @param [x] {number} specify a rectangle of tiles to operate. The x position in tiles of rectangle's left-top corner. - * @param [y] {number} specify a rectangle of tiles to operate. The y position in tiles of rectangle's left-top corner. - * @param [width] {number} specify a rectangle of tiles to operate. The width in tiles. - * @param [height] {number} specify a rectangle of tiles to operate. The height in tiles. + * @param [x] {number} specify a Rectangle of tiles to operate. The x position in tiles of Rectangle's left-top corner. + * @param [y] {number} specify a Rectangle of tiles to operate. The y position in tiles of Rectangle's left-top corner. + * @param [width] {number} specify a Rectangle of tiles to operate. The width in tiles. + * @param [height] {number} specify a Rectangle of tiles to operate. The height in tiles. */ public swapTile(tileA: number, tileB: number, x?: number = 0, y?: number = 0, width?: number = this.widthInTiles, height?: number = this.heightInTiles) { diff --git a/Phaser/components/Transform.ts b/Phaser/components/Transform.ts new file mode 100644 index 00000000..70dd8f84 --- /dev/null +++ b/Phaser/components/Transform.ts @@ -0,0 +1,72 @@ +/// + +/** +* Phaser - Components - Transform +*/ + +module Phaser.Components { + + export class Transform { + + /** + * Creates a new Sprite Transform component + * @param parent The Sprite using this transform + */ + constructor(parent) { + + this.game = parent.game; + this.parent = parent; + + this.scrollFactor = new Phaser.Vec2(1, 1); + this.origin = new Phaser.Vec2; + this.scale = new Phaser.Vec2(1, 1); + this.skew = new Phaser.Vec2; + + } + + /** + * Reference to Phaser.Game + */ + public game: Game; + + /** + * Reference to the parent object (Sprite, Group, etc) + */ + public parent: Phaser.Sprite; + + /** + * Scale of the object. A scale of 1.0 is the original size. 0.5 half size. 2.0 double sized. + */ + public scale: Phaser.Vec2; + + /** + * Skew the object along the x and y axis. A skew value of 0 is no skew. + */ + public skew: Phaser.Vec2; + + /** + * The influence of camera movement upon the object, if supported. + */ + public scrollFactor: Phaser.Vec2; + + /** + * The origin is the point around which scale and rotation takes place. + */ + public origin: Phaser.Vec2; + + /** + * This value is added to the rotation of the object. + * For example if you had a texture drawn facing straight up then you could set + * rotationOffset to 90 and it would correspond correctly with Phasers right-handed coordinate system. + * @type {number} + */ + public rotationOffset: number = 0; + + /** + * The rotation of the object in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + */ + public rotation: number = 0; + + } + +} \ No newline at end of file diff --git a/Phaser/components/animation/Animation.ts b/Phaser/components/animation/Animation.ts index abb91319..95495b05 100644 --- a/Phaser/components/animation/Animation.ts +++ b/Phaser/components/animation/Animation.ts @@ -140,8 +140,8 @@ module Phaser { if (this.currentFrame !== null) { - this._parent.frameBounds.width = this.currentFrame.width; - this._parent.frameBounds.height = this.currentFrame.height; + this._parent.texture.width = this.currentFrame.width; + this._parent.texture.height = this.currentFrame.height; this._frameIndex = value; } diff --git a/Phaser/components/animation/AnimationManager.ts b/Phaser/components/animation/AnimationManager.ts index 5fbbca8c..3615fe89 100644 --- a/Phaser/components/animation/AnimationManager.ts +++ b/Phaser/components/animation/AnimationManager.ts @@ -22,7 +22,7 @@ module Phaser.Components { * * @param parent {Sprite} Owner sprite of this manager. */ - constructor(parent: Sprite) { + constructor(parent: Phaser.Sprite) { this._parent = parent; this._game = parent.game; @@ -38,7 +38,7 @@ module Phaser.Components { /** * Local private reference to its owner sprite. */ - private _parent: Sprite; + private _parent: Phaser.Sprite; /** * Animation key-value container. @@ -57,6 +57,14 @@ module Phaser.Components { */ private _frameData: FrameData = null; + /** + * When an animation frame changes you can choose to automatically update the physics bounds of the parent Sprite + * to the width and height of the new frame. If you've set a specific physics bounds that you don't want changed during + * animation then set this to false, otherwise leave it set to true. + * @type {boolean} + */ + public autoUpdateBounds: bool = true; + /** * Keeps track of the current animation being played. */ @@ -200,8 +208,8 @@ module Phaser.Components { 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; + this._parent.texture.width = this.currentFrame.width; + this._parent.texture.height = this.currentFrame.height; } } @@ -232,8 +240,15 @@ module Phaser.Components { { this.currentFrame = this._frameData.getFrame(value); - this._parent.frameBounds.width = this.currentFrame.width; - this._parent.frameBounds.height = this.currentFrame.height; + this._parent.texture.width = this.currentFrame.width; + this._parent.texture.height = this.currentFrame.height; + + if (this.autoUpdateBounds && this._parent['body']) + { + this._parent.body.bounds.width = this.currentFrame.width; + this._parent.body.bounds.height = this.currentFrame.height; + } + this._frameIndex = value; } @@ -249,10 +264,9 @@ module Phaser.Components { { this.currentFrame = this._frameData.getFrameByName(value); - this._parent.frameBounds.width = this.currentFrame.width; - this._parent.frameBounds.height = this.currentFrame.height; - //this._parent.frameBounds.width = this.currentFrame.sourceSizeW; - //this._parent.frameBounds.height = this.currentFrame.sourceSizeH; + this._parent.texture.width = this.currentFrame.width; + this._parent.texture.height = this.currentFrame.height; + this._frameIndex = this.currentFrame.index; } diff --git a/Phaser/components/animation/Frame.ts b/Phaser/components/animation/Frame.ts index aa74a684..795dc319 100644 --- a/Phaser/components/animation/Frame.ts +++ b/Phaser/components/animation/Frame.ts @@ -143,14 +143,21 @@ module Phaser { */ public setTrim(trimmed: bool, actualWidth: number, actualHeight: number, destX: number, destY: number, destWidth: number, destHeight: number) { + //console.log('setTrim', trimmed, 'aw', actualWidth, 'ah', actualHeight, 'dx', destX, 'dy', destY, 'dw', destWidth, 'dh', destHeight); + this.trimmed = trimmed; - this.sourceSizeW = actualWidth; - this.sourceSizeH = actualHeight; - this.spriteSourceSizeX = destX; - this.spriteSourceSizeY = destY; - this.spriteSourceSizeW = destWidth; - this.spriteSourceSizeH = destHeight; + if (trimmed) + { + this.width = actualWidth; + this.height = actualHeight; + this.sourceSizeW = actualWidth; + this.sourceSizeH = actualHeight; + this.spriteSourceSizeX = destX; + this.spriteSourceSizeY = destY; + this.spriteSourceSizeW = destWidth; + this.spriteSourceSizeH = destHeight; + } } diff --git a/Phaser/components/sprite/Events.ts b/Phaser/components/sprite/Events.ts index 468531ad..2dcd55e9 100644 --- a/Phaser/components/sprite/Events.ts +++ b/Phaser/components/sprite/Events.ts @@ -6,7 +6,7 @@ * Signals that are dispatched by the Sprite and its various components */ -module Phaser.Components { +module Phaser.Components.Sprite { export class Events { @@ -14,10 +14,10 @@ module Phaser.Components { * The Events component is a collection of events fired by the parent Sprite and its other components. * @param parent The Sprite using this Input component */ - constructor(parent: Sprite) { + constructor(parent: Phaser.Sprite) { this.game = parent.game; - this._sprite = parent; + this.sprite = parent; this.onAddedToGroup = new Phaser.Signal; this.onRemovedFromGroup = new Phaser.Signal; @@ -39,7 +39,7 @@ module Phaser.Components { /** * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. */ - private _sprite: Sprite; + private sprite: Phaser.Sprite; /** * Dispatched by the Group this Sprite is added to. diff --git a/Phaser/components/sprite/Input.ts b/Phaser/components/sprite/Input.ts index 3e7dbe57..91641e98 100644 --- a/Phaser/components/sprite/Input.ts +++ b/Phaser/components/sprite/Input.ts @@ -9,7 +9,7 @@ * Input detection component */ -module Phaser.Components { +module Phaser.Components.Sprite { export class Input { @@ -17,10 +17,10 @@ module Phaser.Components { * Sprite Input component constructor * @param parent The Sprite using this Input component */ - constructor(parent: Sprite) { + constructor(parent: Phaser.Sprite) { this.game = parent.game; - this._sprite = parent; + this.sprite = parent; this.enabled = false; } @@ -33,7 +33,7 @@ module Phaser.Components { /** * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. */ - private _sprite: Sprite; + private sprite: Phaser.Sprite; private _pointerData; @@ -82,7 +82,7 @@ module Phaser.Components { * An Sprite the bounds of which this sprite is restricted during drag * @default null */ - public boundsSprite: Sprite = null; + public boundsSprite: Phaser.Sprite = null; /** * The Input component can monitor either the physics body of the Sprite or the frameBounds @@ -196,7 +196,7 @@ module Phaser.Components { return this._pointerData[pointer].isDragged; } - public start(priority:number = 0, checkBody?:bool = false, useHandCursor?:bool = false): Sprite { + public start(priority:number = 0, checkBody?:bool = false, useHandCursor?:bool = false): Phaser.Sprite { // Turning on if (this.enabled == false) @@ -216,10 +216,10 @@ module Phaser.Components { this.snapOffset = new Point; this.enabled = true; - this.game.input.addGameObject(this._sprite); + this.game.input.addGameObject(this.sprite); } - return this._sprite; + return this.sprite; } @@ -245,20 +245,20 @@ module Phaser.Components { { // De-register, etc this.enabled = false; - this.game.input.removeGameObject(this._sprite); + this.game.input.removeGameObject(this.sprite); } } public checkPointerOver(pointer: Phaser.Pointer): bool { - if (this.enabled == false || this._sprite.visible == false) + if (this.enabled == false || this.sprite.visible == false) { return false; } else { - return RectangleUtils.contains(this._sprite.frameBounds, pointer.scaledX, pointer.scaledY); + return RectangleUtils.contains(this.sprite.worldView, pointer.scaledX, pointer.scaledY); } } @@ -268,7 +268,7 @@ module Phaser.Components { */ public update(pointer: Phaser.Pointer): bool { - if (this.enabled == false || this._sprite.visible == false) + if (this.enabled == false || this.sprite.visible == false) { return false; } @@ -279,10 +279,10 @@ module Phaser.Components { } else if (this._pointerData[pointer.id].isOver == true) { - if (RectangleUtils.contains(this._sprite.frameBounds, pointer.scaledX, pointer.scaledY)) + if (RectangleUtils.contains(this.sprite.worldView, pointer.scaledX, pointer.scaledY)) { - this._pointerData[pointer.id].x = pointer.scaledX - this._sprite.x; - this._pointerData[pointer.id].y = pointer.scaledY - this._sprite.y; + this._pointerData[pointer.id].x = pointer.scaledX - this.sprite.x; + this._pointerData[pointer.id].y = pointer.scaledY - this.sprite.y; return true; } else @@ -303,15 +303,15 @@ module Phaser.Components { this._pointerData[pointer.id].isOver = true; this._pointerData[pointer.id].isOut = false; this._pointerData[pointer.id].timeOver = this.game.time.now; - this._pointerData[pointer.id].x = pointer.x - this._sprite.x; - this._pointerData[pointer.id].y = pointer.y - this._sprite.y; + this._pointerData[pointer.id].x = pointer.x - this.sprite.x; + this._pointerData[pointer.id].y = pointer.y - this.sprite.y; if (this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { this.game.stage.canvas.style.cursor = "pointer"; } - this._sprite.events.onInputOver.dispatch(this._sprite, pointer); + this.sprite.events.onInputOver.dispatch(this.sprite, pointer); } } @@ -327,7 +327,7 @@ module Phaser.Components { this.game.stage.canvas.style.cursor = "default"; } - this._sprite.events.onInputOut.dispatch(this._sprite, pointer); + this.sprite.events.onInputOut.dispatch(this.sprite, pointer); } @@ -341,7 +341,7 @@ module Phaser.Components { this._pointerData[pointer.id].isUp = false; this._pointerData[pointer.id].timeDown = this.game.time.now; - this._sprite.events.onInputDown.dispatch(this._sprite, pointer); + this.sprite.events.onInputDown.dispatch(this.sprite, pointer); // Start drag //if (this.draggable && this.isDragged == false && pointer.targetObject == null) @@ -367,7 +367,7 @@ module Phaser.Components { this._pointerData[pointer.id].timeUp = this.game.time.now; this._pointerData[pointer.id].downDuration = this._pointerData[pointer.id].timeUp - this._pointerData[pointer.id].timeDown; - this._sprite.events.onInputUp.dispatch(this._sprite, pointer); + this.sprite.events.onInputUp.dispatch(this.sprite, pointer); // Stop drag if (this.draggable && this.isDragged && this._draggedPointerID == pointer.id) @@ -396,12 +396,12 @@ module Phaser.Components { if (this.allowHorizontalDrag) { - this._sprite.x = pointer.x + this._dragPoint.x + this.dragOffset.x; + this.sprite.x = pointer.x + this._dragPoint.x + this.dragOffset.x; } if (this.allowVerticalDrag) { - this._sprite.y = pointer.y + this._dragPoint.y + this.dragOffset.y; + this.sprite.y = pointer.y + this._dragPoint.y + this.dragOffset.y; } if (this.boundsRect) @@ -416,8 +416,8 @@ module Phaser.Components { if (this.snapOnDrag) { - this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; - this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; + this.sprite.x = Math.floor(this.sprite.x / this.snapX) * this.snapX; + this.sprite.y = Math.floor(this.sprite.y / this.snapY) * this.snapY; } return true; @@ -498,7 +498,7 @@ module Phaser.Components { * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here */ - public enableDrag(lockCenter:bool = false, pixelPerfect:bool = false, alphaThreshold:number = 255, boundsRect:Rectangle = null, boundsSprite:Sprite = null):void + public enableDrag(lockCenter:bool = false, pixelPerfect:bool = false, alphaThreshold:number = 255, boundsRect:Rectangle = null, boundsSprite:Phaser.Sprite = null):void { this._dragPoint = new Point; @@ -550,11 +550,11 @@ module Phaser.Components { if (this.dragFromCenter) { // Move the sprite to the middle of the pointer - this._dragPoint.setTo(-this._sprite.frameBounds.halfWidth, -this._sprite.frameBounds.halfHeight); + this._dragPoint.setTo(-this.sprite.worldView.halfWidth, -this.sprite.worldView.halfHeight); } else { - this._dragPoint.setTo(this._sprite.x - pointer.x, this._sprite.y - pointer.y); + this._dragPoint.setTo(this.sprite.x - pointer.x, this.sprite.y - pointer.y); } this.updateDrag(pointer); @@ -572,8 +572,8 @@ module Phaser.Components { if (this.snapOnRelease) { - this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; - this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; + this.sprite.x = Math.floor(this.sprite.x / this.snapX) * this.snapX; + this.sprite.y = Math.floor(this.sprite.y / this.snapY) * this.snapY; } //pointer.draggedObject = null; @@ -622,22 +622,22 @@ module Phaser.Components { */ private checkBoundsRect():void { - if (this._sprite.x < this.boundsRect.left) + if (this.sprite.x < this.boundsRect.left) { - this._sprite.x = this.boundsRect.x; + this.sprite.x = this.boundsRect.x; } - else if ((this._sprite.x + this._sprite.width) > this.boundsRect.right) + else if ((this.sprite.x + this.sprite.width) > this.boundsRect.right) { - this._sprite.x = this.boundsRect.right - this._sprite.width; + this.sprite.x = this.boundsRect.right - this.sprite.width; } - if (this._sprite.y < this.boundsRect.top) + if (this.sprite.y < this.boundsRect.top) { - this._sprite.y = this.boundsRect.top; + this.sprite.y = this.boundsRect.top; } - else if ((this._sprite.y + this._sprite.height) > this.boundsRect.bottom) + else if ((this.sprite.y + this.sprite.height) > this.boundsRect.bottom) { - this._sprite.y = this.boundsRect.bottom - this._sprite.height; + this.sprite.y = this.boundsRect.bottom - this.sprite.height; } } @@ -646,22 +646,22 @@ module Phaser.Components { */ private checkBoundsSprite():void { - if (this._sprite.x < this.boundsSprite.x) + if (this.sprite.x < this.boundsSprite.x) { - this._sprite.x = this.boundsSprite.x; + this.sprite.x = this.boundsSprite.x; } - else if ((this._sprite.x + this._sprite.width) > (this.boundsSprite.x + this.boundsSprite.width)) + else if ((this.sprite.x + this.sprite.width) > (this.boundsSprite.x + this.boundsSprite.width)) { - this._sprite.x = (this.boundsSprite.x + this.boundsSprite.width) - this._sprite.width; + this.sprite.x = (this.boundsSprite.x + this.boundsSprite.width) - this.sprite.width; } - if (this._sprite.y < this.boundsSprite.y) + if (this.sprite.y < this.boundsSprite.y) { - this._sprite.y = this.boundsSprite.y; + this.sprite.y = this.boundsSprite.y; } - else if ((this._sprite.y + this._sprite.height) > (this.boundsSprite.y + this.boundsSprite.height)) + else if ((this.sprite.y + this.sprite.height) > (this.boundsSprite.y + this.boundsSprite.height)) { - this._sprite.y = (this.boundsSprite.y + this.boundsSprite.height) - this._sprite.height; + this.sprite.y = (this.boundsSprite.y + this.boundsSprite.height) - this.sprite.height; } } @@ -673,13 +673,13 @@ module Phaser.Components { */ public renderDebugInfo(x: number, y: number, color?: string = 'rgb(255,255,255)') { - this._sprite.texture.context.font = '14px Courier'; - this._sprite.texture.context.fillStyle = color; - this._sprite.texture.context.fillText('Sprite Input: (' + this._sprite.frameBounds.width + ' x ' + this._sprite.frameBounds.height + ')', x, y); - this._sprite.texture.context.fillText('x: ' + this.pointerX().toFixed(1) + ' y: ' + this.pointerY().toFixed(1), x, y + 14); - this._sprite.texture.context.fillText('over: ' + this.pointerOver() + ' duration: ' + this.overDuration().toFixed(0), x, y + 28); - this._sprite.texture.context.fillText('down: ' + this.pointerDown() + ' duration: ' + this.downDuration().toFixed(0), x, y + 42); - this._sprite.texture.context.fillText('just over: ' + this.justOver() + ' just out: ' + this.justOut(), x, y + 56); + this.sprite.texture.context.font = '14px Courier'; + this.sprite.texture.context.fillStyle = color; + this.sprite.texture.context.fillText('Sprite Input: (' + this.sprite.worldView.width + ' x ' + this.sprite.worldView.height + ')', x, y); + this.sprite.texture.context.fillText('x: ' + this.pointerX().toFixed(1) + ' y: ' + this.pointerY().toFixed(1), x, y + 14); + this.sprite.texture.context.fillText('over: ' + this.pointerOver() + ' duration: ' + this.overDuration().toFixed(0), x, y + 28); + this.sprite.texture.context.fillText('down: ' + this.pointerDown() + ' duration: ' + this.downDuration().toFixed(0), x, y + 42); + this.sprite.texture.context.fillText('just over: ' + this.justOver() + ' just out: ' + this.justOut(), x, y + 56); } diff --git a/Phaser/core/Group.ts b/Phaser/core/Group.ts index bab0c8d4..3fe8f725 100644 --- a/Phaser/core/Group.ts +++ b/Phaser/core/Group.ts @@ -1,5 +1,7 @@ /// /// +/// +/// /** * Phaser - Group @@ -25,10 +27,12 @@ module Phaser { this._marker = 0; this._sortIndex = null; - this.cameraBlacklist = []; - this.ID = this.game.world.getNextGroupID(); + this.transform = new Phaser.Components.Transform(this); + this.texture = new Phaser.Components.Texture(this); + this.texture.opaque = false; + } /** @@ -91,6 +95,21 @@ module Phaser { */ public group: Group = null; + /** + * Optional texture used in the background of the Camera. + */ + public texture: Phaser.Components.Texture; + + /** + * The transform component. + */ + public transform: Phaser.Components.Transform; + + /** + * A boolean representing if the Group has been modified in any way via a scale, rotate, flip or skew. + */ + public modified: bool = false; + /** * If this Group exists or not. Can be set to false to skip certain loop checks. */ @@ -123,27 +142,6 @@ module Phaser { */ public length: number; - /** - * You can set a globalCompositeOperation that will be applied before the render method is called on this Groups children. - * This is useful if you wish to apply an effect like 'lighten' to a whole group of children as it saves doing it one-by-one. - * If this value is set it will call a canvas context save and restore before and after the render pass. - * Set to null to disable. - */ - public globalCompositeOperation: string = null; - - /** - * You can set an alpha value on this Group that will be applied before the render method is called on this Groups children. - * This is useful if you wish to alpha a whole group of children as it saves doing it one-by-one. - * Set to 0 to disable. - */ - public alpha: number = 0; - - /** - * An Array of Cameras to which this Group, or any of its children, won't render - * @type {Array} - */ - public cameraBlacklist: number[]; - /** * Gets the next z index value for children of this Group */ @@ -184,6 +182,15 @@ module Phaser { */ public update() { + if (this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) + { + this.modified = true; + } + else if (this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) + { + this.modified = false; + } + this._i = 0; while (this._i < this.length) @@ -210,17 +217,7 @@ module Phaser { return; } - if (this.globalCompositeOperation) - { - this.game.stage.context.save(); - this.game.stage.context.globalCompositeOperation = this.globalCompositeOperation; - } - - if (this.alpha > 0) - { - this._prevAlpha = this.game.stage.context.globalAlpha; - this.game.stage.context.globalAlpha = this.alpha; - } + this.game.renderer.preRenderGroup(camera, this); this._i = 0; @@ -241,15 +238,7 @@ module Phaser { } } - if (this.alpha > 0) - { - this.game.stage.context.globalAlpha = this._prevAlpha; - } - - if (this.globalCompositeOperation) - { - this.game.stage.context.restore(); - } + this.game.renderer.postRenderGroup(camera, this); } @@ -259,17 +248,7 @@ module Phaser { */ public directRender(camera: Camera) { - if (this.globalCompositeOperation) - { - this.game.stage.context.save(); - this.game.stage.context.globalCompositeOperation = this.globalCompositeOperation; - } - - if (this.alpha > 0) - { - this._prevAlpha = this.game.stage.context.globalAlpha; - this.game.stage.context.globalAlpha = this.alpha; - } + this.game.renderer.preRenderGroup(camera, this); this._i = 0; @@ -290,15 +269,7 @@ module Phaser { } } - if (this.alpha > 0) - { - this.game.stage.context.globalAlpha = this._prevAlpha; - } - - if (this.globalCompositeOperation) - { - this.game.stage.context.restore(); - } + this.game.renderer.postRenderGroup(camera, this); } @@ -426,11 +397,12 @@ module Phaser { * @param x {number} X position of the new sprite. * @param y {number} Y position of the new sprite. * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this sprite + * @param [frame] {string|number} If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name. * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) * @returns {Sprite} The newly created sprite object. */ - public addNewSprite(x: number, y: number, key?: string = '', bodyType?: number = Phaser.Types.BODY_DISABLED): Sprite { - return this.add(new Sprite(this.game, x, y, key, bodyType)); + public addNewSprite(x: number, y: number, key?: string = '', frame? = null, bodyType?: number = Phaser.Types.BODY_DISABLED): Sprite { + return this.add(new Sprite(this.game, x, y, key, frame, bodyType)); } /** @@ -620,7 +592,7 @@ module Phaser { * State.update() override. To sort all existing objects after * a big explosion or bomb attack, you might call myGroup.sort("exists",Group.DESCENDING). * - * @param {string} index The string name of the member variable you want to sort on. Default value is "y". + * @param {string} index The string name of the member variable you want to sort on. Default value is "z". * @param {number} order A Group constant that defines the sort order. Possible values are Group.ASCENDING and Group.DESCENDING. Default value is Group.ASCENDING. */ public sort(index: string = 'z', order: number = Group.ASCENDING) { diff --git a/Phaser/core/Rectangle.ts b/Phaser/core/Rectangle.ts index 9cced955..c99dc156 100644 --- a/Phaser/core/Rectangle.ts +++ b/Phaser/core/Rectangle.ts @@ -14,14 +14,14 @@ module Phaser { export class Rectangle { /** - * Creates a new Rectangle object with the top-left corner specified by the x and y parameters and with the specified width and height parameters. If you call this function without parameters, a rectangle with x, y, width, and height properties set to 0 is created. + * Creates a new Rectangle object with the top-left corner specified by the x and y parameters and with the specified width and height parameters. If you call this function without parameters, a Rectangle with x, y, width, and height properties set to 0 is created. * @class Rectangle * @constructor - * @param {Number} x The x coordinate of the top-left corner of the rectangle. - * @param {Number} y The y coordinate of the top-left corner of the rectangle. - * @param {Number} width The width of the rectangle in pixels. - * @param {Number} height The height of the rectangle in pixels. - * @return {Rectangle} This rectangle object + * @param {Number} x The x coordinate of the top-left corner of the Rectangle. + * @param {Number} y The y coordinate of the top-left corner of the Rectangle. + * @param {Number} width The width of the Rectangle in pixels. + * @param {Number} height The height of the Rectangle in pixels. + * @return {Rectangle} This Rectangle object **/ constructor(x: number = 0, y: number = 0, width: number = 0, height: number = 0) { @@ -33,35 +33,35 @@ module Phaser { } /** - * The x coordinate of the top-left corner of the rectangle + * The x coordinate of the top-left corner of the Rectangle * @property x * @type Number **/ x: number; /** - * The y coordinate of the top-left corner of the rectangle + * The y coordinate of the top-left corner of the Rectangle * @property y * @type Number **/ y: number; /** - * The width of the rectangle in pixels + * The width of the Rectangle in pixels * @property width * @type Number **/ width: number; /** - * The height of the rectangle in pixels + * The height of the Rectangle in pixels * @property height * @type Number **/ height: number; /** - * Half of the width of the rectangle + * Half of the width of the Rectangle * @property halfWidth * @type Number **/ @@ -70,7 +70,7 @@ module Phaser { } /** - * Half of the height of the rectangle + * Half of the height of the Rectangle * @property halfHeight * @type Number **/ @@ -248,7 +248,7 @@ module Phaser { /** * Sets all of the Rectangle object's properties to 0. A Rectangle object is empty if its width or height is less than or equal to 0. * @method setEmpty - * @return {Rectangle} This rectangle object + * @return {Rectangle} This Rectangle object **/ set empty(value: bool) { return this.setTo(0, 0, 0, 0); @@ -283,11 +283,11 @@ module Phaser { /** * Sets the members of Rectangle to the specified values. * @method setTo - * @param {Number} x The x coordinate of the top-left corner of the rectangle. - * @param {Number} y The y coordinate of the top-left corner of the rectangle. - * @param {Number} width The width of the rectangle in pixels. - * @param {Number} height The height of the rectangle in pixels. - * @return {Rectangle} This rectangle object + * @param {Number} x The x coordinate of the top-left corner of the Rectangle. + * @param {Number} y The y coordinate of the top-left corner of the Rectangle. + * @param {Number} width The width of the Rectangle in pixels. + * @param {Number} height The height of the Rectangle in pixels. + * @return {Rectangle} This Rectangle object **/ setTo(x: number, y: number, width: number, height: number): Rectangle { diff --git a/Phaser/gameobjects/DynamicTexture.ts b/Phaser/gameobjects/DynamicTexture.ts index ffee34c2..2b77407d 100644 --- a/Phaser/gameobjects/DynamicTexture.ts +++ b/Phaser/gameobjects/DynamicTexture.ts @@ -110,8 +110,8 @@ module Phaser { } /** - * Get pixels in array in a specific rectangle. - * @param rect {Rectangle} The specific rectangle. + * Get pixels in array in a specific Rectangle. + * @param rect {Rectangle} The specific Rectangle. * @returns {array} CanvasPixelArray. */ public getPixels(rect: Rectangle) { @@ -147,8 +147,8 @@ module Phaser { } /** - * Set image data to a specific rectangle. - * @param rect {Rectangle} Target rectangle. + * Set image data to a specific Rectangle. + * @param rect {Rectangle} Target Rectangle. * @param input {object} Source image data. */ public setPixels(rect: Rectangle, input) { @@ -158,8 +158,8 @@ module Phaser { } /** - * Fill a given rectangle with specific color. - * @param rect {Rectangle} Target rectangle you want to fill. + * Fill a given Rectangle with specific color. + * @param rect {Rectangle} Target Rectangle you want to fill. * @param color {number} A native number with color value. (format: 0xRRGGBB) */ public fillRect(rect: Rectangle, color: number) { @@ -231,7 +231,7 @@ module Phaser { /** * Copy pixel from another DynamicTexture to this texture. * @param sourceTexture {DynamicTexture} Source texture object. - * @param sourceRect {Rectangle} The specific region rectangle to be copied to this in the source. + * @param sourceRect {Rectangle} The specific region Rectangle to be copied to this in the source. * @param destPoint {Point} Top-left point the target image data will be paste at. */ public copyPixels(sourceTexture: DynamicTexture, sourceRect: Rectangle, destPoint: Point) { diff --git a/Phaser/gameobjects/Emitter.ts b/Phaser/gameobjects/Emitter.ts index 0a7c5fe3..661a38bd 100644 --- a/Phaser/gameobjects/Emitter.ts +++ b/Phaser/gameobjects/Emitter.ts @@ -250,7 +250,7 @@ module Phaser { particle.exists = false; // Center the origin for rotation assistance - particle.origin.setTo(particle.body.bounds.halfWidth, particle.body.bounds.halfHeight); + particle.transform.origin.setTo(particle.body.bounds.halfWidth, particle.body.bounds.halfHeight); this.add(particle); @@ -398,7 +398,7 @@ module Phaser { if (particle.body.angularVelocity != 0) { - particle.angle = this.game.math.random() * 360 - 180; + particle.rotation = this.game.math.random() * 360 - 180; } particle.body.drag.x = this.particleDrag.x; diff --git a/Phaser/gameobjects/GameObjectFactory.ts b/Phaser/gameobjects/GameObjectFactory.ts index d77d6b1b..22a6de4b 100644 --- a/Phaser/gameobjects/GameObjectFactory.ts +++ b/Phaser/gameobjects/GameObjectFactory.ts @@ -68,11 +68,12 @@ module Phaser { * @param x {number} X position of the new sprite. * @param y {number} Y position of the new sprite. * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this sprite + * @param [frame] {string|number} If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name. * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) * @returns {Sprite} The newly created sprite object. */ - public sprite(x: number, y: number, key?: string = '', bodyType?: number = Phaser.Types.BODY_DISABLED): Sprite { - return this._world.group.add(new Sprite(this._game, x, y, key, bodyType)); + public sprite(x: number, y: number, key?: string = '', frame? = null, bodyType?: number = Phaser.Types.BODY_DISABLED): Sprite { + return this._world.group.add(new Sprite(this._game, x, y, key, frame, bodyType)); } /** diff --git a/Phaser/gameobjects/IGameObject.ts b/Phaser/gameobjects/IGameObject.ts index c76a436f..26784eb7 100644 --- a/Phaser/gameobjects/IGameObject.ts +++ b/Phaser/gameobjects/IGameObject.ts @@ -30,7 +30,7 @@ module Phaser { y: number; /** - * Z-order value of the object. + * z-index value of the object. */ z: number; @@ -45,24 +45,19 @@ module Phaser { active: bool; /** - * Controls if this Sprite is rendered or skipped during the core game loop. + * Controls if this is rendered or skipped during the core game loop. */ visible: bool; /** - * The texture used to render the Sprite. + * The texture used to render. */ texture: Phaser.Components.Texture; /** - * Scale of the Sprite. A scale of 1.0 is the original size. 0.5 half size. 2.0 double sized. + * The transform component. */ - scale: Phaser.Vec2; - - /** - * The influence of camera movement upon the Sprite. - */ - scrollFactor: Phaser.Vec2; + transform: Phaser.Components.Transform; } diff --git a/Phaser/gameobjects/Sprite.ts b/Phaser/gameobjects/Sprite.ts index 97c20a97..c58cda21 100644 --- a/Phaser/gameobjects/Sprite.ts +++ b/Phaser/gameobjects/Sprite.ts @@ -2,14 +2,14 @@ /// /// /// -/// +/// +/// /// /// /// /** * Phaser - Sprite -* */ module Phaser { @@ -25,7 +25,7 @@ module Phaser { * @param [key] {string} Key of the graphic you want to load for this sprite. * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) */ - constructor(game: Game, x?: number = 0, y?: number = 0, key?: string = null, bodyType?: number = Phaser.Types.BODY_DISABLED) { + constructor(game: Game, x?: number = 0, y?: number = 0, key?: string = null, frame? = null, bodyType?: number = Phaser.Types.BODY_DISABLED) { this.game = game; this.type = Phaser.Types.SPRITE; @@ -35,30 +35,41 @@ module Phaser { this.visible = true; this.alive = true; - // We give it a default size of 16x16 but when the texture loads (if given) it will reset this - this.frameBounds = new Rectangle(x, y, 16, 16); - this.scrollFactor = new Phaser.Vec2(1, 1); - this.x = x; this.y = y; this.z = -1; this.group = null; - this.screen = new Point; - - // If a texture has been given the body will be set to that size, otherwise 16x16 - this.body = new Phaser.Physics.Body(this, bodyType); + this.transform = new Phaser.Components.Transform(this); this.animations = new Phaser.Components.AnimationManager(this); - this.texture = new Phaser.Components.Texture(this, key); - this.input = new Phaser.Components.Input(this); - this.events = new Phaser.Components.Events(this); + this.texture = new Phaser.Components.Texture(this); + this.body = new Phaser.Physics.Body(this, bodyType); + this.input = new Phaser.Components.Sprite.Input(this); + this.events = new Phaser.Components.Sprite.Events(this); - this.cameraBlacklist = []; + if (key !== null) + { + this.texture.loadImage(key, false); + } + else + { + this.texture.opaque = true; + } + + if (frame !== null) + { + if (typeof frame == 'string') + { + this.frameName = frame; + } + else + { + this.frame = frame; + } + } + + this.worldView = new Rectangle(x, y, this.width, this.height); - // Transform related (if we add any more then move to a component) - this.origin = new Phaser.Vec2(0, 0); - this.scale = new Phaser.Vec2(1, 1); - this.skew = new Phaser.Vec2(0, 0); } /** @@ -92,7 +103,7 @@ module Phaser { public visible: bool; /** - * + * A useful state for many game objects. Kill and revive both flip this switch. */ public alive: bool; @@ -106,15 +117,20 @@ module Phaser { */ public texture: Phaser.Components.Texture; + /** + * The Sprite transform component. + */ + public transform: Phaser.Components.Transform; + /** * The Input component */ - public input: Phaser.Components.Input; + public input: Phaser.Components.Sprite.Input; /** * The Events component */ - public events: Phaser.Components.Events; + public events: Phaser.Components.Sprite.Events; /** * This manages animations of the sprite. You can modify animations though it. (see AnimationManager) @@ -123,50 +139,16 @@ module Phaser { public animations: Phaser.Components.AnimationManager; /** - * An Array of Cameras to which this GameObject won't render - * @type {Array} + * A Rectangle that defines the size and placement of the Sprite in the game world, + * after taking into consideration both scrollFactor and scaling. */ - public cameraBlacklist: number[]; - - /** - * 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. - */ - public frameBounds: Phaser.Rectangle; - - /** - * Scale of the Sprite. A scale of 1.0 is the original size. 0.5 half size. 2.0 double sized. - */ - 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; + public worldView: Phaser.Rectangle; /** * 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. - */ - public scrollFactor: Phaser.Vec2; - - /** - * The Sprite origin is the point around which scale and rotation takes place. - */ - public origin: Phaser.Vec2; - - /** - * A Point holding the x/y coordinate of this Sprite relative to the screen. It uses the default created world - * camera to calculate its values. If you have changed the default camera (i.e. resized it, deleted it) this value - * will be incorrect and should be ignored. - */ - public screen: Point; - /** * x value of the object. */ @@ -183,31 +165,23 @@ module Phaser { public z: number = 0; /** - * Render iteration + * Render iteration counter */ public renderOrderID: number = 0; /** - * This value is added to the angle of the Sprite. - * For example if you had a sprite graphic drawn facing straight up then you could set - * angleOffset to 90 and it would correspond correctly with Phasers right-handed coordinate system. - * @type {number} - */ - public angleOffset: number = 0; - - /** - * The angle of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + * The rotation of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. */ - public get angle(): number { - return this.body.angle; + public get rotation(): number { + return this.transform.rotation; } /** - * Set the angle of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + * Set the rotation of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. * The value is automatically wrapped to be between 0 and 360. */ - public set angle(value: number) { - this.body.angle = this.game.math.wrap(value, 360, 0); + public set rotation(value: number) { + this.transform.rotation = this.game.math.wrap(value, 360, 0); } /** @@ -239,19 +213,19 @@ module Phaser { } public set width(value: number) { - this.frameBounds.width = value; + this.transform.scale.x = value / this.texture.width; } public get width(): number { - return this.frameBounds.width; + return this.texture.width * this.transform.scale.x; } public set height(value: number) { - this.frameBounds.height = value; + this.transform.scale.y = value / this.texture.height; } public get height(): number { - return this.frameBounds.height; + return this.texture.height * this.transform.scale.y; } /** @@ -259,13 +233,12 @@ module Phaser { */ public preUpdate() { - this.frameBounds.x = this.x; - this.frameBounds.y = this.y; + this.worldView.x = this.x - (this.game.world.cameras.default.worldView.x * this.transform.scrollFactor.x); + this.worldView.y = this.y - (this.game.world.cameras.default.worldView.y * this.transform.scrollFactor.y); + this.worldView.width = this.width; + this.worldView.height = this.height; - this.screen.x = this.x - (this.game.world.cameras.default.worldView.x * this.scrollFactor.x); - this.screen.y = this.y - (this.game.world.cameras.default.worldView.y * this.scrollFactor.y); - - if (this.modified == false && (!this.scale.equals(1) || !this.skew.equals(0) || this.angle != 0 || this.angleOffset != 0 || this.texture.flippedX || this.texture.flippedY)) + if (this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { this.modified = true; } @@ -319,7 +292,7 @@ module Phaser { } */ - if (this.modified == true && this.scale.equals(1) && this.skew.equals(0) && this.angle == 0 && this.angleOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) + if (this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { this.modified = false; } diff --git a/Phaser/input/Pointer.ts b/Phaser/input/Pointer.ts index ef44917f..a5edaf65 100644 --- a/Phaser/input/Pointer.ts +++ b/Phaser/input/Pointer.ts @@ -263,7 +263,7 @@ module Phaser { public targetObject = null; /** - * Gets the X value of this Pointer in world coordinate space + * Gets the X value of this Pointer in world coordinate space (is it properly scaled?) * @param {Camera} [camera] */ public getWorldX(camera?: Camera = this.game.camera) { @@ -329,6 +329,7 @@ module Phaser { this.timeDown = this.game.time.now; this._holdSent = false; + // x and y are the old values here? this.positionDown.setTo(this.x, this.y); this.move(event); diff --git a/Phaser/loader/AnimationLoader.ts b/Phaser/loader/AnimationLoader.ts index aa1a680d..d064e84c 100644 --- a/Phaser/loader/AnimationLoader.ts +++ b/Phaser/loader/AnimationLoader.ts @@ -81,6 +81,7 @@ module Phaser { // Malformed? if (!json['frames']) { + console.log(json); throw new Error("Phaser.AnimationLoader.parseJSONData: Invalid Texture Atlas JSON given, missing 'frames' array"); } diff --git a/Phaser/loader/Loader.ts b/Phaser/loader/Loader.ts index d7acf982..ca50c91e 100644 --- a/Phaser/loader/Loader.ts +++ b/Phaser/loader/Loader.ts @@ -167,7 +167,7 @@ module Phaser { } this._queueSize++; - this._fileList[key] = { type: 'textureatlas', key: key, url: textureURL, data: null, atlasURL: null, atlasData: atlasData['frames'], format: format, error: false, loaded: false }; + this._fileList[key] = { type: 'textureatlas', key: key, url: textureURL, data: null, atlasURL: null, atlasData: atlasData, format: format, error: false, loaded: false }; this._keys.push(key); } else if (format == Loader.TEXTURE_ATLAS_XML_STARLING) diff --git a/Phaser/math/GameMath.ts b/Phaser/math/GameMath.ts index 7610ae80..0c071772 100644 --- a/Phaser/math/GameMath.ts +++ b/Phaser/math/GameMath.ts @@ -308,7 +308,7 @@ module Phaser { /** - * set an angle with in the bounds of -PI to PI + * set an angle within the bounds of -PI to PI */ public normalizeAngle(angle: number, radians: bool = true): number { var rd: number = (radians) ? GameMath.PI : 180; @@ -1022,20 +1022,20 @@ module Phaser { } /** - * Rotates the point around the x/y coordinates given to the desired angle and distance + * Rotates the point around the x/y coordinates given to the desired rotation and distance * @param point {Object} Any object with exposed x and y properties * @param x {number} The x coordinate of the anchor point * @param y {number} The y coordinate of the anchor point - * @param {Number} angle The angle in radians (unless asDegrees is true) to return the point from. - * @param {Boolean} asDegrees Is the given angle in radians (false) or degrees (true)? + * @param {Number} rotation The rotation in radians (unless asDegrees is true) to return the point from. + * @param {Boolean} asDegrees Is the given rotation in radians (false) or degrees (true)? * @param {Number} distance An optional distance constraint between the point and the anchor * @return The modified point object */ - public rotatePoint(point, x1: number, y1: number, angle: number, asDegrees: bool = false, distance?:number = null) { + public rotatePoint(point, x1: number, y1: number, rotation: number, asDegrees: bool = false, distance?:number = null) { if (asDegrees) { - angle = angle * GameMath.DEG_TO_RAD; + rotation = rotation * GameMath.DEG_TO_RAD; } // Get distance from origin to the point @@ -1044,8 +1044,8 @@ module Phaser { distance = Math.sqrt(((x1 - point.x) * (x1 - point.x)) + ((y1 - point.y) * (y1 - point.y))); } - point.x = x1 + distance * Math.cos(angle); - point.y = y1 + distance * Math.sin(angle); + point.x = x1 + distance * Math.cos(rotation); + point.y = y1 + distance * Math.sin(rotation); return point; diff --git a/Phaser/physics/Body.ts b/Phaser/physics/Body.ts index 8e72f85d..cd2d17fa 100644 --- a/Phaser/physics/Body.ts +++ b/Phaser/physics/Body.ts @@ -10,15 +10,15 @@ module Phaser.Physics { export class Body { - constructor(parent: Sprite, type: number) { + constructor(sprite: Phaser.Sprite, type: number) { - this.parent = parent; - this.game = parent.game; + this.sprite = sprite; + this.game = sprite.game; this.type = type; // Fixture properties // Will extend into its own class at a later date - can move the fixture defs there and add shape support, but this will do for 1.0 release - this.bounds = new Rectangle(parent.x + Math.round(parent.width / 2), parent.y + Math.round(parent.height / 2), parent.width, parent.height); + this.bounds = new Rectangle(sprite.x + Math.round(sprite.width / 2), sprite.y + Math.round(sprite.height / 2), sprite.width, sprite.height); this.bounce = Vec2Utils.clone(this.game.world.physics.bounce); // Body properties @@ -29,7 +29,6 @@ module Phaser.Physics { this.drag = Vec2Utils.clone(this.game.world.physics.drag); this.maxVelocity = new Vec2(10000, 10000); - this.angle = 0; this.angularVelocity = 0; this.angularAcceleration = 0; this.angularDrag = 0; @@ -38,14 +37,21 @@ module Phaser.Physics { this.wasTouching = Types.NONE; this.allowCollisions = Types.ANY; - this.position = new Vec2(parent.x + this.bounds.halfWidth, parent.y + this.bounds.halfHeight); - this.oldPosition = new Vec2(parent.x + this.bounds.halfWidth, parent.y + this.bounds.halfHeight); + this.position = new Vec2(sprite.x + this.bounds.halfWidth, sprite.y + this.bounds.halfHeight); + this.oldPosition = new Vec2(sprite.x + this.bounds.halfWidth, sprite.y + this.bounds.halfHeight); this.offset = new Vec2; } + /** + * Reference to Phaser.Game + */ public game: Game; - public parent: Sprite; + + /** + * Reference to the sprite Sprite + */ + public sprite: Phaser.Sprite; /** * The type of Body (disabled, dynamic, static or kinematic) @@ -70,12 +76,6 @@ module Phaser.Physics { public angularDrag: number = 0; public maxAngular: number = 10000; - /** - * Angle of rotation of this body. - * @type {number} - */ - public angle: number; - /** * Orientation of the object. * @type {number} @@ -102,7 +102,7 @@ module Phaser.Physics { this.bounds.x = this.position.x - this.bounds.halfWidth; this.bounds.y = this.position.y - this.bounds.halfHeight; - if (this.parent.scale.equals(1) == false) + if (this.sprite.transform.scale.equals(1) == false) { } @@ -117,8 +117,8 @@ module Phaser.Physics { { this.game.world.physics.updateMotion(this); - this.parent.x = (this.position.x - this.bounds.halfWidth) - this.offset.x; - this.parent.y = (this.position.y - this.bounds.halfHeight) - this.offset.y; + this.sprite.x = (this.position.x - this.bounds.halfWidth) - this.offset.x; + this.sprite.y = (this.position.y - this.bounds.halfHeight) - this.offset.y; this.wasTouching = this.touching; this.touching = Phaser.Types.NONE; @@ -267,13 +267,13 @@ module Phaser.Physics { */ public renderDebugInfo(x: number, y: number, color?: string = 'rgb(255,255,255)') { - this.parent.texture.context.fillStyle = color; - this.parent.texture.context.fillText('Sprite: (' + this.parent.frameBounds.width + ' x ' + this.parent.frameBounds.height + ')', x, y); - //this.parent.texture.context.fillText('x: ' + this._parent.frameBounds.x.toFixed(1) + ' y: ' + this._parent.frameBounds.y.toFixed(1) + ' rotation: ' + this._parent.rotation.toFixed(1), x, y + 14); - this.parent.texture.context.fillText('x: ' + this.bounds.x.toFixed(1) + ' y: ' + this.bounds.y.toFixed(1) + ' angle: ' + this.angle.toFixed(0), x, y + 14); - this.parent.texture.context.fillText('vx: ' + this.velocity.x.toFixed(1) + ' vy: ' + this.velocity.y.toFixed(1), x, y + 28); - this.parent.texture.context.fillText('acx: ' + this.acceleration.x.toFixed(1) + ' acy: ' + this.acceleration.y.toFixed(1), x, y + 42); - this.parent.texture.context.fillText('angVx: ' + this.angularVelocity.toFixed(1) + ' angAc: ' + this.angularAcceleration.toFixed(1), x, y + 56); + this.sprite.texture.context.fillStyle = color; + this.sprite.texture.context.fillText('Sprite: (' + this.sprite.width + ' x ' + this.sprite.height + ')', x, y); + //this.sprite.texture.context.fillText('x: ' + this._sprite.frameBounds.x.toFixed(1) + ' y: ' + this._sprite.frameBounds.y.toFixed(1) + ' rotation: ' + this._sprite.rotation.toFixed(1), x, y + 14); + this.sprite.texture.context.fillText('x: ' + this.bounds.x.toFixed(1) + ' y: ' + this.bounds.y.toFixed(1) + ' rotation: ' + this.sprite.transform.rotation.toFixed(0), x, y + 14); + this.sprite.texture.context.fillText('vx: ' + this.velocity.x.toFixed(1) + ' vy: ' + this.velocity.y.toFixed(1), x, y + 28); + this.sprite.texture.context.fillText('acx: ' + this.acceleration.x.toFixed(1) + ' acy: ' + this.acceleration.y.toFixed(1), x, y + 42); + this.sprite.texture.context.fillText('angVx: ' + this.angularVelocity.toFixed(1) + ' angAc: ' + this.angularAcceleration.toFixed(1), x, y + 56); } diff --git a/Phaser/physics/PhysicsManager.ts b/Phaser/physics/PhysicsManager.ts index 02ca1b5b..d11399da 100644 --- a/Phaser/physics/PhysicsManager.ts +++ b/Phaser/physics/PhysicsManager.ts @@ -141,7 +141,7 @@ module Phaser.Physics { this._velocityDelta = (this.computeVelocity(body.angularVelocity, body.gravity.x, body.angularAcceleration, body.angularDrag, body.maxAngular) - body.angularVelocity) / 2; body.angularVelocity += this._velocityDelta; - body.angle += body.angularVelocity * this.game.time.elapsed; + body.sprite.transform.rotation += body.angularVelocity * this.game.time.elapsed; body.angularVelocity += this._velocityDelta; this._velocityDelta = (this.computeVelocity(body.velocity.x, body.gravity.x, body.acceleration.x, body.drag.x) - body.velocity.x) / 2; @@ -424,7 +424,7 @@ module Phaser.Physics { body1.velocity.y = this._obj2Velocity - this._obj1Velocity * body1.bounce.y; // This is special case code that handles things like horizontal moving platforms you can ride //if (body2.parent.active && body2.moves && (body1.deltaY > body2.deltaY)) - if (body2.parent.active && (body1.deltaY > body2.deltaY)) + if (body2.sprite.active && (body1.deltaY > body2.deltaY)) { body1.position.x += body2.position.x - body2.oldPosition.x; } @@ -436,7 +436,7 @@ module Phaser.Physics { body2.velocity.y = this._obj1Velocity - this._obj2Velocity * body2.bounce.y; // This is special case code that handles things like horizontal moving platforms you can ride //if (object1.active && body1.moves && (body1.deltaY < body2.deltaY)) - if (body1.parent.active && (body1.deltaY < body2.deltaY)) + if (body1.sprite.active && (body1.deltaY < body2.deltaY)) { body2.position.x += body1.position.x - body1.oldPosition.x; } diff --git a/Phaser/renderers/CanvasRenderer.ts b/Phaser/renderers/CanvasRenderer.ts index 241bf1dd..72aedd85 100644 --- a/Phaser/renderers/CanvasRenderer.ts +++ b/Phaser/renderers/CanvasRenderer.ts @@ -53,11 +53,11 @@ module Phaser { { this._camera = this._cameraList[c]; - this._camera.preRender(); + this.preRenderCamera(this._camera); this._game.world.group.render(this._camera); - this._camera.postRender(); + this.postRenderCamera(this._camera); } this.renderTotal = this._count; @@ -77,13 +77,148 @@ module Phaser { } + public preRenderGroup(camera: Camera, group: Group) { + + if (camera.transform.scale.x == 0 || camera.transform.scale.y == 0 || camera.texture.alpha < 0.1 || this.inScreen(camera) == false) + { + return false; + } + + // Reset our temp vars + this._ga = -1; + this._sx = 0; + this._sy = 0; + this._sw = group.texture.width; + this._sh = group.texture.height; + this._fx = group.transform.scale.x; + this._fy = group.transform.scale.y; + this._sin = 0; + this._cos = 1; + //this._dx = (camera.screenView.x * camera.scrollFactor.x) + camera.frameBounds.x - (camera.worldView.x * camera.scrollFactor.x); + //this._dy = (camera.screenView.y * camera.scrollFactor.y) + camera.frameBounds.y - (camera.worldView.y * camera.scrollFactor.y); + this._dx = 0; + this._dy = 0; + this._dw = group.texture.width; + this._dh = group.texture.height; + + // Global Composite Ops + if (group.texture.globalCompositeOperation) + { + group.texture.context.save(); + group.texture.context.globalCompositeOperation = group.texture.globalCompositeOperation; + } + + // Alpha + if (group.texture.alpha !== 1 && group.texture.context.globalAlpha !== group.texture.alpha) + { + this._ga = group.texture.context.globalAlpha; + group.texture.context.globalAlpha = group.texture.alpha; + } + + // Flip X + if (group.texture.flippedX) + { + this._fx = -group.transform.scale.x; + } + + // Flip Y + if (group.texture.flippedY) + { + this._fy = -group.transform.scale.y; + } + + // Rotation and Flipped + if (group.modified) + { + if (group.transform.rotation !== 0 || group.transform.rotationOffset !== 0) + { + this._sin = Math.sin(group.game.math.degreesToRadians(group.transform.rotationOffset + group.transform.rotation)); + this._cos = Math.cos(group.game.math.degreesToRadians(group.transform.rotationOffset + group.transform.rotation)); + } + + // setTransform(a, b, c, d, e, f); + // a = scale x + // b = skew x + // c = skew y + // d = scale y + // e = translate x + // f = translate y + + group.texture.context.save(); + group.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + group.transform.skew.x, -(this._sin * this._fy) + group.transform.skew.y, this._cos * this._fy, this._dx, this._dy); + + this._dx = -group.transform.origin.x; + this._dy = -group.transform.origin.y; + } + else + { + if (!group.transform.origin.equals(0)) + { + this._dx -= group.transform.origin.x; + this._dy -= group.transform.origin.y; + } + } + + this._sx = Math.round(this._sx); + this._sy = Math.round(this._sy); + this._sw = Math.round(this._sw); + this._sh = Math.round(this._sh); + this._dx = Math.round(this._dx); + this._dy = Math.round(this._dy); + this._dw = Math.round(this._dw); + this._dh = Math.round(this._dh); + + if (group.texture.opaque) + { + group.texture.context.fillStyle = group.texture.backgroundColor; + group.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); + } + + if (group.texture.loaded) + { + group.texture.context.drawImage( + group.texture.texture, // Source Image + this._sx, // Source X (location within the source image) + this._sy, // Source Y + this._sw, // Source Width + this._sh, // Source Height + this._dx, // Destination X (where on the canvas it'll be drawn) + this._dy, // Destination Y + this._dw, // Destination Width (always same as Source Width unless scaled) + this._dh // Destination Height (always same as Source Height unless scaled) + ); + } + + return true; + + } + + public postRenderGroup(camera: Camera, group: Group) { + + if (group.modified || group.texture.globalCompositeOperation) + { + group.texture.context.restore(); + } + + // This could have been over-written by a sprite, need to store elsewhere + if (this._ga > -1) + { + group.texture.context.globalAlpha = this._ga; + } + + } + /** - * Check whether this object is visible in a specific camera rectangle. - * @param camera {Rectangle} The rectangle you want to check. - * @return {boolean} Return true if bounds of this sprite intersects the given rectangle, otherwise return false. + * Check whether this object is visible in a specific camera Rectangle. + * @param camera {Rectangle} The Rectangle you want to check. + * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. */ public inCamera(camera: Camera, sprite: Sprite): bool { + return true; + + /* + // Object fixed in place regardless of the camera scrolling? Then it's always visible if (sprite.scrollFactor.x == 0 && sprite.scrollFactor.y == 0) { @@ -95,7 +230,162 @@ module Phaser { this._dw = sprite.frameBounds.width * sprite.scale.x; this._dh = sprite.frameBounds.height * sprite.scale.y; - return (camera.scaledX + camera.worldView.width > this._dx) && (camera.scaledX < this._dx + this._dw) && (camera.scaledY + camera.worldView.height > this._dy) && (camera.scaledY < this._dy + this._dh); + //return (camera.screenView.x + camera.worldView.width > this._dx) && (camera.screenView.x < this._dx + this._dw) && (camera.screenView.y + camera.worldView.height > this._dy) && (camera.screenView.y < this._dy + this._dh); + + */ + + } + + public inScreen(camera: Camera): bool { + + return true; + + } + + /** + * Render this sprite to specific camera. Called by game loop after update(). + * @param camera {Camera} Camera this sprite will be rendered to. + * @return {boolean} Return false if not rendered, otherwise return true. + */ + public preRenderCamera(camera: Camera): bool { + + if (camera.transform.scale.x == 0 || camera.transform.scale.y == 0 || camera.texture.alpha < 0.1 || this.inScreen(camera) == false) + { + return false; + } + + // Reset our temp vars + this._ga = -1; + this._sx = 0; + this._sy = 0; + this._sw = camera.width; + this._sh = camera.height; + this._fx = camera.transform.scale.x; + this._fy = camera.transform.scale.y; + this._sin = 0; + this._cos = 1; + this._dx = camera.screenView.x; + this._dy = camera.screenView.y; + this._dw = camera.width; + this._dh = camera.height; + + // Global Composite Ops + if (camera.texture.globalCompositeOperation) + { + camera.texture.context.save(); + camera.texture.context.globalCompositeOperation = camera.texture.globalCompositeOperation; + } + + // Alpha + if (camera.texture.alpha !== 1 && camera.texture.context.globalAlpha != camera.texture.alpha) + { + this._ga = camera.texture.context.globalAlpha; + camera.texture.context.globalAlpha = camera.texture.alpha; + } + + // Sprite Flip X + if (camera.texture.flippedX) + { + this._fx = -camera.transform.scale.x; + } + + // Sprite Flip Y + if (camera.texture.flippedY) + { + this._fy = -camera.transform.scale.y; + } + + // Rotation and Flipped + if (camera.modified) + { + if (camera.transform.rotation !== 0 || camera.transform.rotationOffset !== 0) + { + this._sin = Math.sin(camera.game.math.degreesToRadians(camera.transform.rotationOffset + camera.transform.rotation)); + this._cos = Math.cos(camera.game.math.degreesToRadians(camera.transform.rotationOffset + camera.transform.rotation)); + } + + // setTransform(a, b, c, d, e, f); + // a = scale x + // b = skew x + // c = skew y + // d = scale y + // e = translate x + // f = translate y + + camera.texture.context.save(); + camera.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + camera.transform.skew.x, -(this._sin * this._fy) + camera.transform.skew.y, this._cos * this._fy, this._dx, this._dy); + + this._dx = -camera.transform.origin.x; + this._dy = -camera.transform.origin.y; + } + else + { + if (!camera.transform.origin.equals(0)) + { + this._dx -= camera.transform.origin.x; + this._dy -= camera.transform.origin.y; + } + } + + this._sx = Math.round(this._sx); + this._sy = Math.round(this._sy); + this._sw = Math.round(this._sw); + this._sh = Math.round(this._sh); + this._dx = Math.round(this._dx); + this._dy = Math.round(this._dy); + this._dw = Math.round(this._dw); + this._dh = Math.round(this._dh); + + // Clip the camera so we don't get sprites appearing outside the edges + if (camera.clip == true && camera.disableClipping == false) + { + camera.texture.context.beginPath(); + camera.texture.context.rect(camera.screenView.x, camera.screenView.x, camera.screenView.width, camera.screenView.height); + camera.texture.context.closePath(); + camera.texture.context.clip(); + } + + if (camera.texture.opaque) + { + camera.texture.context.fillStyle = camera.texture.backgroundColor; + camera.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); + } + + //camera.fx.render(camera); + + if (camera.texture.loaded) + { + camera.texture.context.drawImage( + camera.texture.texture, // Source Image + this._sx, // Source X (location within the source image) + this._sy, // Source Y + this._sw, // Source Width + this._sh, // Source Height + this._dx, // Destination X (where on the canvas it'll be drawn) + this._dy, // Destination Y + this._dw, // Destination Width (always same as Source Width unless scaled) + this._dh // Destination Height (always same as Source Height unless scaled) + ); + } + + return true; + + } + + public postRenderCamera(camera: Camera) { + + //camera.fx.postRender(camera); + + if (camera.modified || camera.texture.globalCompositeOperation) + { + camera.texture.context.restore(); + } + + // This could have been over-written by a sprite, need to store elsewhere + if (this._ga > -1) + { + camera.texture.context.globalAlpha = this._ga; + } } @@ -112,8 +402,8 @@ module Phaser { this._fy = 1; this._sin = 0; this._cos = 1; - this._dx = camera.scaledX + circle.x - camera.worldView.x; - this._dy = camera.scaledY + circle.y - camera.worldView.y; + this._dx = camera.screenView.x + circle.x - camera.worldView.x; + this._dy = camera.screenView.y + circle.y - camera.worldView.y; this._dw = circle.diameter; this._dh = circle.diameter; @@ -162,7 +452,7 @@ module Phaser { */ public renderSprite(camera: Camera, sprite: Sprite): bool { - if (sprite.scale.x == 0 || sprite.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) + if (sprite.transform.scale.x == 0 || sprite.transform.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { return false; } @@ -175,19 +465,26 @@ module Phaser { this._ga = -1; this._sx = 0; this._sy = 0; - this._sw = sprite.frameBounds.width; - this._sh = sprite.frameBounds.height; - this._fx = sprite.scale.x; - this._fy = sprite.scale.y; + this._sw = sprite.texture.width; + this._sh = sprite.texture.height; + this._fx = sprite.transform.scale.x; + this._fy = sprite.transform.scale.y; this._sin = 0; this._cos = 1; - this._dx = (camera.scaledX * sprite.scrollFactor.x) + sprite.frameBounds.x - (camera.worldView.x * sprite.scrollFactor.x); - 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; + this._dx = (camera.screenView.x * sprite.transform.scrollFactor.x) + sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + this._dy = (camera.screenView.y * sprite.transform.scrollFactor.y) + sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + this._dw = sprite.texture.width; + this._dh = sprite.texture.height; + + // Global Composite Ops + if (sprite.texture.globalCompositeOperation) + { + sprite.texture.context.save(); + sprite.texture.context.globalCompositeOperation = sprite.texture.globalCompositeOperation; + } // Alpha - if (sprite.texture.alpha !== 1) + if (sprite.texture.alpha !== 1 && sprite.texture.context.globalAlpha != sprite.texture.alpha) { this._ga = sprite.texture.context.globalAlpha; sprite.texture.context.globalAlpha = sprite.texture.alpha; @@ -196,13 +493,13 @@ module Phaser { // Sprite Flip X if (sprite.texture.flippedX) { - this._fx = -sprite.scale.x; + this._fx = -sprite.transform.scale.x; } // Sprite Flip Y if (sprite.texture.flippedY) { - this._fy = -sprite.scale.y; + this._fy = -sprite.transform.scale.y; } if (sprite.animations.currentFrame !== null) @@ -214,16 +511,20 @@ module Phaser { { this._dx += sprite.animations.currentFrame.spriteSourceSizeX; this._dy += sprite.animations.currentFrame.spriteSourceSizeY; + this._sw = sprite.animations.currentFrame.spriteSourceSizeW; + this._sh = sprite.animations.currentFrame.spriteSourceSizeH; + this._dw = sprite.animations.currentFrame.spriteSourceSizeW; + this._dh = sprite.animations.currentFrame.spriteSourceSizeH; } } // Rotation and Flipped if (sprite.modified) { - if (sprite.texture.renderRotation == true && (sprite.angle !== 0 || sprite.angleOffset !== 0)) + if (sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.transform.rotationOffset !== 0)) { - this._sin = Math.sin(sprite.game.math.degreesToRadians(sprite.angleOffset + sprite.angle)); - this._cos = Math.cos(sprite.game.math.degreesToRadians(sprite.angleOffset + sprite.angle)); + this._sin = Math.sin(sprite.game.math.degreesToRadians(sprite.transform.rotationOffset + sprite.rotation)); + this._cos = Math.cos(sprite.game.math.degreesToRadians(sprite.transform.rotationOffset + sprite.rotation)); } // setTransform(a, b, c, d, e, f); @@ -235,17 +536,17 @@ module Phaser { // f = translate y sprite.texture.context.save(); - 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); + sprite.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + sprite.transform.skew.x, -(this._sin * this._fy) + sprite.transform.skew.y, this._cos * this._fy, this._dx, this._dy); - this._dx = -sprite.origin.x; - this._dy = -sprite.origin.y; + this._dx = -sprite.transform.origin.x; + this._dy = -sprite.transform.origin.y; } else { - if (!sprite.origin.equals(0)) + if (!sprite.transform.origin.equals(0)) { - this._dx -= sprite.origin.x; - this._dy -= sprite.origin.y; + this._dx -= sprite.transform.origin.x; + this._dy -= sprite.transform.origin.y; } } @@ -258,6 +559,12 @@ module Phaser { this._dw = Math.round(this._dw); this._dh = Math.round(this._dh); + if (sprite.texture.opaque) + { + sprite.texture.context.fillStyle = sprite.texture.backgroundColor; + sprite.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); + } + if (sprite.texture.loaded) { sprite.texture.context.drawImage( @@ -272,14 +579,8 @@ module Phaser { this._dh // Destination Height (always same as Source Height unless scaled) ); } - else - { - //sprite.texture.context.fillStyle = this.fillColor; - sprite.texture.context.fillStyle = 'rgb(255,255,255)'; - sprite.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); - } - if (sprite.modified) + if (sprite.modified || sprite.texture.globalCompositeOperation) { sprite.texture.context.restore(); } @@ -295,7 +596,7 @@ module Phaser { public renderScrollZone(camera: Camera, scrollZone: ScrollZone): bool { - if (scrollZone.scale.x == 0 || scrollZone.scale.y == 0 || scrollZone.texture.alpha < 0.1 || this.inCamera(camera, scrollZone) == false) + if (scrollZone.transform.scale.x == 0 || scrollZone.transform.scale.y == 0 || scrollZone.texture.alpha < 0.1 || this.inCamera(camera, scrollZone) == false) { return false; } @@ -306,16 +607,16 @@ module Phaser { this._ga = -1; this._sx = 0; this._sy = 0; - this._sw = scrollZone.frameBounds.width; - this._sh = scrollZone.frameBounds.height; - this._fx = scrollZone.scale.x; - this._fy = scrollZone.scale.y; + this._sw = scrollZone.width; + this._sh = scrollZone.height; + this._fx = scrollZone.transform.scale.x; + this._fy = scrollZone.transform.scale.y; this._sin = 0; this._cos = 1; - this._dx = (camera.scaledX * scrollZone.scrollFactor.x) + scrollZone.frameBounds.x - (camera.worldView.x * scrollZone.scrollFactor.x); - this._dy = (camera.scaledY * scrollZone.scrollFactor.y) + scrollZone.frameBounds.y - (camera.worldView.y * scrollZone.scrollFactor.y); - this._dw = scrollZone.frameBounds.width; - this._dh = scrollZone.frameBounds.height; + this._dx = (camera.screenView.x * scrollZone.transform.scrollFactor.x) + scrollZone.x - (camera.worldView.x * scrollZone.transform.scrollFactor.x); + this._dy = (camera.screenView.y * scrollZone.transform.scrollFactor.y) + scrollZone.y - (camera.worldView.y * scrollZone.transform.scrollFactor.y); + this._dw = scrollZone.width; + this._dh = scrollZone.height; // Alpha if (scrollZone.texture.alpha !== 1) @@ -327,22 +628,22 @@ module Phaser { // Sprite Flip X if (scrollZone.texture.flippedX) { - this._fx = -scrollZone.scale.x; + this._fx = -scrollZone.transform.scale.x; } // Sprite Flip Y if (scrollZone.texture.flippedY) { - this._fy = -scrollZone.scale.y; + this._fy = -scrollZone.transform.scale.y; } // Rotation and Flipped if (scrollZone.modified) { - if (scrollZone.texture.renderRotation == true && (scrollZone.angle !== 0 || scrollZone.angleOffset !== 0)) + if (scrollZone.texture.renderRotation == true && (scrollZone.rotation !== 0 || scrollZone.transform.rotationOffset !== 0)) { - this._sin = Math.sin(scrollZone.game.math.degreesToRadians(scrollZone.angleOffset + scrollZone.angle)); - this._cos = Math.cos(scrollZone.game.math.degreesToRadians(scrollZone.angleOffset + scrollZone.angle)); + this._sin = Math.sin(scrollZone.game.math.degreesToRadians(scrollZone.transform.rotationOffset + scrollZone.rotation)); + this._cos = Math.cos(scrollZone.game.math.degreesToRadians(scrollZone.transform.rotationOffset + scrollZone.rotation)); } // setTransform(a, b, c, d, e, f); @@ -354,17 +655,17 @@ module Phaser { // f = translate y scrollZone.texture.context.save(); - scrollZone.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + scrollZone.skew.x, -(this._sin * this._fy) + scrollZone.skew.y, this._cos * this._fy, this._dx, this._dy); + scrollZone.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + scrollZone.transform.skew.x, -(this._sin * this._fy) + scrollZone.transform.skew.y, this._cos * this._fy, this._dx, this._dy); - this._dx = -scrollZone.origin.x; - this._dy = -scrollZone.origin.y; + this._dx = -scrollZone.transform.origin.x; + this._dy = -scrollZone.transform.origin.y; } else { - if (!scrollZone.origin.equals(0)) + if (!scrollZone.transform.origin.equals(0)) { - this._dx -= scrollZone.origin.x; - this._dy -= scrollZone.origin.y; + this._dx -= scrollZone.transform.origin.x; + this._dy -= scrollZone.transform.origin.y; } } diff --git a/Phaser/renderers/HeadlessRenderer.ts b/Phaser/renderers/HeadlessRenderer.ts index 1a961ace..7225c950 100644 --- a/Phaser/renderers/HeadlessRenderer.ts +++ b/Phaser/renderers/HeadlessRenderer.ts @@ -32,6 +32,18 @@ module Phaser { return true; } + public preRenderCamera(camera: Camera) { + } + + public postRenderCamera(camera: Camera) { + } + + public preRenderGroup(camera: Camera, group: Group) { + } + + public postRenderGroup(camera: Camera, group: Group) { + } + } } \ No newline at end of file diff --git a/Phaser/renderers/IRenderer.ts b/Phaser/renderers/IRenderer.ts index dc82fa4e..07acbc94 100644 --- a/Phaser/renderers/IRenderer.ts +++ b/Phaser/renderers/IRenderer.ts @@ -8,8 +8,12 @@ module Phaser { renderGameObject(object); renderSprite(camera: Camera, sprite: Sprite): bool; renderScrollZone(camera: Camera, sprite: ScrollZone): bool; - renderCircle(camera: Camera, circle: Circle, context, outline?: bool, fill?: bool, lineColor?: string, fillColor?: string, lineWidth?: number); + preRenderGroup(camera: Camera, group: Group); + postRenderGroup(camera: Camera, group: Group); + preRenderCamera(camera: Camera); + postRenderCamera(camera: Camera); + } diff --git a/Phaser/system/StageScaleMode.ts b/Phaser/system/StageScaleMode.ts index bddfaa89..fd3e5fe1 100644 --- a/Phaser/system/StageScaleMode.ts +++ b/Phaser/system/StageScaleMode.ts @@ -15,7 +15,7 @@ module Phaser { /** * StageScaleMode constructor */ - constructor(game: Game) { + constructor(game: Game, width: number, height: number) { this._game = game; @@ -40,6 +40,10 @@ module Phaser { this.scaleFactor = new Vec2(1, 1); this.aspectRatio = 0; + this.minWidth = width; + this.minHeight = height; + this.maxWidth = width; + this.maxHeight = height; window.addEventListener('orientationchange', (event) => this.checkOrientation(event), false); window.addEventListener('resize', (event) => this.checkResize(event), false); @@ -95,6 +99,22 @@ module Phaser { */ public incorrectOrientation: bool = false; + /** + * If you wish to align your game in the middle of the page then you can set this value to true. + * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing. + * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin. + * @type {Boolean} + */ + public pageAlignHorizontally: bool = false; + + /** + * If you wish to align your game in the middle of the page then you can set this value to true. + * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing. + * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin. + * @type {Boolean} + */ + public pageAlignVeritcally: bool = false; + /** * Minimum width the canvas should be scaled to (in pixels) * @type {number} @@ -354,7 +374,7 @@ module Phaser { /** * Set screen size automatically based on the scaleMode. */ - private setScreenSize() { + public setScreenSize(force: bool = false) { if (this._game.device.iPad == false && this._game.device.webApp == false && this._game.device.desktop == false) { @@ -370,7 +390,7 @@ module Phaser { this._iterations--; - if (window.innerHeight > this._startHeight || this._iterations < 0) + if (force || window.innerHeight > this._startHeight || this._iterations < 0) { // Set minimum height of content to new window height document.documentElement.style.minHeight = window.innerHeight + 'px'; @@ -400,24 +420,27 @@ module Phaser { private setSize() { - if (this.maxWidth && this.width > this.maxWidth) + if (this.incorrectOrientation == false) { - this.width = this.maxWidth; - } + if (this.maxWidth && this.width > this.maxWidth) + { + this.width = this.maxWidth; + } - if (this.maxHeight && this.height > this.maxHeight) - { - this.height = this.maxHeight; - } + if (this.maxHeight && this.height > this.maxHeight) + { + this.height = this.maxHeight; + } - if (this.minWidth && this.width < this.minWidth) - { - this.width = this.minWidth; - } + if (this.minWidth && this.width < this.minWidth) + { + this.width = this.minWidth; + } - if (this.minHeight && this.height < this.minHeight) - { - this.height = this.minHeight; + if (this.minHeight && this.height < this.minHeight) + { + this.height = this.minHeight; + } } this._game.stage.canvas.style.width = this.width + 'px'; @@ -426,13 +449,35 @@ module Phaser { this._game.input.scaleX = this._game.stage.width / this.width; this._game.input.scaleY = this._game.stage.height / this.height; + if (this.pageAlignHorizontally) + { + if (this.width < window.innerWidth && this.incorrectOrientation == false) + { + this._game.stage.canvas.style.marginLeft = Math.round((window.innerWidth - this.width) / 2) + 'px'; + } + else + { + this._game.stage.canvas.style.marginLeft = '0px'; + } + } + + if (this.pageAlignVeritcally) + { + if (this.height < window.innerHeight && this.incorrectOrientation == false) + { + this._game.stage.canvas.style.marginTop = Math.round((window.innerHeight - this.height) / 2) + 'px'; + } + else + { + this._game.stage.canvas.style.marginTop = '0px'; + } + } + this._game.stage.getOffset(this._game.stage.canvas); this.aspectRatio = this.width / this.height; this.scaleFactor.x = this._game.stage.width / this.width; this.scaleFactor.y = this._game.stage.height / this.height; - //this.scaleFactor.x = this.width / this._game.stage.width; - //this.scaleFactor.y = this.height / this._game.stage.height; } diff --git a/Phaser/utils/DebugUtils.ts b/Phaser/utils/DebugUtils.ts index 8d76db9a..8a775fbe 100644 --- a/Phaser/utils/DebugUtils.ts +++ b/Phaser/utils/DebugUtils.ts @@ -26,8 +26,8 @@ module Phaser { static renderSpriteInfo(sprite: Sprite, x: number, y: number, color?: string = 'rgb(255,255,255)') { DebugUtils.game.stage.context.fillStyle = color; - DebugUtils.game.stage.context.fillText('Sprite: ' + ' (' + sprite.frameBounds.width + ' x ' + sprite.frameBounds.height + ')', x, y); - DebugUtils.game.stage.context.fillText('x: ' + sprite.frameBounds.x.toFixed(1) + ' y: ' + sprite.frameBounds.y.toFixed(1) + ' angle: ' + sprite.angle.toFixed(1), x, y + 14); + DebugUtils.game.stage.context.fillText('Sprite: ' + ' (' + sprite.width + ' x ' + sprite.height + ')', x, y); + DebugUtils.game.stage.context.fillText('x: ' + sprite.x.toFixed(1) + ' y: ' + sprite.y.toFixed(1) + ' rotation: ' + sprite.rotation.toFixed(1), x, y + 14); //DebugUtils.game.stage.context.fillText('dx: ' + this._dx.toFixed(1) + ' dy: ' + this._dy.toFixed(1) + ' dw: ' + this._dw.toFixed(1) + ' dh: ' + this._dh.toFixed(1), x, y + 28); //DebugUtils.game.stage.context.fillText('sx: ' + this._sx.toFixed(1) + ' sy: ' + this._sy.toFixed(1) + ' sw: ' + this._sw.toFixed(1) + ' sh: ' + this._sh.toFixed(1), x, y + 42); diff --git a/Phaser/utils/PointUtils.ts b/Phaser/utils/PointUtils.ts index be2e9739..f15cea4d 100644 --- a/Phaser/utils/PointUtils.ts +++ b/Phaser/utils/PointUtils.ts @@ -180,7 +180,7 @@ module Phaser { * @param x {number} The x coordinate of the anchor point * @param y {number} The y coordinate of the anchor point * @param {Number} angle The angle in radians (unless asDegrees is true) to rotate the Point to. - * @param {Boolean} asDegrees Is the given angle in radians (false) or degrees (true)? + * @param {Boolean} asDegrees Is the given rotation in radians (false) or degrees (true)? * @param {Number} distance An optional distance constraint between the Point and the anchor. * @return The modified point object */ @@ -208,7 +208,7 @@ module Phaser { * @param x {number} The x coordinate of the anchor point * @param y {number} The y coordinate of the anchor point * @param {Number} angle The angle in radians (unless asDegrees is true) to rotate the Point to. - * @param {Boolean} asDegrees Is the given angle in radians (false) or degrees (true)? + * @param {Boolean} asDegrees Is the given rotation in radians (false) or degrees (true)? * @param {Number} distance An optional distance constraint between the Point and the anchor. * @return The modified point object */ diff --git a/Phaser/utils/RectangleUtils.ts b/Phaser/utils/RectangleUtils.ts index 49e581d8..7882f27b 100644 --- a/Phaser/utils/RectangleUtils.ts +++ b/Phaser/utils/RectangleUtils.ts @@ -145,12 +145,12 @@ module Phaser { } /** - * If the Rectangle object specified in the toIntersect parameter intersects with this Rectangle object, returns the area of intersection as a Rectangle object. If the rectangles do not intersect, this method returns an empty Rectangle object with its properties set to 0. + * If the Rectangle object specified in the toIntersect parameter intersects with this Rectangle object, returns the area of intersection as a Rectangle object. If the Rectangles do not intersect, this method returns an empty Rectangle object with its properties set to 0. * @method intersection * @param {Rectangle} a - The first Rectangle object. * @param {Rectangle} b - The second Rectangle object. * @param {Rectangle} output Optional Rectangle object. If given the intersection values will be set into this object, otherwise a brand new Rectangle object will be created and returned. - * @return {Rectangle} A Rectangle object that equals the area of intersection. If the rectangles do not intersect, this method returns an empty Rectangle object; that is, a rectangle with its x, y, width, and height properties set to 0. + * @return {Rectangle} A Rectangle object that equals the area of intersection. If the Rectangles do not intersect, this method returns an empty Rectangle object; that is, a Rectangle with its x, y, width, and height properties set to 0. **/ static intersection(a: Rectangle, b: Rectangle, out?: Rectangle = new Rectangle): Rectangle { @@ -194,12 +194,12 @@ module Phaser { } /** - * Adds two rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two rectangles. + * Adds two Rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two Rectangles. * @method union * @param {Rectangle} a - The first Rectangle object. * @param {Rectangle} b - The second Rectangle object. * @param {Rectangle} output Optional Rectangle object. If given the new values will be set into this object, otherwise a brand new Rectangle object will be created and returned. - * @return {Rectangle} A Rectangle object that is the union of the two rectangles. + * @return {Rectangle} A Rectangle object that is the union of the two Rectangles. **/ static union(a: Rectangle, b: Rectangle, out?: Rectangle = new Rectangle): Rectangle { return out.setTo(Math.min(a.x, b.x), Math.min(a.y, b.y), Math.max(a.right, b.right), Math.max(a.bottom, b.bottom)); diff --git a/Phaser/utils/SpriteUtils.ts b/Phaser/utils/SpriteUtils.ts index 4b9253e0..f3bd461d 100644 --- a/Phaser/utils/SpriteUtils.ts +++ b/Phaser/utils/SpriteUtils.ts @@ -18,24 +18,24 @@ module Phaser { static _tempPoint: Point; /** - * Check whether this object is visible in a specific camera rectangle. - * @param camera {Rectangle} The rectangle you want to check. - * @return {boolean} Return true if bounds of this sprite intersects the given rectangle, otherwise return false. + * Check whether this object is visible in a specific camera Rectangle. + * @param camera {Rectangle} The Rectangle you want to check. + * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. */ static inCamera(camera: Camera, sprite: Sprite): bool { // Object fixed in place regardless of the camera scrolling? Then it's always visible - if (sprite.scrollFactor.x == 0 && sprite.scrollFactor.y == 0) + if (sprite.transform.scrollFactor.x == 0 && sprite.transform.scrollFactor.y == 0) { return true; } - var dx = sprite.frameBounds.x - (camera.worldView.x * sprite.scrollFactor.x); - var dy = sprite.frameBounds.y - (camera.worldView.y * sprite.scrollFactor.y); - var dw = sprite.frameBounds.width * sprite.scale.x; - var dh = sprite.frameBounds.height * sprite.scale.y; + var dx = sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + var dy = sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + var dw = sprite.width * sprite.transform.scale.x; + var dh = sprite.height * sprite.transform.scale.y; - return (camera.scaledX + camera.worldView.width > this._dx) && (camera.scaledX < this._dx + this._dw) && (camera.scaledY + camera.worldView.height > this._dy) && (camera.scaledY < this._dy + this._dh); + return (camera.screenView.x + camera.worldView.width > this._dx) && (camera.screenView.x < this._dx + this._dw) && (camera.screenView.y + camera.worldView.height > this._dy) && (camera.screenView.y < this._dy + this._dh); } @@ -158,8 +158,8 @@ module Phaser { var objectScreenPos: Point = objectOrGroup.getScreenXY(null, Camera); - this._point.x = X - camera.scroll.x * this.scrollFactor.x; //copied from getScreenXY() - this._point.y = Y - camera.scroll.y * this.scrollFactor.y; + this._point.x = X - camera.scroll.x * this.transform.scrollFactor.x; //copied from getScreenXY() + this._point.y = Y - camera.scroll.y * this.transform.scrollFactor.y; this._point.x += (this._point.x > 0) ? 0.0000001 : -0.0000001; this._point.y += (this._point.y > 0) ? 0.0000001 : -0.0000001; @@ -239,8 +239,8 @@ module Phaser { camera = this._game.camera; } - point.x = sprite.x - camera.scroll.x * sprite.scrollFactor.x; - point.y = sprite.y - camera.scroll.y * sprite.scrollFactor.y; + point.x = sprite.x - camera.x * sprite.transform.scrollFactor.x; + point.y = sprite.y - camera.y * sprite.transform.scrollFactor.y; point.x += (point.x > 0) ? 0.0000001 : -0.0000001; point.y += (point.y > 0) ? 0.0000001 : -0.0000001; @@ -287,11 +287,11 @@ module Phaser { if (fromFrameBounds) { - sprite.origin.setTo(sprite.frameBounds.halfWidth, sprite.frameBounds.halfHeight); + sprite.transform.origin.setTo(sprite.width / 2, sprite.height / 2); } else if (fromBody) { - sprite.origin.setTo(sprite.body.bounds.halfWidth, sprite.body.bounds.halfHeight); + sprite.transform.origin.setTo(sprite.body.bounds.halfWidth, sprite.body.bounds.halfHeight); } } diff --git a/README.md b/README.md index 8e8d0068..d6b9efea 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,6 @@ TODO: * Dispatch world resize event * Investigate why tweens don't restart after the game pauses * Fix bug in Tween yoyo + loop combo -* Copy the setTransform from Sprite to Camera -* Move Camera.scroll.x to just Camera.x/y * Apply Sprite scaling to Body.bounds * When you modify the sprite x/y directly the body position doesn't update, which leads to weird results. Need to work out who controls who. * Check that tween pausing works with the new performance.now @@ -40,13 +38,15 @@ TODO: * Input CSS cursor those little 4-way arrows on drag? * Stage CSS3 transforms!!! Color tints, sepia, greyscale, all of those cool things :) * Cameras should have option to be input disabled + Pointers should check which camera they are over before doing Sprite selection -* Can Cameras be positioned within the world? * Added JSON Texture Atlas object support. -* Bug in AnimationManager set frame/frameName - the width/height are trimmed and wrong * RenderOrderID won't work across cameras - but then neither do Pointers yet anyway * Swap to using time based motion (like the tweens) rather than delta timer - it just doesn't work well on slow phones * Bug in World drag +* Add clip support + shape options to Texture Component. + + + V1.0.0 * Massive refactoring across the entire codebase. @@ -91,7 +91,18 @@ V1.0.0 * Vastly improved orientation detection and response speed. * Added custom callback support for all Touch and Mouse Events so you can easily hook events to custom APIs. * Updated Game.loader and its methods. You now load images by: game.load.image() and also: game.load.atlas, game.load.audio, game.load.spritesheet, game.load.text. And you start it with game.load.start(). - +* Added optional frame parameter to Phaser.Sprite (and game.add.sprite) so you can set a frame ID or frame name on construction. +* Fixed bug where passing a texture atlas string would incorrectly skip the frames array. +* Added AnimationManager.autoUpdateBounds to control if a new frame should change the physics bounds of a sprite body or not. +* Added StageScaleMode.pageAlignHorizontally and pageAlignVertically booleans. When on Phaser will set the margin-left and top of the canvas element so that it is positioned in the middle of the page (based on window.innerWidth). +* Added support for globalCompositeOperation, opaque and backgroundColor to the Sprite.Texture and Camera.Texture components. +* Added ability for a Camera to skew and rotate around an origin. +* Moved the Camera rendering into CanvasRenderer to keep things consistent. +* Added Stage.setImageRenderingCrisp to quickly set the canvas image-rendering to crisp-edges (note: poor browser support atm) +* Sprite.width / height now report the scaled width height, setting them adjusts the scale as it does so. +* Created a Transform component containing scale, skew, rotation, scrollFactor, origin and rotationOffset. Added to Sprite, Camera, Group. +* Created a Texture component containing image data, alpha, flippedX, flippedY, etc. Added to Sprite, Camera, Group. +* Added CameraManager.swap and CameraManager.sort methods and added a z-index property to Camera to control render order. @@ -169,7 +180,7 @@ V0.9.6 * Added Point.rotate to allow you to rotate a point around another point, with optional distance clamping. Also created test cases. * Added Group.alpha to apply a globalAlpha before the groups children are rendered. Useful to save on alpha calls. * Added Group.globalCompositeOperation to apply a composite operation before all of the groups children are rendered. -* Added Camera black list support to Group along with Group.showToCamera, Group.hideFromCamera and Group.clearCameraList +* Added Camera black list support to Sprite and Group along with Camera.show, Camera.hide and Camera.isHidden methods to populate them. * Added GameMath.rotatePoint to allow for point rotation at any angle around a given anchor and distance * Updated World.setSize() to optionally update the VerletManager dimensions as well * Added GameObject.setPosition(x, y) diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 780c76f3..f5e72a6e 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -69,34 +69,6 @@ - - - ballmover.ts - - - - - colorwhirl.ts - - - - - fruitfall.ts - - - fujiboink.ts - - - - metalslug.ts - - - scroller1.ts - - - - starray.ts - create group 1.ts @@ -201,6 +173,14 @@ skewed scroller.ts + + + atlas 1.ts + + + + atlas 2.ts + tween loop 1.ts @@ -262,6 +242,8 @@ boot screen.ts - + + + \ No newline at end of file diff --git a/Tests/assets/sprites/invaderpig.json b/Tests/assets/sprites/invaderpig.json new file mode 100644 index 00000000..e7e6582f --- /dev/null +++ b/Tests/assets/sprites/invaderpig.json @@ -0,0 +1,28 @@ +{"frames": [ + +{ + "filename": "invader1", + "frame": {"x":0,"y":0,"w":128,"h":104}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":36,"y":73,"w":128,"h":104}, + "sourceSize": {"w":200,"h":250} +}, +{ + "filename": "tennyson", + "frame": {"x":128,"y":0,"w":120,"h":104}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":24,"w":120,"h":104}, + "sourceSize": {"w":120,"h":128} +}], +"meta": { + "app": "http://www.texturepacker.com", + "version": "1.0", + "image": "invaderpig.png", + "format": "RGBA8888", + "size": {"w":248,"h":104}, + "scale": "1", + "smartupdate": "$TexturePacker:SmartUpdate:aaccbd2de0ca8112964651683164d103$" +} +} diff --git a/Tests/assets/sprites/invaderpig.png b/Tests/assets/sprites/invaderpig.png new file mode 100644 index 0000000000000000000000000000000000000000..b22dcbc296d96dccb1d8208eb812b8d0a0c1c9de GIT binary patch literal 1956 zcmYLKeK^x=AOAU>Vz+}HKJzt{c8{e8K=pU>z1{j{%#t~OK~ z003R2r`s9O%Rr0P(ggSECI?T@eVgclJgWt+6s=3Q!1MNa&vS_YpkuIU8bDsbJ^+B6 zM7lYjP38&;{h~uqyECFNCAapJY3*`mKs(=Z0|TBteF6)LP1A`T%jzq2$-i4ZTWaG~ z|0q154(m0h-QwvM4RwAR8))e^cH!qym5%mp?%{pk?7Dxru;la%+^E=Tn4 z{Llbtk^i{sdIv%1U`MS-;y>K;TfY{gn2c8Tz5bL^JF+`z1M)gb+`J=aO;z2i;nd}l zx^3qya5}r{i}K~jhkF>&6s0>xpZd$kh7;^-27Xx;n1XHZ@(U&5VrIp*t3kx^7^*Q0 z4IQYY;8PeY_pe-CTdmf-91nbB3~0pz(K~e=lgLy3?Sj~#`aSHu1(I2(usc2cI$<2G z4HJ<+7Kh^*+c=pU&O4n=7~X1_PtOjd!@CF83K#G?bb`~m`MC5VP_s zY?wUkTIjEkPFB0pugj(~=*n7_)H-b&prHqRdkm08$6IAN98spx4Pg@OaA79bx!G2A zzhq^BE3$|+@mJ=|jovdt!5c&DfEPRToKnAD)Ma#vT@nxFoov87?X$-@R?`y7%9~cX zxr-Z(2K@x>%$_w@Wtfc(5u2&F?b1Hi>pn!vPipp#8rR_0#H7jB*3y-CU*^-5i!0AH z!g=aBQwM#@djnqQa?f$#W9eoNFw={=$=T4nE2Fa30c(BMOQQ6}*;oQRR0H zv$0)O50!iNg)}{Pp+0p$unUT=CjMPKf|5>-%zJ-=NFA0L^iL_x z#oWm%%30RTa}jnzeK*dwf}_%psOzyw2pfl`AppZjyaK*L>W-o9wg-uH+{=UiiP^=<@SR=H0{eCVur44C)hK@V;W#BAl$$}`|GEFFBTuRv4oe~ z!v@~gw0jQ1u85dYI3fEZ)gEEI1>~dN@une6USo|-G7FAl)k+fmNJUYmiq_BJCCH?Twuo%`b=WX= zq0b_avXU}Bv&_*6)4YyoP@8u}q1Z{}W7fxj>?Ht1f>XH+LHvAh(8w$6CwMb%@JQHT zo^1(HsilgNR~@~e`IR?X@u`tM{I~IVi!Yf1c3PZl{T4dHhZA3K!x*nx{ihYSgYXZ0 z$8%9I=|e{qsYoKz)BEzQqxr$2(CkBi$PSShz{(J2FbOWwF7zVJ3?sU@#b&cWuR#lJ z#X2UKDB&1EX3oG%Li*ztZbla3i5*L~6n!gqlcp>lj`Zr$e2o*ioO97e$7c2F($5W5=va!UNZqPS&uSw{FJ&pO$WbK;kQ?fw`X((MA&l~-Mka4E38DqIH4p?w0C|3wgnY}6NaD^=5WHRWLj18zYV|2A_$%0YtU)> z<2~pnmi~)uCX$W7x4JG@p_5oNX^~biJ8q%b$fQ!umOT88i7PY%`SJe@zvve2%^MvJ zvG`*{q@7jd?Vt~XyVDi97K70D|7tj^h+t&pihRPU=QX$9AQT$nj%n3CwU;7jmfv<_ zPBhv``fBSih#H=#(1it$V^Q>B!;2h{%2W_-VORziddkCE&fg39B2_OD{4o@*te*@?lXd12x=|&WKWH u-YmaiXk6@UXiOb6m<4pTt&cgSiLKfOs44g!lp*-d0!VjXH>S&l-~I$rJkFv3 literal 0 HcmV?d00001 diff --git a/Tests/cameras/basic camera 1.js b/Tests/cameras/basic camera 1.js index 3a601655..6bdbd0f1 100644 --- a/Tests/cameras/basic camera 1.js +++ b/Tests/cameras/basic camera 1.js @@ -15,14 +15,14 @@ } function update() { if(game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { - game.camera.scroll.x -= 4; + game.camera.x -= 4; } else if(game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { - game.camera.scroll.x += 4; + game.camera.x += 4; } if(game.input.keyboard.isDown(Phaser.Keyboard.UP)) { - game.camera.scroll.y -= 4; + game.camera.y -= 4; } else if(game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { - game.camera.scroll.y += 4; + game.camera.y += 4; } } function render() { diff --git a/Tests/cameras/basic camera 1.ts b/Tests/cameras/basic camera 1.ts index b5b3f22d..2d908496 100644 --- a/Tests/cameras/basic camera 1.ts +++ b/Tests/cameras/basic camera 1.ts @@ -30,20 +30,20 @@ if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { - game.camera.scroll.x -= 4; + game.camera.x -= 4; } else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { - game.camera.scroll.x += 4; + game.camera.x += 4; } if (game.input.keyboard.isDown(Phaser.Keyboard.UP)) { - game.camera.scroll.y -= 4; + game.camera.y -= 4; } else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { - game.camera.scroll.y += 4; + game.camera.y += 4; } } diff --git a/Tests/cameras/scrollfactor 1.js b/Tests/cameras/scrollfactor 1.js index 5f7cd17a..73dd64a2 100644 --- a/Tests/cameras/scrollfactor 1.js +++ b/Tests/cameras/scrollfactor 1.js @@ -11,19 +11,19 @@ game.add.sprite(0, 0, 'backdrop'); for(var i = 0; i < 400; i++) { var tempBall = game.add.sprite(game.world.randomX * 2, game.world.randomY * 2, 'ball'); - tempBall.scrollFactor.setTo(2, 2); + tempBall.transform.scrollFactor.setTo(2, 2); } } function update() { if(game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { - game.camera.scroll.x -= 4; + game.camera.x -= 4; } else if(game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { - game.camera.scroll.x += 4; + game.camera.x += 4; } if(game.input.keyboard.isDown(Phaser.Keyboard.UP)) { - game.camera.scroll.y -= 4; + game.camera.y -= 4; } else if(game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { - game.camera.scroll.y += 4; + game.camera.y += 4; } } function render() { diff --git a/Tests/cameras/scrollfactor 1.ts b/Tests/cameras/scrollfactor 1.ts index 4125ff45..edb1771f 100644 --- a/Tests/cameras/scrollfactor 1.ts +++ b/Tests/cameras/scrollfactor 1.ts @@ -22,7 +22,7 @@ for (var i = 0; i < 400; i++) { var tempBall:Phaser.Sprite = game.add.sprite(game.world.randomX * 2, game.world.randomY * 2, 'ball'); - tempBall.scrollFactor.setTo(2, 2); + tempBall.transform.scrollFactor.setTo(2, 2); } } @@ -31,20 +31,20 @@ if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { - game.camera.scroll.x -= 4; + game.camera.x -= 4; } else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { - game.camera.scroll.x += 4; + game.camera.x += 4; } if (game.input.keyboard.isDown(Phaser.Keyboard.UP)) { - game.camera.scroll.y -= 4; + game.camera.y -= 4; } else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { - game.camera.scroll.y += 4; + game.camera.y += 4; } } diff --git a/Tests/cameras/scrollfactor 2.js b/Tests/cameras/scrollfactor 2.js index dedbfeac..36930136 100644 --- a/Tests/cameras/scrollfactor 2.js +++ b/Tests/cameras/scrollfactor 2.js @@ -9,19 +9,19 @@ function create() { for(var i = 0; i < 10; i++) { var temp = game.add.sprite(600 + (10 * i), 200 + (10 * i), 'disk'); - temp.scrollFactor.setTo(i / 2, i / 2); + temp.transform.scrollFactor.setTo(i / 2, i / 2); } } function update() { if(game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { - game.camera.scroll.x -= 4; + game.camera.x -= 4; } else if(game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { - game.camera.scroll.x += 4; + game.camera.x += 4; } if(game.input.keyboard.isDown(Phaser.Keyboard.UP)) { - game.camera.scroll.y -= 4; + game.camera.y -= 4; } else if(game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { - game.camera.scroll.y += 4; + game.camera.y += 4; } } function render() { diff --git a/Tests/cameras/scrollfactor 2.ts b/Tests/cameras/scrollfactor 2.ts index f25abcdc..6a0ba486 100644 --- a/Tests/cameras/scrollfactor 2.ts +++ b/Tests/cameras/scrollfactor 2.ts @@ -19,7 +19,7 @@ for (var i = 0; i < 10; i++) { var temp:Phaser.Sprite = game.add.sprite(600 + (10 * i), 200 + (10 * i), 'disk'); - temp.scrollFactor.setTo(i / 2, i / 2); + temp.transform.scrollFactor.setTo(i / 2, i / 2); } } @@ -28,20 +28,20 @@ if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { - game.camera.scroll.x -= 4; + game.camera.x -= 4; } else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { - game.camera.scroll.x += 4; + game.camera.x += 4; } if (game.input.keyboard.isDown(Phaser.Keyboard.UP)) { - game.camera.scroll.y -= 4; + game.camera.y -= 4; } else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { - game.camera.scroll.y += 4; + game.camera.y += 4; } } diff --git a/Tests/input/drag sprite 1.js b/Tests/input/drag sprite 1.js index 934ef0a9..08624934 100644 --- a/Tests/input/drag sprite 1.js +++ b/Tests/input/drag sprite 1.js @@ -18,6 +18,7 @@ } function render() { game.input.renderDebugInfo(32, 32); + //game.input.mousePointer.renderDebug(32, 32); sprite.input.renderDebugInfo(300, 32); } })(); diff --git a/Tests/input/world drag.js b/Tests/input/world drag.js index 138d3588..685e7198 100644 --- a/Tests/input/world drag.js +++ b/Tests/input/world drag.js @@ -21,14 +21,14 @@ } function update() { if(game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { - game.camera.scroll.x -= 4; + game.camera.x -= 4; } else if(game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { - game.camera.scroll.x += 4; + game.camera.x += 4; } if(game.input.keyboard.isDown(Phaser.Keyboard.UP)) { - game.camera.scroll.y -= 4; + game.camera.y -= 4; } else if(game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { - game.camera.scroll.y += 4; + game.camera.y += 4; } } function render() { diff --git a/Tests/input/world drag.ts b/Tests/input/world drag.ts index 10d0ec2c..8cb78a8c 100644 --- a/Tests/input/world drag.ts +++ b/Tests/input/world drag.ts @@ -40,20 +40,20 @@ if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { - game.camera.scroll.x -= 4; + game.camera.x -= 4; } else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { - game.camera.scroll.x += 4; + game.camera.x += 4; } if (game.input.keyboard.isDown(Phaser.Keyboard.UP)) { - game.camera.scroll.y -= 4; + game.camera.y -= 4; } else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { - game.camera.scroll.y += 4; + game.camera.y += 4; } } diff --git a/Tests/particles/mousetrail.js b/Tests/particles/mousetrail.js index cf882a31..eb456d73 100644 --- a/Tests/particles/mousetrail.js +++ b/Tests/particles/mousetrail.js @@ -14,7 +14,7 @@ scroller.setSpeed(0, -1); emitter = game.add.emitter(game.stage.centerX, game.stage.centerY); emitter.makeParticles('jet', 200); - emitter.globalCompositeOperation = 'lighter'; + emitter.texture.globalCompositeOperation = 'lighter'; emitter.gravity = 300; emitter.setXSpeed(-50, 50); emitter.setYSpeed(-50, -100); diff --git a/Tests/particles/mousetrail.ts b/Tests/particles/mousetrail.ts index 3369ca86..52f7afdf 100644 --- a/Tests/particles/mousetrail.ts +++ b/Tests/particles/mousetrail.ts @@ -25,7 +25,7 @@ emitter = game.add.emitter(game.stage.centerX, game.stage.centerY); emitter.makeParticles('jet', 200); - emitter.globalCompositeOperation = 'lighter'; + emitter.texture.globalCompositeOperation = 'lighter'; emitter.gravity = 300; emitter.setXSpeed(-50, 50); diff --git a/Tests/phaser.js b/Tests/phaser.js index 92335948..4839d5cb 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -74,14 +74,14 @@ var Phaser; (function (Phaser) { var Rectangle = (function () { /** - * Creates a new Rectangle object with the top-left corner specified by the x and y parameters and with the specified width and height parameters. If you call this function without parameters, a rectangle with x, y, width, and height properties set to 0 is created. + * Creates a new Rectangle object with the top-left corner specified by the x and y parameters and with the specified width and height parameters. If you call this function without parameters, a Rectangle with x, y, width, and height properties set to 0 is created. * @class Rectangle * @constructor - * @param {Number} x The x coordinate of the top-left corner of the rectangle. - * @param {Number} y The y coordinate of the top-left corner of the rectangle. - * @param {Number} width The width of the rectangle in pixels. - * @param {Number} height The height of the rectangle in pixels. - * @return {Rectangle} This rectangle object + * @param {Number} x The x coordinate of the top-left corner of the Rectangle. + * @param {Number} y The y coordinate of the top-left corner of the Rectangle. + * @param {Number} width The width of the Rectangle in pixels. + * @param {Number} height The height of the Rectangle in pixels. + * @return {Rectangle} This Rectangle object **/ function Rectangle(x, y, width, height) { if (typeof x === "undefined") { x = 0; } @@ -95,7 +95,7 @@ var Phaser; } Object.defineProperty(Rectangle.prototype, "halfWidth", { get: /** - * Half of the width of the rectangle + * Half of the width of the Rectangle * @property halfWidth * @type Number **/ @@ -107,7 +107,7 @@ var Phaser; }); Object.defineProperty(Rectangle.prototype, "halfHeight", { get: /** - * Half of the height of the rectangle + * Half of the height of the Rectangle * @property halfHeight * @type Number **/ @@ -282,7 +282,7 @@ var Phaser; set: /** * Sets all of the Rectangle object's properties to 0. A Rectangle object is empty if its width or height is less than or equal to 0. * @method setEmpty - * @return {Rectangle} This rectangle object + * @return {Rectangle} This Rectangle object **/ function (value) { return this.setTo(0, 0, 0, 0); @@ -314,11 +314,11 @@ var Phaser; Rectangle.prototype.setTo = /** * Sets the members of Rectangle to the specified values. * @method setTo - * @param {Number} x The x coordinate of the top-left corner of the rectangle. - * @param {Number} y The y coordinate of the top-left corner of the rectangle. - * @param {Number} width The width of the rectangle in pixels. - * @param {Number} height The height of the rectangle in pixels. - * @return {Rectangle} This rectangle object + * @param {Number} x The x coordinate of the top-left corner of the Rectangle. + * @param {Number} y The y coordinate of the top-left corner of the Rectangle. + * @param {Number} width The width of the Rectangle in pixels. + * @param {Number} height The height of the Rectangle in pixels. + * @return {Rectangle} This Rectangle object **/ function (x, y, width, height) { this.x = x; @@ -1243,7 +1243,7 @@ var Phaser; Types.SCROLLZONE = 6; Types.GEOM_POINT = 0; Types.GEOM_CIRCLE = 1; - Types.GEOM_RECTANGLE = 2; + Types.GEOM_Rectangle = 2; Types.GEOM_LINE = 3; Types.GEOM_POLYGON = 4; Types.BODY_DISABLED = 0; @@ -1264,7 +1264,3364 @@ var Phaser; Phaser.Types = Types; })(Phaser || (Phaser = {})); /// +/// +/// +/** +* Phaser - RectangleUtils +* +* A collection of methods useful for manipulating and comparing Rectangle objects. +* +* TODO: Check docs + overlap + intersect + toPolygon? +*/ +var Phaser; +(function (Phaser) { + var RectangleUtils = (function () { + function RectangleUtils() { } + RectangleUtils.getTopLeftAsPoint = /** + * Get the location of the Rectangles top-left corner as a Point object. + * @method getTopLeftAsPoint + * @param {Rectangle} a - The Rectangle object. + * @param {Point} out - Optional Point to store the value in, if not supplied a new Point object will be created. + * @return {Point} The new Point object. + **/ + function getTopLeftAsPoint(a, out) { + if (typeof out === "undefined") { out = new Phaser.Point(); } + return out.setTo(a.x, a.y); + }; + RectangleUtils.getBottomRightAsPoint = /** + * Get the location of the Rectangles bottom-right corner as a Point object. + * @method getTopLeftAsPoint + * @param {Rectangle} a - The Rectangle object. + * @param {Point} out - Optional Point to store the value in, if not supplied a new Point object will be created. + * @return {Point} The new Point object. + **/ + function getBottomRightAsPoint(a, out) { + if (typeof out === "undefined") { out = new Phaser.Point(); } + return out.setTo(a.right, a.bottom); + }; + RectangleUtils.inflate = /** + * Increases the size of the Rectangle object by the specified amounts. The center point of the Rectangle object stays the same, and its size increases to the left and right by the dx value, and to the top and the bottom by the dy value. + * @method inflate + * @param {Rectangle} a - The Rectangle object. + * @param {Number} dx The amount to be added to the left side of the Rectangle. + * @param {Number} dy The amount to be added to the bottom side of the Rectangle. + * @return {Rectangle} This Rectangle object. + **/ + function inflate(a, dx, dy) { + a.x -= dx; + a.width += 2 * dx; + a.y -= dy; + a.height += 2 * dy; + return a; + }; + RectangleUtils.inflatePoint = /** + * Increases the size of the Rectangle object. This method is similar to the Rectangle.inflate() method except it takes a Point object as a parameter. + * @method inflatePoint + * @param {Rectangle} a - The Rectangle object. + * @param {Point} point The x property of this Point object is used to increase the horizontal dimension of the Rectangle object. The y property is used to increase the vertical dimension of the Rectangle object. + * @return {Rectangle} The Rectangle object. + **/ + function inflatePoint(a, point) { + return RectangleUtils.inflate(a, point.x, point.y); + }; + RectangleUtils.size = /** + * The size of the Rectangle object, expressed as a Point object with the values of the width and height properties. + * @method size + * @param {Rectangle} a - The Rectangle object. + * @param {Point} output Optional Point object. If given the values will be set into the object, otherwise a brand new Point object will be created and returned. + * @return {Point} The size of the Rectangle object + **/ + function size(a, output) { + if (typeof output === "undefined") { output = new Phaser.Point(); } + return output.setTo(a.width, a.height); + }; + RectangleUtils.clone = /** + * Returns a new Rectangle object with the same values for the x, y, width, and height properties as the original Rectangle object. + * @method clone + * @param {Rectangle} a - The Rectangle object. + * @param {Rectangle} output Optional Rectangle object. If given the values will be set into the object, otherwise a brand new Rectangle object will be created and returned. + * @return {Rectangle} + **/ + function clone(a, output) { + if (typeof output === "undefined") { output = new Phaser.Rectangle(); } + return output.setTo(a.x, a.y, a.width, a.height); + }; + RectangleUtils.contains = /** + * Determines whether the specified coordinates are contained within the region defined by this Rectangle object. + * @method contains + * @param {Rectangle} a - The Rectangle object. + * @param {Number} x The x coordinate of the point to test. + * @param {Number} y The y coordinate of the point to test. + * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. + **/ + function contains(a, x, y) { + return (x >= a.x && x <= a.right && y >= a.y && y <= a.bottom); + }; + RectangleUtils.containsPoint = /** + * Determines whether the specified point is contained within the rectangular region defined by this Rectangle object. This method is similar to the Rectangle.contains() method, except that it takes a Point object as a parameter. + * @method containsPoint + * @param {Rectangle} a - The Rectangle object. + * @param {Point} point The point object being checked. Can be Point or any object with .x and .y values. + * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. + **/ + function containsPoint(a, point) { + return RectangleUtils.contains(a, point.x, point.y); + }; + RectangleUtils.containsRect = /** + * Determines whether the first Rectangle object is fully contained within the second Rectangle object. + * A Rectangle object is said to contain another if the second Rectangle object falls entirely within the boundaries of the first. + * @method containsRect + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. + **/ + function containsRect(a, b) { + // If the given rect has a larger volume than this one then it can never contain it + if(a.volume > b.volume) { + return false; + } + return (a.x >= b.x && a.y >= b.y && a.right <= b.right && a.bottom <= b.bottom); + }; + RectangleUtils.equals = /** + * Determines whether the two Rectangles are equal. + * This method compares the x, y, width and height properties of each Rectangle. + * @method equals + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @return {Boolean} A value of true if the two Rectangles have exactly the same values for the x, y, width and height properties; otherwise false. + **/ + function equals(a, b) { + return (a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height); + }; + RectangleUtils.intersection = /** + * If the Rectangle object specified in the toIntersect parameter intersects with this Rectangle object, returns the area of intersection as a Rectangle object. If the Rectangles do not intersect, this method returns an empty Rectangle object with its properties set to 0. + * @method intersection + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @param {Rectangle} output Optional Rectangle object. If given the intersection values will be set into this object, otherwise a brand new Rectangle object will be created and returned. + * @return {Rectangle} A Rectangle object that equals the area of intersection. If the Rectangles do not intersect, this method returns an empty Rectangle object; that is, a Rectangle with its x, y, width, and height properties set to 0. + **/ + function intersection(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Rectangle(); } + if(RectangleUtils.intersects(a, b)) { + out.x = Math.max(a.x, b.x); + out.y = Math.max(a.y, b.y); + out.width = Math.min(a.right, b.right) - out.x; + out.height = Math.min(a.bottom, b.bottom) - out.y; + } + return out; + }; + RectangleUtils.intersects = /** + * Determines whether the two Rectangles intersect with each other. + * This method checks the x, y, width, and height properties of the Rectangles. + * @method intersects + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @param {Number} tolerance A tolerance value to allow for an intersection test with padding, default to 0 + * @return {Boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false. + **/ + function intersects(a, b, tolerance) { + if (typeof tolerance === "undefined") { tolerance = 0; } + return !(a.left > b.right + tolerance || a.right < b.left - tolerance || a.top > b.bottom + tolerance || a.bottom < b.top - tolerance); + }; + RectangleUtils.intersectsRaw = /** + * Determines whether the object specified intersects (overlaps) with the given values. + * @method intersectsRaw + * @param {Number} left + * @param {Number} right + * @param {Number} top + * @param {Number} bottomt + * @param {Number} tolerance A tolerance value to allow for an intersection test with padding, default to 0 + * @return {Boolean} A value of true if the specified object intersects with the Rectangle; otherwise false. + **/ + function intersectsRaw(a, left, right, top, bottom, tolerance) { + if (typeof tolerance === "undefined") { tolerance = 0; } + return !(left > a.right + tolerance || right < a.left - tolerance || top > a.bottom + tolerance || bottom < a.top - tolerance); + }; + RectangleUtils.union = /** + * Adds two Rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two Rectangles. + * @method union + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @param {Rectangle} output Optional Rectangle object. If given the new values will be set into this object, otherwise a brand new Rectangle object will be created and returned. + * @return {Rectangle} A Rectangle object that is the union of the two Rectangles. + **/ + function union(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Rectangle(); } + return out.setTo(Math.min(a.x, b.x), Math.min(a.y, b.y), Math.max(a.right, b.right), Math.max(a.bottom, b.bottom)); + }; + return RectangleUtils; + })(); + Phaser.RectangleUtils = RectangleUtils; +})(Phaser || (Phaser = {})); +/// +/// +/// +/// +/** +* Phaser - ColorUtils +* +* A collection of methods useful for manipulating color values. +*/ +var Phaser; +(function (Phaser) { + var ColorUtils = (function () { + function ColorUtils() { } + ColorUtils.getColor32 = /** + * Given an alpha and 3 color values this will return an integer representation of it + * + * @param alpha {number} The Alpha value (between 0 and 255) + * @param red {number} The Red channel value (between 0 and 255) + * @param green {number} The Green channel value (between 0 and 255) + * @param blue {number} The Blue channel value (between 0 and 255) + * + * @return A native color value integer (format: 0xAARRGGBB) + */ + function getColor32(alpha, red, green, blue) { + return alpha << 24 | red << 16 | green << 8 | blue; + }; + ColorUtils.getColor = /** + * Given 3 color values this will return an integer representation of it + * + * @param red {number} The Red channel value (between 0 and 255) + * @param green {number} The Green channel value (between 0 and 255) + * @param blue {number} The Blue channel value (between 0 and 255) + * + * @return A native color value integer (format: 0xRRGGBB) + */ + function getColor(red, green, blue) { + return red << 16 | green << 8 | blue; + }; + ColorUtils.getHSVColorWheel = /** + * Get HSV color wheel values in an array which will be 360 elements in size + * + * @param alpha Alpha value for each color of the color wheel, between 0 (transparent) and 255 (opaque) + * + * @return Array + */ + function getHSVColorWheel(alpha) { + if (typeof alpha === "undefined") { alpha = 255; } + var colors = []; + for(var c = 0; c <= 359; c++) { + //colors[c] = HSVtoRGB(c, 1.0, 1.0, alpha); + colors[c] = ColorUtils.getWebRGB(ColorUtils.HSVtoRGB(c, 1.0, 1.0, alpha)); + } + return colors; + }; + ColorUtils.getComplementHarmony = /** + * Returns a Complementary Color Harmony for the given color. + *

A complementary hue is one directly opposite the color given on the color wheel

+ *

Value returned in 0xAARRGGBB format with Alpha set to 255.

+ * + * @param color The color to base the harmony on + * + * @return 0xAARRGGBB format color value + */ + function getComplementHarmony(color) { + var hsv = ColorUtils.RGBtoHSV(color); + var opposite = ColorUtils.game.math.wrapValue(hsv.hue, 180, 359); + return ColorUtils.HSVtoRGB(opposite, 1.0, 1.0); + }; + ColorUtils.getAnalogousHarmony = /** + * Returns an Analogous Color Harmony for the given color. + *

An Analogous harmony are hues adjacent to each other on the color wheel

+ *

Values returned in 0xAARRGGBB format with Alpha set to 255.

+ * + * @param color The color to base the harmony on + * @param threshold Control how adjacent the colors will be (default +- 30 degrees) + * + * @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color) + */ + function getAnalogousHarmony(color, threshold) { + if (typeof threshold === "undefined") { threshold = 30; } + var hsv = ColorUtils.RGBtoHSV(color); + if(threshold > 359 || threshold < 0) { + throw Error("Color Warning: Invalid threshold given to getAnalogousHarmony()"); + } + var warmer = ColorUtils.game.math.wrapValue(hsv.hue, 359 - threshold, 359); + var colder = ColorUtils.game.math.wrapValue(hsv.hue, threshold, 359); + return { + color1: color, + color2: ColorUtils.HSVtoRGB(warmer, 1.0, 1.0), + color3: ColorUtils.HSVtoRGB(colder, 1.0, 1.0), + hue1: hsv.hue, + hue2: warmer, + hue3: colder + }; + }; + ColorUtils.getSplitComplementHarmony = /** + * Returns an Split Complement Color Harmony for the given color. + *

A Split Complement harmony are the two hues on either side of the color's Complement

+ *

Values returned in 0xAARRGGBB format with Alpha set to 255.

+ * + * @param color The color to base the harmony on + * @param threshold Control how adjacent the colors will be to the Complement (default +- 30 degrees) + * + * @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color) + */ + function getSplitComplementHarmony(color, threshold) { + if (typeof threshold === "undefined") { threshold = 30; } + var hsv = ColorUtils.RGBtoHSV(color); + if(threshold >= 359 || threshold <= 0) { + throw Error("FlxColor Warning: Invalid threshold given to getSplitComplementHarmony()"); + } + var opposite = ColorUtils.game.math.wrapValue(hsv.hue, 180, 359); + var warmer = ColorUtils.game.math.wrapValue(hsv.hue, opposite - threshold, 359); + var colder = ColorUtils.game.math.wrapValue(hsv.hue, opposite + threshold, 359); + return { + color1: color, + color2: ColorUtils.HSVtoRGB(warmer, hsv.saturation, hsv.value), + color3: ColorUtils.HSVtoRGB(colder, hsv.saturation, hsv.value), + hue1: hsv.hue, + hue2: warmer, + hue3: colder + }; + }; + ColorUtils.getTriadicHarmony = /** + * Returns a Triadic Color Harmony for the given color. + *

A Triadic harmony are 3 hues equidistant from each other on the color wheel

+ *

Values returned in 0xAARRGGBB format with Alpha set to 255.

+ * + * @param color The color to base the harmony on + * + * @return Object containing 3 properties: color1 (the original color), color2 and color3 (the equidistant colors) + */ + function getTriadicHarmony(color) { + var hsv = ColorUtils.RGBtoHSV(color); + var triadic1 = ColorUtils.game.math.wrapValue(hsv.hue, 120, 359); + var triadic2 = ColorUtils.game.math.wrapValue(triadic1, 120, 359); + return { + color1: color, + color2: ColorUtils.HSVtoRGB(triadic1, 1.0, 1.0), + color3: ColorUtils.HSVtoRGB(triadic2, 1.0, 1.0) + }; + }; + ColorUtils.getColorInfo = /** + * Returns a string containing handy information about the given color including string hex value, + * RGB format information and HSL information. Each section starts on a newline, 3 lines in total. + * + * @param color A color value in the format 0xAARRGGBB + * + * @return string containing the 3 lines of information + */ + function getColorInfo(color) { + var argb = ColorUtils.getRGB(color); + var hsl = ColorUtils.RGBtoHSV(color); + // Hex format + var result = ColorUtils.RGBtoHexstring(color) + "\n"; + // RGB format + result = result.concat("Alpha: " + argb.alpha + " Red: " + argb.red + " Green: " + argb.green + " Blue: " + argb.blue) + "\n"; + // HSL info + result = result.concat("Hue: " + hsl.hue + " Saturation: " + hsl.saturation + " Lightnes: " + hsl.lightness); + return result; + }; + ColorUtils.RGBtoHexstring = /** + * Return a string representation of the color in the format 0xAARRGGBB + * + * @param color The color to get the string representation for + * + * @return A string of length 10 characters in the format 0xAARRGGBB + */ + function RGBtoHexstring(color) { + var argb = ColorUtils.getRGB(color); + return "0x" + ColorUtils.colorToHexstring(argb.alpha) + ColorUtils.colorToHexstring(argb.red) + ColorUtils.colorToHexstring(argb.green) + ColorUtils.colorToHexstring(argb.blue); + }; + ColorUtils.RGBtoWebstring = /** + * Return a string representation of the color in the format #RRGGBB + * + * @param color The color to get the string representation for + * + * @return A string of length 10 characters in the format 0xAARRGGBB + */ + function RGBtoWebstring(color) { + var argb = ColorUtils.getRGB(color); + return "#" + ColorUtils.colorToHexstring(argb.red) + ColorUtils.colorToHexstring(argb.green) + ColorUtils.colorToHexstring(argb.blue); + }; + ColorUtils.colorToHexstring = /** + * Return a string containing a hex representation of the given color + * + * @param color The color channel to get the hex value for, must be a value between 0 and 255) + * + * @return A string of length 2 characters, i.e. 255 = FF, 0 = 00 + */ + function colorToHexstring(color) { + var digits = "0123456789ABCDEF"; + var lsd = color % 16; + var msd = (color - lsd) / 16; + var hexified = digits.charAt(msd) + digits.charAt(lsd); + return hexified; + }; + ColorUtils.HSVtoRGB = /** + * Convert a HSV (hue, saturation, lightness) color space value to an RGB color + * + * @param h Hue degree, between 0 and 359 + * @param s Saturation, between 0.0 (grey) and 1.0 + * @param v Value, between 0.0 (black) and 1.0 + * @param alpha Alpha value to set per color (between 0 and 255) + * + * @return 32-bit ARGB color value (0xAARRGGBB) + */ + function HSVtoRGB(h, s, v, alpha) { + if (typeof alpha === "undefined") { alpha = 255; } + var result; + if(s == 0.0) { + result = ColorUtils.getColor32(alpha, v * 255, v * 255, v * 255); + } else { + h = h / 60.0; + var f = h - Math.floor(h); + var p = v * (1.0 - s); + var q = v * (1.0 - s * f); + var t = v * (1.0 - s * (1.0 - f)); + switch(Math.floor(h)) { + case 0: + result = ColorUtils.getColor32(alpha, v * 255, t * 255, p * 255); + break; + case 1: + result = ColorUtils.getColor32(alpha, q * 255, v * 255, p * 255); + break; + case 2: + result = ColorUtils.getColor32(alpha, p * 255, v * 255, t * 255); + break; + case 3: + result = ColorUtils.getColor32(alpha, p * 255, q * 255, v * 255); + break; + case 4: + result = ColorUtils.getColor32(alpha, t * 255, p * 255, v * 255); + break; + case 5: + result = ColorUtils.getColor32(alpha, v * 255, p * 255, q * 255); + break; + default: + throw new Error("ColorUtils.HSVtoRGB : Unknown color"); + } + } + return result; + }; + ColorUtils.RGBtoHSV = /** + * Convert an RGB color value to an object containing the HSV color space values: Hue, Saturation and Lightness + * + * @param color In format 0xRRGGBB + * + * @return Object with the properties hue (from 0 to 360), saturation (from 0 to 1.0) and lightness (from 0 to 1.0, also available under .value) + */ + function RGBtoHSV(color) { + var rgb = ColorUtils.getRGB(color); + var red = rgb.red / 255; + var green = rgb.green / 255; + var blue = rgb.blue / 255; + var min = Math.min(red, green, blue); + var max = Math.max(red, green, blue); + var delta = max - min; + var lightness = (max + min) / 2; + var hue; + var saturation; + // Grey color, no chroma + if(delta == 0) { + hue = 0; + saturation = 0; + } else { + if(lightness < 0.5) { + saturation = delta / (max + min); + } else { + saturation = delta / (2 - max - min); + } + var delta_r = (((max - red) / 6) + (delta / 2)) / delta; + var delta_g = (((max - green) / 6) + (delta / 2)) / delta; + var delta_b = (((max - blue) / 6) + (delta / 2)) / delta; + if(red == max) { + hue = delta_b - delta_g; + } else if(green == max) { + hue = (1 / 3) + delta_r - delta_b; + } else if(blue == max) { + hue = (2 / 3) + delta_g - delta_r; + } + if(hue < 0) { + hue += 1; + } + if(hue > 1) { + hue -= 1; + } + } + // Keep the value with 0 to 359 + hue *= 360; + hue = Math.round(hue); + return { + hue: hue, + saturation: saturation, + lightness: lightness, + value: lightness + }; + }; + ColorUtils.interpolateColor = /** + * + * @method interpolateColor + * @param {Number} color1 + * @param {Number} color2 + * @param {Number} steps + * @param {Number} currentStep + * @param {Number} alpha + * @return {Number} + * @static + */ + function interpolateColor(color1, color2, steps, currentStep, alpha) { + if (typeof alpha === "undefined") { alpha = 255; } + var src1 = ColorUtils.getRGB(color1); + var src2 = ColorUtils.getRGB(color2); + var r = (((src2.red - src1.red) * currentStep) / steps) + src1.red; + var g = (((src2.green - src1.green) * currentStep) / steps) + src1.green; + var b = (((src2.blue - src1.blue) * currentStep) / steps) + src1.blue; + return ColorUtils.getColor32(alpha, r, g, b); + }; + ColorUtils.interpolateColorWithRGB = /** + * + * @method interpolateColorWithRGB + * @param {Number} color + * @param {Number} r2 + * @param {Number} g2 + * @param {Number} b2 + * @param {Number} steps + * @param {Number} currentStep + * @return {Number} + * @static + */ + function interpolateColorWithRGB(color, r2, g2, b2, steps, currentStep) { + var src = ColorUtils.getRGB(color); + var r = (((r2 - src.red) * currentStep) / steps) + src.red; + var g = (((g2 - src.green) * currentStep) / steps) + src.green; + var b = (((b2 - src.blue) * currentStep) / steps) + src.blue; + return ColorUtils.getColor(r, g, b); + }; + ColorUtils.interpolateRGB = /** + * + * @method interpolateRGB + * @param {Number} r1 + * @param {Number} g1 + * @param {Number} b1 + * @param {Number} r2 + * @param {Number} g2 + * @param {Number} b2 + * @param {Number} steps + * @param {Number} currentStep + * @return {Number} + * @static + */ + function interpolateRGB(r1, g1, b1, r2, g2, b2, steps, currentStep) { + var r = (((r2 - r1) * currentStep) / steps) + r1; + var g = (((g2 - g1) * currentStep) / steps) + g1; + var b = (((b2 - b1) * currentStep) / steps) + b1; + return ColorUtils.getColor(r, g, b); + }; + ColorUtils.getRandomColor = /** + * Returns a random color value between black and white + *

Set the min value to start each channel from the given offset.

+ *

Set the max value to restrict the maximum color used per channel

+ * + * @param min The lowest value to use for the color + * @param max The highest value to use for the color + * @param alpha The alpha value of the returning color (default 255 = fully opaque) + * + * @return 32-bit color value with alpha + */ + function getRandomColor(min, max, alpha) { + if (typeof min === "undefined") { min = 0; } + if (typeof max === "undefined") { max = 255; } + if (typeof alpha === "undefined") { alpha = 255; } + // Sanity checks + if(max > 255) { + return ColorUtils.getColor(255, 255, 255); + } + if(min > max) { + return ColorUtils.getColor(255, 255, 255); + } + var red = min + Math.round(Math.random() * (max - min)); + var green = min + Math.round(Math.random() * (max - min)); + var blue = min + Math.round(Math.random() * (max - min)); + return ColorUtils.getColor32(alpha, red, green, blue); + }; + ColorUtils.getRGB = /** + * Return the component parts of a color as an Object with the properties alpha, red, green, blue + * + *

Alpha will only be set if it exist in the given color (0xAARRGGBB)

+ * + * @param color in RGB (0xRRGGBB) or ARGB format (0xAARRGGBB) + * + * @return Object with properties: alpha, red, green, blue + */ + function getRGB(color) { + return { + alpha: color >>> 24, + red: color >> 16 & 0xFF, + green: color >> 8 & 0xFF, + blue: color & 0xFF + }; + }; + ColorUtils.getWebRGB = /** + * + * @method getWebRGB + * @param {Number} color + * @return {Any} + */ + function getWebRGB(color) { + var alpha = (color >>> 24) / 255; + var red = color >> 16 & 0xFF; + var green = color >> 8 & 0xFF; + var blue = color & 0xFF; + return 'rgba(' + red.toString() + ',' + green.toString() + ',' + blue.toString() + ',' + alpha.toString() + ')'; + }; + ColorUtils.getAlpha = /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component, as a value between 0 and 255 + * + * @param color In the format 0xAARRGGBB + * + * @return The Alpha component of the color, will be between 0 and 255 (0 being no Alpha, 255 full Alpha) + */ + function getAlpha(color) { + return color >>> 24; + }; + ColorUtils.getAlphaFloat = /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component as a value between 0 and 1 + * + * @param color In the format 0xAARRGGBB + * + * @return The Alpha component of the color, will be between 0 and 1 (0 being no Alpha (opaque), 1 full Alpha (transparent)) + */ + function getAlphaFloat(color) { + return (color >>> 24) / 255; + }; + ColorUtils.getRed = /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Red component, as a value between 0 and 255 + * + * @param color In the format 0xAARRGGBB + * + * @return The Red component of the color, will be between 0 and 255 (0 being no color, 255 full Red) + */ + function getRed(color) { + return color >> 16 & 0xFF; + }; + ColorUtils.getGreen = /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Green component, as a value between 0 and 255 + * + * @param color In the format 0xAARRGGBB + * + * @return The Green component of the color, will be between 0 and 255 (0 being no color, 255 full Green) + */ + function getGreen(color) { + return color >> 8 & 0xFF; + }; + ColorUtils.getBlue = /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Blue component, as a value between 0 and 255 + * + * @param color In the format 0xAARRGGBB + * + * @return The Blue component of the color, will be between 0 and 255 (0 being no color, 255 full Blue) + */ + function getBlue(color) { + return color & 0xFF; + }; + return ColorUtils; + })(); + Phaser.ColorUtils = ColorUtils; +})(Phaser || (Phaser = {})); +/// +/// +/// +/// +/** +* Phaser - DynamicTexture +* +* A DynamicTexture can be thought of as a mini canvas into which you can draw anything. +* Game Objects can be assigned a DynamicTexture, so when they render in the world they do so +* based on the contents of the texture at the time. This allows you to create powerful effects +* once and have them replicated across as many game objects as you like. +*/ +var Phaser; +(function (Phaser) { + var DynamicTexture = (function () { + /** + * DynamicTexture constructor + * Create a new DynamicTexture. + * + * @param game {Phaser.Game} Current game instance. + * @param width {number} Init width of this texture. + * @param height {number} Init height of this texture. + */ + function DynamicTexture(game, width, height) { + this._sx = 0; + this._sy = 0; + this._sw = 0; + this._sh = 0; + this._dx = 0; + this._dy = 0; + this._dw = 0; + this._dh = 0; + this.game = game; + this.type = Phaser.Types.GEOMSPRITE; + this.canvas = document.createElement('canvas'); + this.canvas.width = width; + this.canvas.height = height; + this.context = this.canvas.getContext('2d'); + this.bounds = new Phaser.Rectangle(0, 0, width, height); + } + DynamicTexture.prototype.getPixel = /** + * Get a color of a specific pixel. + * @param x {number} X position of the pixel in this texture. + * @param y {number} Y position of the pixel in this texture. + * @return {number} A native color value integer (format: 0xRRGGBB) + */ + function (x, y) { + //r = imageData.data[0]; + //g = imageData.data[1]; + //b = imageData.data[2]; + //a = imageData.data[3]; + var imageData = this.context.getImageData(x, y, 1, 1); + return Phaser.ColorUtils.getColor(imageData.data[0], imageData.data[1], imageData.data[2]); + }; + DynamicTexture.prototype.getPixel32 = /** + * Get a color of a specific pixel (including alpha value). + * @param x {number} X position of the pixel in this texture. + * @param y {number} Y position of the pixel in this texture. + * @return A native color value integer (format: 0xAARRGGBB) + */ + function (x, y) { + var imageData = this.context.getImageData(x, y, 1, 1); + return Phaser.ColorUtils.getColor32(imageData.data[3], imageData.data[0], imageData.data[1], imageData.data[2]); + }; + DynamicTexture.prototype.getPixels = /** + * Get pixels in array in a specific Rectangle. + * @param rect {Rectangle} The specific Rectangle. + * @returns {array} CanvasPixelArray. + */ + function (rect) { + return this.context.getImageData(rect.x, rect.y, rect.width, rect.height); + }; + DynamicTexture.prototype.setPixel = /** + * Set color of a specific pixel. + * @param x {number} X position of the target pixel. + * @param y {number} Y position of the target pixel. + * @param color {number} Native integer with color value. (format: 0xRRGGBB) + */ + function (x, y, color) { + this.context.fillStyle = color; + this.context.fillRect(x, y, 1, 1); + }; + DynamicTexture.prototype.setPixel32 = /** + * Set color (with alpha) of a specific pixel. + * @param x {number} X position of the target pixel. + * @param y {number} Y position of the target pixel. + * @param color {number} Native integer with color value. (format: 0xAARRGGBB) + */ + function (x, y, color) { + this.context.fillStyle = color; + this.context.fillRect(x, y, 1, 1); + }; + DynamicTexture.prototype.setPixels = /** + * Set image data to a specific Rectangle. + * @param rect {Rectangle} Target Rectangle. + * @param input {object} Source image data. + */ + function (rect, input) { + this.context.putImageData(input, rect.x, rect.y); + }; + DynamicTexture.prototype.fillRect = /** + * Fill a given Rectangle with specific color. + * @param rect {Rectangle} Target Rectangle you want to fill. + * @param color {number} A native number with color value. (format: 0xRRGGBB) + */ + function (rect, color) { + this.context.fillStyle = color; + this.context.fillRect(rect.x, rect.y, rect.width, rect.height); + }; + DynamicTexture.prototype.pasteImage = /** + * + */ + function (key, frame, destX, destY, destWidth, destHeight) { + if (typeof frame === "undefined") { frame = -1; } + if (typeof destX === "undefined") { destX = 0; } + if (typeof destY === "undefined") { destY = 0; } + if (typeof destWidth === "undefined") { destWidth = null; } + if (typeof destHeight === "undefined") { destHeight = null; } + var texture = null; + var frameData; + this._sx = 0; + this._sy = 0; + this._dx = destX; + this._dy = destY; + // TODO - Load a frame from a sprite sheet, otherwise we'll draw the whole lot + if(frame > -1) { + //if (this.game.cache.isSpriteSheet(key)) + //{ + // texture = this.game.cache.getImage(key); + //this.animations.loadFrameData(this.game.cache.getFrameData(key)); + //} + } else { + texture = this.game.cache.getImage(key); + this._sw = texture.width; + this._sh = texture.height; + this._dw = texture.width; + this._dh = texture.height; + } + if(destWidth !== null) { + this._dw = destWidth; + } + if(destHeight !== null) { + this._dh = destHeight; + } + if(texture != null) { + this.context.drawImage(texture, // Source Image + this._sx, // Source X (location within the source image) + this._sy, // Source Y + this._sw, // Source Width + this._sh, // Source Height + this._dx, // Destination X (where on the canvas it'll be drawn) + this._dy, // Destination Y + this._dw, // Destination Width (always same as Source Width unless scaled) + this._dh); + // Destination Height (always same as Source Height unless scaled) + } + }; + DynamicTexture.prototype.copyPixels = // TODO - Add in support for: alphaBitmapData: BitmapData = null, alphaPoint: Point = null, mergeAlpha: bool = false + /** + * Copy pixel from another DynamicTexture to this texture. + * @param sourceTexture {DynamicTexture} Source texture object. + * @param sourceRect {Rectangle} The specific region Rectangle to be copied to this in the source. + * @param destPoint {Point} Top-left point the target image data will be paste at. + */ + function (sourceTexture, sourceRect, destPoint) { + // Swap for drawImage if the sourceRect is the same size as the sourceTexture to avoid a costly getImageData call + if(Phaser.RectangleUtils.equals(sourceRect, this.bounds) == true) { + this.context.drawImage(sourceTexture.canvas, destPoint.x, destPoint.y); + } else { + this.context.putImageData(sourceTexture.getPixels(sourceRect), destPoint.x, destPoint.y); + } + }; + DynamicTexture.prototype.assignCanvasToGameObjects = /** + * Given an array of Sprites it will update each of them so that their canvas/contexts reference this DynamicTexture + * @param objects {Array} An array of GameObjects, or objects that inherit from it such as Sprites + */ + function (objects) { + for(var i = 0; i < objects.length; i++) { + objects[i].texture.canvas = this.canvas; + objects[i].texture.context = this.context; + } + }; + DynamicTexture.prototype.clear = /** + * Clear the whole canvas. + */ + function () { + this.context.clearRect(0, 0, this.bounds.width, this.bounds.height); + }; + DynamicTexture.prototype.render = /** + * Renders this DynamicTexture to the Stage at the given x/y coordinates + * + * @param x {number} The X coordinate to render on the stage to (given in screen coordinates, not world) + * @param y {number} The Y coordinate to render on the stage to (given in screen coordinates, not world) + */ + function (x, y) { + if (typeof x === "undefined") { x = 0; } + if (typeof y === "undefined") { y = 0; } + this.game.stage.context.drawImage(this.canvas, x, y); + }; + Object.defineProperty(DynamicTexture.prototype, "width", { + get: function () { + return this.bounds.width; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(DynamicTexture.prototype, "height", { + get: function () { + return this.bounds.height; + }, + enumerable: true, + configurable: true + }); + return DynamicTexture; + })(); + Phaser.DynamicTexture = DynamicTexture; +})(Phaser || (Phaser = {})); +/// +/** +* Phaser - AnimationLoader +* +* Responsible for parsing sprite sheet and JSON data into the internal FrameData format that Phaser uses for animations. +*/ +var Phaser; +(function (Phaser) { + var AnimationLoader = (function () { + function AnimationLoader() { } + AnimationLoader.parseSpriteSheet = /** + * Parse a sprite sheet from asset data. + * @param key {string} Asset key for the sprite sheet data. + * @param frameWidth {number} Width of animation frame. + * @param frameHeight {number} Height of animation frame. + * @param frameMax {number} Number of animation frames. + * @return {FrameData} Generated FrameData object. + */ + function parseSpriteSheet(game, key, frameWidth, frameHeight, frameMax) { + // How big is our image? + var img = game.cache.getImage(key); + if(img == null) { + return null; + } + var width = img.width; + var height = img.height; + var row = Math.round(width / frameWidth); + var column = Math.round(height / frameHeight); + var total = row * column; + if(frameMax !== -1) { + total = frameMax; + } + // Zero or smaller than frame sizes? + if(width == 0 || height == 0 || width < frameWidth || height < frameHeight || total === 0) { + return null; + } + // Let's create some frames then + var data = new Phaser.FrameData(); + var x = 0; + var y = 0; + for(var i = 0; i < total; i++) { + data.addFrame(new Phaser.Frame(x, y, frameWidth, frameHeight, '')); + x += frameWidth; + if(x === width) { + x = 0; + y += frameHeight; + } + } + return data; + }; + AnimationLoader.parseJSONData = /** + * Parse frame datas from json. + * @param json {object} Json data you want to parse. + * @return {FrameData} Generated FrameData object. + */ + function parseJSONData(game, json) { + // Malformed? + if(!json['frames']) { + console.log(json); + throw new Error("Phaser.AnimationLoader.parseJSONData: Invalid Texture Atlas JSON given, missing 'frames' array"); + } + // Let's create some frames then + var data = new Phaser.FrameData(); + // By this stage frames is a fully parsed array + var frames = json['frames']; + var newFrame; + for(var i = 0; i < frames.length; i++) { + newFrame = data.addFrame(new Phaser.Frame(frames[i].frame.x, frames[i].frame.y, frames[i].frame.w, frames[i].frame.h, frames[i].filename)); + newFrame.setTrim(frames[i].trimmed, frames[i].sourceSize.w, frames[i].sourceSize.h, frames[i].spriteSourceSize.x, frames[i].spriteSourceSize.y, frames[i].spriteSourceSize.w, frames[i].spriteSourceSize.h); + } + return data; + }; + AnimationLoader.parseXMLData = function parseXMLData(game, xml, format) { + // Malformed? + if(!xml.getElementsByTagName('TextureAtlas')) { + throw new Error("Phaser.AnimationLoader.parseXMLData: Invalid Texture Atlas XML given, missing tag"); + } + // Let's create some frames then + var data = new Phaser.FrameData(); + var frames = xml.getElementsByTagName('SubTexture'); + var newFrame; + for(var i = 0; i < frames.length; i++) { + var frame = frames[i].attributes; + newFrame = data.addFrame(new Phaser.Frame(frame.x.nodeValue, frame.y.nodeValue, frame.width.nodeValue, frame.height.nodeValue, frame.name.nodeValue)); + // Trimmed? + if(frame.frameX.nodeValue != '-0' || frame.frameY.nodeValue != '-0') { + newFrame.setTrim(true, frame.width.nodeValue, frame.height.nodeValue, Math.abs(frame.frameX.nodeValue), Math.abs(frame.frameY.nodeValue), frame.frameWidth.nodeValue, frame.frameHeight.nodeValue); + } + } + return data; + }; + return AnimationLoader; + })(); + Phaser.AnimationLoader = AnimationLoader; +})(Phaser || (Phaser = {})); +/// +/** +* Phaser - Animation +* +* An Animation is a single animation. It is created by the AnimationManager and belongs to Sprite objects. +*/ +var Phaser; +(function (Phaser) { + var Animation = (function () { + /** + * Animation constructor + * Create a new Animation. + * + * @param parent {Sprite} Owner sprite of this animation. + * @param frameData {FrameData} The FrameData object contains animation data. + * @param name {string} Unique name of this animation. + * @param frames {number[]/string[]} An array of numbers or strings indicating what frames to play in what order. + * @param delay {number} Time between frames in ms. + * @param looped {boolean} Whether or not the animation is looped or just plays once. + */ + function Animation(game, parent, frameData, name, frames, delay, looped) { + this._game = game; + this._parent = parent; + this._frames = frames; + this._frameData = frameData; + this.name = name; + this.delay = 1000 / delay; + this.looped = looped; + this.isFinished = false; + this.isPlaying = false; + this._frameIndex = 0; + this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); + } + Object.defineProperty(Animation.prototype, "frameTotal", { + get: function () { + return this._frames.length; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Animation.prototype, "frame", { + get: function () { + if(this.currentFrame !== null) { + return this.currentFrame.index; + } else { + return this._frameIndex; + } + }, + set: function (value) { + this.currentFrame = this._frameData.getFrame(value); + if(this.currentFrame !== null) { + this._parent.texture.width = this.currentFrame.width; + this._parent.texture.height = this.currentFrame.height; + this._frameIndex = value; + } + }, + enumerable: true, + configurable: true + }); + Animation.prototype.play = /** + * Play this animation. + * @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 (frameRate, loop) { + if (typeof frameRate === "undefined") { frameRate = null; } + if(frameRate !== null) { + this.delay = 1000 / frameRate; + } + if(loop !== undefined) { + this.looped = loop; + } + this.isPlaying = true; + this.isFinished = false; + this._timeLastFrame = this._game.time.now; + this._timeNextFrame = this._game.time.now + this.delay; + this._frameIndex = 0; + this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); + }; + Animation.prototype.restart = /** + * Play this animation from the first frame. + */ + function () { + this.isPlaying = true; + this.isFinished = false; + this._timeLastFrame = this._game.time.now; + this._timeNextFrame = this._game.time.now + this.delay; + this._frameIndex = 0; + this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); + }; + Animation.prototype.stop = /** + * Stop playing animation and set it finished. + */ + function () { + this.isPlaying = false; + this.isFinished = true; + }; + Animation.prototype.update = /** + * Update animation frames. + */ + function () { + if(this.isPlaying == true && this._game.time.now >= this._timeNextFrame) { + this._frameIndex++; + if(this._frameIndex == this._frames.length) { + if(this.looped) { + this._frameIndex = 0; + this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); + } else { + this.onComplete(); + } + } else { + this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); + } + this._timeLastFrame = this._game.time.now; + this._timeNextFrame = this._game.time.now + this.delay; + return true; + } + return false; + }; + Animation.prototype.destroy = /** + * Clean up animation memory. + */ + function () { + this._game = null; + this._parent = null; + this._frames = null; + this._frameData = null; + this.currentFrame = null; + this.isPlaying = false; + }; + Animation.prototype.onComplete = /** + * Animation complete callback method. + */ + function () { + this.isPlaying = false; + this.isFinished = true; + // callback goes here + }; + return Animation; + })(); + Phaser.Animation = Animation; +})(Phaser || (Phaser = {})); +/// +/** +* Phaser - Frame +* +* A Frame is a single frame of an animation and is part of a FrameData collection. +*/ +var Phaser; +(function (Phaser) { + var Frame = (function () { + /** + * Frame constructor + * Create a new Frame with specific position, size and name. + * + * @param x {number} X position within the image to cut from. + * @param y {number} Y position within the image to cut from. + * @param width {number} Width of the frame. + * @param height {number} Height of the frame. + * @param name {string} Name of this frame. + */ + function Frame(x, y, width, height, name) { + /** + * Useful for Texture Atlas files. (is set to the filename value) + */ + this.name = ''; + /** + * Rotated? (not yet implemented) + */ + this.rotated = false; + /** + * Either cw or ccw, rotation is always 90 degrees. + */ + this.rotationDirection = 'cw'; + //console.log('Creating Frame', name, 'x', x, 'y', y, 'width', width, 'height', height); + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.name = name; + this.rotated = false; + this.trimmed = false; + } + Frame.prototype.setRotation = /** + * Set rotation of this frame. (Not yet supported!) + */ + function (rotated, rotationDirection) { + // Not yet supported + }; + Frame.prototype.setTrim = /** + * Set trim of the frame. + * @param trimmed {boolean} Whether this frame trimmed or not. + * @param actualWidth {number} Actual width of this frame. + * @param actualHeight {number} Actual height of this frame. + * @param destX {number} Destination x position. + * @param destY {number} Destination y position. + * @param destWidth {number} Destination draw width. + * @param destHeight {number} Destination draw height. + */ + function (trimmed, actualWidth, actualHeight, destX, destY, destWidth, destHeight) { + //console.log('setTrim', trimmed, 'aw', actualWidth, 'ah', actualHeight, 'dx', destX, 'dy', destY, 'dw', destWidth, 'dh', destHeight); + this.trimmed = trimmed; + if(trimmed) { + this.width = actualWidth; + this.height = actualHeight; + this.sourceSizeW = actualWidth; + this.sourceSizeH = actualHeight; + this.spriteSourceSizeX = destX; + this.spriteSourceSizeY = destY; + this.spriteSourceSizeW = destWidth; + this.spriteSourceSizeH = destHeight; + } + }; + return Frame; + })(); + Phaser.Frame = Frame; +})(Phaser || (Phaser = {})); +/// +/** +* Phaser - FrameData +* +* FrameData is a container for Frame objects, the internal representation of animation data in Phaser. +*/ +var Phaser; +(function (Phaser) { + var FrameData = (function () { + /** + * FrameData constructor + */ + function FrameData() { + this._frames = []; + this._frameNames = []; + } + Object.defineProperty(FrameData.prototype, "total", { + get: function () { + return this._frames.length; + }, + enumerable: true, + configurable: true + }); + FrameData.prototype.addFrame = /** + * Add a new frame. + * @param frame {Frame} The frame you want to add. + * @return {Frame} The frame you just added. + */ + function (frame) { + frame.index = this._frames.length; + this._frames.push(frame); + if(frame.name !== '') { + this._frameNames[frame.name] = frame.index; + } + return frame; + }; + FrameData.prototype.getFrame = /** + * Get a frame by its index. + * @param index {number} Index of the frame you want to get. + * @return {Frame} The frame you want. + */ + function (index) { + if(this._frames[index]) { + return this._frames[index]; + } + return null; + }; + FrameData.prototype.getFrameByName = /** + * Get a frame by its name. + * @param name {string} Name of the frame you want to get. + * @return {Frame} The frame you want. + */ + function (name) { + if(this._frameNames[name] !== '') { + return this._frames[this._frameNames[name]]; + } + return null; + }; + FrameData.prototype.checkFrameName = /** + * Check whether there's a frame with given name. + * @param name {string} Name of the frame you want to check. + * @return {boolean} True if frame with given name found, otherwise return false. + */ + function (name) { + if(this._frameNames[name]) { + return true; + } + return false; + }; + FrameData.prototype.getFrameRange = /** + * Get ranges of frames in an array. + * @param start {number} Start index of frames you want. + * @param end {number} End index of frames you want. + * @param [output] {Frame[]} result will be added into this array. + * @return {Frame[]} Ranges of specific frames in an array. + */ + function (start, end, output) { + if (typeof output === "undefined") { output = []; } + for(var i = start; i <= end; i++) { + output.push(this._frames[i]); + } + return output; + }; + FrameData.prototype.getFrameIndexes = /** + * Get all indexes of frames by giving their name. + * @param [output] {number[]} result will be added into this array. + * @return {number[]} Indexes of specific frames in an array. + */ + function (output) { + if (typeof output === "undefined") { output = []; } + output.length = 0; + for(var i = 0; i < this._frames.length; i++) { + output.push(i); + } + return output; + }; + FrameData.prototype.getFrameIndexesByName = /** + * Get the frame indexes by giving the frame names. + * @param [output] {number[]} result will be added into this array. + * @return {number[]} Names of specific frames in an array. + */ + function (input) { + var output = []; + for(var i = 0; i < input.length; i++) { + if(this.getFrameByName(input[i])) { + output.push(this.getFrameByName(input[i]).index); + } + } + return output; + }; + FrameData.prototype.getAllFrames = /** + * Get all frames in this frame data. + * @return {Frame[]} All the frames in an array. + */ + function () { + return this._frames; + }; + FrameData.prototype.getFrames = /** + * Get All frames with specific ranges. + * @param range {number[]} Ranges in an array. + * @return {Frame[]} All frames in an array. + */ + function (range) { + var output = []; + for(var i = 0; i < range.length; i++) { + output.push(this._frames[i]); + } + return output; + }; + return FrameData; + })(); + Phaser.FrameData = FrameData; +})(Phaser || (Phaser = {})); +var Phaser; +(function (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. + */ + (function (Components) { + var AnimationManager = (function () { + /** + * AnimationManager constructor + * Create a new AnimationManager. + * + * @param parent {Sprite} Owner sprite of this manager. + */ + function AnimationManager(parent) { + /** + * Data contains animation frames. + * @type {FrameData} + */ + this._frameData = null; + /** + * When an animation frame changes you can choose to automatically update the physics bounds of the parent Sprite + * to the width and height of the new frame. If you've set a specific physics bounds that you don't want changed during + * animation then set this to false, otherwise leave it set to true. + * @type {boolean} + */ + this.autoUpdateBounds = true; + /** + * Keeps track of the current frame of animation. + */ + this.currentFrame = null; + this._parent = parent; + this._game = parent.game; + 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; + } + if(frames == null) { + frames = this._frameData.getFrameIndexes(); + } else { + if(this.validateFrames(frames, useNumericIndex) == false) { + throw Error('Invalid frames given to Animation ' + name); + 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; + } + } 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); + } + } + }; + 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.texture.width = this.currentFrame.width; + this._parent.texture.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.texture.width = this.currentFrame.width; + this._parent.texture.height = this.currentFrame.height; + if(this.autoUpdateBounds && this._parent['body']) { + this._parent.body.bounds.width = this.currentFrame.width; + this._parent.body.bounds.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.texture.width = this.currentFrame.width; + this._parent.texture.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 = {})); +var Phaser; +(function (Phaser) { + /// + /** + * Phaser - Components - Transform + */ + (function (Components) { + var Transform = (function () { + /** + * Creates a new Sprite Transform component + * @param parent The Sprite using this transform + */ + function Transform(parent) { + /** + * This value is added to the rotation of the object. + * For example if you had a texture drawn facing straight up then you could set + * rotationOffset to 90 and it would correspond correctly with Phasers right-handed coordinate system. + * @type {number} + */ + this.rotationOffset = 0; + /** + * The rotation of the object in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + */ + this.rotation = 0; + this.game = parent.game; + this.parent = parent; + this.scrollFactor = new Phaser.Vec2(1, 1); + this.origin = new Phaser.Vec2(); + this.scale = new Phaser.Vec2(1, 1); + this.skew = new Phaser.Vec2(); + } + return Transform; + })(); + Components.Transform = Transform; + })(Phaser.Components || (Phaser.Components = {})); + var Components = Phaser.Components; +})(Phaser || (Phaser = {})); +var Phaser; +(function (Phaser) { + (function (Components) { + /// + /// + /// + /// + /** + * Phaser - Components - Input + * + * Input detection component + */ + (function (Sprite) { + var Input = (function () { + /** + * Sprite Input component constructor + * @param parent The Sprite using this Input component + */ + function Input(parent) { + /** + * The PriorityID controls which Sprite receives an Input event first if they should overlap. + */ + this.priorityID = 0; + this.isDragged = false; + this.dragPixelPerfect = false; + this.allowHorizontalDrag = true; + this.allowVerticalDrag = true; + this.snapOnDrag = false; + this.snapOnRelease = false; + this.snapX = 0; + this.snapY = 0; + /** + * Is this sprite allowed to be dragged by the mouse? true = yes, false = no + * @default false + */ + this.draggable = false; + /** + * A region of the game world within which the sprite is restricted during drag + * @default null + */ + this.boundsRect = null; + /** + * An Sprite the bounds of which this sprite is restricted during drag + * @default null + */ + this.boundsSprite = null; + this.consumePointerEvent = false; + this.game = parent.game; + this.sprite = parent; + this.enabled = false; + } + Input.prototype.pointerX = /** + * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. + * This value is only set when the pointer is over this Sprite. + * @type {number} + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].x; + }; + Input.prototype.pointerY = /** + * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite + * This value is only set when the pointer is over this Sprite. + * @type {number} + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].y; + }; + Input.prototype.pointerDown = /** + * If the Pointer is touching the touchscreen, or the mouse button is held down, isDown is set to true + * @property isDown + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isDown; + }; + Input.prototype.pointerUp = /** + * If the Pointer is not touching the touchscreen, or the mouse button is up, isUp is set to true + * @property isUp + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isUp; + }; + Input.prototype.pointerTimeDown = /** + * A timestamp representing when the Pointer first touched the touchscreen. + * @property timeDown + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeDown; + }; + Input.prototype.pointerTimeUp = /** + * A timestamp representing when the Pointer left the touchscreen. + * @property timeUp + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeUp; + }; + Input.prototype.pointerOver = /** + * Is the Pointer over this Sprite + * @property isOver + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isOver; + }; + Input.prototype.pointerOut = /** + * Is the Pointer outside of this Sprite + * @property isOut + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isOut; + }; + Input.prototype.pointerTimeOver = /** + * A timestamp representing when the Pointer first touched the touchscreen. + * @property timeDown + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeOver; + }; + Input.prototype.pointerTimeOut = /** + * A timestamp representing when the Pointer left the touchscreen. + * @property timeUp + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeOut; + }; + Input.prototype.pointerDragged = /** + * Is this sprite being dragged by the mouse or not? + * @default false + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isDragged; + }; + Input.prototype.start = function (priority, checkBody, useHandCursor) { + if (typeof priority === "undefined") { priority = 0; } + if (typeof checkBody === "undefined") { checkBody = false; } + if (typeof useHandCursor === "undefined") { useHandCursor = false; } + // Turning on + if(this.enabled == false) { + // Register, etc + this.checkBody = checkBody; + this.useHandCursor = useHandCursor; + this.priorityID = priority; + this._pointerData = []; + for(var i = 0; i < 10; i++) { + this._pointerData.push({ + id: i, + x: 0, + y: 0, + isDown: false, + isUp: false, + isOver: false, + isOut: false, + timeOver: 0, + timeOut: 0, + timeDown: 0, + timeUp: 0, + downDuration: 0, + isDragged: false + }); + } + this.snapOffset = new Phaser.Point(); + this.enabled = true; + this.game.input.addGameObject(this.sprite); + } + return this.sprite; + }; + Input.prototype.reset = function () { + this.enabled = false; + for(var i = 0; i < 10; i++) { + this._pointerData[i] = { + id: i, + x: 0, + y: 0, + isDown: false, + isUp: false, + isOver: false, + isOut: false, + timeOver: 0, + timeOut: 0, + timeDown: 0, + timeUp: 0, + downDuration: 0, + isDragged: false + }; + } + }; + Input.prototype.stop = function () { + // Turning off + if(this.enabled == false) { + return; + } else { + // De-register, etc + this.enabled = false; + this.game.input.removeGameObject(this.sprite); + } + }; + Input.prototype.checkPointerOver = function (pointer) { + if(this.enabled == false || this.sprite.visible == false) { + return false; + } else { + return Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.scaledX, pointer.scaledY); + } + }; + Input.prototype.update = /** + * Update + */ + function (pointer) { + if(this.enabled == false || this.sprite.visible == false) { + return false; + } + if(this.draggable && this._draggedPointerID == pointer.id) { + return this.updateDrag(pointer); + } else if(this._pointerData[pointer.id].isOver == true) { + if(Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.scaledX, pointer.scaledY)) { + this._pointerData[pointer.id].x = pointer.scaledX - this.sprite.x; + this._pointerData[pointer.id].y = pointer.scaledY - this.sprite.y; + return true; + } else { + this._pointerOutHandler(pointer); + return false; + } + } + }; + Input.prototype._pointerOverHandler = function (pointer) { + // { id: i, x: 0, y: 0, isDown: false, isUp: false, isOver: false, isOut: false, timeOver: 0, timeOut: 0, isDragged: false } + if(this._pointerData[pointer.id].isOver == false) { + this._pointerData[pointer.id].isOver = true; + this._pointerData[pointer.id].isOut = false; + this._pointerData[pointer.id].timeOver = this.game.time.now; + this._pointerData[pointer.id].x = pointer.x - this.sprite.x; + this._pointerData[pointer.id].y = pointer.y - this.sprite.y; + if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { + this.game.stage.canvas.style.cursor = "pointer"; + } + this.sprite.events.onInputOver.dispatch(this.sprite, pointer); + } + }; + Input.prototype._pointerOutHandler = function (pointer) { + this._pointerData[pointer.id].isOver = false; + this._pointerData[pointer.id].isOut = true; + this._pointerData[pointer.id].timeOut = this.game.time.now; + if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { + this.game.stage.canvas.style.cursor = "default"; + } + this.sprite.events.onInputOut.dispatch(this.sprite, pointer); + }; + Input.prototype._touchedHandler = function (pointer) { + if(this._pointerData[pointer.id].isDown == false && this._pointerData[pointer.id].isOver == true) { + this._pointerData[pointer.id].isDown = true; + this._pointerData[pointer.id].isUp = false; + this._pointerData[pointer.id].timeDown = this.game.time.now; + this.sprite.events.onInputDown.dispatch(this.sprite, pointer); + // Start drag + //if (this.draggable && this.isDragged == false && pointer.targetObject == null) + if(this.draggable && this.isDragged == false) { + this.startDrag(pointer); + } + } + // Consume the event? + return this.consumePointerEvent; + }; + Input.prototype._releasedHandler = function (pointer) { + // If was previously touched by this Pointer, check if still is + if(this._pointerData[pointer.id].isDown && pointer.isUp) { + this._pointerData[pointer.id].isDown = false; + this._pointerData[pointer.id].isUp = true; + this._pointerData[pointer.id].timeUp = this.game.time.now; + this._pointerData[pointer.id].downDuration = this._pointerData[pointer.id].timeUp - this._pointerData[pointer.id].timeDown; + this.sprite.events.onInputUp.dispatch(this.sprite, pointer); + // Stop drag + if(this.draggable && this.isDragged && this._draggedPointerID == pointer.id) { + this.stopDrag(pointer); + } + if(this.useHandCursor) { + this.game.stage.canvas.style.cursor = "default"; + } + } + }; + Input.prototype.updateDrag = /** + * Updates the Pointer drag on this Sprite. + */ + function (pointer) { + if(pointer.isUp) { + this.stopDrag(pointer); + return false; + } + if(this.allowHorizontalDrag) { + this.sprite.x = pointer.x + this._dragPoint.x + this.dragOffset.x; + } + if(this.allowVerticalDrag) { + this.sprite.y = pointer.y + this._dragPoint.y + this.dragOffset.y; + } + if(this.boundsRect) { + this.checkBoundsRect(); + } + if(this.boundsSprite) { + this.checkBoundsSprite(); + } + if(this.snapOnDrag) { + this.sprite.x = Math.floor(this.sprite.x / this.snapX) * this.snapX; + this.sprite.y = Math.floor(this.sprite.y / this.snapY) * this.snapY; + } + return true; + }; + Input.prototype.justOver = /** + * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just over. + * @returns {boolean} + */ + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } + if (typeof delay === "undefined") { delay = 500; } + return (this._pointerData[pointer].isOver && this.overDuration(pointer) < delay); + }; + Input.prototype.justOut = /** + * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just out. + * @returns {boolean} + */ + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } + if (typeof delay === "undefined") { delay = 500; } + return (this._pointerData[pointer].isOut && (this.game.time.now - this._pointerData[pointer].timeOut < delay)); + }; + Input.prototype.justPressed = /** + * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just over. + * @returns {boolean} + */ + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } + if (typeof delay === "undefined") { delay = 500; } + return (this._pointerData[pointer].isDown && this.downDuration(pointer) < delay); + }; + Input.prototype.justReleased = /** + * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just out. + * @returns {boolean} + */ + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } + if (typeof delay === "undefined") { delay = 500; } + return (this._pointerData[pointer].isUp && (this.game.time.now - this._pointerData[pointer].timeUp < delay)); + }; + Input.prototype.overDuration = /** + * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. + * @returns {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over. + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + if(this._pointerData[pointer].isOver) { + return this.game.time.now - this._pointerData[pointer].timeOver; + } + return -1; + }; + Input.prototype.downDuration = /** + * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. + * @returns {number} The number of milliseconds the pointer has been pressed down on the Sprite, or -1 if not over. + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + if(this._pointerData[pointer].isDown) { + return this.game.time.now - this._pointerData[pointer].timeDown; + } + return -1; + }; + Input.prototype.enableDrag = /** + * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback + * + * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. + * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. + * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) + * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere + * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here + */ + function (lockCenter, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) { + if (typeof lockCenter === "undefined") { lockCenter = false; } + if (typeof pixelPerfect === "undefined") { pixelPerfect = false; } + if (typeof alphaThreshold === "undefined") { alphaThreshold = 255; } + if (typeof boundsRect === "undefined") { boundsRect = null; } + if (typeof boundsSprite === "undefined") { boundsSprite = null; } + this._dragPoint = new Phaser.Point(); + this.draggable = true; + this.dragOffset = new Phaser.Point(); + this.dragFromCenter = lockCenter; + this.dragPixelPerfect = pixelPerfect; + this.dragPixelPerfectAlpha = alphaThreshold; + if(boundsRect) { + this.boundsRect = boundsRect; + } + if(boundsSprite) { + this.boundsSprite = boundsSprite; + } + }; + Input.prototype.disableDrag = /** + * Stops this sprite from being able to be dragged. If it is currently the target of an active drag it will be stopped immediately. Also disables any set callbacks. + */ + function () { + if(this._pointerData) { + for(var i = 0; i < 10; i++) { + this._pointerData[i].isDragged = false; + } + } + this.draggable = false; + this.isDragged = false; + this._draggedPointerID = -1; + }; + Input.prototype.startDrag = /** + * Called by Pointer when drag starts on this Sprite. Should not usually be called directly. + */ + function (pointer) { + this.isDragged = true; + this._draggedPointerID = pointer.id; + this._pointerData[pointer.id].isDragged = true; + if(this.dragFromCenter) { + // Move the sprite to the middle of the pointer + this._dragPoint.setTo(-this.sprite.worldView.halfWidth, -this.sprite.worldView.halfHeight); + } else { + this._dragPoint.setTo(this.sprite.x - pointer.x, this.sprite.y - pointer.y); + } + this.updateDrag(pointer); + }; + Input.prototype.stopDrag = /** + * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. + */ + function (pointer) { + this.isDragged = false; + this._draggedPointerID = -1; + this._pointerData[pointer.id].isDragged = false; + if(this.snapOnRelease) { + this.sprite.x = Math.floor(this.sprite.x / this.snapX) * this.snapX; + this.sprite.y = Math.floor(this.sprite.y / this.snapY) * this.snapY; + } + //pointer.draggedObject = null; + }; + Input.prototype.setDragLock = /** + * Restricts this sprite to drag movement only on the given axis. Note: If both are set to false the sprite will never move! + * + * @param allowHorizontal To enable the sprite to be dragged horizontally set to true, otherwise false + * @param allowVertical To enable the sprite to be dragged vertically set to true, otherwise false + */ + function (allowHorizontal, allowVertical) { + if (typeof allowHorizontal === "undefined") { allowHorizontal = true; } + if (typeof allowVertical === "undefined") { allowVertical = true; } + this.allowHorizontalDrag = allowHorizontal; + this.allowVerticalDrag = allowVertical; + }; + Input.prototype.enableSnap = /** + * Make this Sprite snap to the given grid either during drag or when it's released. + * For example 16x16 as the snapX and snapY would make the sprite snap to every 16 pixels. + * + * @param snapX The width of the grid cell in pixels + * @param snapY The height of the grid cell in pixels + * @param onDrag If true the sprite will snap to the grid while being dragged + * @param onRelease If true the sprite will snap to the grid when released + */ + function (snapX, snapY, onDrag, onRelease) { + if (typeof onDrag === "undefined") { onDrag = true; } + if (typeof onRelease === "undefined") { onRelease = false; } + this.snapOnDrag = onDrag; + this.snapOnRelease = onRelease; + this.snapX = snapX; + this.snapY = snapY; + }; + Input.prototype.disableSnap = /** + * Stops the sprite from snapping to a grid during drag or release. + */ + function () { + this.snapOnDrag = false; + this.snapOnRelease = false; + }; + Input.prototype.checkBoundsRect = /** + * Bounds Rect check for the sprite drag + */ + function () { + if(this.sprite.x < this.boundsRect.left) { + this.sprite.x = this.boundsRect.x; + } else if((this.sprite.x + this.sprite.width) > this.boundsRect.right) { + this.sprite.x = this.boundsRect.right - this.sprite.width; + } + if(this.sprite.y < this.boundsRect.top) { + this.sprite.y = this.boundsRect.top; + } else if((this.sprite.y + this.sprite.height) > this.boundsRect.bottom) { + this.sprite.y = this.boundsRect.bottom - this.sprite.height; + } + }; + Input.prototype.checkBoundsSprite = /** + * Parent Sprite Bounds check for the sprite drag + */ + function () { + if(this.sprite.x < this.boundsSprite.x) { + this.sprite.x = this.boundsSprite.x; + } else if((this.sprite.x + this.sprite.width) > (this.boundsSprite.x + this.boundsSprite.width)) { + this.sprite.x = (this.boundsSprite.x + this.boundsSprite.width) - this.sprite.width; + } + if(this.sprite.y < this.boundsSprite.y) { + this.sprite.y = this.boundsSprite.y; + } else if((this.sprite.y + this.sprite.height) > (this.boundsSprite.y + this.boundsSprite.height)) { + this.sprite.y = (this.boundsSprite.y + this.boundsSprite.height) - this.sprite.height; + } + }; + Input.prototype.renderDebugInfo = /** + * Render debug infos. (including name, bounds info, position and some other properties) + * @param x {number} X position of the debug info to be rendered. + * @param y {number} Y position of the debug info to be rendered. + * @param [color] {number} color of the debug info to be rendered. (format is css color string) + */ + function (x, y, color) { + if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } + this.sprite.texture.context.font = '14px Courier'; + this.sprite.texture.context.fillStyle = color; + this.sprite.texture.context.fillText('Sprite Input: (' + this.sprite.worldView.width + ' x ' + this.sprite.worldView.height + ')', x, y); + this.sprite.texture.context.fillText('x: ' + this.pointerX().toFixed(1) + ' y: ' + this.pointerY().toFixed(1), x, y + 14); + this.sprite.texture.context.fillText('over: ' + this.pointerOver() + ' duration: ' + this.overDuration().toFixed(0), x, y + 28); + this.sprite.texture.context.fillText('down: ' + this.pointerDown() + ' duration: ' + this.downDuration().toFixed(0), x, y + 42); + this.sprite.texture.context.fillText('just over: ' + this.justOver() + ' just out: ' + this.justOut(), x, y + 56); + }; + return Input; + })(); + Sprite.Input = Input; + })(Components.Sprite || (Components.Sprite = {})); + var Sprite = Components.Sprite; + })(Phaser.Components || (Phaser.Components = {})); + var Components = Phaser.Components; +})(Phaser || (Phaser = {})); +var Phaser; +(function (Phaser) { + (function (Components) { + /// + /** + * Phaser - Components - Events + * + * Signals that are dispatched by the Sprite and its various components + */ + (function (Sprite) { + var Events = (function () { + /** + * The Events component is a collection of events fired by the parent Sprite and its other components. + * @param parent The Sprite using this Input component + */ + function Events(parent) { + this.game = parent.game; + this.sprite = parent; + this.onAddedToGroup = new Phaser.Signal(); + this.onRemovedFromGroup = new Phaser.Signal(); + this.onKilled = new Phaser.Signal(); + this.onRevived = new Phaser.Signal(); + this.onInputOver = new Phaser.Signal(); + this.onInputOut = new Phaser.Signal(); + this.onInputDown = new Phaser.Signal(); + this.onInputUp = new Phaser.Signal(); + } + return Events; + })(); + Sprite.Events = Events; + })(Components.Sprite || (Components.Sprite = {})); + var Sprite = Components.Sprite; + })(Phaser.Components || (Phaser.Components = {})); + var Components = Phaser.Components; +})(Phaser || (Phaser = {})); +/// +/// +/** +* Phaser - Vec2Utils +* +* A collection of methods useful for manipulating and performing operations on 2D vectors. +* +*/ +var Phaser; +(function (Phaser) { + var Vec2Utils = (function () { + function Vec2Utils() { } + Vec2Utils.add = /** + * Adds two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the sum of the two vectors. + */ + function add(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.x + b.x, a.y + b.y); + }; + Vec2Utils.subtract = /** + * Subtracts two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the difference of the two vectors. + */ + function subtract(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.x - b.x, a.y - b.y); + }; + Vec2Utils.multiply = /** + * Multiplies two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the sum of the two vectors multiplied. + */ + function multiply(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.x * b.x, a.y * b.y); + }; + Vec2Utils.divide = /** + * Divides two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the sum of the two vectors divided. + */ + function divide(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.x / b.x, a.y / b.y); + }; + Vec2Utils.scale = /** + * Scales a 2D vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {number} s Scaling value. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the scaled vector. + */ + function scale(a, s, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.x * s, a.y * s); + }; + Vec2Utils.perp = /** + * Rotate a 2D vector by 90 degrees. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the scaled vector. + */ + function perp(a, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.y, -a.x); + }; + Vec2Utils.equals = /** + * Checks if two 2D vectors are equal. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Boolean} + */ + function equals(a, b) { + return a.x == b.x && a.y == b.y; + }; + Vec2Utils.epsilonEquals = /** + * + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} epsilon + * @return {Boolean} + */ + function epsilonEquals(a, b, epsilon) { + return Math.abs(a.x - b.x) <= epsilon && Math.abs(a.y - b.y) <= epsilon; + }; + Vec2Utils.distance = /** + * Get the distance between two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + function distance(a, b) { + return Math.sqrt(Vec2Utils.distanceSq(a, b)); + }; + Vec2Utils.distanceSq = /** + * Get the distance squared between two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + function distanceSq(a, b) { + return ((a.x - b.x) * (a.x - b.x)) + ((a.y - b.y) * (a.y - b.y)); + }; + Vec2Utils.project = /** + * Project two 2D vectors onto another vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + function project(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + var amt = a.dot(b) / b.lengthSq(); + if(amt != 0) { + out.setTo(amt * b.x, amt * b.y); + } + return out; + }; + Vec2Utils.projectUnit = /** + * Project this vector onto a vector of unit length. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + function projectUnit(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + var amt = a.dot(b); + if(amt != 0) { + out.setTo(amt * b.x, amt * b.y); + } + return out; + }; + Vec2Utils.normalRightHand = /** + * Right-hand normalize (make unit length) a 2D vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + function normalRightHand(a, out) { + if (typeof out === "undefined") { out = this; } + return out.setTo(a.y * -1, a.x); + }; + Vec2Utils.normalize = /** + * Normalize (make unit length) a 2D vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + function normalize(a, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + var m = a.length(); + if(m != 0) { + out.setTo(a.x / m, a.y / m); + } + return out; + }; + Vec2Utils.dot = /** + * The dot product of two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + function dot(a, b) { + return ((a.x * b.x) + (a.y * b.y)); + }; + Vec2Utils.cross = /** + * The cross product of two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + function cross(a, b) { + return ((a.x * b.y) - (a.y * b.x)); + }; + Vec2Utils.angle = /** + * The angle between two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + function angle(a, b) { + return Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y); + }; + Vec2Utils.angleSq = /** + * The angle squared between two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + function angleSq(a, b) { + return a.subtract(b).angle(b.subtract(a)); + }; + Vec2Utils.rotate = /** + * Rotate a 2D vector around the origin to the given angle (theta). + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Number} theta The angle of rotation in radians. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + function rotate(a, b, theta, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + var x = a.x - b.x; + var y = a.y - b.y; + return out.setTo(x * Math.cos(theta) - y * Math.sin(theta) + b.x, x * Math.sin(theta) + y * Math.cos(theta) + b.y); + }; + Vec2Utils.clone = /** + * Clone a 2D vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is a copy of the source Vec2. + */ + function clone(a, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.x, a.y); + }; + return Vec2Utils; + })(); + Phaser.Vec2Utils = Vec2Utils; + /** + * Reflect this vector on an arbitrary axis. + * + * @param {Vec2} axis The vector representing the axis. + * @return {Vec2} This for chaining. + */ + /* + static reflect(axis): Vec2 { + + var x = this.x; + var y = this.y; + this.project(axis).scale(2); + this.x -= x; + this.y -= y; + + return this; + + } + */ + /** + * Reflect this vector on an arbitrary axis (represented by a unit vector) + * + * @param {Vec2} axis The unit vector representing the axis. + * @return {Vec2} This for chaining. + */ + /* + static reflectN(axis): Vec2 { + + var x = this.x; + var y = this.y; + this.projectN(axis).scale(2); + this.x -= x; + this.y -= y; + + return this; + + } + + static getMagnitude(): number { + return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)); + } + */ + })(Phaser || (Phaser = {})); +var Phaser; +(function (Phaser) { + /// + /// + /// + /** + * Phaser - Physics - Body + */ + (function (Physics) { + var Body = (function () { + function Body(sprite, type) { + this.angularVelocity = 0; + this.angularAcceleration = 0; + this.angularDrag = 0; + this.maxAngular = 10000; + this.mass = 1; + this.sprite = sprite; + this.game = sprite.game; + this.type = type; + // Fixture properties + // Will extend into its own class at a later date - can move the fixture defs there and add shape support, but this will do for 1.0 release + this.bounds = new Phaser.Rectangle(sprite.x + Math.round(sprite.width / 2), sprite.y + Math.round(sprite.height / 2), sprite.width, sprite.height); + this.bounce = Phaser.Vec2Utils.clone(this.game.world.physics.bounce); + // Body properties + this.gravity = Phaser.Vec2Utils.clone(this.game.world.physics.gravity); + this.velocity = new Phaser.Vec2(); + this.acceleration = new Phaser.Vec2(); + this.drag = Phaser.Vec2Utils.clone(this.game.world.physics.drag); + this.maxVelocity = new Phaser.Vec2(10000, 10000); + this.angularVelocity = 0; + this.angularAcceleration = 0; + this.angularDrag = 0; + this.touching = Phaser.Types.NONE; + this.wasTouching = Phaser.Types.NONE; + this.allowCollisions = Phaser.Types.ANY; + this.position = new Phaser.Vec2(sprite.x + this.bounds.halfWidth, sprite.y + this.bounds.halfHeight); + this.oldPosition = new Phaser.Vec2(sprite.x + this.bounds.halfWidth, sprite.y + this.bounds.halfHeight); + this.offset = new Phaser.Vec2(); + } + Body.prototype.preUpdate = function () { + this.oldPosition.copyFrom(this.position); + this.bounds.x = this.position.x - this.bounds.halfWidth; + this.bounds.y = this.position.y - this.bounds.halfHeight; + if(this.sprite.transform.scale.equals(1) == false) { + } + }; + Body.prototype.postUpdate = // Shall we do this? Or just update the values directly in the separate functions? But then the bounds will be out of sync - as long as + // the bounds are updated and used in calculations then we can do one final sprite movement here I guess? + function () { + // if this is all it does maybe move elsewhere? Sprite postUpdate? + if(this.type !== Phaser.Types.BODY_DISABLED) { + this.game.world.physics.updateMotion(this); + this.sprite.x = (this.position.x - this.bounds.halfWidth) - this.offset.x; + this.sprite.y = (this.position.y - this.bounds.halfHeight) - this.offset.y; + this.wasTouching = this.touching; + this.touching = Phaser.Types.NONE; + } + }; + Object.defineProperty(Body.prototype, "hullWidth", { + get: function () { + if(this.deltaX > 0) { + return this.bounds.width + this.deltaX; + } else { + return this.bounds.width - this.deltaX; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "hullHeight", { + get: function () { + if(this.deltaY > 0) { + return this.bounds.height + this.deltaY; + } else { + return this.bounds.height - this.deltaY; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "hullX", { + get: function () { + if(this.position.x < this.oldPosition.x) { + return this.position.x; + } else { + return this.oldPosition.x; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "hullY", { + get: function () { + if(this.position.y < this.oldPosition.y) { + return this.position.y; + } else { + return this.oldPosition.y; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "deltaXAbs", { + get: function () { + return (this.deltaX > 0 ? this.deltaX : -this.deltaX); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "deltaYAbs", { + get: function () { + return (this.deltaY > 0 ? this.deltaY : -this.deltaY); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "deltaX", { + get: function () { + return this.position.x - this.oldPosition.x; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "deltaY", { + get: function () { + return this.position.y - this.oldPosition.y; + }, + enumerable: true, + configurable: true + }); + Body.prototype.render = // MOVE THESE TO A UTIL + function (context) { + context.beginPath(); + context.strokeStyle = 'rgb(0,255,0)'; + context.strokeRect(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight, this.bounds.width, this.bounds.height); + context.stroke(); + context.closePath(); + // center point + context.fillStyle = 'rgb(0,255,0)'; + context.fillRect(this.position.x, this.position.y, 2, 2); + if(this.touching & Phaser.Types.LEFT) { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); + context.lineTo(this.position.x - this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); + context.stroke(); + context.closePath(); + } + if(this.touching & Phaser.Types.RIGHT) { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.position.x + this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); + context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); + context.stroke(); + context.closePath(); + } + if(this.touching & Phaser.Types.UP) { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); + context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); + context.stroke(); + context.closePath(); + } + if(this.touching & Phaser.Types.DOWN) { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); + context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); + context.stroke(); + context.closePath(); + } + }; + Body.prototype.renderDebugInfo = /** + * Render debug infos. (including name, bounds info, position and some other properties) + * @param x {number} X position of the debug info to be rendered. + * @param y {number} Y position of the debug info to be rendered. + * @param [color] {number} color of the debug info to be rendered. (format is css color string) + */ + function (x, y, color) { + if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } + this.sprite.texture.context.fillStyle = color; + this.sprite.texture.context.fillText('Sprite: (' + this.sprite.width + ' x ' + this.sprite.height + ')', x, y); + //this.sprite.texture.context.fillText('x: ' + this._sprite.frameBounds.x.toFixed(1) + ' y: ' + this._sprite.frameBounds.y.toFixed(1) + ' rotation: ' + this._sprite.rotation.toFixed(1), x, y + 14); + this.sprite.texture.context.fillText('x: ' + this.bounds.x.toFixed(1) + ' y: ' + this.bounds.y.toFixed(1) + ' rotation: ' + this.sprite.transform.rotation.toFixed(0), x, y + 14); + this.sprite.texture.context.fillText('vx: ' + this.velocity.x.toFixed(1) + ' vy: ' + this.velocity.y.toFixed(1), x, y + 28); + this.sprite.texture.context.fillText('acx: ' + this.acceleration.x.toFixed(1) + ' acy: ' + this.acceleration.y.toFixed(1), x, y + 42); + this.sprite.texture.context.fillText('angVx: ' + this.angularVelocity.toFixed(1) + ' angAc: ' + this.angularAcceleration.toFixed(1), x, y + 56); + }; + return Body; + })(); + Physics.Body = Body; + })(Phaser.Physics || (Phaser.Physics = {})); + var Physics = Phaser.Physics; +})(Phaser || (Phaser = {})); +/// +/// +/// +/// +/// +/// +/// +/// +/// +/** +* Phaser - Sprite +*/ +var Phaser; +(function (Phaser) { + var Sprite = (function () { + /** + * Create a new Sprite. + * + * @param game {Phaser.Game} Current game instance. + * @param [x] {number} the initial x position of the sprite. + * @param [y] {number} the initial y position of the sprite. + * @param [key] {string} Key of the graphic you want to load for this sprite. + * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) + */ + function Sprite(game, x, y, key, frame, bodyType) { + if (typeof x === "undefined") { x = 0; } + if (typeof y === "undefined") { y = 0; } + if (typeof key === "undefined") { key = null; } + if (typeof frame === "undefined") { frame = null; } + if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } + /** + * 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; + /** + * y value of the object. + */ + this.y = 0; + /** + * z order value of the object. + */ + this.z = 0; + /** + * Render iteration counter + */ + this.renderOrderID = 0; + this.game = game; + this.type = Phaser.Types.SPRITE; + this.exists = true; + this.active = true; + this.visible = true; + this.alive = true; + this.x = x; + this.y = y; + this.z = -1; + this.group = null; + this.transform = new Phaser.Components.Transform(this); + this.animations = new Phaser.Components.AnimationManager(this); + this.texture = new Phaser.Components.Texture(this); + this.body = new Phaser.Physics.Body(this, bodyType); + this.input = new Phaser.Components.Sprite.Input(this); + this.events = new Phaser.Components.Sprite.Events(this); + if(key !== null) { + this.texture.loadImage(key, false); + } else { + this.texture.opaque = true; + } + if(frame !== null) { + if(typeof frame == 'string') { + this.frameName = frame; + } else { + this.frame = frame; + } + } + this.worldView = new Phaser.Rectangle(x, y, this.width, this.height); + } + Object.defineProperty(Sprite.prototype, "rotation", { + get: /** + * The rotation of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + */ + function () { + return this.transform.rotation; + }, + set: /** + * Set the rotation of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + * The value is automatically wrapped to be between 0 and 360. + */ + function (value) { + this.transform.rotation = this.game.math.wrap(value, 360, 0); + }, + 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 + }); + Object.defineProperty(Sprite.prototype, "width", { + get: function () { + return this.texture.width * this.transform.scale.x; + }, + set: function (value) { + this.transform.scale.x = value / this.texture.width; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Sprite.prototype, "height", { + get: function () { + return this.texture.height * this.transform.scale.y; + }, + set: function (value) { + this.transform.scale.y = value / this.texture.height; + }, + enumerable: true, + configurable: true + }); + Sprite.prototype.preUpdate = /** + * Pre-update is called right before update() on each object in the game loop. + */ + function () { + this.worldView.x = this.x - (this.game.world.cameras.default.worldView.x * this.transform.scrollFactor.x); + this.worldView.y = this.y - (this.game.world.cameras.default.worldView.y * this.transform.scrollFactor.y); + this.worldView.width = this.width; + this.worldView.height = this.height; + if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.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. + */ + function () { + }; + Sprite.prototype.postUpdate = /** + * Automatically called after update() by the game loop. + */ + function () { + this.animations.update(); + this.body.postUpdate(); + /* + if (this.worldBounds != null) + { + if (this.outOfBoundsAction == GameObject.OUT_OF_BOUNDS_KILL) + { + if (this.x < this.worldBounds.x || this.x > this.worldBounds.right || this.y < this.worldBounds.y || this.y > this.worldBounds.bottom) + { + this.kill(); + } + } + else + { + if (this.x < this.worldBounds.x) + { + this.x = this.worldBounds.x; + } + else if (this.x > this.worldBounds.right) + { + this.x = this.worldBounds.right; + } + + if (this.y < this.worldBounds.y) + { + this.y = this.worldBounds.y; + } + else if (this.y > this.worldBounds.bottom) + { + this.y = this.worldBounds.bottom; + } + } + } + */ + if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { + this.modified = false; + } + }; + Sprite.prototype.destroy = /** + * Clean up memory. + */ + function () { + //this.input.destroy(); + }; + Sprite.prototype.kill = /** + * Handy for "killing" game objects. + * Default behavior is to flag them as nonexistent AND dead. + * However, if you want the "corpse" to remain in the game, + * like to animate an effect or whatever, you should override this, + * setting only alive to false, and leaving exists true. + */ + function (removeFromGroup) { + if (typeof removeFromGroup === "undefined") { removeFromGroup = false; } + this.alive = false; + this.exists = false; + if(removeFromGroup && this.group) { + this.group.remove(this); + } + this.events.onKilled.dispatch(this); + }; + Sprite.prototype.revive = /** + * Handy for bringing game objects "back to life". Just sets alive and exists back to true. + * In practice, this is most often called by Object.reset(). + */ + function () { + this.alive = true; + this.exists = true; + this.events.onRevived.dispatch(this); + }; + return Sprite; + })(); + Phaser.Sprite = Sprite; +})(Phaser || (Phaser = {})); +/// +/// +/// +/// +/// +/// +/** +* Phaser - SpriteUtils +* +* A collection of methods useful for manipulating and checking Sprites. +*/ +var Phaser; +(function (Phaser) { + var SpriteUtils = (function () { + function SpriteUtils() { } + SpriteUtils.inCamera = /** + * Check whether this object is visible in a specific camera Rectangle. + * @param camera {Rectangle} The Rectangle you want to check. + * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. + */ + function inCamera(camera, sprite) { + // Object fixed in place regardless of the camera scrolling? Then it's always visible + if(sprite.transform.scrollFactor.x == 0 && sprite.transform.scrollFactor.y == 0) { + return true; + } + var dx = sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + var dy = sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + var dw = sprite.width * sprite.transform.scale.x; + var dh = sprite.height * sprite.transform.scale.y; + return (camera.screenView.x + camera.worldView.width > this._dx) && (camera.screenView.x < this._dx + this._dw) && (camera.screenView.y + camera.worldView.height > this._dy) && (camera.screenView.y < this._dy + this._dh); + }; + SpriteUtils.getAsPoints = function getAsPoints(sprite) { + var out = []; + // top left + out.push(new Phaser.Point(sprite.x, sprite.y)); + // top right + out.push(new Phaser.Point(sprite.x + sprite.width, sprite.y)); + // bottom right + out.push(new Phaser.Point(sprite.x + sprite.width, sprite.y + sprite.height)); + // bottom left + out.push(new Phaser.Point(sprite.x, sprite.y + sprite.height)); + return out; + }; + SpriteUtils.overlapsPoint = /** + * Checks to see if some GameObject overlaps this GameObject or Group. + * If the group has a LOT of things in it, it might be faster to use Collision.overlaps(). + * WARNING: Currently tilemaps do NOT support screen space overlap checks! + * + * @param objectOrGroup {object} The object or group being tested. + * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return {boolean} Whether or not the objects overlap this. + */ + /* + static overlaps(objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { + + if (objectOrGroup.isGroup) + { + var results: bool = false; + var i: number = 0; + var members = objectOrGroup.members; + + while (i < length) + { + if (this.overlaps(members[i++], inScreenSpace, camera)) + { + results = true; + } + } + + return results; + + } + + if (!inScreenSpace) + { + return (objectOrGroup.x + objectOrGroup.width > this.x) && (objectOrGroup.x < this.x + this.width) && + (objectOrGroup.y + objectOrGroup.height > this.y) && (objectOrGroup.y < this.y + this.height); + } + + if (camera == null) + { + camera = this._game.camera; + } + + var objectScreenPos: Point = objectOrGroup.getScreenXY(null, camera); + + this.getScreenXY(this._point, camera); + + return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && + (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); + } + */ + /** + * Checks to see if this GameObject were located at the given position, would it overlap the GameObject or Group? + * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size numbero account. + * WARNING: Currently tilemaps do NOT support screen space overlap checks! + * + * @param X {number} The X position you want to check. Pretends this object (the caller, not the parameter) is located here. + * @param Y {number} The Y position you want to check. Pretends this object (the caller, not the parameter) is located here. + * @param objectOrGroup {object} The object or group being tested. + * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return {boolean} Whether or not the two objects overlap. + */ + /* + static overlapsAt(X: number, Y: number, objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { + + if (objectOrGroup.isGroup) + { + var results: bool = false; + var basic; + var i: number = 0; + var members = objectOrGroup.members; + + while (i < length) + { + if (this.overlapsAt(X, Y, members[i++], inScreenSpace, camera)) + { + results = true; + } + } + + return results; + } + + if (!inScreenSpace) + { + return (objectOrGroup.x + objectOrGroup.width > X) && (objectOrGroup.x < X + this.width) && + (objectOrGroup.y + objectOrGroup.height > Y) && (objectOrGroup.y < Y + this.height); + } + + if (camera == null) + { + camera = this._game.camera; + } + + var objectScreenPos: Point = objectOrGroup.getScreenXY(null, Camera); + + this._point.x = X - camera.scroll.x * this.transform.scrollFactor.x; //copied from getScreenXY() + this._point.y = Y - camera.scroll.y * this.transform.scrollFactor.y; + this._point.x += (this._point.x > 0) ? 0.0000001 : -0.0000001; + this._point.y += (this._point.y > 0) ? 0.0000001 : -0.0000001; + + return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && + (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); + } + */ + /** + * Checks to see if a point in 2D world space overlaps this GameObject. + * + * @param point {Point} The point in world space you want to check. + * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return Whether or not the point overlaps this object. + */ + function overlapsPoint(sprite, point, inScreenSpace, camera) { + if (typeof inScreenSpace === "undefined") { inScreenSpace = false; } + if (typeof camera === "undefined") { camera = null; } + if(!inScreenSpace) { + return Phaser.RectangleUtils.containsPoint(sprite.body.bounds, point); + //return (point.x > sprite.x) && (point.x < sprite.x + sprite.width) && (point.y > sprite.y) && (point.y < sprite.y + sprite.height); + } + if(camera == null) { + camera = sprite.game.camera; + } + //var x: number = point.x - camera.scroll.x; + //var y: number = point.y - camera.scroll.y; + //this.getScreenXY(this._point, camera); + //return (x > this._point.x) && (X < this._point.x + this.width) && (Y > this._point.y) && (Y < this._point.y + this.height); + }; + SpriteUtils.onScreen = /** + * Check and see if this object is currently on screen. + * + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return {boolean} Whether the object is on screen or not. + */ + function onScreen(sprite, camera) { + if (typeof camera === "undefined") { camera = null; } + if(camera == null) { + camera = sprite.game.camera; + } + SpriteUtils.getScreenXY(sprite, SpriteUtils._tempPoint, camera); + return (SpriteUtils._tempPoint.x + sprite.width > 0) && (SpriteUtils._tempPoint.x < camera.width) && (SpriteUtils._tempPoint.y + sprite.height > 0) && (SpriteUtils._tempPoint.y < camera.height); + }; + SpriteUtils.getScreenXY = /** + * Call this to figure out the on-screen position of the object. + * + * @param point {Point} Takes a Point object and assigns the post-scrolled X and Y values of this object to it. + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return {Point} The Point you passed in, or a new Point if you didn't pass one, containing the screen X and Y position of this object. + */ + function getScreenXY(sprite, point, camera) { + if (typeof point === "undefined") { point = null; } + if (typeof camera === "undefined") { camera = null; } + if(point == null) { + point = new Phaser.Point(); + } + if(camera == null) { + camera = this._game.camera; + } + point.x = sprite.x - camera.x * sprite.transform.scrollFactor.x; + point.y = sprite.y - camera.y * sprite.transform.scrollFactor.y; + point.x += (point.x > 0) ? 0.0000001 : -0.0000001; + point.y += (point.y > 0) ? 0.0000001 : -0.0000001; + return point; + }; + SpriteUtils.reset = /** + * Set the world bounds that this GameObject can exist within based on the size of the current game world. + * + * @param action {number} The action to take if the object hits the world bounds, either OUT_OF_BOUNDS_KILL or OUT_OF_BOUNDS_STOP + */ + /* + static setBoundsFromWorld(action?: number = GameObject.OUT_OF_BOUNDS_STOP) { + + this.setBounds(this._game.world.bounds.x, this._game.world.bounds.y, this._game.world.bounds.width, this._game.world.bounds.height); + this.outOfBoundsAction = action; + + } + */ + /** + * Handy for reviving game objects. + * Resets their existence flags and position. + * + * @param x {number} The new X position of this object. + * @param y {number} The new Y position of this object. + */ + function reset(sprite, x, y) { + sprite.revive(); + sprite.body.touching = Phaser.Types.NONE; + sprite.body.wasTouching = Phaser.Types.NONE; + sprite.x = x; + sprite.y = y; + sprite.body.velocity.x = 0; + sprite.body.velocity.y = 0; + sprite.body.position.x = x; + sprite.body.position.y = y; + }; + SpriteUtils.setOriginToCenter = function setOriginToCenter(sprite, fromFrameBounds, fromBody) { + if (typeof fromFrameBounds === "undefined") { fromFrameBounds = true; } + if (typeof fromBody === "undefined") { fromBody = false; } + if(fromFrameBounds) { + sprite.transform.origin.setTo(sprite.width / 2, sprite.height / 2); + } else if(fromBody) { + sprite.transform.origin.setTo(sprite.body.bounds.halfWidth, sprite.body.bounds.halfHeight); + } + }; + SpriteUtils.setBounds = /** + * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere + * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) + * it can be stopped from leaving the world, or a section of it. + * + * @param x {number} x position of the bound + * @param y {number} y position of the bound + * @param width {number} width of its bound + * @param height {number} height of its bound + */ + function setBounds(x, y, width, height) { + //this.worldBounds = new Quad(x, y, width, height); + }; + return SpriteUtils; + })(); + Phaser.SpriteUtils = SpriteUtils; + /** + * This function creates a flat colored square image dynamically. + * @param width {number} The width of the sprite you want to generate. + * @param height {number} The height of the sprite you want to generate. + * @param [color] {number} specifies the color of the generated block. (format is 0xAARRGGBB) + * @return {Sprite} Sprite instance itself. + */ + /* + static makeGraphic(width: number, height: number, color: string = 'rgb(255,255,255)'): Sprite { + + this._texture = null; + this.width = width; + this.height = height; + this.fillColor = color; + this._dynamicTexture = false; + + return this; + } + */ + })(Phaser || (Phaser = {})); +var Phaser; +(function (Phaser) { + /// + /// + /// + /** + * Phaser - Components - Texture + * + * The Texture being used to render the object (Sprite, Group background, etc). Either Image based on a DynamicTexture. + */ + (function (Components) { + var Texture = (function () { + /** + * Creates a new Texture component + * @param parent The object using this Texture to render. + * @param key An optional Game.Cache key to load an image from + */ + function Texture(parent) { + /** + * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. + */ + this.imageTexture = null; + /** + * Reference to the DynamicTexture that is used as the texture for the Sprite. + * @type {DynamicTexture} + */ + this.dynamicTexture = null; + /** + * The load status of the texture image. + * @type {boolean} + */ + this.loaded = false; + /** + * Whether the Sprite background is opaque or not. If set to true the Sprite is filled with + * the value of Texture.backgroundColor every frame. Normally you wouldn't enable this but + * for some effects it can be handy. + * @type {boolean} + */ + this.opaque = false; + /** + * The Background Color of the Sprite if Texture.opaque is set to true. + * Given in css color string format, i.e. 'rgb(0,0,0)' or '#ff0000'. + * @type {string} + */ + this.backgroundColor = 'rgb(255,255,255)'; + /** + * You can set a globalCompositeOperation that will be applied before the render method is called on this Sprite. + * This is useful if you wish to apply an effect like 'lighten'. + * If this value is set it will call a canvas context save and restore before and after the render pass, so use it sparingly. + * Set to null to disable. + */ + this.globalCompositeOperation = null; + /** + * Controls if the Sprite is rendered rotated or not. + * If renderRotation is false then the object can still rotate but it will never be rendered rotated. + * @type {boolean} + */ + this.renderRotation = true; + /** + * Flip the graphic horizontally (defaults to false) + * @type {boolean} + */ + this.flippedX = false; + /** + * Flip the graphic vertically (defaults to false) + * @type {boolean} + */ + this.flippedY = false; + /** + * Is the texture a DynamicTexture? + * @type {boolean} + */ + this.isDynamic = false; + this.game = parent.game; + this.parent = parent; + this.canvas = parent.game.stage.canvas; + this.context = parent.game.stage.context; + this.alpha = 1; + this.flippedX = false; + this.flippedY = false; + this._width = 16; + this._height = 16; + this.cameraBlacklist = []; + } + Texture.prototype.setTo = /** + * Updates the texture being used to render the Sprite. + * Called automatically by SpriteUtils.loadTexture and SpriteUtils.loadDynamicTexture. + */ + function (image, dynamic) { + if (typeof image === "undefined") { image = null; } + if (typeof dynamic === "undefined") { dynamic = null; } + if(dynamic) { + this.isDynamic = true; + this.dynamicTexture = dynamic; + this.texture = this.dynamicTexture.canvas; + } else { + this.isDynamic = false; + this.imageTexture = image; + this.texture = this.imageTexture; + this._width = image.width; + this._height = image.height; + } + this.loaded = true; + return this.parent; + }; + Texture.prototype.loadImage = /** + * Sets a new graphic from the game cache to use as the texture for this Sprite. + * The graphic can be SpriteSheet or Texture Atlas. If you need to use a DynamicTexture see loadDynamicTexture. + * @param key {string} Key of the graphic you want to load for this sprite. + * @param clearAnimations {boolean} If this Sprite has a set of animation data already loaded you can choose to keep or clear it with this boolean + * @param updateBody {boolean} Update the physics body dimensions to match the newly loaded texture/frame? + */ + function (key, clearAnimations, updateBody) { + if (typeof clearAnimations === "undefined") { clearAnimations = true; } + if (typeof updateBody === "undefined") { updateBody = true; } + if(clearAnimations && this.parent['animations'] && this.parent['animations'].frameData !== null) { + this.parent.animations.destroy(); + } + if(this.game.cache.getImage(key) !== null) { + this.setTo(this.game.cache.getImage(key), null); + this.cacheKey = key; + if(this.game.cache.isSpriteSheet(key) && this.parent['animations']) { + this.parent.animations.loadFrameData(this.parent.game.cache.getFrameData(key)); + } else { + if(updateBody && this.parent['body']) { + this.parent.body.bounds.width = this.width; + this.parent.body.bounds.height = this.height; + } + } + } + }; + Texture.prototype.loadDynamicTexture = /** + * Load a DynamicTexture as its texture. + * @param texture {DynamicTexture} The texture object to be used by this sprite. + */ + function (texture) { + if(this.parent.animations.frameData !== null) { + this.parent.animations.destroy(); + } + this.setTo(null, texture); + this.parent.texture.width = this.width; + this.parent.texture.height = this.height; + }; + Object.defineProperty(Texture.prototype, "width", { + get: /** + * The width of the texture. If an animation it will be the frame width, not the width of the sprite sheet. + * If using a DynamicTexture it will be the width of the dynamic texture itself. + * @type {number} + */ + function () { + if(this.isDynamic) { + return this.dynamicTexture.width; + } else { + return this._width; + } + }, + set: function (value) { + this._width = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Texture.prototype, "height", { + get: /** + * The height of the texture. If an animation it will be the frame height, not the height of the sprite sheet. + * If using a DynamicTexture it will be the height of the dynamic texture itself. + * @type {number} + */ + function () { + if(this.isDynamic) { + return this.dynamicTexture.height; + } else { + return this._height; + } + }, + set: function (value) { + this._height = value; + }, + enumerable: true, + configurable: true + }); + return Texture; + })(); + Components.Texture = Texture; + })(Phaser.Components || (Phaser.Components = {})); + var Components = Phaser.Components; +})(Phaser || (Phaser = {})); +/// /// +/// +/// /** * Phaser - Group * @@ -1296,18 +4653,9 @@ var Phaser; */ this.group = null; /** - * You can set a globalCompositeOperation that will be applied before the render method is called on this Groups children. - * This is useful if you wish to apply an effect like 'lighten' to a whole group of children as it saves doing it one-by-one. - * If this value is set it will call a canvas context save and restore before and after the render pass. - * Set to null to disable. + * A boolean representing if the Group has been modified in any way via a scale, rotate, flip or skew. */ - this.globalCompositeOperation = null; - /** - * You can set an alpha value on this Group that will be applied before the render method is called on this Groups children. - * This is useful if you wish to alpha a whole group of children as it saves doing it one-by-one. - * Set to 0 to disable. - */ - this.alpha = 0; + this.modified = false; this.game = game; this.type = Phaser.Types.GROUP; this.exists = true; @@ -1317,8 +4665,10 @@ var Phaser; this._maxSize = maxSize; this._marker = 0; this._sortIndex = null; - this.cameraBlacklist = []; this.ID = this.game.world.getNextGroupID(); + this.transform = new Phaser.Components.Transform(this); + this.texture = new Phaser.Components.Texture(this); + this.texture.opaque = false; } Group.ASCENDING = -1; Group.DESCENDING = 1; @@ -1350,6 +4700,11 @@ var Phaser; * You can also call Object.update directly, which will bypass the active/exists check. */ function () { + if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { + this.modified = true; + } else if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { + this.modified = false; + } this._i = 0; while(this._i < this.length) { this._member = this.members[this._i++]; @@ -1368,14 +4723,7 @@ var Phaser; if(camera.isHidden(this) == true) { return; } - if(this.globalCompositeOperation) { - this.game.stage.context.save(); - this.game.stage.context.globalCompositeOperation = this.globalCompositeOperation; - } - if(this.alpha > 0) { - this._prevAlpha = this.game.stage.context.globalAlpha; - this.game.stage.context.globalAlpha = this.alpha; - } + this.game.renderer.preRenderGroup(camera, this); this._i = 0; while(this._i < this.length) { this._member = this.members[this._i++]; @@ -1387,26 +4735,14 @@ var Phaser; } } } - if(this.alpha > 0) { - this.game.stage.context.globalAlpha = this._prevAlpha; - } - if(this.globalCompositeOperation) { - this.game.stage.context.restore(); - } + this.game.renderer.postRenderGroup(camera, this); }; Group.prototype.directRender = /** * Calls render on all members of this Group regardless of their visible status and also ignores the camera blacklist. * Use this when the Group objects render to hidden canvases for example. */ function (camera) { - if(this.globalCompositeOperation) { - this.game.stage.context.save(); - this.game.stage.context.globalCompositeOperation = this.globalCompositeOperation; - } - if(this.alpha > 0) { - this._prevAlpha = this.game.stage.context.globalAlpha; - this.game.stage.context.globalAlpha = this.alpha; - } + this.game.renderer.preRenderGroup(camera, this); this._i = 0; while(this._i < this.length) { this._member = this.members[this._i++]; @@ -1418,12 +4754,7 @@ var Phaser; } } } - if(this.alpha > 0) { - this.game.stage.context.globalAlpha = this._prevAlpha; - } - if(this.globalCompositeOperation) { - this.game.stage.context.restore(); - } + this.game.renderer.postRenderGroup(camera, this); }; Object.defineProperty(Group.prototype, "maxSize", { get: /** @@ -1514,13 +4845,15 @@ var Phaser; * @param x {number} X position of the new sprite. * @param y {number} Y position of the new sprite. * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this sprite + * @param [frame] {string|number} If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name. * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) * @returns {Sprite} The newly created sprite object. */ - function (x, y, key, bodyType) { + function (x, y, key, frame, bodyType) { if (typeof key === "undefined") { key = ''; } + if (typeof frame === "undefined") { frame = null; } if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } - return this.add(new Phaser.Sprite(this.game, x, y, key, bodyType)); + return this.add(new Phaser.Sprite(this.game, x, y, key, frame, bodyType)); }; Group.prototype.setObjectIDs = /** * Sets all of the game object properties needed to exist within this Group. @@ -1655,7 +4988,7 @@ var Phaser; * State.update() override. To sort all existing objects after * a big explosion or bomb attack, you might call myGroup.sort("exists",Group.DESCENDING). * - * @param {string} index The string name of the member variable you want to sort on. Default value is "y". + * @param {string} index The string name of the member variable you want to sort on. Default value is "z". * @param {number} order A Group constant that defines the sort order. Possible values are Group.ASCENDING and Group.DESCENDING. Default value is Group.ASCENDING. */ function (index, order) { @@ -2422,7 +5755,7 @@ var Phaser; url: textureURL, data: null, atlasURL: null, - atlasData: atlasData['frames'], + atlasData: atlasData, format: format, error: false, loaded: false @@ -3261,7 +6594,7 @@ var Phaser; return Math.atan2(y2 - y1, x2 - x1); }; GameMath.prototype.normalizeAngle = /** - * set an angle with in the bounds of -PI to PI + * set an angle within the bounds of -PI to PI */ function (angle, radians) { if (typeof radians === "undefined") { radians = true; } @@ -3835,27 +7168,27 @@ var Phaser; return Math.sqrt(dx * dx + dy * dy); }; GameMath.prototype.rotatePoint = /** - * Rotates the point around the x/y coordinates given to the desired angle and distance + * Rotates the point around the x/y coordinates given to the desired rotation and distance * @param point {Object} Any object with exposed x and y properties * @param x {number} The x coordinate of the anchor point * @param y {number} The y coordinate of the anchor point - * @param {Number} angle The angle in radians (unless asDegrees is true) to return the point from. - * @param {Boolean} asDegrees Is the given angle in radians (false) or degrees (true)? + * @param {Number} rotation The rotation in radians (unless asDegrees is true) to return the point from. + * @param {Boolean} asDegrees Is the given rotation in radians (false) or degrees (true)? * @param {Number} distance An optional distance constraint between the point and the anchor * @return The modified point object */ - function (point, x1, y1, angle, asDegrees, distance) { + function (point, x1, y1, rotation, asDegrees, distance) { if (typeof asDegrees === "undefined") { asDegrees = false; } if (typeof distance === "undefined") { distance = null; } if(asDegrees) { - angle = angle * GameMath.DEG_TO_RAD; + rotation = rotation * GameMath.DEG_TO_RAD; } // Get distance from origin to the point if(distance === null) { distance = Math.sqrt(((x1 - point.x) * (x1 - point.x)) + ((y1 - point.y) * (y1 - point.y))); } - point.x = x1 + distance * Math.cos(angle); - point.y = y1 + distance * Math.sin(angle); + point.x = x1 + distance * Math.cos(rotation); + point.y = y1 + distance * Math.sin(rotation); return point; }; return GameMath; @@ -4089,3278 +7422,6 @@ var Phaser; })(); Phaser.RandomDataGenerator = RandomDataGenerator; })(Phaser || (Phaser = {})); -/// -/** -* Phaser - AnimationLoader -* -* Responsible for parsing sprite sheet and JSON data into the internal FrameData format that Phaser uses for animations. -*/ -var Phaser; -(function (Phaser) { - var AnimationLoader = (function () { - function AnimationLoader() { } - AnimationLoader.parseSpriteSheet = /** - * Parse a sprite sheet from asset data. - * @param key {string} Asset key for the sprite sheet data. - * @param frameWidth {number} Width of animation frame. - * @param frameHeight {number} Height of animation frame. - * @param frameMax {number} Number of animation frames. - * @return {FrameData} Generated FrameData object. - */ - function parseSpriteSheet(game, key, frameWidth, frameHeight, frameMax) { - // How big is our image? - var img = game.cache.getImage(key); - if(img == null) { - return null; - } - var width = img.width; - var height = img.height; - var row = Math.round(width / frameWidth); - var column = Math.round(height / frameHeight); - var total = row * column; - if(frameMax !== -1) { - total = frameMax; - } - // Zero or smaller than frame sizes? - if(width == 0 || height == 0 || width < frameWidth || height < frameHeight || total === 0) { - return null; - } - // Let's create some frames then - var data = new Phaser.FrameData(); - var x = 0; - var y = 0; - for(var i = 0; i < total; i++) { - data.addFrame(new Phaser.Frame(x, y, frameWidth, frameHeight, '')); - x += frameWidth; - if(x === width) { - x = 0; - y += frameHeight; - } - } - return data; - }; - AnimationLoader.parseJSONData = /** - * Parse frame datas from json. - * @param json {object} Json data you want to parse. - * @return {FrameData} Generated FrameData object. - */ - function parseJSONData(game, json) { - // Malformed? - if(!json['frames']) { - throw new Error("Phaser.AnimationLoader.parseJSONData: Invalid Texture Atlas JSON given, missing 'frames' array"); - } - // Let's create some frames then - var data = new Phaser.FrameData(); - // By this stage frames is a fully parsed array - var frames = json['frames']; - var newFrame; - for(var i = 0; i < frames.length; i++) { - newFrame = data.addFrame(new Phaser.Frame(frames[i].frame.x, frames[i].frame.y, frames[i].frame.w, frames[i].frame.h, frames[i].filename)); - newFrame.setTrim(frames[i].trimmed, frames[i].sourceSize.w, frames[i].sourceSize.h, frames[i].spriteSourceSize.x, frames[i].spriteSourceSize.y, frames[i].spriteSourceSize.w, frames[i].spriteSourceSize.h); - } - return data; - }; - AnimationLoader.parseXMLData = function parseXMLData(game, xml, format) { - // Malformed? - if(!xml.getElementsByTagName('TextureAtlas')) { - throw new Error("Phaser.AnimationLoader.parseXMLData: Invalid Texture Atlas XML given, missing tag"); - } - // Let's create some frames then - var data = new Phaser.FrameData(); - var frames = xml.getElementsByTagName('SubTexture'); - var newFrame; - for(var i = 0; i < frames.length; i++) { - var frame = frames[i].attributes; - newFrame = data.addFrame(new Phaser.Frame(frame.x.nodeValue, frame.y.nodeValue, frame.width.nodeValue, frame.height.nodeValue, frame.name.nodeValue)); - // Trimmed? - if(frame.frameX.nodeValue != '-0' || frame.frameY.nodeValue != '-0') { - newFrame.setTrim(true, frame.width.nodeValue, frame.height.nodeValue, Math.abs(frame.frameX.nodeValue), Math.abs(frame.frameY.nodeValue), frame.frameWidth.nodeValue, frame.frameHeight.nodeValue); - } - } - return data; - }; - return AnimationLoader; - })(); - Phaser.AnimationLoader = AnimationLoader; -})(Phaser || (Phaser = {})); -/// -/** -* Phaser - Animation -* -* An Animation is a single animation. It is created by the AnimationManager and belongs to Sprite objects. -*/ -var Phaser; -(function (Phaser) { - var Animation = (function () { - /** - * Animation constructor - * Create a new Animation. - * - * @param parent {Sprite} Owner sprite of this animation. - * @param frameData {FrameData} The FrameData object contains animation data. - * @param name {string} Unique name of this animation. - * @param frames {number[]/string[]} An array of numbers or strings indicating what frames to play in what order. - * @param delay {number} Time between frames in ms. - * @param looped {boolean} Whether or not the animation is looped or just plays once. - */ - function Animation(game, parent, frameData, name, frames, delay, looped) { - this._game = game; - this._parent = parent; - this._frames = frames; - this._frameData = frameData; - this.name = name; - this.delay = 1000 / delay; - this.looped = looped; - this.isFinished = false; - this.isPlaying = false; - this._frameIndex = 0; - this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); - } - Object.defineProperty(Animation.prototype, "frameTotal", { - get: function () { - return this._frames.length; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Animation.prototype, "frame", { - get: function () { - if(this.currentFrame !== null) { - return this.currentFrame.index; - } else { - return this._frameIndex; - } - }, - set: function (value) { - this.currentFrame = this._frameData.getFrame(value); - if(this.currentFrame !== null) { - this._parent.frameBounds.width = this.currentFrame.width; - this._parent.frameBounds.height = this.currentFrame.height; - this._frameIndex = value; - } - }, - enumerable: true, - configurable: true - }); - Animation.prototype.play = /** - * Play this animation. - * @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 (frameRate, loop) { - if (typeof frameRate === "undefined") { frameRate = null; } - if(frameRate !== null) { - this.delay = 1000 / frameRate; - } - if(loop !== undefined) { - this.looped = loop; - } - this.isPlaying = true; - this.isFinished = false; - this._timeLastFrame = this._game.time.now; - this._timeNextFrame = this._game.time.now + this.delay; - this._frameIndex = 0; - this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); - }; - Animation.prototype.restart = /** - * Play this animation from the first frame. - */ - function () { - this.isPlaying = true; - this.isFinished = false; - this._timeLastFrame = this._game.time.now; - this._timeNextFrame = this._game.time.now + this.delay; - this._frameIndex = 0; - this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); - }; - Animation.prototype.stop = /** - * Stop playing animation and set it finished. - */ - function () { - this.isPlaying = false; - this.isFinished = true; - }; - Animation.prototype.update = /** - * Update animation frames. - */ - function () { - if(this.isPlaying == true && this._game.time.now >= this._timeNextFrame) { - this._frameIndex++; - if(this._frameIndex == this._frames.length) { - if(this.looped) { - this._frameIndex = 0; - this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); - } else { - this.onComplete(); - } - } else { - this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); - } - this._timeLastFrame = this._game.time.now; - this._timeNextFrame = this._game.time.now + this.delay; - return true; - } - return false; - }; - Animation.prototype.destroy = /** - * Clean up animation memory. - */ - function () { - this._game = null; - this._parent = null; - this._frames = null; - this._frameData = null; - this.currentFrame = null; - this.isPlaying = false; - }; - Animation.prototype.onComplete = /** - * Animation complete callback method. - */ - function () { - this.isPlaying = false; - this.isFinished = true; - // callback goes here - }; - return Animation; - })(); - Phaser.Animation = Animation; -})(Phaser || (Phaser = {})); -/// -/** -* Phaser - Frame -* -* A Frame is a single frame of an animation and is part of a FrameData collection. -*/ -var Phaser; -(function (Phaser) { - var Frame = (function () { - /** - * Frame constructor - * Create a new Frame with specific position, size and name. - * - * @param x {number} X position within the image to cut from. - * @param y {number} Y position within the image to cut from. - * @param width {number} Width of the frame. - * @param height {number} Height of the frame. - * @param name {string} Name of this frame. - */ - function Frame(x, y, width, height, name) { - /** - * Useful for Texture Atlas files. (is set to the filename value) - */ - this.name = ''; - /** - * Rotated? (not yet implemented) - */ - this.rotated = false; - /** - * Either cw or ccw, rotation is always 90 degrees. - */ - this.rotationDirection = 'cw'; - //console.log('Creating Frame', name, 'x', x, 'y', y, 'width', width, 'height', height); - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.name = name; - this.rotated = false; - this.trimmed = false; - } - Frame.prototype.setRotation = /** - * Set rotation of this frame. (Not yet supported!) - */ - function (rotated, rotationDirection) { - // Not yet supported - }; - Frame.prototype.setTrim = /** - * Set trim of the frame. - * @param trimmed {boolean} Whether this frame trimmed or not. - * @param actualWidth {number} Actual width of this frame. - * @param actualHeight {number} Actual height of this frame. - * @param destX {number} Destination x position. - * @param destY {number} Destination y position. - * @param destWidth {number} Destination draw width. - * @param destHeight {number} Destination draw height. - */ - function (trimmed, actualWidth, actualHeight, destX, destY, destWidth, destHeight) { - this.trimmed = trimmed; - this.sourceSizeW = actualWidth; - this.sourceSizeH = actualHeight; - this.spriteSourceSizeX = destX; - this.spriteSourceSizeY = destY; - this.spriteSourceSizeW = destWidth; - this.spriteSourceSizeH = destHeight; - }; - return Frame; - })(); - Phaser.Frame = Frame; -})(Phaser || (Phaser = {})); -/// -/** -* Phaser - FrameData -* -* FrameData is a container for Frame objects, the internal representation of animation data in Phaser. -*/ -var Phaser; -(function (Phaser) { - var FrameData = (function () { - /** - * FrameData constructor - */ - function FrameData() { - this._frames = []; - this._frameNames = []; - } - Object.defineProperty(FrameData.prototype, "total", { - get: function () { - return this._frames.length; - }, - enumerable: true, - configurable: true - }); - FrameData.prototype.addFrame = /** - * Add a new frame. - * @param frame {Frame} The frame you want to add. - * @return {Frame} The frame you just added. - */ - function (frame) { - frame.index = this._frames.length; - this._frames.push(frame); - if(frame.name !== '') { - this._frameNames[frame.name] = frame.index; - } - return frame; - }; - FrameData.prototype.getFrame = /** - * Get a frame by its index. - * @param index {number} Index of the frame you want to get. - * @return {Frame} The frame you want. - */ - function (index) { - if(this._frames[index]) { - return this._frames[index]; - } - return null; - }; - FrameData.prototype.getFrameByName = /** - * Get a frame by its name. - * @param name {string} Name of the frame you want to get. - * @return {Frame} The frame you want. - */ - function (name) { - if(this._frameNames[name] !== '') { - return this._frames[this._frameNames[name]]; - } - return null; - }; - FrameData.prototype.checkFrameName = /** - * Check whether there's a frame with given name. - * @param name {string} Name of the frame you want to check. - * @return {boolean} True if frame with given name found, otherwise return false. - */ - function (name) { - if(this._frameNames[name]) { - return true; - } - return false; - }; - FrameData.prototype.getFrameRange = /** - * Get ranges of frames in an array. - * @param start {number} Start index of frames you want. - * @param end {number} End index of frames you want. - * @param [output] {Frame[]} result will be added into this array. - * @return {Frame[]} Ranges of specific frames in an array. - */ - function (start, end, output) { - if (typeof output === "undefined") { output = []; } - for(var i = start; i <= end; i++) { - output.push(this._frames[i]); - } - return output; - }; - FrameData.prototype.getFrameIndexes = /** - * Get all indexes of frames by giving their name. - * @param [output] {number[]} result will be added into this array. - * @return {number[]} Indexes of specific frames in an array. - */ - function (output) { - if (typeof output === "undefined") { output = []; } - output.length = 0; - for(var i = 0; i < this._frames.length; i++) { - output.push(i); - } - return output; - }; - FrameData.prototype.getFrameIndexesByName = /** - * Get the frame indexes by giving the frame names. - * @param [output] {number[]} result will be added into this array. - * @return {number[]} Names of specific frames in an array. - */ - function (input) { - var output = []; - for(var i = 0; i < input.length; i++) { - if(this.getFrameByName(input[i])) { - output.push(this.getFrameByName(input[i]).index); - } - } - return output; - }; - FrameData.prototype.getAllFrames = /** - * Get all frames in this frame data. - * @return {Frame[]} All the frames in an array. - */ - function () { - return this._frames; - }; - FrameData.prototype.getFrames = /** - * Get All frames with specific ranges. - * @param range {number[]} Ranges in an array. - * @return {Frame[]} All frames in an array. - */ - function (range) { - var output = []; - for(var i = 0; i < range.length; i++) { - output.push(this._frames[i]); - } - return output; - }; - return FrameData; - })(); - Phaser.FrameData = FrameData; -})(Phaser || (Phaser = {})); -var Phaser; -(function (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. - */ - (function (Components) { - var AnimationManager = (function () { - /** - * AnimationManager constructor - * Create a new AnimationManager. - * - * @param parent {Sprite} Owner sprite of this manager. - */ - 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 = { - }; - } - 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(frames == null) { - frames = this._frameData.getFrameIndexes(); - } else { - if(this.validateFrames(frames, useNumericIndex) == false) { - throw Error('Invalid frames given to Animation ' + name); - 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; - } - } 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); - } - } - }; - 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._parent.frameBounds.width = this.currentFrame.sourceSizeW; - //this._parent.frameBounds.height = this.currentFrame.sourceSizeH; - 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 = {})); -/// -/// -/// -/** -* Phaser - RectangleUtils -* -* A collection of methods useful for manipulating and comparing Rectangle objects. -* -* TODO: Check docs + overlap + intersect + toPolygon? -*/ -var Phaser; -(function (Phaser) { - var RectangleUtils = (function () { - function RectangleUtils() { } - RectangleUtils.getTopLeftAsPoint = /** - * Get the location of the Rectangles top-left corner as a Point object. - * @method getTopLeftAsPoint - * @param {Rectangle} a - The Rectangle object. - * @param {Point} out - Optional Point to store the value in, if not supplied a new Point object will be created. - * @return {Point} The new Point object. - **/ - function getTopLeftAsPoint(a, out) { - if (typeof out === "undefined") { out = new Phaser.Point(); } - return out.setTo(a.x, a.y); - }; - RectangleUtils.getBottomRightAsPoint = /** - * Get the location of the Rectangles bottom-right corner as a Point object. - * @method getTopLeftAsPoint - * @param {Rectangle} a - The Rectangle object. - * @param {Point} out - Optional Point to store the value in, if not supplied a new Point object will be created. - * @return {Point} The new Point object. - **/ - function getBottomRightAsPoint(a, out) { - if (typeof out === "undefined") { out = new Phaser.Point(); } - return out.setTo(a.right, a.bottom); - }; - RectangleUtils.inflate = /** - * Increases the size of the Rectangle object by the specified amounts. The center point of the Rectangle object stays the same, and its size increases to the left and right by the dx value, and to the top and the bottom by the dy value. - * @method inflate - * @param {Rectangle} a - The Rectangle object. - * @param {Number} dx The amount to be added to the left side of the Rectangle. - * @param {Number} dy The amount to be added to the bottom side of the Rectangle. - * @return {Rectangle} This Rectangle object. - **/ - function inflate(a, dx, dy) { - a.x -= dx; - a.width += 2 * dx; - a.y -= dy; - a.height += 2 * dy; - return a; - }; - RectangleUtils.inflatePoint = /** - * Increases the size of the Rectangle object. This method is similar to the Rectangle.inflate() method except it takes a Point object as a parameter. - * @method inflatePoint - * @param {Rectangle} a - The Rectangle object. - * @param {Point} point The x property of this Point object is used to increase the horizontal dimension of the Rectangle object. The y property is used to increase the vertical dimension of the Rectangle object. - * @return {Rectangle} The Rectangle object. - **/ - function inflatePoint(a, point) { - return RectangleUtils.inflate(a, point.x, point.y); - }; - RectangleUtils.size = /** - * The size of the Rectangle object, expressed as a Point object with the values of the width and height properties. - * @method size - * @param {Rectangle} a - The Rectangle object. - * @param {Point} output Optional Point object. If given the values will be set into the object, otherwise a brand new Point object will be created and returned. - * @return {Point} The size of the Rectangle object - **/ - function size(a, output) { - if (typeof output === "undefined") { output = new Phaser.Point(); } - return output.setTo(a.width, a.height); - }; - RectangleUtils.clone = /** - * Returns a new Rectangle object with the same values for the x, y, width, and height properties as the original Rectangle object. - * @method clone - * @param {Rectangle} a - The Rectangle object. - * @param {Rectangle} output Optional Rectangle object. If given the values will be set into the object, otherwise a brand new Rectangle object will be created and returned. - * @return {Rectangle} - **/ - function clone(a, output) { - if (typeof output === "undefined") { output = new Phaser.Rectangle(); } - return output.setTo(a.x, a.y, a.width, a.height); - }; - RectangleUtils.contains = /** - * Determines whether the specified coordinates are contained within the region defined by this Rectangle object. - * @method contains - * @param {Rectangle} a - The Rectangle object. - * @param {Number} x The x coordinate of the point to test. - * @param {Number} y The y coordinate of the point to test. - * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. - **/ - function contains(a, x, y) { - return (x >= a.x && x <= a.right && y >= a.y && y <= a.bottom); - }; - RectangleUtils.containsPoint = /** - * Determines whether the specified point is contained within the rectangular region defined by this Rectangle object. This method is similar to the Rectangle.contains() method, except that it takes a Point object as a parameter. - * @method containsPoint - * @param {Rectangle} a - The Rectangle object. - * @param {Point} point The point object being checked. Can be Point or any object with .x and .y values. - * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. - **/ - function containsPoint(a, point) { - return RectangleUtils.contains(a, point.x, point.y); - }; - RectangleUtils.containsRect = /** - * Determines whether the first Rectangle object is fully contained within the second Rectangle object. - * A Rectangle object is said to contain another if the second Rectangle object falls entirely within the boundaries of the first. - * @method containsRect - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. - **/ - function containsRect(a, b) { - // If the given rect has a larger volume than this one then it can never contain it - if(a.volume > b.volume) { - return false; - } - return (a.x >= b.x && a.y >= b.y && a.right <= b.right && a.bottom <= b.bottom); - }; - RectangleUtils.equals = /** - * Determines whether the two Rectangles are equal. - * This method compares the x, y, width and height properties of each Rectangle. - * @method equals - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @return {Boolean} A value of true if the two Rectangles have exactly the same values for the x, y, width and height properties; otherwise false. - **/ - function equals(a, b) { - return (a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height); - }; - RectangleUtils.intersection = /** - * If the Rectangle object specified in the toIntersect parameter intersects with this Rectangle object, returns the area of intersection as a Rectangle object. If the rectangles do not intersect, this method returns an empty Rectangle object with its properties set to 0. - * @method intersection - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @param {Rectangle} output Optional Rectangle object. If given the intersection values will be set into this object, otherwise a brand new Rectangle object will be created and returned. - * @return {Rectangle} A Rectangle object that equals the area of intersection. If the rectangles do not intersect, this method returns an empty Rectangle object; that is, a rectangle with its x, y, width, and height properties set to 0. - **/ - function intersection(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Rectangle(); } - if(RectangleUtils.intersects(a, b)) { - out.x = Math.max(a.x, b.x); - out.y = Math.max(a.y, b.y); - out.width = Math.min(a.right, b.right) - out.x; - out.height = Math.min(a.bottom, b.bottom) - out.y; - } - return out; - }; - RectangleUtils.intersects = /** - * Determines whether the two Rectangles intersect with each other. - * This method checks the x, y, width, and height properties of the Rectangles. - * @method intersects - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @param {Number} tolerance A tolerance value to allow for an intersection test with padding, default to 0 - * @return {Boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false. - **/ - function intersects(a, b, tolerance) { - if (typeof tolerance === "undefined") { tolerance = 0; } - return !(a.left > b.right + tolerance || a.right < b.left - tolerance || a.top > b.bottom + tolerance || a.bottom < b.top - tolerance); - }; - RectangleUtils.intersectsRaw = /** - * Determines whether the object specified intersects (overlaps) with the given values. - * @method intersectsRaw - * @param {Number} left - * @param {Number} right - * @param {Number} top - * @param {Number} bottomt - * @param {Number} tolerance A tolerance value to allow for an intersection test with padding, default to 0 - * @return {Boolean} A value of true if the specified object intersects with the Rectangle; otherwise false. - **/ - function intersectsRaw(a, left, right, top, bottom, tolerance) { - if (typeof tolerance === "undefined") { tolerance = 0; } - return !(left > a.right + tolerance || right < a.left - tolerance || top > a.bottom + tolerance || bottom < a.top - tolerance); - }; - RectangleUtils.union = /** - * Adds two rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two rectangles. - * @method union - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @param {Rectangle} output Optional Rectangle object. If given the new values will be set into this object, otherwise a brand new Rectangle object will be created and returned. - * @return {Rectangle} A Rectangle object that is the union of the two rectangles. - **/ - function union(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Rectangle(); } - return out.setTo(Math.min(a.x, b.x), Math.min(a.y, b.y), Math.max(a.right, b.right), Math.max(a.bottom, b.bottom)); - }; - return RectangleUtils; - })(); - Phaser.RectangleUtils = RectangleUtils; -})(Phaser || (Phaser = {})); -/// -/// -/// -/// -/** -* Phaser - ColorUtils -* -* A collection of methods useful for manipulating color values. -*/ -var Phaser; -(function (Phaser) { - var ColorUtils = (function () { - function ColorUtils() { } - ColorUtils.getColor32 = /** - * Given an alpha and 3 color values this will return an integer representation of it - * - * @param alpha {number} The Alpha value (between 0 and 255) - * @param red {number} The Red channel value (between 0 and 255) - * @param green {number} The Green channel value (between 0 and 255) - * @param blue {number} The Blue channel value (between 0 and 255) - * - * @return A native color value integer (format: 0xAARRGGBB) - */ - function getColor32(alpha, red, green, blue) { - return alpha << 24 | red << 16 | green << 8 | blue; - }; - ColorUtils.getColor = /** - * Given 3 color values this will return an integer representation of it - * - * @param red {number} The Red channel value (between 0 and 255) - * @param green {number} The Green channel value (between 0 and 255) - * @param blue {number} The Blue channel value (between 0 and 255) - * - * @return A native color value integer (format: 0xRRGGBB) - */ - function getColor(red, green, blue) { - return red << 16 | green << 8 | blue; - }; - ColorUtils.getHSVColorWheel = /** - * Get HSV color wheel values in an array which will be 360 elements in size - * - * @param alpha Alpha value for each color of the color wheel, between 0 (transparent) and 255 (opaque) - * - * @return Array - */ - function getHSVColorWheel(alpha) { - if (typeof alpha === "undefined") { alpha = 255; } - var colors = []; - for(var c = 0; c <= 359; c++) { - //colors[c] = HSVtoRGB(c, 1.0, 1.0, alpha); - colors[c] = ColorUtils.getWebRGB(ColorUtils.HSVtoRGB(c, 1.0, 1.0, alpha)); - } - return colors; - }; - ColorUtils.getComplementHarmony = /** - * Returns a Complementary Color Harmony for the given color. - *

A complementary hue is one directly opposite the color given on the color wheel

- *

Value returned in 0xAARRGGBB format with Alpha set to 255.

- * - * @param color The color to base the harmony on - * - * @return 0xAARRGGBB format color value - */ - function getComplementHarmony(color) { - var hsv = ColorUtils.RGBtoHSV(color); - var opposite = ColorUtils.game.math.wrapValue(hsv.hue, 180, 359); - return ColorUtils.HSVtoRGB(opposite, 1.0, 1.0); - }; - ColorUtils.getAnalogousHarmony = /** - * Returns an Analogous Color Harmony for the given color. - *

An Analogous harmony are hues adjacent to each other on the color wheel

- *

Values returned in 0xAARRGGBB format with Alpha set to 255.

- * - * @param color The color to base the harmony on - * @param threshold Control how adjacent the colors will be (default +- 30 degrees) - * - * @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color) - */ - function getAnalogousHarmony(color, threshold) { - if (typeof threshold === "undefined") { threshold = 30; } - var hsv = ColorUtils.RGBtoHSV(color); - if(threshold > 359 || threshold < 0) { - throw Error("Color Warning: Invalid threshold given to getAnalogousHarmony()"); - } - var warmer = ColorUtils.game.math.wrapValue(hsv.hue, 359 - threshold, 359); - var colder = ColorUtils.game.math.wrapValue(hsv.hue, threshold, 359); - return { - color1: color, - color2: ColorUtils.HSVtoRGB(warmer, 1.0, 1.0), - color3: ColorUtils.HSVtoRGB(colder, 1.0, 1.0), - hue1: hsv.hue, - hue2: warmer, - hue3: colder - }; - }; - ColorUtils.getSplitComplementHarmony = /** - * Returns an Split Complement Color Harmony for the given color. - *

A Split Complement harmony are the two hues on either side of the color's Complement

- *

Values returned in 0xAARRGGBB format with Alpha set to 255.

- * - * @param color The color to base the harmony on - * @param threshold Control how adjacent the colors will be to the Complement (default +- 30 degrees) - * - * @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color) - */ - function getSplitComplementHarmony(color, threshold) { - if (typeof threshold === "undefined") { threshold = 30; } - var hsv = ColorUtils.RGBtoHSV(color); - if(threshold >= 359 || threshold <= 0) { - throw Error("FlxColor Warning: Invalid threshold given to getSplitComplementHarmony()"); - } - var opposite = ColorUtils.game.math.wrapValue(hsv.hue, 180, 359); - var warmer = ColorUtils.game.math.wrapValue(hsv.hue, opposite - threshold, 359); - var colder = ColorUtils.game.math.wrapValue(hsv.hue, opposite + threshold, 359); - return { - color1: color, - color2: ColorUtils.HSVtoRGB(warmer, hsv.saturation, hsv.value), - color3: ColorUtils.HSVtoRGB(colder, hsv.saturation, hsv.value), - hue1: hsv.hue, - hue2: warmer, - hue3: colder - }; - }; - ColorUtils.getTriadicHarmony = /** - * Returns a Triadic Color Harmony for the given color. - *

A Triadic harmony are 3 hues equidistant from each other on the color wheel

- *

Values returned in 0xAARRGGBB format with Alpha set to 255.

- * - * @param color The color to base the harmony on - * - * @return Object containing 3 properties: color1 (the original color), color2 and color3 (the equidistant colors) - */ - function getTriadicHarmony(color) { - var hsv = ColorUtils.RGBtoHSV(color); - var triadic1 = ColorUtils.game.math.wrapValue(hsv.hue, 120, 359); - var triadic2 = ColorUtils.game.math.wrapValue(triadic1, 120, 359); - return { - color1: color, - color2: ColorUtils.HSVtoRGB(triadic1, 1.0, 1.0), - color3: ColorUtils.HSVtoRGB(triadic2, 1.0, 1.0) - }; - }; - ColorUtils.getColorInfo = /** - * Returns a string containing handy information about the given color including string hex value, - * RGB format information and HSL information. Each section starts on a newline, 3 lines in total. - * - * @param color A color value in the format 0xAARRGGBB - * - * @return string containing the 3 lines of information - */ - function getColorInfo(color) { - var argb = ColorUtils.getRGB(color); - var hsl = ColorUtils.RGBtoHSV(color); - // Hex format - var result = ColorUtils.RGBtoHexstring(color) + "\n"; - // RGB format - result = result.concat("Alpha: " + argb.alpha + " Red: " + argb.red + " Green: " + argb.green + " Blue: " + argb.blue) + "\n"; - // HSL info - result = result.concat("Hue: " + hsl.hue + " Saturation: " + hsl.saturation + " Lightnes: " + hsl.lightness); - return result; - }; - ColorUtils.RGBtoHexstring = /** - * Return a string representation of the color in the format 0xAARRGGBB - * - * @param color The color to get the string representation for - * - * @return A string of length 10 characters in the format 0xAARRGGBB - */ - function RGBtoHexstring(color) { - var argb = ColorUtils.getRGB(color); - return "0x" + ColorUtils.colorToHexstring(argb.alpha) + ColorUtils.colorToHexstring(argb.red) + ColorUtils.colorToHexstring(argb.green) + ColorUtils.colorToHexstring(argb.blue); - }; - ColorUtils.RGBtoWebstring = /** - * Return a string representation of the color in the format #RRGGBB - * - * @param color The color to get the string representation for - * - * @return A string of length 10 characters in the format 0xAARRGGBB - */ - function RGBtoWebstring(color) { - var argb = ColorUtils.getRGB(color); - return "#" + ColorUtils.colorToHexstring(argb.red) + ColorUtils.colorToHexstring(argb.green) + ColorUtils.colorToHexstring(argb.blue); - }; - ColorUtils.colorToHexstring = /** - * Return a string containing a hex representation of the given color - * - * @param color The color channel to get the hex value for, must be a value between 0 and 255) - * - * @return A string of length 2 characters, i.e. 255 = FF, 0 = 00 - */ - function colorToHexstring(color) { - var digits = "0123456789ABCDEF"; - var lsd = color % 16; - var msd = (color - lsd) / 16; - var hexified = digits.charAt(msd) + digits.charAt(lsd); - return hexified; - }; - ColorUtils.HSVtoRGB = /** - * Convert a HSV (hue, saturation, lightness) color space value to an RGB color - * - * @param h Hue degree, between 0 and 359 - * @param s Saturation, between 0.0 (grey) and 1.0 - * @param v Value, between 0.0 (black) and 1.0 - * @param alpha Alpha value to set per color (between 0 and 255) - * - * @return 32-bit ARGB color value (0xAARRGGBB) - */ - function HSVtoRGB(h, s, v, alpha) { - if (typeof alpha === "undefined") { alpha = 255; } - var result; - if(s == 0.0) { - result = ColorUtils.getColor32(alpha, v * 255, v * 255, v * 255); - } else { - h = h / 60.0; - var f = h - Math.floor(h); - var p = v * (1.0 - s); - var q = v * (1.0 - s * f); - var t = v * (1.0 - s * (1.0 - f)); - switch(Math.floor(h)) { - case 0: - result = ColorUtils.getColor32(alpha, v * 255, t * 255, p * 255); - break; - case 1: - result = ColorUtils.getColor32(alpha, q * 255, v * 255, p * 255); - break; - case 2: - result = ColorUtils.getColor32(alpha, p * 255, v * 255, t * 255); - break; - case 3: - result = ColorUtils.getColor32(alpha, p * 255, q * 255, v * 255); - break; - case 4: - result = ColorUtils.getColor32(alpha, t * 255, p * 255, v * 255); - break; - case 5: - result = ColorUtils.getColor32(alpha, v * 255, p * 255, q * 255); - break; - default: - throw new Error("ColorUtils.HSVtoRGB : Unknown color"); - } - } - return result; - }; - ColorUtils.RGBtoHSV = /** - * Convert an RGB color value to an object containing the HSV color space values: Hue, Saturation and Lightness - * - * @param color In format 0xRRGGBB - * - * @return Object with the properties hue (from 0 to 360), saturation (from 0 to 1.0) and lightness (from 0 to 1.0, also available under .value) - */ - function RGBtoHSV(color) { - var rgb = ColorUtils.getRGB(color); - var red = rgb.red / 255; - var green = rgb.green / 255; - var blue = rgb.blue / 255; - var min = Math.min(red, green, blue); - var max = Math.max(red, green, blue); - var delta = max - min; - var lightness = (max + min) / 2; - var hue; - var saturation; - // Grey color, no chroma - if(delta == 0) { - hue = 0; - saturation = 0; - } else { - if(lightness < 0.5) { - saturation = delta / (max + min); - } else { - saturation = delta / (2 - max - min); - } - var delta_r = (((max - red) / 6) + (delta / 2)) / delta; - var delta_g = (((max - green) / 6) + (delta / 2)) / delta; - var delta_b = (((max - blue) / 6) + (delta / 2)) / delta; - if(red == max) { - hue = delta_b - delta_g; - } else if(green == max) { - hue = (1 / 3) + delta_r - delta_b; - } else if(blue == max) { - hue = (2 / 3) + delta_g - delta_r; - } - if(hue < 0) { - hue += 1; - } - if(hue > 1) { - hue -= 1; - } - } - // Keep the value with 0 to 359 - hue *= 360; - hue = Math.round(hue); - return { - hue: hue, - saturation: saturation, - lightness: lightness, - value: lightness - }; - }; - ColorUtils.interpolateColor = /** - * - * @method interpolateColor - * @param {Number} color1 - * @param {Number} color2 - * @param {Number} steps - * @param {Number} currentStep - * @param {Number} alpha - * @return {Number} - * @static - */ - function interpolateColor(color1, color2, steps, currentStep, alpha) { - if (typeof alpha === "undefined") { alpha = 255; } - var src1 = ColorUtils.getRGB(color1); - var src2 = ColorUtils.getRGB(color2); - var r = (((src2.red - src1.red) * currentStep) / steps) + src1.red; - var g = (((src2.green - src1.green) * currentStep) / steps) + src1.green; - var b = (((src2.blue - src1.blue) * currentStep) / steps) + src1.blue; - return ColorUtils.getColor32(alpha, r, g, b); - }; - ColorUtils.interpolateColorWithRGB = /** - * - * @method interpolateColorWithRGB - * @param {Number} color - * @param {Number} r2 - * @param {Number} g2 - * @param {Number} b2 - * @param {Number} steps - * @param {Number} currentStep - * @return {Number} - * @static - */ - function interpolateColorWithRGB(color, r2, g2, b2, steps, currentStep) { - var src = ColorUtils.getRGB(color); - var r = (((r2 - src.red) * currentStep) / steps) + src.red; - var g = (((g2 - src.green) * currentStep) / steps) + src.green; - var b = (((b2 - src.blue) * currentStep) / steps) + src.blue; - return ColorUtils.getColor(r, g, b); - }; - ColorUtils.interpolateRGB = /** - * - * @method interpolateRGB - * @param {Number} r1 - * @param {Number} g1 - * @param {Number} b1 - * @param {Number} r2 - * @param {Number} g2 - * @param {Number} b2 - * @param {Number} steps - * @param {Number} currentStep - * @return {Number} - * @static - */ - function interpolateRGB(r1, g1, b1, r2, g2, b2, steps, currentStep) { - var r = (((r2 - r1) * currentStep) / steps) + r1; - var g = (((g2 - g1) * currentStep) / steps) + g1; - var b = (((b2 - b1) * currentStep) / steps) + b1; - return ColorUtils.getColor(r, g, b); - }; - ColorUtils.getRandomColor = /** - * Returns a random color value between black and white - *

Set the min value to start each channel from the given offset.

- *

Set the max value to restrict the maximum color used per channel

- * - * @param min The lowest value to use for the color - * @param max The highest value to use for the color - * @param alpha The alpha value of the returning color (default 255 = fully opaque) - * - * @return 32-bit color value with alpha - */ - function getRandomColor(min, max, alpha) { - if (typeof min === "undefined") { min = 0; } - if (typeof max === "undefined") { max = 255; } - if (typeof alpha === "undefined") { alpha = 255; } - // Sanity checks - if(max > 255) { - return ColorUtils.getColor(255, 255, 255); - } - if(min > max) { - return ColorUtils.getColor(255, 255, 255); - } - var red = min + Math.round(Math.random() * (max - min)); - var green = min + Math.round(Math.random() * (max - min)); - var blue = min + Math.round(Math.random() * (max - min)); - return ColorUtils.getColor32(alpha, red, green, blue); - }; - ColorUtils.getRGB = /** - * Return the component parts of a color as an Object with the properties alpha, red, green, blue - * - *

Alpha will only be set if it exist in the given color (0xAARRGGBB)

- * - * @param color in RGB (0xRRGGBB) or ARGB format (0xAARRGGBB) - * - * @return Object with properties: alpha, red, green, blue - */ - function getRGB(color) { - return { - alpha: color >>> 24, - red: color >> 16 & 0xFF, - green: color >> 8 & 0xFF, - blue: color & 0xFF - }; - }; - ColorUtils.getWebRGB = /** - * - * @method getWebRGB - * @param {Number} color - * @return {Any} - */ - function getWebRGB(color) { - var alpha = (color >>> 24) / 255; - var red = color >> 16 & 0xFF; - var green = color >> 8 & 0xFF; - var blue = color & 0xFF; - return 'rgba(' + red.toString() + ',' + green.toString() + ',' + blue.toString() + ',' + alpha.toString() + ')'; - }; - ColorUtils.getAlpha = /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component, as a value between 0 and 255 - * - * @param color In the format 0xAARRGGBB - * - * @return The Alpha component of the color, will be between 0 and 255 (0 being no Alpha, 255 full Alpha) - */ - function getAlpha(color) { - return color >>> 24; - }; - ColorUtils.getAlphaFloat = /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component as a value between 0 and 1 - * - * @param color In the format 0xAARRGGBB - * - * @return The Alpha component of the color, will be between 0 and 1 (0 being no Alpha (opaque), 1 full Alpha (transparent)) - */ - function getAlphaFloat(color) { - return (color >>> 24) / 255; - }; - ColorUtils.getRed = /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Red component, as a value between 0 and 255 - * - * @param color In the format 0xAARRGGBB - * - * @return The Red component of the color, will be between 0 and 255 (0 being no color, 255 full Red) - */ - function getRed(color) { - return color >> 16 & 0xFF; - }; - ColorUtils.getGreen = /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Green component, as a value between 0 and 255 - * - * @param color In the format 0xAARRGGBB - * - * @return The Green component of the color, will be between 0 and 255 (0 being no color, 255 full Green) - */ - function getGreen(color) { - return color >> 8 & 0xFF; - }; - ColorUtils.getBlue = /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Blue component, as a value between 0 and 255 - * - * @param color In the format 0xAARRGGBB - * - * @return The Blue component of the color, will be between 0 and 255 (0 being no color, 255 full Blue) - */ - function getBlue(color) { - return color & 0xFF; - }; - return ColorUtils; - })(); - Phaser.ColorUtils = ColorUtils; -})(Phaser || (Phaser = {})); -/// -/// -/// -/// -/** -* Phaser - DynamicTexture -* -* A DynamicTexture can be thought of as a mini canvas into which you can draw anything. -* Game Objects can be assigned a DynamicTexture, so when they render in the world they do so -* based on the contents of the texture at the time. This allows you to create powerful effects -* once and have them replicated across as many game objects as you like. -*/ -var Phaser; -(function (Phaser) { - var DynamicTexture = (function () { - /** - * DynamicTexture constructor - * Create a new DynamicTexture. - * - * @param game {Phaser.Game} Current game instance. - * @param width {number} Init width of this texture. - * @param height {number} Init height of this texture. - */ - function DynamicTexture(game, width, height) { - this._sx = 0; - this._sy = 0; - this._sw = 0; - this._sh = 0; - this._dx = 0; - this._dy = 0; - this._dw = 0; - this._dh = 0; - this.game = game; - this.type = Phaser.Types.GEOMSPRITE; - this.canvas = document.createElement('canvas'); - this.canvas.width = width; - this.canvas.height = height; - this.context = this.canvas.getContext('2d'); - this.bounds = new Phaser.Rectangle(0, 0, width, height); - } - DynamicTexture.prototype.getPixel = /** - * Get a color of a specific pixel. - * @param x {number} X position of the pixel in this texture. - * @param y {number} Y position of the pixel in this texture. - * @return {number} A native color value integer (format: 0xRRGGBB) - */ - function (x, y) { - //r = imageData.data[0]; - //g = imageData.data[1]; - //b = imageData.data[2]; - //a = imageData.data[3]; - var imageData = this.context.getImageData(x, y, 1, 1); - return Phaser.ColorUtils.getColor(imageData.data[0], imageData.data[1], imageData.data[2]); - }; - DynamicTexture.prototype.getPixel32 = /** - * Get a color of a specific pixel (including alpha value). - * @param x {number} X position of the pixel in this texture. - * @param y {number} Y position of the pixel in this texture. - * @return A native color value integer (format: 0xAARRGGBB) - */ - function (x, y) { - var imageData = this.context.getImageData(x, y, 1, 1); - return Phaser.ColorUtils.getColor32(imageData.data[3], imageData.data[0], imageData.data[1], imageData.data[2]); - }; - DynamicTexture.prototype.getPixels = /** - * Get pixels in array in a specific rectangle. - * @param rect {Rectangle} The specific rectangle. - * @returns {array} CanvasPixelArray. - */ - function (rect) { - return this.context.getImageData(rect.x, rect.y, rect.width, rect.height); - }; - DynamicTexture.prototype.setPixel = /** - * Set color of a specific pixel. - * @param x {number} X position of the target pixel. - * @param y {number} Y position of the target pixel. - * @param color {number} Native integer with color value. (format: 0xRRGGBB) - */ - function (x, y, color) { - this.context.fillStyle = color; - this.context.fillRect(x, y, 1, 1); - }; - DynamicTexture.prototype.setPixel32 = /** - * Set color (with alpha) of a specific pixel. - * @param x {number} X position of the target pixel. - * @param y {number} Y position of the target pixel. - * @param color {number} Native integer with color value. (format: 0xAARRGGBB) - */ - function (x, y, color) { - this.context.fillStyle = color; - this.context.fillRect(x, y, 1, 1); - }; - DynamicTexture.prototype.setPixels = /** - * Set image data to a specific rectangle. - * @param rect {Rectangle} Target rectangle. - * @param input {object} Source image data. - */ - function (rect, input) { - this.context.putImageData(input, rect.x, rect.y); - }; - DynamicTexture.prototype.fillRect = /** - * Fill a given rectangle with specific color. - * @param rect {Rectangle} Target rectangle you want to fill. - * @param color {number} A native number with color value. (format: 0xRRGGBB) - */ - function (rect, color) { - this.context.fillStyle = color; - this.context.fillRect(rect.x, rect.y, rect.width, rect.height); - }; - DynamicTexture.prototype.pasteImage = /** - * - */ - function (key, frame, destX, destY, destWidth, destHeight) { - if (typeof frame === "undefined") { frame = -1; } - if (typeof destX === "undefined") { destX = 0; } - if (typeof destY === "undefined") { destY = 0; } - if (typeof destWidth === "undefined") { destWidth = null; } - if (typeof destHeight === "undefined") { destHeight = null; } - var texture = null; - var frameData; - this._sx = 0; - this._sy = 0; - this._dx = destX; - this._dy = destY; - // TODO - Load a frame from a sprite sheet, otherwise we'll draw the whole lot - if(frame > -1) { - //if (this.game.cache.isSpriteSheet(key)) - //{ - // texture = this.game.cache.getImage(key); - //this.animations.loadFrameData(this.game.cache.getFrameData(key)); - //} - } else { - texture = this.game.cache.getImage(key); - this._sw = texture.width; - this._sh = texture.height; - this._dw = texture.width; - this._dh = texture.height; - } - if(destWidth !== null) { - this._dw = destWidth; - } - if(destHeight !== null) { - this._dh = destHeight; - } - if(texture != null) { - this.context.drawImage(texture, // Source Image - this._sx, // Source X (location within the source image) - this._sy, // Source Y - this._sw, // Source Width - this._sh, // Source Height - this._dx, // Destination X (where on the canvas it'll be drawn) - this._dy, // Destination Y - this._dw, // Destination Width (always same as Source Width unless scaled) - this._dh); - // Destination Height (always same as Source Height unless scaled) - } - }; - DynamicTexture.prototype.copyPixels = // TODO - Add in support for: alphaBitmapData: BitmapData = null, alphaPoint: Point = null, mergeAlpha: bool = false - /** - * Copy pixel from another DynamicTexture to this texture. - * @param sourceTexture {DynamicTexture} Source texture object. - * @param sourceRect {Rectangle} The specific region rectangle to be copied to this in the source. - * @param destPoint {Point} Top-left point the target image data will be paste at. - */ - function (sourceTexture, sourceRect, destPoint) { - // Swap for drawImage if the sourceRect is the same size as the sourceTexture to avoid a costly getImageData call - if(Phaser.RectangleUtils.equals(sourceRect, this.bounds) == true) { - this.context.drawImage(sourceTexture.canvas, destPoint.x, destPoint.y); - } else { - this.context.putImageData(sourceTexture.getPixels(sourceRect), destPoint.x, destPoint.y); - } - }; - DynamicTexture.prototype.assignCanvasToGameObjects = /** - * Given an array of Sprites it will update each of them so that their canvas/contexts reference this DynamicTexture - * @param objects {Array} An array of GameObjects, or objects that inherit from it such as Sprites - */ - function (objects) { - for(var i = 0; i < objects.length; i++) { - objects[i].texture.canvas = this.canvas; - objects[i].texture.context = this.context; - } - }; - DynamicTexture.prototype.clear = /** - * Clear the whole canvas. - */ - function () { - this.context.clearRect(0, 0, this.bounds.width, this.bounds.height); - }; - DynamicTexture.prototype.render = /** - * Renders this DynamicTexture to the Stage at the given x/y coordinates - * - * @param x {number} The X coordinate to render on the stage to (given in screen coordinates, not world) - * @param y {number} The Y coordinate to render on the stage to (given in screen coordinates, not world) - */ - function (x, y) { - if (typeof x === "undefined") { x = 0; } - if (typeof y === "undefined") { y = 0; } - this.game.stage.context.drawImage(this.canvas, x, y); - }; - Object.defineProperty(DynamicTexture.prototype, "width", { - get: function () { - return this.bounds.width; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(DynamicTexture.prototype, "height", { - get: function () { - return this.bounds.height; - }, - enumerable: true, - configurable: true - }); - return DynamicTexture; - })(); - Phaser.DynamicTexture = DynamicTexture; -})(Phaser || (Phaser = {})); -/// -/// -/// -/// -/// -/// -/** -* Phaser - SpriteUtils -* -* A collection of methods useful for manipulating and checking Sprites. -*/ -var Phaser; -(function (Phaser) { - var SpriteUtils = (function () { - function SpriteUtils() { } - SpriteUtils.inCamera = /** - * Check whether this object is visible in a specific camera rectangle. - * @param camera {Rectangle} The rectangle you want to check. - * @return {boolean} Return true if bounds of this sprite intersects the given rectangle, otherwise return false. - */ - function inCamera(camera, sprite) { - // Object fixed in place regardless of the camera scrolling? Then it's always visible - if(sprite.scrollFactor.x == 0 && sprite.scrollFactor.y == 0) { - return true; - } - var dx = sprite.frameBounds.x - (camera.worldView.x * sprite.scrollFactor.x); - var dy = sprite.frameBounds.y - (camera.worldView.y * sprite.scrollFactor.y); - var dw = sprite.frameBounds.width * sprite.scale.x; - var dh = sprite.frameBounds.height * sprite.scale.y; - return (camera.scaledX + camera.worldView.width > this._dx) && (camera.scaledX < this._dx + this._dw) && (camera.scaledY + camera.worldView.height > this._dy) && (camera.scaledY < this._dy + this._dh); - }; - SpriteUtils.getAsPoints = function getAsPoints(sprite) { - var out = []; - // top left - out.push(new Phaser.Point(sprite.x, sprite.y)); - // top right - out.push(new Phaser.Point(sprite.x + sprite.width, sprite.y)); - // bottom right - out.push(new Phaser.Point(sprite.x + sprite.width, sprite.y + sprite.height)); - // bottom left - out.push(new Phaser.Point(sprite.x, sprite.y + sprite.height)); - return out; - }; - SpriteUtils.overlapsPoint = /** - * Checks to see if some GameObject overlaps this GameObject or Group. - * If the group has a LOT of things in it, it might be faster to use Collision.overlaps(). - * WARNING: Currently tilemaps do NOT support screen space overlap checks! - * - * @param objectOrGroup {object} The object or group being tested. - * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {boolean} Whether or not the objects overlap this. - */ - /* - static overlaps(objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { - - if (objectOrGroup.isGroup) - { - var results: bool = false; - var i: number = 0; - var members = objectOrGroup.members; - - while (i < length) - { - if (this.overlaps(members[i++], inScreenSpace, camera)) - { - results = true; - } - } - - return results; - - } - - if (!inScreenSpace) - { - return (objectOrGroup.x + objectOrGroup.width > this.x) && (objectOrGroup.x < this.x + this.width) && - (objectOrGroup.y + objectOrGroup.height > this.y) && (objectOrGroup.y < this.y + this.height); - } - - if (camera == null) - { - camera = this._game.camera; - } - - var objectScreenPos: Point = objectOrGroup.getScreenXY(null, camera); - - this.getScreenXY(this._point, camera); - - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && - (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); - } - */ - /** - * Checks to see if this GameObject were located at the given position, would it overlap the GameObject or Group? - * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size numbero account. - * WARNING: Currently tilemaps do NOT support screen space overlap checks! - * - * @param X {number} The X position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param Y {number} The Y position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param objectOrGroup {object} The object or group being tested. - * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {boolean} Whether or not the two objects overlap. - */ - /* - static overlapsAt(X: number, Y: number, objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { - - if (objectOrGroup.isGroup) - { - var results: bool = false; - var basic; - var i: number = 0; - var members = objectOrGroup.members; - - while (i < length) - { - if (this.overlapsAt(X, Y, members[i++], inScreenSpace, camera)) - { - results = true; - } - } - - return results; - } - - if (!inScreenSpace) - { - return (objectOrGroup.x + objectOrGroup.width > X) && (objectOrGroup.x < X + this.width) && - (objectOrGroup.y + objectOrGroup.height > Y) && (objectOrGroup.y < Y + this.height); - } - - if (camera == null) - { - camera = this._game.camera; - } - - var objectScreenPos: Point = objectOrGroup.getScreenXY(null, Camera); - - this._point.x = X - camera.scroll.x * this.scrollFactor.x; //copied from getScreenXY() - this._point.y = Y - camera.scroll.y * this.scrollFactor.y; - this._point.x += (this._point.x > 0) ? 0.0000001 : -0.0000001; - this._point.y += (this._point.y > 0) ? 0.0000001 : -0.0000001; - - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && - (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); - } - */ - /** - * Checks to see if a point in 2D world space overlaps this GameObject. - * - * @param point {Point} The point in world space you want to check. - * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return Whether or not the point overlaps this object. - */ - function overlapsPoint(sprite, point, inScreenSpace, camera) { - if (typeof inScreenSpace === "undefined") { inScreenSpace = false; } - if (typeof camera === "undefined") { camera = null; } - if(!inScreenSpace) { - return Phaser.RectangleUtils.containsPoint(sprite.body.bounds, point); - //return (point.x > sprite.x) && (point.x < sprite.x + sprite.width) && (point.y > sprite.y) && (point.y < sprite.y + sprite.height); - } - if(camera == null) { - camera = sprite.game.camera; - } - //var x: number = point.x - camera.scroll.x; - //var y: number = point.y - camera.scroll.y; - //this.getScreenXY(this._point, camera); - //return (x > this._point.x) && (X < this._point.x + this.width) && (Y > this._point.y) && (Y < this._point.y + this.height); - }; - SpriteUtils.onScreen = /** - * Check and see if this object is currently on screen. - * - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {boolean} Whether the object is on screen or not. - */ - function onScreen(sprite, camera) { - if (typeof camera === "undefined") { camera = null; } - if(camera == null) { - camera = sprite.game.camera; - } - SpriteUtils.getScreenXY(sprite, SpriteUtils._tempPoint, camera); - return (SpriteUtils._tempPoint.x + sprite.width > 0) && (SpriteUtils._tempPoint.x < camera.width) && (SpriteUtils._tempPoint.y + sprite.height > 0) && (SpriteUtils._tempPoint.y < camera.height); - }; - SpriteUtils.getScreenXY = /** - * Call this to figure out the on-screen position of the object. - * - * @param point {Point} Takes a Point object and assigns the post-scrolled X and Y values of this object to it. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {Point} The Point you passed in, or a new Point if you didn't pass one, containing the screen X and Y position of this object. - */ - function getScreenXY(sprite, point, camera) { - if (typeof point === "undefined") { point = null; } - if (typeof camera === "undefined") { camera = null; } - if(point == null) { - point = new Phaser.Point(); - } - if(camera == null) { - camera = this._game.camera; - } - point.x = sprite.x - camera.scroll.x * sprite.scrollFactor.x; - point.y = sprite.y - camera.scroll.y * sprite.scrollFactor.y; - point.x += (point.x > 0) ? 0.0000001 : -0.0000001; - point.y += (point.y > 0) ? 0.0000001 : -0.0000001; - return point; - }; - SpriteUtils.reset = /** - * Set the world bounds that this GameObject can exist within based on the size of the current game world. - * - * @param action {number} The action to take if the object hits the world bounds, either OUT_OF_BOUNDS_KILL or OUT_OF_BOUNDS_STOP - */ - /* - static setBoundsFromWorld(action?: number = GameObject.OUT_OF_BOUNDS_STOP) { - - this.setBounds(this._game.world.bounds.x, this._game.world.bounds.y, this._game.world.bounds.width, this._game.world.bounds.height); - this.outOfBoundsAction = action; - - } - */ - /** - * Handy for reviving game objects. - * Resets their existence flags and position. - * - * @param x {number} The new X position of this object. - * @param y {number} The new Y position of this object. - */ - function reset(sprite, x, y) { - sprite.revive(); - sprite.body.touching = Phaser.Types.NONE; - sprite.body.wasTouching = Phaser.Types.NONE; - sprite.x = x; - sprite.y = y; - sprite.body.velocity.x = 0; - sprite.body.velocity.y = 0; - sprite.body.position.x = x; - sprite.body.position.y = y; - }; - SpriteUtils.setOriginToCenter = function setOriginToCenter(sprite, fromFrameBounds, fromBody) { - if (typeof fromFrameBounds === "undefined") { fromFrameBounds = true; } - if (typeof fromBody === "undefined") { fromBody = false; } - if(fromFrameBounds) { - sprite.origin.setTo(sprite.frameBounds.halfWidth, sprite.frameBounds.halfHeight); - } else if(fromBody) { - sprite.origin.setTo(sprite.body.bounds.halfWidth, sprite.body.bounds.halfHeight); - } - }; - SpriteUtils.setBounds = /** - * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere - * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) - * it can be stopped from leaving the world, or a section of it. - * - * @param x {number} x position of the bound - * @param y {number} y position of the bound - * @param width {number} width of its bound - * @param height {number} height of its bound - */ - function setBounds(x, y, width, height) { - //this.worldBounds = new Quad(x, y, width, height); - }; - return SpriteUtils; - })(); - Phaser.SpriteUtils = SpriteUtils; - /** - * This function creates a flat colored square image dynamically. - * @param width {number} The width of the sprite you want to generate. - * @param height {number} The height of the sprite you want to generate. - * @param [color] {number} specifies the color of the generated block. (format is 0xAARRGGBB) - * @return {Sprite} Sprite instance itself. - */ - /* - static makeGraphic(width: number, height: number, color: string = 'rgb(255,255,255)'): Sprite { - - this._texture = null; - this.width = width; - this.height = height; - this.fillColor = color; - this._dynamicTexture = false; - - return this; - } - */ - })(Phaser || (Phaser = {})); -var Phaser; -(function (Phaser) { - /// - /// - /// - /** - * Phaser - Components - Texture - * - * The Texture being used to render the Sprite. Either Image based on a DynamicTexture. - */ - (function (Components) { - var Texture = (function () { - /** - * Creates a new Sprite Texture component - * @param parent The Sprite using this Texture to render - * @param key An optional Game.Cache key to load an image from - */ - function Texture(parent, key) { - if (typeof key === "undefined") { key = ''; } - /** - * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. - */ - this.imageTexture = null; - /** - * Reference to the DynamicTexture that is used as the texture for the Sprite. - * @type {DynamicTexture} - */ - this.dynamicTexture = null; - /** - * The load status of the texture image. - * @type {boolean} - */ - this.loaded = false; - /** - * Controls if the Sprite is rendered rotated or not. - * If renderRotation is false then the object can still rotate but it will never be rendered rotated. - * @type {boolean} - */ - this.renderRotation = true; - /** - * Flip the graphic horizontally (defaults to false) - * @type {boolean} - */ - this.flippedX = false; - /** - * Flip the graphic vertically (defaults to false) - * @type {boolean} - */ - this.flippedY = false; - /** - * Is the texture a DynamicTexture? - * @type {boolean} - */ - this.isDynamic = false; - this.game = parent.game; - this._sprite = parent; - this.canvas = parent.game.stage.canvas; - this.context = parent.game.stage.context; - this.alpha = 1; - this.flippedX = false; - this.flippedY = false; - if(key !== null) { - this.cacheKey = key; - this.loadImage(key); - } - } - Texture.prototype.setTo = /** - * Updates the texture being used to render the Sprite. - * Called automatically by SpriteUtils.loadTexture and SpriteUtils.loadDynamicTexture. - */ - function (image, dynamic) { - if (typeof image === "undefined") { image = null; } - if (typeof dynamic === "undefined") { dynamic = null; } - if(dynamic) { - this.isDynamic = true; - this.dynamicTexture = dynamic; - this.texture = this.dynamicTexture.canvas; - } else { - this.isDynamic = false; - this.imageTexture = image; - this.texture = this.imageTexture; - } - this.loaded = true; - return this._sprite; - }; - Texture.prototype.loadImage = /** - * Sets a new graphic from the game cache to use as the texture for this Sprite. - * The graphic can be SpriteSheet or Texture Atlas. If you need to use a DynamicTexture see loadDynamicTexture. - * @param key {string} Key of the graphic you want to load for this sprite. - * @param clearAnimations {boolean} If this Sprite has a set of animation data already loaded you can choose to keep or clear it with this boolean - */ - function (key, clearAnimations, updateBody) { - if (typeof clearAnimations === "undefined") { clearAnimations = true; } - if (typeof updateBody === "undefined") { updateBody = true; } - 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)) { - this._sprite.animations.loadFrameData(this._sprite.game.cache.getFrameData(key)); - } else { - this._sprite.frameBounds.width = this.width; - this._sprite.frameBounds.height = this.height; - } - if(updateBody) { - this._sprite.body.bounds.width = this.width; - this._sprite.body.bounds.height = this.height; - } - } - }; - Texture.prototype.loadDynamicTexture = /** - * Load a DynamicTexture as its texture. - * @param texture {DynamicTexture} The texture object to be used by this sprite. - */ - function (texture) { - 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; - }; - Object.defineProperty(Texture.prototype, "width", { - get: /** - * Getter only. The width of the texture. - * @type {number} - */ - function () { - if(this.isDynamic) { - return this.dynamicTexture.width; - } else { - return this.imageTexture.width; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Texture.prototype, "height", { - get: /** - * Getter only. The height of the texture. - * @type {number} - */ - function () { - if(this.isDynamic) { - return this.dynamicTexture.height; - } else { - return this.imageTexture.height; - } - }, - enumerable: true, - configurable: true - }); - return Texture; - })(); - Components.Texture = Texture; - })(Phaser.Components || (Phaser.Components = {})); - var Components = Phaser.Components; -})(Phaser || (Phaser = {})); -var Phaser; -(function (Phaser) { - /// - /// - /// - /// - /** - * Phaser - Components - Input - * - * Input detection component - */ - (function (Components) { - var Input = (function () { - /** - * Sprite Input component constructor - * @param parent The Sprite using this Input component - */ - function Input(parent) { - /** - * The PriorityID controls which Sprite receives an Input event first if they should overlap. - */ - this.priorityID = 0; - this.isDragged = false; - this.dragPixelPerfect = false; - this.allowHorizontalDrag = true; - this.allowVerticalDrag = true; - this.snapOnDrag = false; - this.snapOnRelease = false; - this.snapX = 0; - this.snapY = 0; - /** - * Is this sprite allowed to be dragged by the mouse? true = yes, false = no - * @default false - */ - this.draggable = false; - /** - * A region of the game world within which the sprite is restricted during drag - * @default null - */ - this.boundsRect = null; - /** - * An Sprite the bounds of which this sprite is restricted during drag - * @default null - */ - this.boundsSprite = null; - this.consumePointerEvent = false; - this.game = parent.game; - this._sprite = parent; - this.enabled = false; - } - Input.prototype.pointerX = /** - * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. - * This value is only set when the pointer is over this Sprite. - * @type {number} - */ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].x; - }; - Input.prototype.pointerY = /** - * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite - * This value is only set when the pointer is over this Sprite. - * @type {number} - */ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].y; - }; - Input.prototype.pointerDown = /** - * If the Pointer is touching the touchscreen, or the mouse button is held down, isDown is set to true - * @property isDown - * @type {Boolean} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].isDown; - }; - Input.prototype.pointerUp = /** - * If the Pointer is not touching the touchscreen, or the mouse button is up, isUp is set to true - * @property isUp - * @type {Boolean} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].isUp; - }; - Input.prototype.pointerTimeDown = /** - * A timestamp representing when the Pointer first touched the touchscreen. - * @property timeDown - * @type {Number} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].timeDown; - }; - Input.prototype.pointerTimeUp = /** - * A timestamp representing when the Pointer left the touchscreen. - * @property timeUp - * @type {Number} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].timeUp; - }; - Input.prototype.pointerOver = /** - * Is the Pointer over this Sprite - * @property isOver - * @type {Boolean} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].isOver; - }; - Input.prototype.pointerOut = /** - * Is the Pointer outside of this Sprite - * @property isOut - * @type {Boolean} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].isOut; - }; - Input.prototype.pointerTimeOver = /** - * A timestamp representing when the Pointer first touched the touchscreen. - * @property timeDown - * @type {Number} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].timeOver; - }; - Input.prototype.pointerTimeOut = /** - * A timestamp representing when the Pointer left the touchscreen. - * @property timeUp - * @type {Number} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].timeOut; - }; - Input.prototype.pointerDragged = /** - * Is this sprite being dragged by the mouse or not? - * @default false - */ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].isDragged; - }; - Input.prototype.start = function (priority, checkBody, useHandCursor) { - if (typeof priority === "undefined") { priority = 0; } - if (typeof checkBody === "undefined") { checkBody = false; } - if (typeof useHandCursor === "undefined") { useHandCursor = false; } - // Turning on - if(this.enabled == false) { - // Register, etc - this.checkBody = checkBody; - this.useHandCursor = useHandCursor; - this.priorityID = priority; - this._pointerData = []; - for(var i = 0; i < 10; i++) { - this._pointerData.push({ - id: i, - x: 0, - y: 0, - isDown: false, - isUp: false, - isOver: false, - isOut: false, - timeOver: 0, - timeOut: 0, - timeDown: 0, - timeUp: 0, - downDuration: 0, - isDragged: false - }); - } - this.snapOffset = new Phaser.Point(); - this.enabled = true; - this.game.input.addGameObject(this._sprite); - } - return this._sprite; - }; - Input.prototype.reset = function () { - this.enabled = false; - for(var i = 0; i < 10; i++) { - this._pointerData[i] = { - id: i, - x: 0, - y: 0, - isDown: false, - isUp: false, - isOver: false, - isOut: false, - timeOver: 0, - timeOut: 0, - timeDown: 0, - timeUp: 0, - downDuration: 0, - isDragged: false - }; - } - }; - Input.prototype.stop = function () { - // Turning off - if(this.enabled == false) { - return; - } else { - // De-register, etc - this.enabled = false; - this.game.input.removeGameObject(this._sprite); - } - }; - Input.prototype.checkPointerOver = function (pointer) { - if(this.enabled == false || this._sprite.visible == false) { - return false; - } else { - return Phaser.RectangleUtils.contains(this._sprite.frameBounds, pointer.scaledX, pointer.scaledY); - } - }; - Input.prototype.update = /** - * Update - */ - function (pointer) { - if(this.enabled == false || this._sprite.visible == false) { - return false; - } - if(this.draggable && this._draggedPointerID == pointer.id) { - return this.updateDrag(pointer); - } else if(this._pointerData[pointer.id].isOver == true) { - if(Phaser.RectangleUtils.contains(this._sprite.frameBounds, pointer.scaledX, pointer.scaledY)) { - this._pointerData[pointer.id].x = pointer.scaledX - this._sprite.x; - this._pointerData[pointer.id].y = pointer.scaledY - this._sprite.y; - return true; - } else { - this._pointerOutHandler(pointer); - return false; - } - } - }; - Input.prototype._pointerOverHandler = function (pointer) { - // { id: i, x: 0, y: 0, isDown: false, isUp: false, isOver: false, isOut: false, timeOver: 0, timeOut: 0, isDragged: false } - if(this._pointerData[pointer.id].isOver == false) { - this._pointerData[pointer.id].isOver = true; - this._pointerData[pointer.id].isOut = false; - this._pointerData[pointer.id].timeOver = this.game.time.now; - this._pointerData[pointer.id].x = pointer.x - this._sprite.x; - this._pointerData[pointer.id].y = pointer.y - this._sprite.y; - if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { - this.game.stage.canvas.style.cursor = "pointer"; - } - this._sprite.events.onInputOver.dispatch(this._sprite, pointer); - } - }; - Input.prototype._pointerOutHandler = function (pointer) { - this._pointerData[pointer.id].isOver = false; - this._pointerData[pointer.id].isOut = true; - this._pointerData[pointer.id].timeOut = this.game.time.now; - if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { - this.game.stage.canvas.style.cursor = "default"; - } - this._sprite.events.onInputOut.dispatch(this._sprite, pointer); - }; - Input.prototype._touchedHandler = function (pointer) { - if(this._pointerData[pointer.id].isDown == false && this._pointerData[pointer.id].isOver == true) { - this._pointerData[pointer.id].isDown = true; - this._pointerData[pointer.id].isUp = false; - this._pointerData[pointer.id].timeDown = this.game.time.now; - this._sprite.events.onInputDown.dispatch(this._sprite, pointer); - // Start drag - //if (this.draggable && this.isDragged == false && pointer.targetObject == null) - if(this.draggable && this.isDragged == false) { - this.startDrag(pointer); - } - } - // Consume the event? - return this.consumePointerEvent; - }; - Input.prototype._releasedHandler = function (pointer) { - // If was previously touched by this Pointer, check if still is - if(this._pointerData[pointer.id].isDown && pointer.isUp) { - this._pointerData[pointer.id].isDown = false; - this._pointerData[pointer.id].isUp = true; - this._pointerData[pointer.id].timeUp = this.game.time.now; - this._pointerData[pointer.id].downDuration = this._pointerData[pointer.id].timeUp - this._pointerData[pointer.id].timeDown; - this._sprite.events.onInputUp.dispatch(this._sprite, pointer); - // Stop drag - if(this.draggable && this.isDragged && this._draggedPointerID == pointer.id) { - this.stopDrag(pointer); - } - if(this.useHandCursor) { - this.game.stage.canvas.style.cursor = "default"; - } - } - }; - Input.prototype.updateDrag = /** - * Updates the Pointer drag on this Sprite. - */ - function (pointer) { - if(pointer.isUp) { - this.stopDrag(pointer); - return false; - } - if(this.allowHorizontalDrag) { - this._sprite.x = pointer.x + this._dragPoint.x + this.dragOffset.x; - } - if(this.allowVerticalDrag) { - this._sprite.y = pointer.y + this._dragPoint.y + this.dragOffset.y; - } - if(this.boundsRect) { - this.checkBoundsRect(); - } - if(this.boundsSprite) { - this.checkBoundsSprite(); - } - if(this.snapOnDrag) { - this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; - this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; - } - return true; - }; - Input.prototype.justOver = /** - * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) - * @param delay The time below which the pointer is considered as just over. - * @returns {boolean} - */ - function (pointer, delay) { - if (typeof pointer === "undefined") { pointer = 0; } - if (typeof delay === "undefined") { delay = 500; } - return (this._pointerData[pointer].isOver && this.overDuration(pointer) < delay); - }; - Input.prototype.justOut = /** - * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) - * @param delay The time below which the pointer is considered as just out. - * @returns {boolean} - */ - function (pointer, delay) { - if (typeof pointer === "undefined") { pointer = 0; } - if (typeof delay === "undefined") { delay = 500; } - return (this._pointerData[pointer].isOut && (this.game.time.now - this._pointerData[pointer].timeOut < delay)); - }; - Input.prototype.justPressed = /** - * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) - * @param delay The time below which the pointer is considered as just over. - * @returns {boolean} - */ - function (pointer, delay) { - if (typeof pointer === "undefined") { pointer = 0; } - if (typeof delay === "undefined") { delay = 500; } - return (this._pointerData[pointer].isDown && this.downDuration(pointer) < delay); - }; - Input.prototype.justReleased = /** - * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) - * @param delay The time below which the pointer is considered as just out. - * @returns {boolean} - */ - function (pointer, delay) { - if (typeof pointer === "undefined") { pointer = 0; } - if (typeof delay === "undefined") { delay = 500; } - return (this._pointerData[pointer].isUp && (this.game.time.now - this._pointerData[pointer].timeUp < delay)); - }; - Input.prototype.overDuration = /** - * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. - * @returns {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over. - */ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - if(this._pointerData[pointer].isOver) { - return this.game.time.now - this._pointerData[pointer].timeOver; - } - return -1; - }; - Input.prototype.downDuration = /** - * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. - * @returns {number} The number of milliseconds the pointer has been pressed down on the Sprite, or -1 if not over. - */ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - if(this._pointerData[pointer].isDown) { - return this.game.time.now - this._pointerData[pointer].timeDown; - } - return -1; - }; - Input.prototype.enableDrag = /** - * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback - * - * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. - * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. - * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) - * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere - * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here - */ - function (lockCenter, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) { - if (typeof lockCenter === "undefined") { lockCenter = false; } - if (typeof pixelPerfect === "undefined") { pixelPerfect = false; } - if (typeof alphaThreshold === "undefined") { alphaThreshold = 255; } - if (typeof boundsRect === "undefined") { boundsRect = null; } - if (typeof boundsSprite === "undefined") { boundsSprite = null; } - this._dragPoint = new Phaser.Point(); - this.draggable = true; - this.dragOffset = new Phaser.Point(); - this.dragFromCenter = lockCenter; - this.dragPixelPerfect = pixelPerfect; - this.dragPixelPerfectAlpha = alphaThreshold; - if(boundsRect) { - this.boundsRect = boundsRect; - } - if(boundsSprite) { - this.boundsSprite = boundsSprite; - } - }; - Input.prototype.disableDrag = /** - * Stops this sprite from being able to be dragged. If it is currently the target of an active drag it will be stopped immediately. Also disables any set callbacks. - */ - function () { - if(this._pointerData) { - for(var i = 0; i < 10; i++) { - this._pointerData[i].isDragged = false; - } - } - this.draggable = false; - this.isDragged = false; - this._draggedPointerID = -1; - }; - Input.prototype.startDrag = /** - * Called by Pointer when drag starts on this Sprite. Should not usually be called directly. - */ - function (pointer) { - this.isDragged = true; - this._draggedPointerID = pointer.id; - this._pointerData[pointer.id].isDragged = true; - if(this.dragFromCenter) { - // Move the sprite to the middle of the pointer - this._dragPoint.setTo(-this._sprite.frameBounds.halfWidth, -this._sprite.frameBounds.halfHeight); - } else { - this._dragPoint.setTo(this._sprite.x - pointer.x, this._sprite.y - pointer.y); - } - this.updateDrag(pointer); - }; - Input.prototype.stopDrag = /** - * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. - */ - function (pointer) { - this.isDragged = false; - this._draggedPointerID = -1; - this._pointerData[pointer.id].isDragged = false; - if(this.snapOnRelease) { - this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; - this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; - } - //pointer.draggedObject = null; - }; - Input.prototype.setDragLock = /** - * Restricts this sprite to drag movement only on the given axis. Note: If both are set to false the sprite will never move! - * - * @param allowHorizontal To enable the sprite to be dragged horizontally set to true, otherwise false - * @param allowVertical To enable the sprite to be dragged vertically set to true, otherwise false - */ - function (allowHorizontal, allowVertical) { - if (typeof allowHorizontal === "undefined") { allowHorizontal = true; } - if (typeof allowVertical === "undefined") { allowVertical = true; } - this.allowHorizontalDrag = allowHorizontal; - this.allowVerticalDrag = allowVertical; - }; - Input.prototype.enableSnap = /** - * Make this Sprite snap to the given grid either during drag or when it's released. - * For example 16x16 as the snapX and snapY would make the sprite snap to every 16 pixels. - * - * @param snapX The width of the grid cell in pixels - * @param snapY The height of the grid cell in pixels - * @param onDrag If true the sprite will snap to the grid while being dragged - * @param onRelease If true the sprite will snap to the grid when released - */ - function (snapX, snapY, onDrag, onRelease) { - if (typeof onDrag === "undefined") { onDrag = true; } - if (typeof onRelease === "undefined") { onRelease = false; } - this.snapOnDrag = onDrag; - this.snapOnRelease = onRelease; - this.snapX = snapX; - this.snapY = snapY; - }; - Input.prototype.disableSnap = /** - * Stops the sprite from snapping to a grid during drag or release. - */ - function () { - this.snapOnDrag = false; - this.snapOnRelease = false; - }; - Input.prototype.checkBoundsRect = /** - * Bounds Rect check for the sprite drag - */ - function () { - if(this._sprite.x < this.boundsRect.left) { - this._sprite.x = this.boundsRect.x; - } else if((this._sprite.x + this._sprite.width) > this.boundsRect.right) { - this._sprite.x = this.boundsRect.right - this._sprite.width; - } - if(this._sprite.y < this.boundsRect.top) { - this._sprite.y = this.boundsRect.top; - } else if((this._sprite.y + this._sprite.height) > this.boundsRect.bottom) { - this._sprite.y = this.boundsRect.bottom - this._sprite.height; - } - }; - Input.prototype.checkBoundsSprite = /** - * Parent Sprite Bounds check for the sprite drag - */ - function () { - if(this._sprite.x < this.boundsSprite.x) { - this._sprite.x = this.boundsSprite.x; - } else if((this._sprite.x + this._sprite.width) > (this.boundsSprite.x + this.boundsSprite.width)) { - this._sprite.x = (this.boundsSprite.x + this.boundsSprite.width) - this._sprite.width; - } - if(this._sprite.y < this.boundsSprite.y) { - this._sprite.y = this.boundsSprite.y; - } else if((this._sprite.y + this._sprite.height) > (this.boundsSprite.y + this.boundsSprite.height)) { - this._sprite.y = (this.boundsSprite.y + this.boundsSprite.height) - this._sprite.height; - } - }; - Input.prototype.renderDebugInfo = /** - * Render debug infos. (including name, bounds info, position and some other properties) - * @param x {number} X position of the debug info to be rendered. - * @param y {number} Y position of the debug info to be rendered. - * @param [color] {number} color of the debug info to be rendered. (format is css color string) - */ - function (x, y, color) { - if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } - this._sprite.texture.context.font = '14px Courier'; - this._sprite.texture.context.fillStyle = color; - this._sprite.texture.context.fillText('Sprite Input: (' + this._sprite.frameBounds.width + ' x ' + this._sprite.frameBounds.height + ')', x, y); - this._sprite.texture.context.fillText('x: ' + this.pointerX().toFixed(1) + ' y: ' + this.pointerY().toFixed(1), x, y + 14); - this._sprite.texture.context.fillText('over: ' + this.pointerOver() + ' duration: ' + this.overDuration().toFixed(0), x, y + 28); - this._sprite.texture.context.fillText('down: ' + this.pointerDown() + ' duration: ' + this.downDuration().toFixed(0), x, y + 42); - this._sprite.texture.context.fillText('just over: ' + this.justOver() + ' just out: ' + this.justOut(), x, y + 56); - }; - return Input; - })(); - Components.Input = Input; - })(Phaser.Components || (Phaser.Components = {})); - var Components = Phaser.Components; -})(Phaser || (Phaser = {})); -var Phaser; -(function (Phaser) { - /// - /** - * Phaser - Components - Events - * - * Signals that are dispatched by the Sprite and its various components - */ - (function (Components) { - var Events = (function () { - /** - * The Events component is a collection of events fired by the parent Sprite and its other components. - * @param parent The Sprite using this Input component - */ - function Events(parent) { - this.game = parent.game; - this._sprite = parent; - this.onAddedToGroup = new Phaser.Signal(); - this.onRemovedFromGroup = new Phaser.Signal(); - this.onKilled = new Phaser.Signal(); - this.onRevived = new Phaser.Signal(); - this.onInputOver = new Phaser.Signal(); - this.onInputOut = new Phaser.Signal(); - this.onInputDown = new Phaser.Signal(); - this.onInputUp = new Phaser.Signal(); - } - return Events; - })(); - Components.Events = Events; - })(Phaser.Components || (Phaser.Components = {})); - var Components = Phaser.Components; -})(Phaser || (Phaser = {})); -/// -/// -/** -* Phaser - Vec2Utils -* -* A collection of methods useful for manipulating and performing operations on 2D vectors. -* -*/ -var Phaser; -(function (Phaser) { - var Vec2Utils = (function () { - function Vec2Utils() { } - Vec2Utils.add = /** - * Adds two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the sum of the two vectors. - */ - function add(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.x + b.x, a.y + b.y); - }; - Vec2Utils.subtract = /** - * Subtracts two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the difference of the two vectors. - */ - function subtract(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.x - b.x, a.y - b.y); - }; - Vec2Utils.multiply = /** - * Multiplies two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the sum of the two vectors multiplied. - */ - function multiply(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.x * b.x, a.y * b.y); - }; - Vec2Utils.divide = /** - * Divides two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the sum of the two vectors divided. - */ - function divide(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.x / b.x, a.y / b.y); - }; - Vec2Utils.scale = /** - * Scales a 2D vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {number} s Scaling value. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the scaled vector. - */ - function scale(a, s, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.x * s, a.y * s); - }; - Vec2Utils.perp = /** - * Rotate a 2D vector by 90 degrees. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the scaled vector. - */ - function perp(a, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.y, -a.x); - }; - Vec2Utils.equals = /** - * Checks if two 2D vectors are equal. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Boolean} - */ - function equals(a, b) { - return a.x == b.x && a.y == b.y; - }; - Vec2Utils.epsilonEquals = /** - * - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} epsilon - * @return {Boolean} - */ - function epsilonEquals(a, b, epsilon) { - return Math.abs(a.x - b.x) <= epsilon && Math.abs(a.y - b.y) <= epsilon; - }; - Vec2Utils.distance = /** - * Get the distance between two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - function distance(a, b) { - return Math.sqrt(Vec2Utils.distanceSq(a, b)); - }; - Vec2Utils.distanceSq = /** - * Get the distance squared between two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - function distanceSq(a, b) { - return ((a.x - b.x) * (a.x - b.x)) + ((a.y - b.y) * (a.y - b.y)); - }; - Vec2Utils.project = /** - * Project two 2D vectors onto another vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - function project(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - var amt = a.dot(b) / b.lengthSq(); - if(amt != 0) { - out.setTo(amt * b.x, amt * b.y); - } - return out; - }; - Vec2Utils.projectUnit = /** - * Project this vector onto a vector of unit length. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - function projectUnit(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - var amt = a.dot(b); - if(amt != 0) { - out.setTo(amt * b.x, amt * b.y); - } - return out; - }; - Vec2Utils.normalRightHand = /** - * Right-hand normalize (make unit length) a 2D vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - function normalRightHand(a, out) { - if (typeof out === "undefined") { out = this; } - return out.setTo(a.y * -1, a.x); - }; - Vec2Utils.normalize = /** - * Normalize (make unit length) a 2D vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - function normalize(a, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - var m = a.length(); - if(m != 0) { - out.setTo(a.x / m, a.y / m); - } - return out; - }; - Vec2Utils.dot = /** - * The dot product of two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - function dot(a, b) { - return ((a.x * b.x) + (a.y * b.y)); - }; - Vec2Utils.cross = /** - * The cross product of two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - function cross(a, b) { - return ((a.x * b.y) - (a.y * b.x)); - }; - Vec2Utils.angle = /** - * The angle between two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - function angle(a, b) { - return Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y); - }; - Vec2Utils.angleSq = /** - * The angle squared between two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - function angleSq(a, b) { - return a.subtract(b).angle(b.subtract(a)); - }; - Vec2Utils.rotate = /** - * Rotate a 2D vector around the origin to the given angle (theta). - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Number} theta The angle of rotation in radians. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - function rotate(a, b, theta, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - var x = a.x - b.x; - var y = a.y - b.y; - return out.setTo(x * Math.cos(theta) - y * Math.sin(theta) + b.x, x * Math.sin(theta) + y * Math.cos(theta) + b.y); - }; - Vec2Utils.clone = /** - * Clone a 2D vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is a copy of the source Vec2. - */ - function clone(a, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.x, a.y); - }; - return Vec2Utils; - })(); - Phaser.Vec2Utils = Vec2Utils; - /** - * Reflect this vector on an arbitrary axis. - * - * @param {Vec2} axis The vector representing the axis. - * @return {Vec2} This for chaining. - */ - /* - static reflect(axis): Vec2 { - - var x = this.x; - var y = this.y; - this.project(axis).scale(2); - this.x -= x; - this.y -= y; - - return this; - - } - */ - /** - * Reflect this vector on an arbitrary axis (represented by a unit vector) - * - * @param {Vec2} axis The unit vector representing the axis. - * @return {Vec2} This for chaining. - */ - /* - static reflectN(axis): Vec2 { - - var x = this.x; - var y = this.y; - this.projectN(axis).scale(2); - this.x -= x; - this.y -= y; - - return this; - - } - - static getMagnitude(): number { - return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)); - } - */ - })(Phaser || (Phaser = {})); -var Phaser; -(function (Phaser) { - /// - /// - /// - /** - * Phaser - Physics - Body - */ - (function (Physics) { - var Body = (function () { - function Body(parent, type) { - this.angularVelocity = 0; - this.angularAcceleration = 0; - this.angularDrag = 0; - this.maxAngular = 10000; - this.mass = 1; - this.parent = parent; - this.game = parent.game; - this.type = type; - // Fixture properties - // Will extend into its own class at a later date - can move the fixture defs there and add shape support, but this will do for 1.0 release - this.bounds = new Phaser.Rectangle(parent.x + Math.round(parent.width / 2), parent.y + Math.round(parent.height / 2), parent.width, parent.height); - this.bounce = Phaser.Vec2Utils.clone(this.game.world.physics.bounce); - // Body properties - this.gravity = Phaser.Vec2Utils.clone(this.game.world.physics.gravity); - this.velocity = new Phaser.Vec2(); - this.acceleration = new Phaser.Vec2(); - this.drag = Phaser.Vec2Utils.clone(this.game.world.physics.drag); - this.maxVelocity = new Phaser.Vec2(10000, 10000); - this.angle = 0; - this.angularVelocity = 0; - this.angularAcceleration = 0; - this.angularDrag = 0; - this.touching = Phaser.Types.NONE; - this.wasTouching = Phaser.Types.NONE; - this.allowCollisions = Phaser.Types.ANY; - this.position = new Phaser.Vec2(parent.x + this.bounds.halfWidth, parent.y + this.bounds.halfHeight); - this.oldPosition = new Phaser.Vec2(parent.x + this.bounds.halfWidth, parent.y + this.bounds.halfHeight); - this.offset = new Phaser.Vec2(); - } - Body.prototype.preUpdate = function () { - this.oldPosition.copyFrom(this.position); - this.bounds.x = this.position.x - this.bounds.halfWidth; - this.bounds.y = this.position.y - this.bounds.halfHeight; - if(this.parent.scale.equals(1) == false) { - } - }; - Body.prototype.postUpdate = // Shall we do this? Or just update the values directly in the separate functions? But then the bounds will be out of sync - as long as - // the bounds are updated and used in calculations then we can do one final sprite movement here I guess? - function () { - // if this is all it does maybe move elsewhere? Sprite postUpdate? - if(this.type !== Phaser.Types.BODY_DISABLED) { - this.game.world.physics.updateMotion(this); - this.parent.x = (this.position.x - this.bounds.halfWidth) - this.offset.x; - this.parent.y = (this.position.y - this.bounds.halfHeight) - this.offset.y; - this.wasTouching = this.touching; - this.touching = Phaser.Types.NONE; - } - }; - Object.defineProperty(Body.prototype, "hullWidth", { - get: function () { - if(this.deltaX > 0) { - return this.bounds.width + this.deltaX; - } else { - return this.bounds.width - this.deltaX; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "hullHeight", { - get: function () { - if(this.deltaY > 0) { - return this.bounds.height + this.deltaY; - } else { - return this.bounds.height - this.deltaY; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "hullX", { - get: function () { - if(this.position.x < this.oldPosition.x) { - return this.position.x; - } else { - return this.oldPosition.x; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "hullY", { - get: function () { - if(this.position.y < this.oldPosition.y) { - return this.position.y; - } else { - return this.oldPosition.y; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "deltaXAbs", { - get: function () { - return (this.deltaX > 0 ? this.deltaX : -this.deltaX); - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "deltaYAbs", { - get: function () { - return (this.deltaY > 0 ? this.deltaY : -this.deltaY); - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "deltaX", { - get: function () { - return this.position.x - this.oldPosition.x; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "deltaY", { - get: function () { - return this.position.y - this.oldPosition.y; - }, - enumerable: true, - configurable: true - }); - Body.prototype.render = // MOVE THESE TO A UTIL - function (context) { - context.beginPath(); - context.strokeStyle = 'rgb(0,255,0)'; - context.strokeRect(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight, this.bounds.width, this.bounds.height); - context.stroke(); - context.closePath(); - // center point - context.fillStyle = 'rgb(0,255,0)'; - context.fillRect(this.position.x, this.position.y, 2, 2); - if(this.touching & Phaser.Types.LEFT) { - context.beginPath(); - context.strokeStyle = 'rgb(255,0,0)'; - context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); - context.lineTo(this.position.x - this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); - context.stroke(); - context.closePath(); - } - if(this.touching & Phaser.Types.RIGHT) { - context.beginPath(); - context.strokeStyle = 'rgb(255,0,0)'; - context.moveTo(this.position.x + this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); - context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); - context.stroke(); - context.closePath(); - } - if(this.touching & Phaser.Types.UP) { - context.beginPath(); - context.strokeStyle = 'rgb(255,0,0)'; - context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); - context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); - context.stroke(); - context.closePath(); - } - if(this.touching & Phaser.Types.DOWN) { - context.beginPath(); - context.strokeStyle = 'rgb(255,0,0)'; - context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); - context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); - context.stroke(); - context.closePath(); - } - }; - Body.prototype.renderDebugInfo = /** - * Render debug infos. (including name, bounds info, position and some other properties) - * @param x {number} X position of the debug info to be rendered. - * @param y {number} Y position of the debug info to be rendered. - * @param [color] {number} color of the debug info to be rendered. (format is css color string) - */ - function (x, y, color) { - if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } - this.parent.texture.context.fillStyle = color; - this.parent.texture.context.fillText('Sprite: (' + this.parent.frameBounds.width + ' x ' + this.parent.frameBounds.height + ')', x, y); - //this.parent.texture.context.fillText('x: ' + this._parent.frameBounds.x.toFixed(1) + ' y: ' + this._parent.frameBounds.y.toFixed(1) + ' rotation: ' + this._parent.rotation.toFixed(1), x, y + 14); - this.parent.texture.context.fillText('x: ' + this.bounds.x.toFixed(1) + ' y: ' + this.bounds.y.toFixed(1) + ' angle: ' + this.angle.toFixed(0), x, y + 14); - this.parent.texture.context.fillText('vx: ' + this.velocity.x.toFixed(1) + ' vy: ' + this.velocity.y.toFixed(1), x, y + 28); - this.parent.texture.context.fillText('acx: ' + this.acceleration.x.toFixed(1) + ' acy: ' + this.acceleration.y.toFixed(1), x, y + 42); - this.parent.texture.context.fillText('angVx: ' + this.angularVelocity.toFixed(1) + ' angAc: ' + this.angularAcceleration.toFixed(1), x, y + 56); - }; - return Body; - })(); - Physics.Body = Body; - })(Phaser.Physics || (Phaser.Physics = {})); - var Physics = Phaser.Physics; -})(Phaser || (Phaser = {})); -/// -/// -/// -/// -/// -/// -/// -/// -/** -* Phaser - Sprite -* -*/ -var Phaser; -(function (Phaser) { - var Sprite = (function () { - /** - * Create a new Sprite. - * - * @param game {Phaser.Game} Current game instance. - * @param [x] {number} the initial x position of the sprite. - * @param [y] {number} the initial y position of the sprite. - * @param [key] {string} Key of the graphic you want to load for this sprite. - * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) - */ - function Sprite(game, x, y, key, bodyType) { - if (typeof x === "undefined") { x = 0; } - if (typeof y === "undefined") { y = 0; } - if (typeof key === "undefined") { key = null; } - if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } - /** - * 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; - /** - * y value of the object. - */ - this.y = 0; - /** - * z order value of the object. - */ - this.z = 0; - /** - * Render iteration - */ - this.renderOrderID = 0; - /** - * This value is added to the angle of the Sprite. - * For example if you had a sprite graphic drawn facing straight up then you could set - * angleOffset to 90 and it would correspond correctly with Phasers right-handed coordinate system. - * @type {number} - */ - this.angleOffset = 0; - this.game = game; - this.type = Phaser.Types.SPRITE; - this.exists = true; - this.active = true; - this.visible = true; - this.alive = true; - // We give it a default size of 16x16 but when the texture loads (if given) it will reset this - this.frameBounds = new Phaser.Rectangle(x, y, 16, 16); - this.scrollFactor = new Phaser.Vec2(1, 1); - this.x = x; - this.y = y; - this.z = -1; - this.group = null; - this.screen = new Phaser.Point(); - // If a texture has been given the body will be set to that size, otherwise 16x16 - this.body = new Phaser.Physics.Body(this, bodyType); - this.animations = new Phaser.Components.AnimationManager(this); - this.texture = new Phaser.Components.Texture(this, key); - this.input = new Phaser.Components.Input(this); - this.events = new Phaser.Components.Events(this); - this.cameraBlacklist = []; - // Transform related (if we add any more then move to a component) - this.origin = new Phaser.Vec2(0, 0); - this.scale = new Phaser.Vec2(1, 1); - this.skew = new Phaser.Vec2(0, 0); - } - Object.defineProperty(Sprite.prototype, "angle", { - get: /** - * The angle of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. - */ - function () { - return this.body.angle; - }, - set: /** - * Set the angle of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. - * The value is automatically wrapped to be between 0 and 360. - */ - function (value) { - this.body.angle = this.game.math.wrap(value, 360, 0); - }, - 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 - }); - Object.defineProperty(Sprite.prototype, "width", { - get: function () { - return this.frameBounds.width; - }, - set: function (value) { - this.frameBounds.width = value; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Sprite.prototype, "height", { - get: function () { - return this.frameBounds.height; - }, - set: function (value) { - this.frameBounds.height = value; - }, - enumerable: true, - configurable: true - }); - Sprite.prototype.preUpdate = /** - * Pre-update is called right before update() on each object in the game loop. - */ - function () { - this.frameBounds.x = this.x; - this.frameBounds.y = this.y; - this.screen.x = this.x - (this.game.world.cameras.default.worldView.x * this.scrollFactor.x); - this.screen.y = this.y - (this.game.world.cameras.default.worldView.y * this.scrollFactor.y); - if(this.modified == false && (!this.scale.equals(1) || !this.skew.equals(0) || this.angle != 0 || this.angleOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { - this.modified = true; - } - }; - Sprite.prototype.update = /** - * Override this function to update your class's position and appearance. - */ - function () { - }; - Sprite.prototype.postUpdate = /** - * Automatically called after update() by the game loop. - */ - function () { - this.animations.update(); - this.body.postUpdate(); - /* - if (this.worldBounds != null) - { - if (this.outOfBoundsAction == GameObject.OUT_OF_BOUNDS_KILL) - { - if (this.x < this.worldBounds.x || this.x > this.worldBounds.right || this.y < this.worldBounds.y || this.y > this.worldBounds.bottom) - { - this.kill(); - } - } - else - { - if (this.x < this.worldBounds.x) - { - this.x = this.worldBounds.x; - } - else if (this.x > this.worldBounds.right) - { - this.x = this.worldBounds.right; - } - - if (this.y < this.worldBounds.y) - { - this.y = this.worldBounds.y; - } - else if (this.y > this.worldBounds.bottom) - { - this.y = this.worldBounds.bottom; - } - } - } - */ - if(this.modified == true && this.scale.equals(1) && this.skew.equals(0) && this.angle == 0 && this.angleOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { - this.modified = false; - } - }; - Sprite.prototype.destroy = /** - * Clean up memory. - */ - function () { - //this.input.destroy(); - }; - Sprite.prototype.kill = /** - * Handy for "killing" game objects. - * Default behavior is to flag them as nonexistent AND dead. - * However, if you want the "corpse" to remain in the game, - * like to animate an effect or whatever, you should override this, - * setting only alive to false, and leaving exists true. - */ - function (removeFromGroup) { - if (typeof removeFromGroup === "undefined") { removeFromGroup = false; } - this.alive = false; - this.exists = false; - if(removeFromGroup && this.group) { - this.group.remove(this); - } - this.events.onKilled.dispatch(this); - }; - Sprite.prototype.revive = /** - * Handy for bringing game objects "back to life". Just sets alive and exists back to true. - * In practice, this is most often called by Object.reset(). - */ - function () { - this.alive = true; - this.exists = true; - this.events.onRevived.dispatch(this); - }; - return Sprite; - })(); - Phaser.Sprite = Sprite; -})(Phaser || (Phaser = {})); /// /// /** @@ -7512,12 +7573,14 @@ var Phaser; })(); Phaser.CameraFX = CameraFX; })(Phaser || (Phaser = {})); +/// /// /// /// -/// -/// /// +/// +/// +/// /** * Phaser - Camera * @@ -7539,26 +7602,22 @@ var Phaser; * @param height {number} The height of the camera display in pixels. */ function Camera(game, id, x, y, width, height) { - this._clip = false; - this._rotation = 0; this._target = null; /** - * Scale factor of the camera. - * @type {Vec2} + * Controls if this camera is clipped or not when rendering. You shouldn't usually set this value directly. */ - this.scale = new Phaser.Vec2(1, 1); + this.clip = false; /** - * Scrolling factor. - * @type {MicroPoint} - */ - this.scroll = new Phaser.Vec2(0, 0); - /** - * Camera bounds. + * Camera worldBounds. * @type {Rectangle} */ - this.bounds = null; + this.worldBounds = null; /** - * Sprite moving inside this rectangle will not cause camera moving. + * A boolean representing if the Camera has been modified in any way via a scale, rotate, flip or skew. + */ + this.modified = false; + /** + * Sprite moving inside this Rectangle will not cause camera moving. * @type {Rectangle} */ this.deadzone = null; @@ -7568,48 +7627,26 @@ var Phaser; */ this.disableClipping = false; /** - * Whether the camera background is opaque or not. If set to true the Camera is filled with - * the value of Camera.backgroundColor every frame. Normally you wouldn't enable this if the - * Camera is the full Stage size, as the Stage.backgroundColor has the same effect. But for - * multiple or mini cameras it can be very useful. - * @type {boolean} - */ - this.opaque = false; - /** - * The Background Color of the camera in css color string format, i.e. 'rgb(0,0,0)' or '#ff0000'. - * Not used if the Camera.opaque property is false. - * @type {string} - */ - this.backgroundColor = 'rgb(0,0,0)'; - /** - * Whether this camera visible or not. (default is true) + * Whether this camera is visible or not. (default is true) * @type {boolean} */ this.visible = true; /** - * Alpha of the camera. (everything rendered to this camera will be affected) - * @type {number} + * The z value of this Camera. Cameras are rendered in z-index order by the Renderer. */ - this.alpha = 1; - /** - * The x position of the current input event in world coordinates. - * @type {number} - */ - this.inputX = 0; - /** - * The y position of the current input event in world coordinates. - * @type {number} - */ - this.inputY = 0; - this._game = game; + this.z = -1; + this.game = game; this.ID = id; - this._stageX = x; - this._stageY = y; - this.scaledX = x; - this.scaledY = y; - this.fx = new Phaser.CameraFX(this._game, this); - // The view into the world canvas we wish to render + this.z = id; + // The view into the world we wish to render (by default the full game world size) + // The size of this Rect is the same as screenView, but the values are all in world coordinates instead of screen coordinates this.worldView = new Phaser.Rectangle(0, 0, width, height); + // The rect of the area being rendered in stage/screen coordinates + this.screenView = new Phaser.Rectangle(x, y, width, height); + this.fx = new Phaser.CameraFX(this.game, this); + this.transform = new Phaser.Components.Transform(this); + this.texture = new Phaser.Components.Texture(this); + this.texture.opaque = false; this.checkClip(); } Camera.STYLE_LOCKON = 0; @@ -7624,7 +7661,7 @@ var Phaser; */ function (object) { if(this.isHidden(object) == false) { - object['cameraBlacklist'].push(this.ID); + object.texture['cameraBlacklist'].push(this.ID); } }; Camera.prototype.isHidden = /** @@ -7633,7 +7670,7 @@ var Phaser; * @param object {Sprite/Group} The object to check. */ function (object) { - return (object['cameraBlacklist'] && object['cameraBlacklist'].length > 0 && object['cameraBlacklist'].indexOf(this.ID) == -1); + return (object.texture['cameraBlacklist'] && object.texture['cameraBlacklist'].length > 0 && object.texture['cameraBlacklist'].indexOf(this.ID) == -1); }; Camera.prototype.show = /** * Un-hides an object previously hidden to this Camera. @@ -7643,7 +7680,7 @@ var Phaser; */ function (object) { if(this.isHidden(object) == true) { - object['cameraBlacklist'].slice(object['cameraBlacklist'].indexOf(this.ID), 1); + object.texture['cameraBlacklist'].slice(object.texture['cameraBlacklist'].indexOf(this.ID), 1); } }; Camera.prototype.follow = /** @@ -7683,8 +7720,8 @@ var Phaser; function (x, y) { x += (x > 0) ? 0.0000001 : -0.0000001; y += (y > 0) ? 0.0000001 : -0.0000001; - this.scroll.x = Math.round(x - this.worldView.halfWidth); - this.scroll.y = Math.round(y - this.worldView.halfHeight); + this.worldView.x = Math.round(x - this.worldView.halfWidth); + this.worldView.y = Math.round(y - this.worldView.halfHeight); }; Camera.prototype.focusOn = /** * Move the camera focus to this location instantly. @@ -7693,8 +7730,8 @@ var Phaser; function (point) { point.x += (point.x > 0) ? 0.0000001 : -0.0000001; point.y += (point.y > 0) ? 0.0000001 : -0.0000001; - this.scroll.x = Math.round(point.x - this.worldView.halfWidth); - this.scroll.y = Math.round(point.y - this.worldView.halfHeight); + this.worldView.x = Math.round(point.x - this.worldView.halfWidth); + this.worldView.y = Math.round(point.y - this.worldView.halfHeight); }; Camera.prototype.setBounds = /** * Specify the boundaries of the world or where the camera is allowed to move. @@ -7709,17 +7746,23 @@ var Phaser; if (typeof y === "undefined") { y = 0; } if (typeof width === "undefined") { width = 0; } if (typeof height === "undefined") { height = 0; } - if(this.bounds == null) { - this.bounds = new Phaser.Rectangle(); + if(this.worldBounds == null) { + this.worldBounds = new Phaser.Rectangle(); } - this.bounds.setTo(x, y, width, height); - this.scroll.setTo(0, 0); + this.worldBounds.setTo(x, y, width, height); + this.worldView.x = x; + this.worldView.y = y; this.update(); }; Camera.prototype.update = /** * Update focusing and scrolling. */ function () { + if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { + this.modified = true; + } else if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { + this.modified = false; + } this.fx.preUpdate(); if(this._target !== null) { if(this.deadzone == null) { @@ -7729,215 +7772,139 @@ var Phaser; var targetX = this._target.x + ((this._target.x > 0) ? 0.0000001 : -0.0000001); var targetY = this._target.y + ((this._target.y > 0) ? 0.0000001 : -0.0000001); edge = targetX - this.deadzone.x; - if(this.scroll.x > edge) { - this.scroll.x = edge; + if(this.worldView.x > edge) { + this.worldView.x = edge; } edge = targetX + this._target.width - this.deadzone.x - this.deadzone.width; - if(this.scroll.x < edge) { - this.scroll.x = edge; + if(this.worldView.x < edge) { + this.worldView.x = edge; } edge = targetY - this.deadzone.y; - if(this.scroll.y > edge) { - this.scroll.y = edge; + if(this.worldView.y > edge) { + this.worldView.y = edge; } edge = targetY + this._target.height - this.deadzone.y - this.deadzone.height; - if(this.scroll.y < edge) { - this.scroll.y = edge; + if(this.worldView.y < edge) { + this.worldView.y = edge; } } } - // Make sure we didn't go outside the cameras bounds - if(this.bounds !== null) { - if(this.scroll.x < this.bounds.left) { - this.scroll.x = this.bounds.left; + // Make sure we didn't go outside the cameras worldBounds + if(this.worldBounds !== null) { + if(this.worldView.x < this.worldBounds.left) { + this.worldView.x = this.worldBounds.left; } - if(this.scroll.x > this.bounds.right - this.width) { - this.scroll.x = (this.bounds.right - this.width) + 1; + if(this.worldView.x > this.worldBounds.right - this.width) { + this.worldView.x = (this.worldBounds.right - this.width) + 1; } - if(this.scroll.y < this.bounds.top) { - this.scroll.y = this.bounds.top; + if(this.worldView.y < this.worldBounds.top) { + this.worldView.y = this.worldBounds.top; } - if(this.scroll.y > this.bounds.bottom - this.height) { - this.scroll.y = (this.bounds.bottom - this.height) + 1; + if(this.worldView.y > this.worldBounds.bottom - this.height) { + this.worldView.y = (this.worldBounds.bottom - this.height) + 1; } } - this.worldView.x = this.scroll.x; - this.worldView.y = this.scroll.y; - // Input values - this.inputX = this.worldView.x + this._game.input.x; - this.inputY = this.worldView.y + this._game.input.y; this.fx.postUpdate(); }; - Camera.prototype.preRender = /** - * Camera preRender - */ - function () { - if(this.visible === false || this.alpha < 0.1) { - return; - } - if(this._rotation !== 0 || this._clip || this.scale.x !== 1 || this.scale.y !== 1) { - this._game.stage.context.save(); - } - this.fx.preRender(this, this._stageX, this._stageY, this.worldView.width, this.worldView.height); - if(this.alpha !== 1) { - this._game.stage.context.globalAlpha = this.alpha; - } - this.scaledX = this._stageX; - this.scaledY = this._stageY; - // Scale on - if(this.scale.x !== 1 || this.scale.y !== 1) { - this._game.stage.context.scale(this.scale.x, this.scale.y); - this.scaledX = this.scaledX / this.scale.x; - this.scaledY = this.scaledY / this.scale.y; - } - // Rotation - translate to the mid-point of the camera - if(this._rotation !== 0) { - this._game.stage.context.translate(this.scaledX + this.worldView.halfWidth, this.scaledY + this.worldView.halfHeight); - this._game.stage.context.rotate(this._rotation * (Math.PI / 180)); - // now shift back to where that should actually render - this._game.stage.context.translate(-(this.scaledX + this.worldView.halfWidth), -(this.scaledY + this.worldView.halfHeight)); - } - // Background - if(this.opaque) { - this._game.stage.context.fillStyle = this.backgroundColor; - this._game.stage.context.fillRect(this.scaledX, this.scaledY, this.worldView.width, this.worldView.height); - } - this.fx.render(this, this._stageX, this._stageY, this.worldView.width, this.worldView.height); - // Clip the camera so we don't get sprites appearing outside the edges - if(this._clip == true && this.disableClipping == false) { - this._game.stage.context.beginPath(); - this._game.stage.context.rect(this.scaledX, this.scaledY, this.worldView.width, this.worldView.height); - this._game.stage.context.closePath(); - this._game.stage.context.clip(); - } - }; - Camera.prototype.postRender = /** - * Camera postRender - */ - function () { - // Scale off - if(this.scale.x !== 1 || this.scale.y !== 1) { - this._game.stage.context.scale(1, 1); - } - this.fx.postRender(this, this.scaledX, this.scaledY, this.worldView.width, this.worldView.height); - if(this._rotation !== 0 || (this._clip && this.disableClipping == false)) { - this._game.stage.context.translate(0, 0); - } - if(this._rotation !== 0 || this._clip || this.scale.x !== 1 || this.scale.y !== 1) { - this._game.stage.context.restore(); - } - if(this.alpha !== 1) { - this._game.stage.context.globalAlpha = 1; - } - }; - Camera.prototype.setPosition = /** - * Set position of this camera. - * @param x {number} X position. - * @param y {number} Y position. - */ - function (x, y) { - this._stageX = x; - this._stageY = y; - this.checkClip(); - }; - Camera.prototype.setSize = /** - * Give this camera a new size. - * @param width {number} Width of new size. - * @param height {number} Height of new size. - */ - function (width, height) { - this.worldView.width = width; - this.worldView.height = height; - this.checkClip(); - }; Camera.prototype.renderDebugInfo = /** - * Render debug infos. (including id, position, rotation, scrolling factor, bounds and some other properties) + * Render debug infos. (including id, position, rotation, scrolling factor, worldBounds and some other properties) * @param x {number} X position of the debug info to be rendered. * @param y {number} Y position of the debug info to be rendered. * @param [color] {number} color of the debug info to be rendered. (format is css color string) */ function (x, y, color) { if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } - this._game.stage.context.fillStyle = color; - this._game.stage.context.fillText('Camera ID: ' + this.ID + ' (' + this.worldView.width + ' x ' + this.worldView.height + ')', x, y); - this._game.stage.context.fillText('X: ' + this._stageX + ' Y: ' + this._stageY + ' Rotation: ' + this._rotation, x, y + 14); - this._game.stage.context.fillText('World X: ' + this.scroll.x.toFixed(1) + ' World Y: ' + this.scroll.y.toFixed(1), x, y + 28); - if(this.bounds) { - this._game.stage.context.fillText('Bounds: ' + this.bounds.width + ' x ' + this.bounds.height, x, y + 42); + this.game.stage.context.fillStyle = color; + this.game.stage.context.fillText('Camera ID: ' + this.ID + ' (' + this.screenView.width + ' x ' + this.screenView.height + ')', x, y); + this.game.stage.context.fillText('X: ' + this.screenView.x + ' Y: ' + this.screenView.y + ' rotation: ' + this.transform.rotation, x, y + 14); + this.game.stage.context.fillText('World X: ' + this.worldView.x.toFixed(1) + ' World Y: ' + this.worldView.y.toFixed(1), x, y + 28); + if(this.worldBounds) { + this.game.stage.context.fillText('Bounds: ' + this.worldBounds.width + ' x ' + this.worldBounds.height, x, y + 42); } }; Camera.prototype.destroy = /** * Destroys this camera, associated FX and removes itself from the CameraManager. */ function () { - this._game.world.cameras.removeCamera(this.ID); + this.game.world.cameras.removeCamera(this.ID); this.fx.destroy(); }; Object.defineProperty(Camera.prototype, "x", { get: function () { - return this._stageX; + return this.worldView.x; }, set: function (value) { - this._stageX = value; - this.checkClip(); + this.worldView.x = value; }, enumerable: true, configurable: true }); Object.defineProperty(Camera.prototype, "y", { get: function () { - return this._stageY; + return this.worldView.y; }, set: function (value) { - this._stageY = value; - this.checkClip(); + this.worldView.y = value; }, enumerable: true, configurable: true }); Object.defineProperty(Camera.prototype, "width", { get: function () { - return this.worldView.width; + return this.screenView.width; }, set: function (value) { - if(value > this._game.stage.width) { - value = this._game.stage.width; - } + this.screenView.width = value; this.worldView.width = value; - this.checkClip(); }, enumerable: true, configurable: true }); Object.defineProperty(Camera.prototype, "height", { get: function () { - return this.worldView.height; + return this.screenView.height; }, set: function (value) { - if(value > this._game.stage.height) { - value = this._game.stage.height; - } + this.screenView.height = value; this.worldView.height = value; - this.checkClip(); }, enumerable: true, configurable: true }); + Camera.prototype.setPosition = function (x, y) { + this.screenView.x = x; + this.screenView.y = y; + this.checkClip(); + }; + Camera.prototype.setSize = function (width, height) { + this.screenView.width = width * this.transform.scale.x; + this.screenView.height = height * this.transform.scale.y; + this.worldView.width = width; + this.worldView.height = height; + this.checkClip(); + }; Object.defineProperty(Camera.prototype, "rotation", { - get: function () { - return this._rotation; + get: /** + * The angle of the Camera in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + */ + function () { + return this.transform.rotation; }, - set: function (value) { - this._rotation = this._game.math.wrap(value, 360, 0); + set: /** + * Set the angle of the Camera in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + * The value is automatically wrapped to be between 0 and 360. + */ + function (value) { + this.transform.rotation = this.game.math.wrap(value, 360, 0); }, enumerable: true, configurable: true }); Camera.prototype.checkClip = function () { - if(this._stageX !== 0 || this._stageY !== 0 || this.worldView.width < this._game.stage.width || this.worldView.height < this._game.stage.height) { - this._clip = true; + if(this.screenView.x != 0 || this.screenView.y != 0 || this.screenView.width < this.game.stage.width || this.screenView.height < this.game.stage.height) { + this.clip = true; } else { - this._clip = false; + this.clip = false; } }; return Camera; @@ -7969,6 +7936,10 @@ var Phaser; * Local helper stores index of next created camera. */ this._cameraInstance = 0; + /** + * Helper for sort. + */ + this._sortIndex = ''; this._game = game; this._cameras = []; this.default = this.addCamera(x, y, width, height); @@ -8026,6 +7997,52 @@ var Phaser; } return false; }; + CameraManager.prototype.swap = function (camera1, camera2, sort) { + if (typeof sort === "undefined") { sort = true; } + if(camera1.ID == camera2.ID) { + return false; + } + var tempZ = camera1.z; + camera1.z = camera2.z; + camera2.z = tempZ; + if(sort) { + this.sort(); + } + return true; + }; + CameraManager.prototype.sort = /** + * Call this function to sort the Cameras according to a particular value and order (default is their Z value). + * The order in which they are sorted determines the render order. If sorted on z then Cameras with a lower z-index value render first. + * + * @param {string} index The string name of the Camera variable you want to sort on. Default value is "z". + * @param {number} order A Group constant that defines the sort order. Possible values are Group.ASCENDING and Group.DESCENDING. Default value is Group.ASCENDING. + */ + function (index, order) { + if (typeof index === "undefined") { index = 'z'; } + if (typeof order === "undefined") { order = Phaser.Group.ASCENDING; } + var _this = this; + this._sortIndex = index; + this._sortOrder = order; + this._cameras.sort(function (a, b) { + return _this.sortHandler(a, b); + }); + }; + CameraManager.prototype.sortHandler = /** + * Helper function for the sort process. + * + * @param {Basic} Obj1 The first object being sorted. + * @param {Basic} Obj2 The second object being sorted. + * + * @return {number} An integer value: -1 (Obj1 before Obj2), 0 (same), or 1 (Obj1 after Obj2). + */ + function (obj1, obj2) { + if(obj1[this._sortIndex] < obj2[this._sortIndex]) { + return this._sortOrder; + } else if(obj1[this._sortIndex] > obj2[this._sortIndex]) { + return -this._sortOrder; + } + return 0; + }; CameraManager.prototype.destroy = /** * Clean up memory. */ @@ -8893,7 +8910,7 @@ var Phaser; } particle.exists = false; // Center the origin for rotation assistance - particle.origin.setTo(particle.body.bounds.halfWidth, particle.body.bounds.halfHeight); + particle.transform.origin.setTo(particle.body.bounds.halfWidth, particle.body.bounds.halfHeight); this.add(particle); i++; } @@ -8999,7 +9016,7 @@ var Phaser; particle.body.angularVelocity = this.minRotation; } if(particle.body.angularVelocity != 0) { - particle.angle = this.game.math.random() * 360 - 180; + particle.rotation = this.game.math.random() * 360 - 180; } particle.body.drag.x = this.particleDrag.x; particle.body.drag.y = this.particleDrag.y; @@ -9436,10 +9453,10 @@ var Phaser; * Swap tiles with 2 kinds of indexes. * @param tileA {number} First tile index. * @param tileB {number} Second tile index. - * @param [x] {number} specify a rectangle of tiles to operate. The x position in tiles of rectangle's left-top corner. - * @param [y] {number} specify a rectangle of tiles to operate. The y position in tiles of rectangle's left-top corner. - * @param [width] {number} specify a rectangle of tiles to operate. The width in tiles. - * @param [height] {number} specify a rectangle of tiles to operate. The height in tiles. + * @param [x] {number} specify a Rectangle of tiles to operate. The x position in tiles of Rectangle's left-top corner. + * @param [y] {number} specify a Rectangle of tiles to operate. The y position in tiles of Rectangle's left-top corner. + * @param [width] {number} specify a Rectangle of tiles to operate. The width in tiles. + * @param [height] {number} specify a Rectangle of tiles to operate. The height in tiles. */ function (tileA, tileB, x, y, width, height) { if (typeof x === "undefined") { x = 0; } @@ -10271,13 +10288,15 @@ var Phaser; * @param x {number} X position of the new sprite. * @param y {number} Y position of the new sprite. * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this sprite + * @param [frame] {string|number} If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name. * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) * @returns {Sprite} The newly created sprite object. */ - function (x, y, key, bodyType) { + function (x, y, key, frame, bodyType) { if (typeof key === "undefined") { key = ''; } + if (typeof frame === "undefined") { frame = null; } if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } - return this._world.group.add(new Phaser.Sprite(this._game, x, y, key, bodyType)); + return this._world.group.add(new Phaser.Sprite(this._game, x, y, key, frame, bodyType)); }; GameObjectFactory.prototype.dynamicTexture = /** * Create a new DynamicTexture with specific size. @@ -10676,7 +10695,7 @@ var Phaser; /** * StageScaleMode constructor */ - function StageScaleMode(game) { + function StageScaleMode(game, width, height) { var _this = this; /** * Stage height when start the game. @@ -10699,6 +10718,20 @@ var Phaser; */ this.incorrectOrientation = false; /** + * If you wish to align your game in the middle of the page then you can set this value to true. + * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing. + * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin. + * @type {Boolean} + */ + this.pageAlignHorizontally = false; + /** + * If you wish to align your game in the middle of the page then you can set this value to true. + * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing. + * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin. + * @type {Boolean} + */ + this.pageAlignVeritcally = false; + /** * Minimum width the canvas should be scaled to (in pixels) * @type {number} */ @@ -10744,6 +10777,10 @@ var Phaser; } this.scaleFactor = new Phaser.Vec2(1, 1); this.aspectRatio = 0; + this.minWidth = width; + this.minHeight = height; + this.maxWidth = width; + this.maxHeight = height; window.addEventListener('orientationchange', function (event) { return _this.checkOrientation(event); }, false); @@ -10888,7 +10925,8 @@ var Phaser; StageScaleMode.prototype.setScreenSize = /** * Set screen size automatically based on the scaleMode. */ - function () { + function (force) { + if (typeof force === "undefined") { force = false; } if(this._game.device.iPad == false && this._game.device.webApp == false && this._game.device.desktop == false) { if(this._game.device.android && this._game.device.chrome == false) { window.scrollTo(0, 1); @@ -10897,7 +10935,7 @@ var Phaser; } } this._iterations--; - if(window.innerHeight > this._startHeight || this._iterations < 0) { + if(force || window.innerHeight > this._startHeight || this._iterations < 0) { // Set minimum height of content to new window height document.documentElement.style.minHeight = window.innerHeight + 'px'; if(this.incorrectOrientation == true) { @@ -10913,29 +10951,43 @@ var Phaser; } }; StageScaleMode.prototype.setSize = function () { - if(this.maxWidth && this.width > this.maxWidth) { - this.width = this.maxWidth; - } - if(this.maxHeight && this.height > this.maxHeight) { - this.height = this.maxHeight; - } - if(this.minWidth && this.width < this.minWidth) { - this.width = this.minWidth; - } - if(this.minHeight && this.height < this.minHeight) { - this.height = this.minHeight; + if(this.incorrectOrientation == false) { + if(this.maxWidth && this.width > this.maxWidth) { + this.width = this.maxWidth; + } + if(this.maxHeight && this.height > this.maxHeight) { + this.height = this.maxHeight; + } + if(this.minWidth && this.width < this.minWidth) { + this.width = this.minWidth; + } + if(this.minHeight && this.height < this.minHeight) { + this.height = this.minHeight; + } } this._game.stage.canvas.style.width = this.width + 'px'; this._game.stage.canvas.style.height = this.height + 'px'; this._game.input.scaleX = this._game.stage.width / this.width; this._game.input.scaleY = this._game.stage.height / this.height; + if(this.pageAlignHorizontally) { + if(this.width < window.innerWidth && this.incorrectOrientation == false) { + this._game.stage.canvas.style.marginLeft = Math.round((window.innerWidth - this.width) / 2) + 'px'; + } else { + this._game.stage.canvas.style.marginLeft = '0px'; + } + } + if(this.pageAlignVeritcally) { + if(this.height < window.innerHeight && this.incorrectOrientation == false) { + this._game.stage.canvas.style.marginTop = Math.round((window.innerHeight - this.height) / 2) + 'px'; + } else { + this._game.stage.canvas.style.marginTop = '0px'; + } + } this._game.stage.getOffset(this._game.stage.canvas); this.aspectRatio = this.width / this.height; this.scaleFactor.x = this._game.stage.width / this.width; this.scaleFactor.y = this._game.stage.height / this.height; - //this.scaleFactor.x = this.width / this._game.stage.width; - //this.scaleFactor.y = this.height / this._game.stage.height; - }; + }; StageScaleMode.prototype.setMaximum = function () { this.width = window.innerWidth; this.height = window.innerHeight; @@ -11283,7 +11335,7 @@ var Phaser; }; this.context = this.canvas.getContext('2d'); this.scaleMode = Phaser.StageScaleMode.NO_SCALE; - this.scale = new Phaser.StageScaleMode(this._game); + this.scale = new Phaser.StageScaleMode(this._game, width, height); this.getOffset(this.canvas); this.bounds = new Phaser.Rectangle(this.offset.x, this.offset.y, width, height); this.aspectRatio = width / height; @@ -11307,6 +11359,7 @@ var Phaser; this.bootScreen = new Phaser.BootScreen(this._game); this.pauseScreen = new Phaser.PauseScreen(this._game, this.width, this.height); this.orientationScreen = new Phaser.OrientationScreen(this._game); + this.scale.setScreenSize(true); }; Stage.prototype.update = /** * Update stage for rendering. This will handle scaling, clearing @@ -11364,6 +11417,12 @@ var Phaser; } } }; + Stage.prototype.setImageRenderingCrisp = function () { + this.canvas.style['image-rendering'] = 'crisp-edges'; + this.canvas.style['image-rendering'] = '-moz-crisp-edges'; + this.canvas.style['image-rendering'] = '-webkit-optimize-contrast'; + this.canvas.style['-ms-interpolation-mode'] = 'nearest-neighbor'; + }; Stage.prototype.pauseGame = function () { if(this.disablePauseScreen == false && this.pauseScreen) { this.pauseScreen.onPaused(); @@ -11967,7 +12026,7 @@ var Phaser; } this._velocityDelta = (this.computeVelocity(body.angularVelocity, body.gravity.x, body.angularAcceleration, body.angularDrag, body.maxAngular) - body.angularVelocity) / 2; body.angularVelocity += this._velocityDelta; - body.angle += body.angularVelocity * this.game.time.elapsed; + body.sprite.transform.rotation += body.angularVelocity * this.game.time.elapsed; body.angularVelocity += this._velocityDelta; this._velocityDelta = (this.computeVelocity(body.velocity.x, body.gravity.x, body.acceleration.x, body.drag.x) - body.velocity.x) / 2; body.velocity.x += this._velocityDelta; @@ -12167,7 +12226,7 @@ var Phaser; body1.velocity.y = this._obj2Velocity - this._obj1Velocity * body1.bounce.y; // This is special case code that handles things like horizontal moving platforms you can ride //if (body2.parent.active && body2.moves && (body1.deltaY > body2.deltaY)) - if(body2.parent.active && (body1.deltaY > body2.deltaY)) { + if(body2.sprite.active && (body1.deltaY > body2.deltaY)) { body1.position.x += body2.position.x - body2.oldPosition.x; } } else if(body1.type != Phaser.Types.BODY_DYNAMIC) { @@ -12176,7 +12235,7 @@ var Phaser; body2.velocity.y = this._obj1Velocity - this._obj2Velocity * body2.bounce.y; // This is special case code that handles things like horizontal moving platforms you can ride //if (object1.active && body1.moves && (body1.deltaY < body2.deltaY)) - if(body1.parent.active && (body1.deltaY < body2.deltaY)) { + if(body1.sprite.active && (body1.deltaY < body2.deltaY)) { body2.position.x += body1.position.x - body1.oldPosition.x; } } @@ -13136,8 +13195,8 @@ var Phaser; * @return {number} Distance (in pixels) */ function (a, target) { - var dx = (a.x + a.origin.x) - (target.x); - var dy = (a.y + a.origin.y) - (target.y); + var dx = (a.x + a.transform.origin.x) - (target.x); + var dy = (a.y + a.transform.origin.y) - (target.y); return this.game.math.vectorLength(dx, dy); }; Motion.prototype.distanceToMouse = /** @@ -13147,8 +13206,8 @@ var Phaser; * @return {number} The distance between the given sprite and the mouse coordinates */ function (a) { - var dx = (a.x + a.origin.x) - this.game.input.x; - var dy = (a.y + a.origin.y) - this.game.input.y; + var dx = (a.x + a.transform.origin.x) - this.game.input.x; + var dy = (a.y + a.transform.origin.y) - this.game.input.y; return this.game.math.vectorLength(dx, dy); }; Motion.prototype.angleBetweenPoint = /** @@ -13163,8 +13222,8 @@ var Phaser; */ function (a, target, asDegrees) { if (typeof asDegrees === "undefined") { asDegrees = false; } - var dx = (target.x) - (a.x + a.origin.x); - var dy = (target.y) - (a.y + a.origin.y); + var dx = (target.x) - (a.x + a.transform.origin.x); + var dy = (target.y) - (a.y + a.transform.origin.y); if(asDegrees) { return this.game.math.radiansToDegrees(Math.atan2(dy, dx)); } else { @@ -13183,8 +13242,8 @@ var Phaser; */ function (a, b, asDegrees) { if (typeof asDegrees === "undefined") { asDegrees = false; } - var dx = (b.x + b.origin.x) - (a.x + a.origin.x); - var dy = (b.y + b.origin.y) - (a.y + a.origin.y); + var dx = (b.x + b.transform.origin.x) - (a.x + a.transform.origin.x); + var dy = (b.y + b.transform.origin.y) - (a.y + a.transform.origin.y); if(asDegrees) { return this.game.math.radiansToDegrees(Math.atan2(dy, dx)); } else { @@ -13941,7 +14000,7 @@ var Phaser; * @param x {number} The x coordinate of the anchor point * @param y {number} The y coordinate of the anchor point * @param {Number} angle The angle in radians (unless asDegrees is true) to rotate the Point to. - * @param {Boolean} asDegrees Is the given angle in radians (false) or degrees (true)? + * @param {Boolean} asDegrees Is the given rotation in radians (false) or degrees (true)? * @param {Number} distance An optional distance constraint between the Point and the anchor. * @return The modified point object */ @@ -13964,7 +14023,7 @@ var Phaser; * @param x {number} The x coordinate of the anchor point * @param y {number} The y coordinate of the anchor point * @param {Number} angle The angle in radians (unless asDegrees is true) to rotate the Point to. - * @param {Boolean} asDegrees Is the given angle in radians (false) or degrees (true)? + * @param {Boolean} asDegrees Is the given rotation in radians (false) or degrees (true)? * @param {Number} distance An optional distance constraint between the Point and the anchor. * @return The modified point object */ @@ -14162,7 +14221,7 @@ var Phaser; configurable: true }); Pointer.prototype.getWorldX = /** - * Gets the X value of this Pointer in world coordinate space + * Gets the X value of this Pointer in world coordinate space (is it properly scaled?) * @param {Camera} [camera] */ function (camera) { @@ -14222,6 +14281,7 @@ var Phaser; this.isUp = false; this.timeDown = this.game.time.now; this._holdSent = false; + // x and y are the old values here? this.positionDown.setTo(this.x, this.y); this.move(event); if(this.game.input.multiInputOverride == Phaser.Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Phaser.Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == Phaser.Input.TOUCH_OVERRIDES_MOUSE && this.game.input.currentPointers == 0)) { @@ -15762,6 +15822,14 @@ var Phaser; if (typeof lineWidth === "undefined") { lineWidth = 1; } return true; }; + HeadlessRenderer.prototype.preRenderCamera = function (camera) { + }; + HeadlessRenderer.prototype.postRenderCamera = function (camera) { + }; + HeadlessRenderer.prototype.preRenderGroup = function (camera, group) { + }; + HeadlessRenderer.prototype.postRenderGroup = function (camera, group) { + }; return HeadlessRenderer; })(); Phaser.HeadlessRenderer = HeadlessRenderer; @@ -15798,9 +15866,9 @@ var Phaser; // Then iterate through world.group on them all (where not blacklisted, etc) for(var c = 0; c < this._cameraList.length; c++) { this._camera = this._cameraList[c]; - this._camera.preRender(); + this.preRenderCamera(this._camera); this._game.world.group.render(this._camera); - this._camera.postRender(); + this.postRenderCamera(this._camera); } this.renderTotal = this._count; }; @@ -15811,21 +15879,236 @@ var Phaser; this.renderScrollZone(this._camera, object); } }; + CanvasRenderer.prototype.preRenderGroup = function (camera, group) { + if(camera.transform.scale.x == 0 || camera.transform.scale.y == 0 || camera.texture.alpha < 0.1 || this.inScreen(camera) == false) { + return false; + } + // Reset our temp vars + this._ga = -1; + this._sx = 0; + this._sy = 0; + this._sw = group.texture.width; + this._sh = group.texture.height; + this._fx = group.transform.scale.x; + this._fy = group.transform.scale.y; + this._sin = 0; + this._cos = 1; + //this._dx = (camera.screenView.x * camera.scrollFactor.x) + camera.frameBounds.x - (camera.worldView.x * camera.scrollFactor.x); + //this._dy = (camera.screenView.y * camera.scrollFactor.y) + camera.frameBounds.y - (camera.worldView.y * camera.scrollFactor.y); + this._dx = 0; + this._dy = 0; + this._dw = group.texture.width; + this._dh = group.texture.height; + // Global Composite Ops + if(group.texture.globalCompositeOperation) { + group.texture.context.save(); + group.texture.context.globalCompositeOperation = group.texture.globalCompositeOperation; + } + // Alpha + if(group.texture.alpha !== 1 && group.texture.context.globalAlpha !== group.texture.alpha) { + this._ga = group.texture.context.globalAlpha; + group.texture.context.globalAlpha = group.texture.alpha; + } + // Flip X + if(group.texture.flippedX) { + this._fx = -group.transform.scale.x; + } + // Flip Y + if(group.texture.flippedY) { + this._fy = -group.transform.scale.y; + } + // Rotation and Flipped + if(group.modified) { + if(group.transform.rotation !== 0 || group.transform.rotationOffset !== 0) { + this._sin = Math.sin(group.game.math.degreesToRadians(group.transform.rotationOffset + group.transform.rotation)); + this._cos = Math.cos(group.game.math.degreesToRadians(group.transform.rotationOffset + group.transform.rotation)); + } + // setTransform(a, b, c, d, e, f); + // a = scale x + // b = skew x + // c = skew y + // d = scale y + // e = translate x + // f = translate y + group.texture.context.save(); + group.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + group.transform.skew.x, -(this._sin * this._fy) + group.transform.skew.y, this._cos * this._fy, this._dx, this._dy); + this._dx = -group.transform.origin.x; + this._dy = -group.transform.origin.y; + } else { + if(!group.transform.origin.equals(0)) { + this._dx -= group.transform.origin.x; + this._dy -= group.transform.origin.y; + } + } + this._sx = Math.round(this._sx); + this._sy = Math.round(this._sy); + this._sw = Math.round(this._sw); + this._sh = Math.round(this._sh); + this._dx = Math.round(this._dx); + this._dy = Math.round(this._dy); + this._dw = Math.round(this._dw); + this._dh = Math.round(this._dh); + if(group.texture.opaque) { + group.texture.context.fillStyle = group.texture.backgroundColor; + group.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); + } + if(group.texture.loaded) { + group.texture.context.drawImage(group.texture.texture, // Source Image + this._sx, // Source X (location within the source image) + this._sy, // Source Y + this._sw, // Source Width + this._sh, // Source Height + this._dx, // Destination X (where on the canvas it'll be drawn) + this._dy, // Destination Y + this._dw, // Destination Width (always same as Source Width unless scaled) + this._dh); + // Destination Height (always same as Source Height unless scaled) + } + return true; + }; + CanvasRenderer.prototype.postRenderGroup = function (camera, group) { + if(group.modified || group.texture.globalCompositeOperation) { + group.texture.context.restore(); + } + // This could have been over-written by a sprite, need to store elsewhere + if(this._ga > -1) { + group.texture.context.globalAlpha = this._ga; + } + }; CanvasRenderer.prototype.inCamera = /** - * Check whether this object is visible in a specific camera rectangle. - * @param camera {Rectangle} The rectangle you want to check. - * @return {boolean} Return true if bounds of this sprite intersects the given rectangle, otherwise return false. + * Check whether this object is visible in a specific camera Rectangle. + * @param camera {Rectangle} The Rectangle you want to check. + * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. */ function (camera, sprite) { + return true; + /* + // Object fixed in place regardless of the camera scrolling? Then it's always visible - if(sprite.scrollFactor.x == 0 && sprite.scrollFactor.y == 0) { - return true; + if (sprite.scrollFactor.x == 0 && sprite.scrollFactor.y == 0) + { + return true; } + this._dx = sprite.frameBounds.x - (camera.worldView.x * sprite.scrollFactor.x); this._dy = sprite.frameBounds.y - (camera.worldView.y * sprite.scrollFactor.y); this._dw = sprite.frameBounds.width * sprite.scale.x; this._dh = sprite.frameBounds.height * sprite.scale.y; - return (camera.scaledX + camera.worldView.width > this._dx) && (camera.scaledX < this._dx + this._dw) && (camera.scaledY + camera.worldView.height > this._dy) && (camera.scaledY < this._dy + this._dh); + + //return (camera.screenView.x + camera.worldView.width > this._dx) && (camera.screenView.x < this._dx + this._dw) && (camera.screenView.y + camera.worldView.height > this._dy) && (camera.screenView.y < this._dy + this._dh); + + */ + }; + CanvasRenderer.prototype.inScreen = function (camera) { + return true; + }; + CanvasRenderer.prototype.preRenderCamera = /** + * Render this sprite to specific camera. Called by game loop after update(). + * @param camera {Camera} Camera this sprite will be rendered to. + * @return {boolean} Return false if not rendered, otherwise return true. + */ + function (camera) { + if(camera.transform.scale.x == 0 || camera.transform.scale.y == 0 || camera.texture.alpha < 0.1 || this.inScreen(camera) == false) { + return false; + } + // Reset our temp vars + this._ga = -1; + this._sx = 0; + this._sy = 0; + this._sw = camera.width; + this._sh = camera.height; + this._fx = camera.transform.scale.x; + this._fy = camera.transform.scale.y; + this._sin = 0; + this._cos = 1; + this._dx = camera.screenView.x; + this._dy = camera.screenView.y; + this._dw = camera.width; + this._dh = camera.height; + // Global Composite Ops + if(camera.texture.globalCompositeOperation) { + camera.texture.context.save(); + camera.texture.context.globalCompositeOperation = camera.texture.globalCompositeOperation; + } + // Alpha + if(camera.texture.alpha !== 1 && camera.texture.context.globalAlpha != camera.texture.alpha) { + this._ga = camera.texture.context.globalAlpha; + camera.texture.context.globalAlpha = camera.texture.alpha; + } + // Sprite Flip X + if(camera.texture.flippedX) { + this._fx = -camera.transform.scale.x; + } + // Sprite Flip Y + if(camera.texture.flippedY) { + this._fy = -camera.transform.scale.y; + } + // Rotation and Flipped + if(camera.modified) { + if(camera.transform.rotation !== 0 || camera.transform.rotationOffset !== 0) { + this._sin = Math.sin(camera.game.math.degreesToRadians(camera.transform.rotationOffset + camera.transform.rotation)); + this._cos = Math.cos(camera.game.math.degreesToRadians(camera.transform.rotationOffset + camera.transform.rotation)); + } + // setTransform(a, b, c, d, e, f); + // a = scale x + // b = skew x + // c = skew y + // d = scale y + // e = translate x + // f = translate y + camera.texture.context.save(); + camera.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + camera.transform.skew.x, -(this._sin * this._fy) + camera.transform.skew.y, this._cos * this._fy, this._dx, this._dy); + this._dx = -camera.transform.origin.x; + this._dy = -camera.transform.origin.y; + } else { + if(!camera.transform.origin.equals(0)) { + this._dx -= camera.transform.origin.x; + this._dy -= camera.transform.origin.y; + } + } + this._sx = Math.round(this._sx); + this._sy = Math.round(this._sy); + this._sw = Math.round(this._sw); + this._sh = Math.round(this._sh); + this._dx = Math.round(this._dx); + this._dy = Math.round(this._dy); + this._dw = Math.round(this._dw); + this._dh = Math.round(this._dh); + // Clip the camera so we don't get sprites appearing outside the edges + if(camera.clip == true && camera.disableClipping == false) { + camera.texture.context.beginPath(); + camera.texture.context.rect(camera.screenView.x, camera.screenView.x, camera.screenView.width, camera.screenView.height); + camera.texture.context.closePath(); + camera.texture.context.clip(); + } + if(camera.texture.opaque) { + camera.texture.context.fillStyle = camera.texture.backgroundColor; + camera.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); + } + //camera.fx.render(camera); + if(camera.texture.loaded) { + camera.texture.context.drawImage(camera.texture.texture, // Source Image + this._sx, // Source X (location within the source image) + this._sy, // Source Y + this._sw, // Source Width + this._sh, // Source Height + this._dx, // Destination X (where on the canvas it'll be drawn) + this._dy, // Destination Y + this._dw, // Destination Width (always same as Source Width unless scaled) + this._dh); + // Destination Height (always same as Source Height unless scaled) + } + return true; + }; + CanvasRenderer.prototype.postRenderCamera = function (camera) { + //camera.fx.postRender(camera); + if(camera.modified || camera.texture.globalCompositeOperation) { + camera.texture.context.restore(); + } + // This could have been over-written by a sprite, need to store elsewhere + if(this._ga > -1) { + camera.texture.context.globalAlpha = this._ga; + } }; CanvasRenderer.prototype.renderCircle = function (camera, circle, context, outline, fill, lineColor, fillColor, lineWidth) { if (typeof outline === "undefined") { outline = false; } @@ -15843,8 +16126,8 @@ var Phaser; this._fy = 1; this._sin = 0; this._cos = 1; - this._dx = camera.scaledX + circle.x - camera.worldView.x; - this._dy = camera.scaledY + circle.y - camera.worldView.y; + this._dx = camera.screenView.x + circle.x - camera.worldView.x; + this._dy = camera.screenView.y + circle.y - camera.worldView.y; this._dw = circle.diameter; this._dh = circle.diameter; this._sx = Math.round(this._sx); @@ -15879,7 +16162,7 @@ var Phaser; * @return {boolean} Return false if not rendered, otherwise return true. */ function (camera, sprite) { - if(sprite.scale.x == 0 || sprite.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { + if(sprite.transform.scale.x == 0 || sprite.transform.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { return false; } sprite.renderOrderID = this._count; @@ -15888,28 +16171,33 @@ var Phaser; this._ga = -1; this._sx = 0; this._sy = 0; - this._sw = sprite.frameBounds.width; - this._sh = sprite.frameBounds.height; - this._fx = sprite.scale.x; - this._fy = sprite.scale.y; + this._sw = sprite.texture.width; + this._sh = sprite.texture.height; + this._fx = sprite.transform.scale.x; + this._fy = sprite.transform.scale.y; this._sin = 0; this._cos = 1; - this._dx = (camera.scaledX * sprite.scrollFactor.x) + sprite.frameBounds.x - (camera.worldView.x * sprite.scrollFactor.x); - 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; + this._dx = (camera.screenView.x * sprite.transform.scrollFactor.x) + sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + this._dy = (camera.screenView.y * sprite.transform.scrollFactor.y) + sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + this._dw = sprite.texture.width; + this._dh = sprite.texture.height; + // Global Composite Ops + if(sprite.texture.globalCompositeOperation) { + sprite.texture.context.save(); + sprite.texture.context.globalCompositeOperation = sprite.texture.globalCompositeOperation; + } // Alpha - if(sprite.texture.alpha !== 1) { + if(sprite.texture.alpha !== 1 && sprite.texture.context.globalAlpha != sprite.texture.alpha) { this._ga = sprite.texture.context.globalAlpha; sprite.texture.context.globalAlpha = sprite.texture.alpha; } // Sprite Flip X if(sprite.texture.flippedX) { - this._fx = -sprite.scale.x; + this._fx = -sprite.transform.scale.x; } // Sprite Flip Y if(sprite.texture.flippedY) { - this._fy = -sprite.scale.y; + this._fy = -sprite.transform.scale.y; } if(sprite.animations.currentFrame !== null) { this._sx = sprite.animations.currentFrame.x; @@ -15917,13 +16205,17 @@ var Phaser; if(sprite.animations.currentFrame.trimmed) { this._dx += sprite.animations.currentFrame.spriteSourceSizeX; this._dy += sprite.animations.currentFrame.spriteSourceSizeY; + this._sw = sprite.animations.currentFrame.spriteSourceSizeW; + this._sh = sprite.animations.currentFrame.spriteSourceSizeH; + this._dw = sprite.animations.currentFrame.spriteSourceSizeW; + this._dh = sprite.animations.currentFrame.spriteSourceSizeH; } } // Rotation and Flipped if(sprite.modified) { - if(sprite.texture.renderRotation == true && (sprite.angle !== 0 || sprite.angleOffset !== 0)) { - this._sin = Math.sin(sprite.game.math.degreesToRadians(sprite.angleOffset + sprite.angle)); - this._cos = Math.cos(sprite.game.math.degreesToRadians(sprite.angleOffset + sprite.angle)); + if(sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.transform.rotationOffset !== 0)) { + this._sin = Math.sin(sprite.game.math.degreesToRadians(sprite.transform.rotationOffset + sprite.rotation)); + this._cos = Math.cos(sprite.game.math.degreesToRadians(sprite.transform.rotationOffset + sprite.rotation)); } // setTransform(a, b, c, d, e, f); // a = scale x @@ -15933,13 +16225,13 @@ var Phaser; // e = translate x // f = translate y sprite.texture.context.save(); - 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; + sprite.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + sprite.transform.skew.x, -(this._sin * this._fy) + sprite.transform.skew.y, this._cos * this._fy, this._dx, this._dy); + this._dx = -sprite.transform.origin.x; + this._dy = -sprite.transform.origin.y; } else { - if(!sprite.origin.equals(0)) { - this._dx -= sprite.origin.x; - this._dy -= sprite.origin.y; + if(!sprite.transform.origin.equals(0)) { + this._dx -= sprite.transform.origin.x; + this._dy -= sprite.transform.origin.y; } } this._sx = Math.round(this._sx); @@ -15950,6 +16242,10 @@ var Phaser; this._dy = Math.round(this._dy); this._dw = Math.round(this._dw); this._dh = Math.round(this._dh); + if(sprite.texture.opaque) { + sprite.texture.context.fillStyle = sprite.texture.backgroundColor; + sprite.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); + } if(sprite.texture.loaded) { sprite.texture.context.drawImage(sprite.texture.texture, // Source Image this._sx, // Source X (location within the source image) @@ -15961,12 +16257,8 @@ var Phaser; this._dw, // Destination Width (always same as Source Width unless scaled) this._dh); // Destination Height (always same as Source Height unless scaled) - } else { - //sprite.texture.context.fillStyle = this.fillColor; - sprite.texture.context.fillStyle = 'rgb(255,255,255)'; - sprite.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); - } - if(sprite.modified) { + } + if(sprite.modified || sprite.texture.globalCompositeOperation) { sprite.texture.context.restore(); } if(this._ga > -1) { @@ -15975,7 +16267,7 @@ var Phaser; return true; }; CanvasRenderer.prototype.renderScrollZone = function (camera, scrollZone) { - if(scrollZone.scale.x == 0 || scrollZone.scale.y == 0 || scrollZone.texture.alpha < 0.1 || this.inCamera(camera, scrollZone) == false) { + if(scrollZone.transform.scale.x == 0 || scrollZone.transform.scale.y == 0 || scrollZone.texture.alpha < 0.1 || this.inCamera(camera, scrollZone) == false) { return false; } this._count++; @@ -15983,16 +16275,16 @@ var Phaser; this._ga = -1; this._sx = 0; this._sy = 0; - this._sw = scrollZone.frameBounds.width; - this._sh = scrollZone.frameBounds.height; - this._fx = scrollZone.scale.x; - this._fy = scrollZone.scale.y; + this._sw = scrollZone.width; + this._sh = scrollZone.height; + this._fx = scrollZone.transform.scale.x; + this._fy = scrollZone.transform.scale.y; this._sin = 0; this._cos = 1; - this._dx = (camera.scaledX * scrollZone.scrollFactor.x) + scrollZone.frameBounds.x - (camera.worldView.x * scrollZone.scrollFactor.x); - this._dy = (camera.scaledY * scrollZone.scrollFactor.y) + scrollZone.frameBounds.y - (camera.worldView.y * scrollZone.scrollFactor.y); - this._dw = scrollZone.frameBounds.width; - this._dh = scrollZone.frameBounds.height; + this._dx = (camera.screenView.x * scrollZone.transform.scrollFactor.x) + scrollZone.x - (camera.worldView.x * scrollZone.transform.scrollFactor.x); + this._dy = (camera.screenView.y * scrollZone.transform.scrollFactor.y) + scrollZone.y - (camera.worldView.y * scrollZone.transform.scrollFactor.y); + this._dw = scrollZone.width; + this._dh = scrollZone.height; // Alpha if(scrollZone.texture.alpha !== 1) { this._ga = scrollZone.texture.context.globalAlpha; @@ -16000,17 +16292,17 @@ var Phaser; } // Sprite Flip X if(scrollZone.texture.flippedX) { - this._fx = -scrollZone.scale.x; + this._fx = -scrollZone.transform.scale.x; } // Sprite Flip Y if(scrollZone.texture.flippedY) { - this._fy = -scrollZone.scale.y; + this._fy = -scrollZone.transform.scale.y; } // Rotation and Flipped if(scrollZone.modified) { - if(scrollZone.texture.renderRotation == true && (scrollZone.angle !== 0 || scrollZone.angleOffset !== 0)) { - this._sin = Math.sin(scrollZone.game.math.degreesToRadians(scrollZone.angleOffset + scrollZone.angle)); - this._cos = Math.cos(scrollZone.game.math.degreesToRadians(scrollZone.angleOffset + scrollZone.angle)); + if(scrollZone.texture.renderRotation == true && (scrollZone.rotation !== 0 || scrollZone.transform.rotationOffset !== 0)) { + this._sin = Math.sin(scrollZone.game.math.degreesToRadians(scrollZone.transform.rotationOffset + scrollZone.rotation)); + this._cos = Math.cos(scrollZone.game.math.degreesToRadians(scrollZone.transform.rotationOffset + scrollZone.rotation)); } // setTransform(a, b, c, d, e, f); // a = scale x @@ -16020,13 +16312,13 @@ var Phaser; // e = translate x // f = translate y scrollZone.texture.context.save(); - scrollZone.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + scrollZone.skew.x, -(this._sin * this._fy) + scrollZone.skew.y, this._cos * this._fy, this._dx, this._dy); - this._dx = -scrollZone.origin.x; - this._dy = -scrollZone.origin.y; + scrollZone.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + scrollZone.transform.skew.x, -(this._sin * this._fy) + scrollZone.transform.skew.y, this._cos * this._fy, this._dx, this._dy); + this._dx = -scrollZone.transform.origin.x; + this._dy = -scrollZone.transform.origin.y; } else { - if(!scrollZone.origin.equals(0)) { - this._dx -= scrollZone.origin.x; - this._dy -= scrollZone.origin.y; + if(!scrollZone.transform.origin.equals(0)) { + this._dx -= scrollZone.transform.origin.x; + this._dy -= scrollZone.transform.origin.y; } } this._sx = Math.round(this._sx); @@ -16080,8 +16372,8 @@ var Phaser; function renderSpriteInfo(sprite, x, y, color) { if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } DebugUtils.game.stage.context.fillStyle = color; - DebugUtils.game.stage.context.fillText('Sprite: ' + ' (' + sprite.frameBounds.width + ' x ' + sprite.frameBounds.height + ')', x, y); - DebugUtils.game.stage.context.fillText('x: ' + sprite.frameBounds.x.toFixed(1) + ' y: ' + sprite.frameBounds.y.toFixed(1) + ' angle: ' + sprite.angle.toFixed(1), x, y + 14); + DebugUtils.game.stage.context.fillText('Sprite: ' + ' (' + sprite.width + ' x ' + sprite.height + ')', x, y); + DebugUtils.game.stage.context.fillText('x: ' + sprite.x.toFixed(1) + ' y: ' + sprite.y.toFixed(1) + ' rotation: ' + sprite.rotation.toFixed(1), x, y + 14); //DebugUtils.game.stage.context.fillText('dx: ' + this._dx.toFixed(1) + ' dy: ' + this._dy.toFixed(1) + ' dw: ' + this._dw.toFixed(1) + ' dh: ' + this._dh.toFixed(1), x, y + 28); //DebugUtils.game.stage.context.fillText('sx: ' + this._sx.toFixed(1) + ' sy: ' + this._sy.toFixed(1) + ' sw: ' + this._sw.toFixed(1) + ' sh: ' + this._sh.toFixed(1), x, y + 42); }; diff --git a/Tests/scrollzones/blasteroids.js b/Tests/scrollzones/blasteroids.js index 2b431080..474a7023 100644 --- a/Tests/scrollzones/blasteroids.js +++ b/Tests/scrollzones/blasteroids.js @@ -24,13 +24,13 @@ // Looks like a smoke trail! //emitter.globalCompositeOperation = 'xor'; // Looks way cool :) - emitter.globalCompositeOperation = 'lighter'; + emitter.texture.globalCompositeOperation = 'lighter'; bullets = game.add.group(50); // Create our bullet pool for(var i = 0; i < 50; i++) { var tempBullet = new Phaser.Sprite(game, game.stage.centerX, game.stage.centerY, 'bullet'); tempBullet.exists = false; - tempBullet.angleOffset = 90; + tempBullet.transform.rotationOffset = 90; //tempBullet.setBounds(-100, -100, 900, 700); //tempBullet.outOfBoundsAction = Phaser.GameObject.OUT_OF_BOUNDS_KILL; bullets.add(tempBullet); @@ -38,7 +38,7 @@ ship = game.add.sprite(game.stage.centerX, game.stage.centerY, 'nashwan', Phaser.Types.BODY_DYNAMIC); Phaser.SpriteUtils.setOriginToCenter(ship); // We do this because the ship was drawn facing up, but 0 degrees is pointing to the right - ship.angleOffset = 90; + ship.transform.rotationOffset = 90; game.input.onDown.add(test, this); } function test(event) { @@ -62,7 +62,7 @@ speed = 0; } } - shipMotion = game.motion.velocityFromAngle(ship.angle, speed); + shipMotion = game.motion.velocityFromAngle(ship.rotation, speed); scroller.setSpeed(shipMotion.x, shipMotion.y); // emit particles if(speed > 2) { @@ -89,9 +89,9 @@ var b = bullets.getFirstAvailable(); b.x = ship.x; b.y = ship.y - 26; - var bulletMotion = game.motion.velocityFromAngle(ship.angle, 400); + var bulletMotion = game.motion.velocityFromAngle(ship.rotation, 400); b.revive(); - b.angle = ship.angle; + b.rotation = ship.rotation; b.body.velocity.setTo(bulletMotion.x, bulletMotion.y); fireRate = game.time.now + 100; } diff --git a/Tests/scrollzones/blasteroids.ts b/Tests/scrollzones/blasteroids.ts index 6f969fef..2877fed1 100644 --- a/Tests/scrollzones/blasteroids.ts +++ b/Tests/scrollzones/blasteroids.ts @@ -37,7 +37,7 @@ //emitter.globalCompositeOperation = 'xor'; // Looks way cool :) - emitter.globalCompositeOperation = 'lighter'; + emitter.texture.globalCompositeOperation = 'lighter'; bullets = game.add.group(50); @@ -46,7 +46,7 @@ { var tempBullet = new Phaser.Sprite(game, game.stage.centerX, game.stage.centerY, 'bullet'); tempBullet.exists = false; - tempBullet.angleOffset = 90; + tempBullet.transform.rotationOffset = 90; //tempBullet.setBounds(-100, -100, 900, 700); //tempBullet.outOfBoundsAction = Phaser.GameObject.OUT_OF_BOUNDS_KILL; bullets.add(tempBullet); @@ -56,7 +56,7 @@ Phaser.SpriteUtils.setOriginToCenter(ship); // We do this because the ship was drawn facing up, but 0 degrees is pointing to the right - ship.angleOffset = 90; + ship.transform.rotationOffset = 90; game.input.onDown.add(test, this); @@ -99,7 +99,7 @@ } } - shipMotion = game.motion.velocityFromAngle(ship.angle, speed); + shipMotion = game.motion.velocityFromAngle(ship.rotation, speed); scroller.setSpeed(shipMotion.x, shipMotion.y); @@ -144,10 +144,10 @@ b.x = ship.x; b.y = ship.y - 26; - var bulletMotion = game.motion.velocityFromAngle(ship.angle, 400); + var bulletMotion = game.motion.velocityFromAngle(ship.rotation, 400); b.revive(); - b.angle = ship.angle; + b.rotation = ship.rotation; b.body.velocity.setTo(bulletMotion.x, bulletMotion.y); fireRate = game.time.now + 100; diff --git a/Tests/scrollzones/skewed scroller.js b/Tests/scrollzones/skewed scroller.js index c217d4ce..6e4ebabf 100644 --- a/Tests/scrollzones/skewed scroller.js +++ b/Tests/scrollzones/skewed scroller.js @@ -11,12 +11,12 @@ var topFace; function create() { topFace = game.add.scrollZone('balls', 200, 0, 204, 204).setSpeed(0, 2.2); - topFace.skew.setTo(0, Math.tan(game.math.radiansToDegrees(-30))); - topFace.scale.setTo(1, 1.3); + topFace.transform.skew.setTo(0, Math.tan(game.math.radiansToDegrees(-30))); + topFace.transform.scale.setTo(1, 1.3); leftFace = game.add.scrollZone('balls', 110, 264, 204, 204).setSpeed(0, 2.1); - leftFace.skew.setTo(0, Math.tan(game.math.radiansToDegrees(30))); + leftFace.transform.skew.setTo(0, Math.tan(game.math.radiansToDegrees(30))); rightFace = game.add.scrollZone('balls', 200, 466, 204, 204).setSpeed(0, 2); - rightFace.skew.setTo(0, Math.tan(game.math.radiansToDegrees(-30))); - rightFace.scale.setTo(1, 0.8); + rightFace.transform.skew.setTo(0, Math.tan(game.math.radiansToDegrees(-30))); + rightFace.transform.scale.setTo(1, 0.8); } })(); diff --git a/Tests/scrollzones/skewed scroller.ts b/Tests/scrollzones/skewed scroller.ts index 58d37f98..4a3c3d10 100644 --- a/Tests/scrollzones/skewed scroller.ts +++ b/Tests/scrollzones/skewed scroller.ts @@ -19,15 +19,15 @@ function create() { topFace = game.add.scrollZone('balls', 200, 0, 204, 204).setSpeed(0, 2.2); - topFace.skew.setTo(0, Math.tan(game.math.radiansToDegrees(-30))); - topFace.scale.setTo(1, 1.3); + topFace.transform.skew.setTo(0, Math.tan(game.math.radiansToDegrees(-30))); + topFace.transform.scale.setTo(1, 1.3); leftFace = game.add.scrollZone('balls', 110, 264, 204, 204).setSpeed(0, 2.1); - leftFace.skew.setTo(0, Math.tan(game.math.radiansToDegrees(30))); + leftFace.transform.skew.setTo(0, Math.tan(game.math.radiansToDegrees(30))); rightFace = game.add.scrollZone('balls', 200, 466, 204, 204).setSpeed(0, 2); - rightFace.skew.setTo(0, Math.tan(game.math.radiansToDegrees(-30))); - rightFace.scale.setTo(1, 0.8); + rightFace.transform.skew.setTo(0, Math.tan(game.math.radiansToDegrees(-30))); + rightFace.transform.scale.setTo(1, 0.8); } diff --git a/Tests/sprites/animation 1.js b/Tests/sprites/animation 1.js index 54013aba..eb481565 100644 --- a/Tests/sprites/animation 1.js +++ b/Tests/sprites/animation 1.js @@ -18,6 +18,6 @@ // 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); + mummy.transform.scale.setTo(4, 4); } })(); diff --git a/Tests/sprites/animation 1.ts b/Tests/sprites/animation 1.ts index 6ee645fb..c2f3eaab 100644 --- a/Tests/sprites/animation 1.ts +++ b/Tests/sprites/animation 1.ts @@ -30,7 +30,7 @@ mummy.animations.play('walk', 20, true); // This just scales the sprite up so you can see the animation better - mummy.scale.setTo(4, 4); + mummy.transform.scale.setTo(4, 4); } diff --git a/Tests/sprites/animation 2.js b/Tests/sprites/animation 2.js index 582c861c..abb16cd1 100644 --- a/Tests/sprites/animation 2.js +++ b/Tests/sprites/animation 2.js @@ -17,6 +17,6 @@ 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); + monster.transform.scale.setTo(2, 2); } })(); diff --git a/Tests/sprites/animation 2.ts b/Tests/sprites/animation 2.ts index 3eb72b74..ae9ff95f 100644 --- a/Tests/sprites/animation 2.ts +++ b/Tests/sprites/animation 2.ts @@ -29,7 +29,7 @@ // 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); + monster.transform.scale.setTo(2, 2); } diff --git a/Tests/sprites/atlas 1.js b/Tests/sprites/atlas 1.js new file mode 100644 index 00000000..8c21c9e1 --- /dev/null +++ b/Tests/sprites/atlas 1.js @@ -0,0 +1,17 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + function init() { + game.load.atlas('atlas', 'assets/sprites/invaderpig.png', 'assets/sprites/invaderpig.json'); + game.load.start(); + } + var pig; + var invader; + function create() { + game.stage.backgroundColor = 'rgb(40, 40, 40)'; + pig = game.add.sprite(200, 200, 'atlas', 'tennyson'); + invader = game.add.sprite(0, 0, 'atlas', 'invader1'); + console.log(pig.width, pig.height, pig.body.bounds.width, pig.body.bounds.height, pig.worldView); + console.log(invader.width, invader.height, invader.body.bounds.width, invader.body.bounds.height, invader.worldView); + } +})(); diff --git a/Tests/sprites/atlas 1.ts b/Tests/sprites/atlas 1.ts new file mode 100644 index 00000000..67a80187 --- /dev/null +++ b/Tests/sprites/atlas 1.ts @@ -0,0 +1,29 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + + function init() { + + game.load.atlas('atlas', 'assets/sprites/invaderpig.png', 'assets/sprites/invaderpig.json'); + game.load.start(); + + } + + var pig: Phaser.Sprite; + var invader: Phaser.Sprite; + + function create() { + + game.stage.backgroundColor = 'rgb(40, 40, 40)'; + + pig = game.add.sprite(200, 200, 'atlas', 'tennyson'); + invader = game.add.sprite(0, 0, 'atlas', 'invader1'); + + console.log(pig.width, pig.height, pig.body.bounds.width, pig.body.bounds.height, pig.worldView); + console.log(invader.width, invader.height, invader.body.bounds.width, invader.body.bounds.height, invader.worldView); + + } + +})(); diff --git a/Tests/sprites/atlas 2.js b/Tests/sprites/atlas 2.js new file mode 100644 index 00000000..6eaa1c33 --- /dev/null +++ b/Tests/sprites/atlas 2.js @@ -0,0 +1,19 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + function init() { + // Texture Atlas Method 2 + // + // In this example we assume that the TexturePacker JSON data is a string of json data stored as a var + // (in this case botData) + game.load.atlas('bot', 'assets/sprites/running_bot.png', null, botData); + game.load.start(); + } + var bot; + function create() { + bot = game.add.sprite(400, 300, 'bot'); + bot.animations.add('run', null, 20, true); + bot.animations.play('run'); + } + var botData = '{"frames": [{"filename": "running bot.swf/0000","frame": { "x": 34, "y": 128, "w": 56, "h": 60 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 2, "w": 56, "h": 60 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0001","frame": { "x": 54, "y": 0, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0002","frame": { "x": 54, "y": 58, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0003","frame": { "x": 0, "y": 192, "w": 34, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 11, "y": 0, "w": 34, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0004","frame": { "x": 0, "y": 64, "w": 54, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 1, "y": 0, "w": 54, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0005","frame": { "x": 196, "y": 0, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0006","frame": { "x": 0, "y": 0, "w": 54, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 1, "y": 0, "w": 54, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0007","frame": { "x": 140, "y": 0, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0008","frame": { "x": 34, "y": 188, "w": 50, "h": 60 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 3, "y": 2, "w": 50, "h": 60 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0009","frame": { "x": 0, "y": 128, "w": 34, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 11, "y": 0, "w": 34, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0010","frame": { "x": 84, "y": 188, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }}]}'; +})(); diff --git a/Tests/sprites/atlas 2.ts b/Tests/sprites/atlas 2.ts new file mode 100644 index 00000000..1092c4c4 --- /dev/null +++ b/Tests/sprites/atlas 2.ts @@ -0,0 +1,33 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create); + + function init() { + + // Texture Atlas Method 2 + // + // In this example we assume that the TexturePacker JSON data is a string of json data stored as a var + // (in this case botData) + game.load.atlas('bot', 'assets/sprites/running_bot.png', null, botData); + + game.load.start(); + + } + + var bot: Phaser.Sprite; + + function create() { + + bot = game.add.sprite(400, 300, 'bot'); + + bot.animations.add('run', null, 20, true); + + bot.animations.play('run'); + + } + + var botData = '{"frames": [{"filename": "running bot.swf/0000","frame": { "x": 34, "y": 128, "w": 56, "h": 60 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 2, "w": 56, "h": 60 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0001","frame": { "x": 54, "y": 0, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0002","frame": { "x": 54, "y": 58, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0003","frame": { "x": 0, "y": 192, "w": 34, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 11, "y": 0, "w": 34, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0004","frame": { "x": 0, "y": 64, "w": 54, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 1, "y": 0, "w": 54, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0005","frame": { "x": 196, "y": 0, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0006","frame": { "x": 0, "y": 0, "w": 54, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 1, "y": 0, "w": 54, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0007","frame": { "x": 140, "y": 0, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0008","frame": { "x": 34, "y": 188, "w": 50, "h": 60 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 3, "y": 2, "w": 50, "h": 60 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0009","frame": { "x": 0, "y": 128, "w": 34, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 11, "y": 0, "w": 34, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0010","frame": { "x": 84, "y": 188, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }}]}'; + +})(); diff --git a/Tests/sprites/create sprite 1.js b/Tests/sprites/create sprite 1.js index dcd1e6e4..2b5be685 100644 --- a/Tests/sprites/create sprite 1.js +++ b/Tests/sprites/create sprite 1.js @@ -9,6 +9,10 @@ function create() { // This will create a Sprite positioned at the top-left of the game (0,0) // Try changing the 0, 0 values - game.add.sprite(0, 0, 'bunny'); - } + game.add.sprite(200, 100, 'bunny'); + game.camera.texture.alpha = 0.5; + //game.world.group.texture.flippedX = true; + //game.world.group.transform.origin.setTo(game.stage.centerX, game.stage.centerY); + //game.world.group.transform.skew.x = 1.2; + } })(); diff --git a/Tests/sprites/create sprite 1.ts b/Tests/sprites/create sprite 1.ts index 73247bc9..6ea3aebf 100644 --- a/Tests/sprites/create sprite 1.ts +++ b/Tests/sprites/create sprite 1.ts @@ -16,7 +16,12 @@ // This will create a Sprite positioned at the top-left of the game (0,0) // Try changing the 0, 0 values - game.add.sprite(0, 0, 'bunny'); + game.add.sprite(200, 100, 'bunny'); + + game.camera.texture.alpha = 0.5; + //game.world.group.texture.flippedX = true; + //game.world.group.transform.origin.setTo(game.stage.centerX, game.stage.centerY); + //game.world.group.transform.skew.x = 1.2; } diff --git a/Tests/sprites/scale sprite 1.js b/Tests/sprites/scale sprite 1.js index 6ee591eb..33b0e381 100644 --- a/Tests/sprites/scale sprite 1.js +++ b/Tests/sprites/scale sprite 1.js @@ -10,11 +10,11 @@ function create() { // Here we'll assign the new sprite to the local smallBunny variable smallBunny = game.add.sprite(0, 0, 'bunny'); - // And now let's scale the sprite in half + // And now let's scale the sprite by half // You can do either: - // smallBunny.scale.x = 0.5; - // smallBunny.scale.y = 0.5; + // smallBunny.transform.scale.x = 0.5; + // smallBunny.transform.scale.y = 0.5; // Or you can set them both at the same time using setTo: - smallBunny.scale.setTo(0.5, 0.5); + smallBunny.transform.scale.setTo(0.5, 0.5); } })(); diff --git a/Tests/sprites/scale sprite 1.ts b/Tests/sprites/scale sprite 1.ts index a5c97347..bc04c51e 100644 --- a/Tests/sprites/scale sprite 1.ts +++ b/Tests/sprites/scale sprite 1.ts @@ -19,14 +19,14 @@ // Here we'll assign the new sprite to the local smallBunny variable smallBunny = game.add.sprite(0, 0, 'bunny'); - // And now let's scale the sprite in half + // And now let's scale the sprite by half // You can do either: - // smallBunny.scale.x = 0.5; - // smallBunny.scale.y = 0.5; + // smallBunny.transform.scale.x = 0.5; + // smallBunny.transform.scale.y = 0.5; // Or you can set them both at the same time using setTo: - smallBunny.scale.setTo(0.5, 0.5); + smallBunny.transform.scale.setTo(0.5, 0.5); } diff --git a/Tests/sprites/scale sprite 2.js b/Tests/sprites/scale sprite 2.js index adde1518..9bbece0b 100644 --- a/Tests/sprites/scale sprite 2.js +++ b/Tests/sprites/scale sprite 2.js @@ -12,9 +12,9 @@ bigBunny = game.add.sprite(0, 0, 'bunny'); // And now let's scale the sprite by two // You can do either: - // smallBunny.scale.x = 2; - // smallBunny.scale.y = 2; + // smallBunny.transform.scale.x = 2; + // smallBunny.transform.scale.y = 2; // Or you can set them both at the same time using setTo: - bigBunny.scale.setTo(2, 2); + bigBunny.transform.scale.setTo(2, 2); } })(); diff --git a/Tests/sprites/scale sprite 2.ts b/Tests/sprites/scale sprite 2.ts index 479b773b..1f2868e5 100644 --- a/Tests/sprites/scale sprite 2.ts +++ b/Tests/sprites/scale sprite 2.ts @@ -22,11 +22,11 @@ // And now let's scale the sprite by two // You can do either: - // smallBunny.scale.x = 2; - // smallBunny.scale.y = 2; + // smallBunny.transform.scale.x = 2; + // smallBunny.transform.scale.y = 2; // Or you can set them both at the same time using setTo: - bigBunny.scale.setTo(2, 2); + bigBunny.transform.scale.setTo(2, 2); } diff --git a/Tests/sprites/scale sprite 3.js b/Tests/sprites/scale sprite 3.js index 02422ae8..4c14ba20 100644 --- a/Tests/sprites/scale sprite 3.js +++ b/Tests/sprites/scale sprite 3.js @@ -12,6 +12,6 @@ bunny = game.add.sprite(0, 0, 'bunny'); // You don't have to use the same values when scaling a sprite, // here we'll create a short and wide bunny - bunny.scale.setTo(3, 0.7); + bunny.transform.scale.setTo(3, 0.7); } })(); diff --git a/Tests/sprites/scale sprite 3.ts b/Tests/sprites/scale sprite 3.ts index 108a4b2a..487a2f39 100644 --- a/Tests/sprites/scale sprite 3.ts +++ b/Tests/sprites/scale sprite 3.ts @@ -22,7 +22,7 @@ // You don't have to use the same values when scaling a sprite, // here we'll create a short and wide bunny - bunny.scale.setTo(3, 0.7); + bunny.transform.scale.setTo(3, 0.7); } diff --git a/Tests/sprites/scale sprite 4.js b/Tests/sprites/scale sprite 4.js index 703f3a68..aae903f6 100644 --- a/Tests/sprites/scale sprite 4.js +++ b/Tests/sprites/scale sprite 4.js @@ -12,9 +12,9 @@ function create() { // Here we'll assign the new sprite to the local bunny variable bunny = game.add.sprite(0, 0, 'bunny'); - bunny.scale.setTo(0.5, 0.5); + bunny.transform.scale.setTo(0.5, 0.5); // This time let's scale the sprite by a looped tween - game.add.tween(bunny.scale).to({ + game.add.tween(bunny.transform.scale).to({ x: 2, y: 2 }, 2000, Phaser.Easing.Elastic.Out, true, 0, true, true); diff --git a/Tests/sprites/scale sprite 4.ts b/Tests/sprites/scale sprite 4.ts index 7de60676..193640b1 100644 --- a/Tests/sprites/scale sprite 4.ts +++ b/Tests/sprites/scale sprite 4.ts @@ -21,10 +21,10 @@ // Here we'll assign the new sprite to the local bunny variable bunny = game.add.sprite(0, 0, 'bunny'); - bunny.scale.setTo(0.5, 0.5); + bunny.transform.scale.setTo(0.5, 0.5); // This time let's scale the sprite by a looped tween - game.add.tween(bunny.scale).to({ x: 2, y: 2 }, 2000, Phaser.Easing.Elastic.Out, true, 0, true, true); + game.add.tween(bunny.transform.scale).to({ x: 2, y: 2 }, 2000, Phaser.Easing.Elastic.Out, true, 0, true, true); } diff --git a/Tests/sprites/scale sprite 5.js b/Tests/sprites/scale sprite 5.js index e67ed729..c1fbef68 100644 --- a/Tests/sprites/scale sprite 5.js +++ b/Tests/sprites/scale sprite 5.js @@ -13,11 +13,11 @@ // Here we'll assign the new sprite to the local fuji variable fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji'); // sets origin to the center of the sprite (half the width and half the height) - fuji.origin.setTo(160, 100); + fuji.transform.origin.setTo(160, 100); // We'll tween the scale down to zero (which will make the sprite invisible) and then flip it // The end result should look like turning over a card // Create our tween - tween = game.add.tween(fuji.scale); + tween = game.add.tween(fuji.transform.scale); // Start it going scaleLeft(); } diff --git a/Tests/sprites/scale sprite 5.ts b/Tests/sprites/scale sprite 5.ts index 66452277..0e8b2e1c 100644 --- a/Tests/sprites/scale sprite 5.ts +++ b/Tests/sprites/scale sprite 5.ts @@ -23,13 +23,13 @@ fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji'); // sets origin to the center of the sprite (half the width and half the height) - fuji.origin.setTo(160, 100); + fuji.transform.origin.setTo(160, 100); // We'll tween the scale down to zero (which will make the sprite invisible) and then flip it // The end result should look like turning over a card // Create our tween - tween = game.add.tween(fuji.scale); + tween = game.add.tween(fuji.transform.scale); // Start it going scaleLeft(); diff --git a/Tests/sprites/sprite origin 1.js b/Tests/sprites/sprite origin 1.js index 03fd6d42..4bf0dbba 100644 --- a/Tests/sprites/sprite origin 1.js +++ b/Tests/sprites/sprite origin 1.js @@ -14,7 +14,7 @@ // 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 game.add.tween(fuji).to({ - angle: 360 + rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); } })(); diff --git a/Tests/sprites/sprite origin 1.ts b/Tests/sprites/sprite origin 1.ts index 7d6d1850..9b27c0f0 100644 --- a/Tests/sprites/sprite origin 1.ts +++ b/Tests/sprites/sprite origin 1.ts @@ -23,7 +23,7 @@ // 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 - game.add.tween(fuji).to({ angle: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); + game.add.tween(fuji).to({ rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); } diff --git a/Tests/sprites/sprite origin 2.js b/Tests/sprites/sprite origin 2.js index f4303b1c..dee0dba8 100644 --- a/Tests/sprites/sprite origin 2.js +++ b/Tests/sprites/sprite origin 2.js @@ -14,9 +14,9 @@ // 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); + fuji.transform.origin.setTo(160, 100); game.add.tween(fuji).to({ - angle: 360 + rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); } })(); diff --git a/Tests/sprites/sprite origin 2.ts b/Tests/sprites/sprite origin 2.ts index 60094fd5..58b3c36c 100644 --- a/Tests/sprites/sprite origin 2.ts +++ b/Tests/sprites/sprite origin 2.ts @@ -24,9 +24,9 @@ // 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); + fuji.transform.origin.setTo(160, 100); - game.add.tween(fuji).to({ angle: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); + game.add.tween(fuji).to({ rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); } diff --git a/Tests/sprites/sprite origin 3.js b/Tests/sprites/sprite origin 3.js index 26f34a79..907f6a1b 100644 --- a/Tests/sprites/sprite origin 3.js +++ b/Tests/sprites/sprite origin 3.js @@ -14,9 +14,9 @@ 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 be the bottom-right of the sprite - fuji.origin.setTo(320, 200); + fuji.transform.origin.setTo(320, 200); game.add.tween(fuji).to({ - angle: 360 + rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); } })(); diff --git a/Tests/sprites/sprite origin 3.ts b/Tests/sprites/sprite origin 3.ts index fb92c18d..ba966bff 100644 --- a/Tests/sprites/sprite origin 3.ts +++ b/Tests/sprites/sprite origin 3.ts @@ -24,9 +24,9 @@ // 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); + fuji.transform.origin.setTo(320, 200); - game.add.tween(fuji).to({ angle: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); + game.add.tween(fuji).to({ rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); } diff --git a/Tests/sprites/sprite origin 4.js b/Tests/sprites/sprite origin 4.js index f7b24b13..f075532d 100644 --- a/Tests/sprites/sprite origin 4.js +++ b/Tests/sprites/sprite origin 4.js @@ -15,13 +15,13 @@ 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); + fuji.transform.origin.setTo(160, 100); game.add.tween(fuji).to({ - angle: 360 + rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); - tweenUp = game.add.tween(fuji.scale); + tweenUp = game.add.tween(fuji.transform.scale); tweenUp.onComplete.add(scaleDown, this); - tweenDown = game.add.tween(fuji.scale); + tweenDown = game.add.tween(fuji.transform.scale); tweenDown.onComplete.add(scaleUp, this); scaleUp(); } diff --git a/Tests/sprites/sprite origin 4.ts b/Tests/sprites/sprite origin 4.ts index 8f1f3f47..4792e9eb 100644 --- a/Tests/sprites/sprite origin 4.ts +++ b/Tests/sprites/sprite origin 4.ts @@ -25,14 +25,14 @@ // 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); + fuji.transform.origin.setTo(160, 100); - game.add.tween(fuji).to({ angle: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); + game.add.tween(fuji).to({ rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); - tweenUp = game.add.tween(fuji.scale); + tweenUp = game.add.tween(fuji.transform.scale); tweenUp.onComplete.add(scaleDown, this); - tweenDown = game.add.tween(fuji.scale); + tweenDown = game.add.tween(fuji.transform.scale); tweenDown.onComplete.add(scaleUp, this); scaleUp(); diff --git a/Tests/tweens/tween loop 1.js b/Tests/tweens/tween loop 1.js index b05bc89f..d677e689 100644 --- a/Tests/tweens/tween loop 1.js +++ b/Tests/tweens/tween loop 1.js @@ -11,12 +11,12 @@ // 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); + swirl.transform.scale.setTo(1.4, 1.4); // Set the origin to the middle of the Sprite to get the effect we need - swirl.origin.setTo(swirl.frameBounds.halfWidth, swirl.frameBounds.halfHeight); + swirl.transform.origin.setTo(swirl.worldView.halfWidth, swirl.worldView.halfHeight); // Create a tween that rotates a full 306 degrees and then repeats (loop set to true) game.add.tween(swirl).to({ - angle: 360 + 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 index af5b72f5..a5ad8638 100644 --- a/Tests/tweens/tween loop 1.ts +++ b/Tests/tweens/tween loop 1.ts @@ -20,13 +20,13 @@ 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); + swirl.transform.scale.setTo(1.4, 1.4); // Set the origin to the middle of the Sprite to get the effect we need - swirl.origin.setTo(swirl.frameBounds.halfWidth, swirl.frameBounds.halfHeight); + swirl.transform.origin.setTo(swirl.worldView.halfWidth, swirl.worldView.halfHeight); // Create a tween that rotates a full 306 degrees and then repeats (loop set to true) - game.add.tween(swirl).to({ angle: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, 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 index 217eae31..dd7ad6a2 100644 --- a/Tests/tweens/tween loop 2.js +++ b/Tests/tweens/tween loop 2.js @@ -11,14 +11,14 @@ // 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); + swirl.transform.scale.setTo(1.4, 1.4); // Set the origin to the middle of the Sprite to get the effect we need - swirl.origin.setTo(swirl.frameBounds.halfWidth, swirl.frameBounds.halfHeight); + swirl.transform.origin.setTo(swirl.worldView.halfWidth, swirl.worldView.halfHeight); // Create a tween that rotates a full 306 degrees and then repeats (loop set to true) game.add.tween(swirl).to({ - angle: 360 + rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); - game.add.tween(swirl.scale).to({ + game.add.tween(swirl.transform.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 index e4242fd3..59501193 100644 --- a/Tests/tweens/tween loop 2.ts +++ b/Tests/tweens/tween loop 2.ts @@ -20,14 +20,14 @@ 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); + swirl.transform.scale.setTo(1.4, 1.4); // Set the origin to the middle of the Sprite to get the effect we need - swirl.origin.setTo(swirl.frameBounds.halfWidth, swirl.frameBounds.halfHeight); + swirl.transform.origin.setTo(swirl.worldView.halfWidth, swirl.worldView.halfHeight); // Create a tween that rotates a full 306 degrees and then repeats (loop set to true) - game.add.tween(swirl).to({ angle: 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); + game.add.tween(swirl).to({ rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); + game.add.tween(swirl.transform.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 a8ef3fb3..797452bf 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -55,48 +55,48 @@ module Phaser { module Phaser { class Rectangle { /** - * Creates a new Rectangle object with the top-left corner specified by the x and y parameters and with the specified width and height parameters. If you call this function without parameters, a rectangle with x, y, width, and height properties set to 0 is created. + * Creates a new Rectangle object with the top-left corner specified by the x and y parameters and with the specified width and height parameters. If you call this function without parameters, a Rectangle with x, y, width, and height properties set to 0 is created. * @class Rectangle * @constructor - * @param {Number} x The x coordinate of the top-left corner of the rectangle. - * @param {Number} y The y coordinate of the top-left corner of the rectangle. - * @param {Number} width The width of the rectangle in pixels. - * @param {Number} height The height of the rectangle in pixels. - * @return {Rectangle} This rectangle object + * @param {Number} x The x coordinate of the top-left corner of the Rectangle. + * @param {Number} y The y coordinate of the top-left corner of the Rectangle. + * @param {Number} width The width of the Rectangle in pixels. + * @param {Number} height The height of the Rectangle in pixels. + * @return {Rectangle} This Rectangle object **/ constructor(x?: number, y?: number, width?: number, height?: number); /** - * The x coordinate of the top-left corner of the rectangle + * The x coordinate of the top-left corner of the Rectangle * @property x * @type Number **/ public x: number; /** - * The y coordinate of the top-left corner of the rectangle + * The y coordinate of the top-left corner of the Rectangle * @property y * @type Number **/ public y: number; /** - * The width of the rectangle in pixels + * The width of the Rectangle in pixels * @property width * @type Number **/ public width: number; /** - * The height of the rectangle in pixels + * The height of the Rectangle in pixels * @property height * @type Number **/ public height: number; /** - * Half of the width of the rectangle + * Half of the width of the Rectangle * @property halfWidth * @type Number **/ public halfWidth : number; /** - * Half of the height of the rectangle + * Half of the height of the Rectangle * @property halfHeight * @type Number **/ @@ -182,7 +182,7 @@ module Phaser { /** * Sets all of the Rectangle object's properties to 0. A Rectangle object is empty if its width or height is less than or equal to 0. * @method setEmpty - * @return {Rectangle} This rectangle object + * @return {Rectangle} This Rectangle object **/ public empty : bool; /** @@ -203,11 +203,11 @@ module Phaser { /** * Sets the members of Rectangle to the specified values. * @method setTo - * @param {Number} x The x coordinate of the top-left corner of the rectangle. - * @param {Number} y The y coordinate of the top-left corner of the rectangle. - * @param {Number} width The width of the rectangle in pixels. - * @param {Number} height The height of the rectangle in pixels. - * @return {Rectangle} This rectangle object + * @param {Number} x The x coordinate of the top-left corner of the Rectangle. + * @param {Number} y The y coordinate of the top-left corner of the Rectangle. + * @param {Number} width The width of the Rectangle in pixels. + * @param {Number} height The height of the Rectangle in pixels. + * @return {Rectangle} This Rectangle object **/ public setTo(x: number, y: number, width: number, height: number): Rectangle; /** @@ -248,7 +248,7 @@ module Phaser { */ y: number; /** - * Z-order value of the object. + * z-index value of the object. */ z: number; /** @@ -260,21 +260,17 @@ module Phaser { */ active: bool; /** - * Controls if this Sprite is rendered or skipped during the core game loop. + * Controls if this is rendered or skipped during the core game loop. */ visible: bool; /** - * The texture used to render the Sprite. + * The texture used to render. */ texture: Components.Texture; /** - * Scale of the Sprite. A scale of 1.0 is the original size. 0.5 half size. 2.0 double sized. + * The transform component. */ - scale: Vec2; - /** - * The influence of camera movement upon the Sprite. - */ - scrollFactor: Vec2; + transform: Components.Transform; } } /** @@ -822,7 +818,7 @@ module Phaser { static SCROLLZONE: number; static GEOM_POINT: number; static GEOM_CIRCLE: number; - static GEOM_RECTANGLE: number; + static GEOM_Rectangle: number; static GEOM_LINE: number; static GEOM_POLYGON: number; static BODY_DISABLED: number; @@ -877,6 +873,1889 @@ module Phaser { } } /** +* Phaser - RectangleUtils +* +* A collection of methods useful for manipulating and comparing Rectangle objects. +* +* TODO: Check docs + overlap + intersect + toPolygon? +*/ +module Phaser { + class RectangleUtils { + /** + * Get the location of the Rectangles top-left corner as a Point object. + * @method getTopLeftAsPoint + * @param {Rectangle} a - The Rectangle object. + * @param {Point} out - Optional Point to store the value in, if not supplied a new Point object will be created. + * @return {Point} The new Point object. + **/ + static getTopLeftAsPoint(a: Rectangle, out?: Point): Point; + /** + * Get the location of the Rectangles bottom-right corner as a Point object. + * @method getTopLeftAsPoint + * @param {Rectangle} a - The Rectangle object. + * @param {Point} out - Optional Point to store the value in, if not supplied a new Point object will be created. + * @return {Point} The new Point object. + **/ + static getBottomRightAsPoint(a: Rectangle, out?: Point): Point; + /** + * Increases the size of the Rectangle object by the specified amounts. The center point of the Rectangle object stays the same, and its size increases to the left and right by the dx value, and to the top and the bottom by the dy value. + * @method inflate + * @param {Rectangle} a - The Rectangle object. + * @param {Number} dx The amount to be added to the left side of the Rectangle. + * @param {Number} dy The amount to be added to the bottom side of the Rectangle. + * @return {Rectangle} This Rectangle object. + **/ + static inflate(a: Rectangle, dx: number, dy: number): Rectangle; + /** + * Increases the size of the Rectangle object. This method is similar to the Rectangle.inflate() method except it takes a Point object as a parameter. + * @method inflatePoint + * @param {Rectangle} a - The Rectangle object. + * @param {Point} point The x property of this Point object is used to increase the horizontal dimension of the Rectangle object. The y property is used to increase the vertical dimension of the Rectangle object. + * @return {Rectangle} The Rectangle object. + **/ + static inflatePoint(a: Rectangle, point: Point): Rectangle; + /** + * The size of the Rectangle object, expressed as a Point object with the values of the width and height properties. + * @method size + * @param {Rectangle} a - The Rectangle object. + * @param {Point} output Optional Point object. If given the values will be set into the object, otherwise a brand new Point object will be created and returned. + * @return {Point} The size of the Rectangle object + **/ + static size(a: Rectangle, output?: Point): Point; + /** + * Returns a new Rectangle object with the same values for the x, y, width, and height properties as the original Rectangle object. + * @method clone + * @param {Rectangle} a - The Rectangle object. + * @param {Rectangle} output Optional Rectangle object. If given the values will be set into the object, otherwise a brand new Rectangle object will be created and returned. + * @return {Rectangle} + **/ + static clone(a: Rectangle, output?: Rectangle): Rectangle; + /** + * Determines whether the specified coordinates are contained within the region defined by this Rectangle object. + * @method contains + * @param {Rectangle} a - The Rectangle object. + * @param {Number} x The x coordinate of the point to test. + * @param {Number} y The y coordinate of the point to test. + * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. + **/ + static contains(a: Rectangle, x: number, y: number): bool; + /** + * Determines whether the specified point is contained within the rectangular region defined by this Rectangle object. This method is similar to the Rectangle.contains() method, except that it takes a Point object as a parameter. + * @method containsPoint + * @param {Rectangle} a - The Rectangle object. + * @param {Point} point The point object being checked. Can be Point or any object with .x and .y values. + * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. + **/ + static containsPoint(a: Rectangle, point: Point): bool; + /** + * Determines whether the first Rectangle object is fully contained within the second Rectangle object. + * A Rectangle object is said to contain another if the second Rectangle object falls entirely within the boundaries of the first. + * @method containsRect + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. + **/ + static containsRect(a: Rectangle, b: Rectangle): bool; + /** + * Determines whether the two Rectangles are equal. + * This method compares the x, y, width and height properties of each Rectangle. + * @method equals + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @return {Boolean} A value of true if the two Rectangles have exactly the same values for the x, y, width and height properties; otherwise false. + **/ + static equals(a: Rectangle, b: Rectangle): bool; + /** + * If the Rectangle object specified in the toIntersect parameter intersects with this Rectangle object, returns the area of intersection as a Rectangle object. If the Rectangles do not intersect, this method returns an empty Rectangle object with its properties set to 0. + * @method intersection + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @param {Rectangle} output Optional Rectangle object. If given the intersection values will be set into this object, otherwise a brand new Rectangle object will be created and returned. + * @return {Rectangle} A Rectangle object that equals the area of intersection. If the Rectangles do not intersect, this method returns an empty Rectangle object; that is, a Rectangle with its x, y, width, and height properties set to 0. + **/ + static intersection(a: Rectangle, b: Rectangle, out?: Rectangle): Rectangle; + /** + * Determines whether the two Rectangles intersect with each other. + * This method checks the x, y, width, and height properties of the Rectangles. + * @method intersects + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @param {Number} tolerance A tolerance value to allow for an intersection test with padding, default to 0 + * @return {Boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false. + **/ + static intersects(a: Rectangle, b: Rectangle, tolerance?: number): bool; + /** + * Determines whether the object specified intersects (overlaps) with the given values. + * @method intersectsRaw + * @param {Number} left + * @param {Number} right + * @param {Number} top + * @param {Number} bottomt + * @param {Number} tolerance A tolerance value to allow for an intersection test with padding, default to 0 + * @return {Boolean} A value of true if the specified object intersects with the Rectangle; otherwise false. + **/ + static intersectsRaw(a: Rectangle, left: number, right: number, top: number, bottom: number, tolerance?: number): bool; + /** + * Adds two Rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two Rectangles. + * @method union + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @param {Rectangle} output Optional Rectangle object. If given the new values will be set into this object, otherwise a brand new Rectangle object will be created and returned. + * @return {Rectangle} A Rectangle object that is the union of the two Rectangles. + **/ + static union(a: Rectangle, b: Rectangle, out?: Rectangle): Rectangle; + } +} +/** +* Phaser - ColorUtils +* +* A collection of methods useful for manipulating color values. +*/ +module Phaser { + class ColorUtils { + static game: Game; + /** + * Given an alpha and 3 color values this will return an integer representation of it + * + * @param alpha {number} The Alpha value (between 0 and 255) + * @param red {number} The Red channel value (between 0 and 255) + * @param green {number} The Green channel value (between 0 and 255) + * @param blue {number} The Blue channel value (between 0 and 255) + * + * @return A native color value integer (format: 0xAARRGGBB) + */ + static getColor32(alpha: number, red: number, green: number, blue: number): number; + /** + * Given 3 color values this will return an integer representation of it + * + * @param red {number} The Red channel value (between 0 and 255) + * @param green {number} The Green channel value (between 0 and 255) + * @param blue {number} The Blue channel value (between 0 and 255) + * + * @return A native color value integer (format: 0xRRGGBB) + */ + static getColor(red: number, green: number, blue: number): number; + /** + * Get HSV color wheel values in an array which will be 360 elements in size + * + * @param alpha Alpha value for each color of the color wheel, between 0 (transparent) and 255 (opaque) + * + * @return Array + */ + static getHSVColorWheel(alpha?: number): any[]; + /** + * Returns a Complementary Color Harmony for the given color. + *

A complementary hue is one directly opposite the color given on the color wheel

+ *

Value returned in 0xAARRGGBB format with Alpha set to 255.

+ * + * @param color The color to base the harmony on + * + * @return 0xAARRGGBB format color value + */ + static getComplementHarmony(color: number): number; + /** + * Returns an Analogous Color Harmony for the given color. + *

An Analogous harmony are hues adjacent to each other on the color wheel

+ *

Values returned in 0xAARRGGBB format with Alpha set to 255.

+ * + * @param color The color to base the harmony on + * @param threshold Control how adjacent the colors will be (default +- 30 degrees) + * + * @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color) + */ + static getAnalogousHarmony(color: number, threshold?: number): { + color1: number; + color2: number; + color3: number; + hue1: any; + hue2: number; + hue3: number; + }; + /** + * Returns an Split Complement Color Harmony for the given color. + *

A Split Complement harmony are the two hues on either side of the color's Complement

+ *

Values returned in 0xAARRGGBB format with Alpha set to 255.

+ * + * @param color The color to base the harmony on + * @param threshold Control how adjacent the colors will be to the Complement (default +- 30 degrees) + * + * @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color) + */ + static getSplitComplementHarmony(color: number, threshold?: number): any; + /** + * Returns a Triadic Color Harmony for the given color. + *

A Triadic harmony are 3 hues equidistant from each other on the color wheel

+ *

Values returned in 0xAARRGGBB format with Alpha set to 255.

+ * + * @param color The color to base the harmony on + * + * @return Object containing 3 properties: color1 (the original color), color2 and color3 (the equidistant colors) + */ + static getTriadicHarmony(color: number): any; + /** + * Returns a string containing handy information about the given color including string hex value, + * RGB format information and HSL information. Each section starts on a newline, 3 lines in total. + * + * @param color A color value in the format 0xAARRGGBB + * + * @return string containing the 3 lines of information + */ + static getColorInfo(color: number): string; + /** + * Return a string representation of the color in the format 0xAARRGGBB + * + * @param color The color to get the string representation for + * + * @return A string of length 10 characters in the format 0xAARRGGBB + */ + static RGBtoHexstring(color: number): string; + /** + * Return a string representation of the color in the format #RRGGBB + * + * @param color The color to get the string representation for + * + * @return A string of length 10 characters in the format 0xAARRGGBB + */ + static RGBtoWebstring(color: number): string; + /** + * Return a string containing a hex representation of the given color + * + * @param color The color channel to get the hex value for, must be a value between 0 and 255) + * + * @return A string of length 2 characters, i.e. 255 = FF, 0 = 00 + */ + static colorToHexstring(color: number): string; + /** + * Convert a HSV (hue, saturation, lightness) color space value to an RGB color + * + * @param h Hue degree, between 0 and 359 + * @param s Saturation, between 0.0 (grey) and 1.0 + * @param v Value, between 0.0 (black) and 1.0 + * @param alpha Alpha value to set per color (between 0 and 255) + * + * @return 32-bit ARGB color value (0xAARRGGBB) + */ + static HSVtoRGB(h: number, s: number, v: number, alpha?: number): number; + /** + * Convert an RGB color value to an object containing the HSV color space values: Hue, Saturation and Lightness + * + * @param color In format 0xRRGGBB + * + * @return Object with the properties hue (from 0 to 360), saturation (from 0 to 1.0) and lightness (from 0 to 1.0, also available under .value) + */ + static RGBtoHSV(color: number): any; + /** + * + * @method interpolateColor + * @param {Number} color1 + * @param {Number} color2 + * @param {Number} steps + * @param {Number} currentStep + * @param {Number} alpha + * @return {Number} + * @static + */ + static interpolateColor(color1: number, color2: number, steps: number, currentStep: number, alpha?: number): number; + /** + * + * @method interpolateColorWithRGB + * @param {Number} color + * @param {Number} r2 + * @param {Number} g2 + * @param {Number} b2 + * @param {Number} steps + * @param {Number} currentStep + * @return {Number} + * @static + */ + static interpolateColorWithRGB(color: number, r2: number, g2: number, b2: number, steps: number, currentStep: number): number; + /** + * + * @method interpolateRGB + * @param {Number} r1 + * @param {Number} g1 + * @param {Number} b1 + * @param {Number} r2 + * @param {Number} g2 + * @param {Number} b2 + * @param {Number} steps + * @param {Number} currentStep + * @return {Number} + * @static + */ + static interpolateRGB(r1: number, g1: number, b1: number, r2: number, g2: number, b2: number, steps: number, currentStep: number): number; + /** + * Returns a random color value between black and white + *

Set the min value to start each channel from the given offset.

+ *

Set the max value to restrict the maximum color used per channel

+ * + * @param min The lowest value to use for the color + * @param max The highest value to use for the color + * @param alpha The alpha value of the returning color (default 255 = fully opaque) + * + * @return 32-bit color value with alpha + */ + static getRandomColor(min?: number, max?: number, alpha?: number): number; + /** + * Return the component parts of a color as an Object with the properties alpha, red, green, blue + * + *

Alpha will only be set if it exist in the given color (0xAARRGGBB)

+ * + * @param color in RGB (0xRRGGBB) or ARGB format (0xAARRGGBB) + * + * @return Object with properties: alpha, red, green, blue + */ + static getRGB(color: number): any; + /** + * + * @method getWebRGB + * @param {Number} color + * @return {Any} + */ + static getWebRGB(color: number): any; + /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component, as a value between 0 and 255 + * + * @param color In the format 0xAARRGGBB + * + * @return The Alpha component of the color, will be between 0 and 255 (0 being no Alpha, 255 full Alpha) + */ + static getAlpha(color: number): number; + /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component as a value between 0 and 1 + * + * @param color In the format 0xAARRGGBB + * + * @return The Alpha component of the color, will be between 0 and 1 (0 being no Alpha (opaque), 1 full Alpha (transparent)) + */ + static getAlphaFloat(color: number): number; + /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Red component, as a value between 0 and 255 + * + * @param color In the format 0xAARRGGBB + * + * @return The Red component of the color, will be between 0 and 255 (0 being no color, 255 full Red) + */ + static getRed(color: number): number; + /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Green component, as a value between 0 and 255 + * + * @param color In the format 0xAARRGGBB + * + * @return The Green component of the color, will be between 0 and 255 (0 being no color, 255 full Green) + */ + static getGreen(color: number): number; + /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Blue component, as a value between 0 and 255 + * + * @param color In the format 0xAARRGGBB + * + * @return The Blue component of the color, will be between 0 and 255 (0 being no color, 255 full Blue) + */ + static getBlue(color: number): number; + } +} +/** +* Phaser - DynamicTexture +* +* A DynamicTexture can be thought of as a mini canvas into which you can draw anything. +* Game Objects can be assigned a DynamicTexture, so when they render in the world they do so +* based on the contents of the texture at the time. This allows you to create powerful effects +* once and have them replicated across as many game objects as you like. +*/ +module Phaser { + class DynamicTexture { + /** + * DynamicTexture constructor + * Create a new DynamicTexture. + * + * @param game {Phaser.Game} Current game instance. + * @param width {number} Init width of this texture. + * @param height {number} Init height of this texture. + */ + constructor(game: Game, width: number, height: number); + /** + * Reference to game. + */ + public game: Game; + /** + * The type of game object. + */ + public type: number; + private _sx; + private _sy; + private _sw; + private _sh; + private _dx; + private _dy; + private _dw; + private _dh; + /** + * Bound of this texture with width and height info. + * @type {Rectangle} + */ + public bounds: Rectangle; + /** + * This class is actually a wrapper of canvas. + * @type {HTMLCanvasElement} + */ + public canvas: HTMLCanvasElement; + /** + * Canvas context of this object. + * @type {CanvasRenderingContext2D} + */ + public context: CanvasRenderingContext2D; + /** + * Get a color of a specific pixel. + * @param x {number} X position of the pixel in this texture. + * @param y {number} Y position of the pixel in this texture. + * @return {number} A native color value integer (format: 0xRRGGBB) + */ + public getPixel(x: number, y: number): number; + /** + * Get a color of a specific pixel (including alpha value). + * @param x {number} X position of the pixel in this texture. + * @param y {number} Y position of the pixel in this texture. + * @return A native color value integer (format: 0xAARRGGBB) + */ + public getPixel32(x: number, y: number): number; + /** + * Get pixels in array in a specific Rectangle. + * @param rect {Rectangle} The specific Rectangle. + * @returns {array} CanvasPixelArray. + */ + public getPixels(rect: Rectangle): ImageData; + /** + * Set color of a specific pixel. + * @param x {number} X position of the target pixel. + * @param y {number} Y position of the target pixel. + * @param color {number} Native integer with color value. (format: 0xRRGGBB) + */ + public setPixel(x: number, y: number, color: string): void; + /** + * Set color (with alpha) of a specific pixel. + * @param x {number} X position of the target pixel. + * @param y {number} Y position of the target pixel. + * @param color {number} Native integer with color value. (format: 0xAARRGGBB) + */ + public setPixel32(x: number, y: number, color: number): void; + /** + * Set image data to a specific Rectangle. + * @param rect {Rectangle} Target Rectangle. + * @param input {object} Source image data. + */ + public setPixels(rect: Rectangle, input): void; + /** + * Fill a given Rectangle with specific color. + * @param rect {Rectangle} Target Rectangle you want to fill. + * @param color {number} A native number with color value. (format: 0xRRGGBB) + */ + public fillRect(rect: Rectangle, color: number): void; + /** + * + */ + public pasteImage(key: string, frame?: number, destX?: number, destY?: number, destWidth?: number, destHeight?: number): void; + /** + * Copy pixel from another DynamicTexture to this texture. + * @param sourceTexture {DynamicTexture} Source texture object. + * @param sourceRect {Rectangle} The specific region Rectangle to be copied to this in the source. + * @param destPoint {Point} Top-left point the target image data will be paste at. + */ + public copyPixels(sourceTexture: DynamicTexture, sourceRect: Rectangle, destPoint: Point): void; + /** + * Given an array of Sprites it will update each of them so that their canvas/contexts reference this DynamicTexture + * @param objects {Array} An array of GameObjects, or objects that inherit from it such as Sprites + */ + public assignCanvasToGameObjects(objects: IGameObject[]): void; + /** + * Clear the whole canvas. + */ + public clear(): void; + /** + * Renders this DynamicTexture to the Stage at the given x/y coordinates + * + * @param x {number} The X coordinate to render on the stage to (given in screen coordinates, not world) + * @param y {number} The Y coordinate to render on the stage to (given in screen coordinates, not world) + */ + public render(x?: number, y?: number): void; + public width : number; + public height : number; + } +} +/** +* Phaser - AnimationLoader +* +* Responsible for parsing sprite sheet and JSON data into the internal FrameData format that Phaser uses for animations. +*/ +module Phaser { + class AnimationLoader { + /** + * Parse a sprite sheet from asset data. + * @param key {string} Asset key for the sprite sheet data. + * @param frameWidth {number} Width of animation frame. + * @param frameHeight {number} Height of animation frame. + * @param frameMax {number} Number of animation frames. + * @return {FrameData} Generated FrameData object. + */ + static parseSpriteSheet(game: Game, key: string, frameWidth: number, frameHeight: number, frameMax: number): FrameData; + /** + * Parse frame datas from json. + * @param json {object} Json data you want to parse. + * @return {FrameData} Generated FrameData object. + */ + static parseJSONData(game: Game, json): FrameData; + static parseXMLData(game: Game, xml, format: number): FrameData; + } +} +/** +* Phaser - Animation +* +* An Animation is a single animation. It is created by the AnimationManager and belongs to Sprite objects. +*/ +module Phaser { + class Animation { + /** + * Animation constructor + * Create a new Animation. + * + * @param parent {Sprite} Owner sprite of this animation. + * @param frameData {FrameData} The FrameData object contains animation data. + * @param name {string} Unique name of this animation. + * @param frames {number[]/string[]} An array of numbers or strings indicating what frames to play in what order. + * @param delay {number} Time between frames in ms. + * @param looped {boolean} Whether or not the animation is looped or just plays once. + */ + constructor(game: Game, parent: Sprite, frameData: FrameData, name: string, frames, delay: number, looped: bool); + /** + * Local private reference to game. + */ + private _game; + /** + * Local private reference to its owner sprite. + * @type {Sprite} + */ + private _parent; + /** + * Animation frame container. + * @type {number[]} + */ + private _frames; + /** + * Frame data of this animation.(parsed from sprite sheet) + * @type {FrameData} + */ + private _frameData; + /** + * Index of current frame. + * @type {number} + */ + private _frameIndex; + /** + * Time when switched to last frame (in ms). + * @type number + */ + private _timeLastFrame; + /** + * Time when this will switch to next frame (in ms). + * @type number + */ + private _timeNextFrame; + /** + * Name of this animation. + * @type {string} + */ + public name: string; + /** + * Currently played frame instance. + * @type {Frame} + */ + public currentFrame: Frame; + /** + * Whether or not this animation finished playing. + * @type {boolean} + */ + public isFinished: bool; + /** + * Whethor or not this animation is currently playing. + * @type {boolean} + */ + public isPlaying: bool; + /** + * Whether or not the animation is looped. + * @type {boolean} + */ + public looped: bool; + /** + * Time between frames in ms. + * @type {number} + */ + public delay: number; + public frameTotal : number; + public frame : number; + /** + * Play this animation. + * @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. + */ + public play(frameRate?: number, loop?: bool): void; + /** + * Play this animation from the first frame. + */ + public restart(): void; + /** + * Stop playing animation and set it finished. + */ + public stop(): void; + /** + * Update animation frames. + */ + public update(): bool; + /** + * Clean up animation memory. + */ + public destroy(): void; + /** + * Animation complete callback method. + */ + private onComplete(); + } +} +/** +* Phaser - Frame +* +* A Frame is a single frame of an animation and is part of a FrameData collection. +*/ +module Phaser { + class Frame { + /** + * Frame constructor + * Create a new Frame with specific position, size and name. + * + * @param x {number} X position within the image to cut from. + * @param y {number} Y position within the image to cut from. + * @param width {number} Width of the frame. + * @param height {number} Height of the frame. + * @param name {string} Name of this frame. + */ + constructor(x: number, y: number, width: number, height: number, name: string); + /** + * X position within the image to cut from. + * @type {number} + */ + public x: number; + /** + * Y position within the image to cut from. + * @type {number} + */ + public y: number; + /** + * Width of the frame. + * @type {number} + */ + public width: number; + /** + * Height of the frame. + * @type {number} + */ + public height: number; + /** + * Useful for Sprite Sheets. + * @type {number} + */ + public index: number; + /** + * Useful for Texture Atlas files. (is set to the filename value) + */ + public name: string; + /** + * Rotated? (not yet implemented) + */ + public rotated: bool; + /** + * Either cw or ccw, rotation is always 90 degrees. + */ + public rotationDirection: string; + /** + * Was it trimmed when packed? + * @type {boolean} + */ + public trimmed: bool; + /** + * Width of the original sprite. + * @type {number} + */ + public sourceSizeW: number; + /** + * Height of the original sprite. + * @type {number} + */ + public sourceSizeH: number; + /** + * X position of the trimmed sprite inside original sprite. + * @type {number} + */ + public spriteSourceSizeX: number; + /** + * Y position of the trimmed sprite inside original sprite. + * @type {number} + */ + public spriteSourceSizeY: number; + /** + * Width of the trimmed sprite. + * @type {number} + */ + public spriteSourceSizeW: number; + /** + * Height of the trimmed sprite. + * @type {number} + */ + public spriteSourceSizeH: number; + /** + * Set rotation of this frame. (Not yet supported!) + */ + public setRotation(rotated: bool, rotationDirection: string): void; + /** + * Set trim of the frame. + * @param trimmed {boolean} Whether this frame trimmed or not. + * @param actualWidth {number} Actual width of this frame. + * @param actualHeight {number} Actual height of this frame. + * @param destX {number} Destination x position. + * @param destY {number} Destination y position. + * @param destWidth {number} Destination draw width. + * @param destHeight {number} Destination draw height. + */ + public setTrim(trimmed: bool, actualWidth: number, actualHeight: number, destX: number, destY: number, destWidth: number, destHeight: number): void; + } +} +/** +* Phaser - FrameData +* +* FrameData is a container for Frame objects, the internal representation of animation data in Phaser. +*/ +module Phaser { + class FrameData { + /** + * FrameData constructor + */ + constructor(); + /** + * Local frame container. + */ + private _frames; + /** + * Local frameName<->index container. + */ + private _frameNames; + public total : number; + /** + * Add a new frame. + * @param frame {Frame} The frame you want to add. + * @return {Frame} The frame you just added. + */ + public addFrame(frame: Frame): Frame; + /** + * Get a frame by its index. + * @param index {number} Index of the frame you want to get. + * @return {Frame} The frame you want. + */ + public getFrame(index: number): Frame; + /** + * Get a frame by its name. + * @param name {string} Name of the frame you want to get. + * @return {Frame} The frame you want. + */ + public getFrameByName(name: string): Frame; + /** + * Check whether there's a frame with given name. + * @param name {string} Name of the frame you want to check. + * @return {boolean} True if frame with given name found, otherwise return false. + */ + public checkFrameName(name: string): bool; + /** + * Get ranges of frames in an array. + * @param start {number} Start index of frames you want. + * @param end {number} End index of frames you want. + * @param [output] {Frame[]} result will be added into this array. + * @return {Frame[]} Ranges of specific frames in an array. + */ + public getFrameRange(start: number, end: number, output?: Frame[]): Frame[]; + /** + * Get all indexes of frames by giving their name. + * @param [output] {number[]} result will be added into this array. + * @return {number[]} Indexes of specific frames in an array. + */ + public getFrameIndexes(output?: number[]): number[]; + /** + * Get the frame indexes by giving the frame names. + * @param [output] {number[]} result will be added into this array. + * @return {number[]} Names of specific frames in an array. + */ + public getFrameIndexesByName(input: string[]): number[]; + /** + * Get all frames in this frame data. + * @return {Frame[]} All the frames in an array. + */ + public getAllFrames(): Frame[]; + /** + * Get All frames with specific ranges. + * @param range {number[]} Ranges in an array. + * @return {Frame[]} All frames in an array. + */ + public getFrames(range: number[]): Frame[]; + } +} +/** +* Phaser - AnimationManager +* +* Any Sprite that has animation contains an instance of the AnimationManager, which is used to add, play and update +* sprite specific animations. +*/ +module Phaser.Components { + class AnimationManager { + /** + * AnimationManager constructor + * Create a new AnimationManager. + * + * @param parent {Sprite} Owner sprite of this manager. + */ + constructor(parent: Sprite); + /** + * Local private reference to game. + */ + private _game; + /** + * Local private reference to its owner sprite. + */ + private _parent; + /** + * Animation key-value container. + */ + private _anims; + /** + * Index of current frame. + * @type {number} + */ + private _frameIndex; + /** + * Data contains animation frames. + * @type {FrameData} + */ + private _frameData; + /** + * When an animation frame changes you can choose to automatically update the physics bounds of the parent Sprite + * to the width and height of the new frame. If you've set a specific physics bounds that you don't want changed during + * animation then set this to false, otherwise leave it set to true. + * @type {boolean} + */ + public autoUpdateBounds: bool; + /** + * Keeps track of the current animation being played. + */ + public currentAnim: Animation; + /** + * Keeps track of the current frame of animation. + */ + public currentFrame: Frame; + /** + * Load animation frame data. + * @param frameData Data to be loaded. + */ + public loadFrameData(frameData: FrameData): void; + /** + * 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 + */ + public add(name: string, frames?: any[], frameRate?: number, loop?: bool, useNumericIndex?: bool): Animation; + /** + * 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. + */ + private validateFrames(frames, useNumericIndex); + /** + * 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. + */ + public play(name: string, frameRate?: number, loop?: bool): void; + /** + * Stop animation by name. + * Current animation will be automatically set to the stopped one. + */ + public stop(name: string): void; + /** + * Update animation and parent sprite's bounds. + */ + public update(): void; + public frameData : FrameData; + public frameTotal : number; + public frame : number; + public frameName : string; + /** + * Removes all related references + */ + public destroy(): void; + } +} +/** +* Phaser - Components - Transform +*/ +module Phaser.Components { + class Transform { + /** + * Creates a new Sprite Transform component + * @param parent The Sprite using this transform + */ + constructor(parent); + /** + * Reference to Phaser.Game + */ + public game: Game; + /** + * Reference to the parent object (Sprite, Group, etc) + */ + public parent: Sprite; + /** + * Scale of the object. A scale of 1.0 is the original size. 0.5 half size. 2.0 double sized. + */ + public scale: Vec2; + /** + * Skew the object along the x and y axis. A skew value of 0 is no skew. + */ + public skew: Vec2; + /** + * The influence of camera movement upon the object, if supported. + */ + public scrollFactor: Vec2; + /** + * The origin is the point around which scale and rotation takes place. + */ + public origin: Vec2; + /** + * This value is added to the rotation of the object. + * For example if you had a texture drawn facing straight up then you could set + * rotationOffset to 90 and it would correspond correctly with Phasers right-handed coordinate system. + * @type {number} + */ + public rotationOffset: number; + /** + * The rotation of the object in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + */ + public rotation: number; + } +} +/** +* Phaser - Components - Input +* +* Input detection component +*/ +module Phaser.Components.Sprite { + class Input { + /** + * Sprite Input component constructor + * @param parent The Sprite using this Input component + */ + constructor(parent: Sprite); + /** + * Reference to Phaser.Game + */ + public game: Game; + /** + * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. + */ + private sprite; + private _pointerData; + /** + * If enabled the Input component will be updated by the parent Sprite + * @type {Boolean} + */ + public enabled: bool; + /** + * The PriorityID controls which Sprite receives an Input event first if they should overlap. + */ + public priorityID: number; + private _dragPoint; + private _draggedPointerID; + public dragOffset: Point; + public isDragged: bool; + public dragFromCenter: bool; + public dragPixelPerfect: bool; + public dragPixelPerfectAlpha: number; + public allowHorizontalDrag: bool; + public allowVerticalDrag: bool; + public snapOnDrag: bool; + public snapOnRelease: bool; + public snapOffset: Point; + public snapX: number; + public snapY: number; + /** + * Is this sprite allowed to be dragged by the mouse? true = yes, false = no + * @default false + */ + public draggable: bool; + /** + * A region of the game world within which the sprite is restricted during drag + * @default null + */ + public boundsRect: Rectangle; + /** + * An Sprite the bounds of which this sprite is restricted during drag + * @default null + */ + public boundsSprite: Sprite; + /** + * The Input component can monitor either the physics body of the Sprite or the frameBounds + * If checkBody is set to true it will monitor the bounds of the physics body. + * @type {Boolean} + */ + public checkBody: bool; + /** + * Turn the mouse pointer into a hand image by temporarily setting the CSS style of the Game canvas + * on Input over. Only works on desktop browsers or browsers with a visible input pointer. + * @type {Boolean} + */ + public useHandCursor: bool; + /** + * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. + * This value is only set when the pointer is over this Sprite. + * @type {number} + */ + public pointerX(pointer?: number): number; + /** + * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite + * This value is only set when the pointer is over this Sprite. + * @type {number} + */ + public pointerY(pointer?: number): number; + /** + * If the Pointer is touching the touchscreen, or the mouse button is held down, isDown is set to true + * @property isDown + * @type {Boolean} + **/ + public pointerDown(pointer?: number): bool; + /** + * If the Pointer is not touching the touchscreen, or the mouse button is up, isUp is set to true + * @property isUp + * @type {Boolean} + **/ + public pointerUp(pointer?: number): bool; + /** + * A timestamp representing when the Pointer first touched the touchscreen. + * @property timeDown + * @type {Number} + **/ + public pointerTimeDown(pointer?: number): bool; + /** + * A timestamp representing when the Pointer left the touchscreen. + * @property timeUp + * @type {Number} + **/ + public pointerTimeUp(pointer?: number): bool; + /** + * Is the Pointer over this Sprite + * @property isOver + * @type {Boolean} + **/ + public pointerOver(pointer?: number): bool; + /** + * Is the Pointer outside of this Sprite + * @property isOut + * @type {Boolean} + **/ + public pointerOut(pointer?: number): bool; + /** + * A timestamp representing when the Pointer first touched the touchscreen. + * @property timeDown + * @type {Number} + **/ + public pointerTimeOver(pointer?: number): bool; + /** + * A timestamp representing when the Pointer left the touchscreen. + * @property timeUp + * @type {Number} + **/ + public pointerTimeOut(pointer?: number): bool; + /** + * Is this sprite being dragged by the mouse or not? + * @default false + */ + public pointerDragged(pointer?: number): bool; + public start(priority?: number, checkBody?: bool, useHandCursor?: bool): Sprite; + public reset(): void; + public stop(): void; + public checkPointerOver(pointer: Pointer): bool; + /** + * Update + */ + public update(pointer: Pointer): bool; + public _pointerOverHandler(pointer: Pointer): void; + public _pointerOutHandler(pointer: Pointer): void; + public consumePointerEvent: bool; + public _touchedHandler(pointer: Pointer): bool; + public _releasedHandler(pointer: Pointer): void; + /** + * Updates the Pointer drag on this Sprite. + */ + private updateDrag(pointer); + /** + * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just over. + * @returns {boolean} + */ + public justOver(pointer?: number, delay?: number): bool; + /** + * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just out. + * @returns {boolean} + */ + public justOut(pointer?: number, delay?: number): bool; + /** + * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just over. + * @returns {boolean} + */ + public justPressed(pointer?: number, delay?: number): bool; + /** + * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just out. + * @returns {boolean} + */ + public justReleased(pointer?: number, delay?: number): bool; + /** + * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. + * @returns {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over. + */ + public overDuration(pointer?: number): number; + /** + * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. + * @returns {number} The number of milliseconds the pointer has been pressed down on the Sprite, or -1 if not over. + */ + public downDuration(pointer?: number): number; + /** + * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback + * + * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. + * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. + * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) + * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere + * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here + */ + public enableDrag(lockCenter?: bool, pixelPerfect?: bool, alphaThreshold?: number, boundsRect?: Rectangle, boundsSprite?: Sprite): void; + /** + * Stops this sprite from being able to be dragged. If it is currently the target of an active drag it will be stopped immediately. Also disables any set callbacks. + */ + public disableDrag(): void; + /** + * Called by Pointer when drag starts on this Sprite. Should not usually be called directly. + */ + public startDrag(pointer: Pointer): void; + /** + * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. + */ + public stopDrag(pointer: Pointer): void; + /** + * Restricts this sprite to drag movement only on the given axis. Note: If both are set to false the sprite will never move! + * + * @param allowHorizontal To enable the sprite to be dragged horizontally set to true, otherwise false + * @param allowVertical To enable the sprite to be dragged vertically set to true, otherwise false + */ + public setDragLock(allowHorizontal?: bool, allowVertical?: bool): void; + /** + * Make this Sprite snap to the given grid either during drag or when it's released. + * For example 16x16 as the snapX and snapY would make the sprite snap to every 16 pixels. + * + * @param snapX The width of the grid cell in pixels + * @param snapY The height of the grid cell in pixels + * @param onDrag If true the sprite will snap to the grid while being dragged + * @param onRelease If true the sprite will snap to the grid when released + */ + public enableSnap(snapX: number, snapY: number, onDrag?: bool, onRelease?: bool): void; + /** + * Stops the sprite from snapping to a grid during drag or release. + */ + public disableSnap(): void; + /** + * Bounds Rect check for the sprite drag + */ + private checkBoundsRect(); + /** + * Parent Sprite Bounds check for the sprite drag + */ + private checkBoundsSprite(); + /** + * Render debug infos. (including name, bounds info, position and some other properties) + * @param x {number} X position of the debug info to be rendered. + * @param y {number} Y position of the debug info to be rendered. + * @param [color] {number} color of the debug info to be rendered. (format is css color string) + */ + public renderDebugInfo(x: number, y: number, color?: string): void; + } +} +/** +* Phaser - Components - Events +* +* Signals that are dispatched by the Sprite and its various components +*/ +module Phaser.Components.Sprite { + class Events { + /** + * The Events component is a collection of events fired by the parent Sprite and its other components. + * @param parent The Sprite using this Input component + */ + constructor(parent: Sprite); + /** + * Reference to Phaser.Game + */ + public game: Game; + /** + * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. + */ + private sprite; + /** + * Dispatched by the Group this Sprite is added to. + */ + public onAddedToGroup: Signal; + /** + * Dispatched by the Group this Sprite is removed from. + */ + public onRemovedFromGroup: Signal; + /** + * Dispatched when this Sprite is killed. + */ + public onKilled: Signal; + /** + * Dispatched when this Sprite is revived. + */ + public onRevived: Signal; + /** + * Dispatched by the Input component when a pointer moves over an Input enabled sprite. + */ + public onInputOver: Signal; + /** + * Dispatched by the Input component when a pointer moves out of an Input enabled sprite. + */ + public onInputOut: Signal; + /** + * Dispatched by the Input component when a pointer is pressed down on an Input enabled sprite. + */ + public onInputDown: Signal; + /** + * Dispatched by the Input component when a pointer is released over an Input enabled sprite + */ + public onInputUp: Signal; + public onOutOfBounds: Signal; + } +} +/** +* Phaser - Vec2Utils +* +* A collection of methods useful for manipulating and performing operations on 2D vectors. +* +*/ +module Phaser { + class Vec2Utils { + /** + * Adds two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the sum of the two vectors. + */ + static add(a: Vec2, b: Vec2, out?: Vec2): Vec2; + /** + * Subtracts two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the difference of the two vectors. + */ + static subtract(a: Vec2, b: Vec2, out?: Vec2): Vec2; + /** + * Multiplies two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the sum of the two vectors multiplied. + */ + static multiply(a: Vec2, b: Vec2, out?: Vec2): Vec2; + /** + * Divides two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the sum of the two vectors divided. + */ + static divide(a: Vec2, b: Vec2, out?: Vec2): Vec2; + /** + * Scales a 2D vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {number} s Scaling value. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the scaled vector. + */ + static scale(a: Vec2, s: number, out?: Vec2): Vec2; + /** + * Rotate a 2D vector by 90 degrees. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the scaled vector. + */ + static perp(a: Vec2, out?: Vec2): Vec2; + /** + * Checks if two 2D vectors are equal. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Boolean} + */ + static equals(a: Vec2, b: Vec2): bool; + /** + * + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} epsilon + * @return {Boolean} + */ + static epsilonEquals(a: Vec2, b: Vec2, epsilon: number): bool; + /** + * Get the distance between two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + static distance(a: Vec2, b: Vec2): number; + /** + * Get the distance squared between two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + static distanceSq(a: Vec2, b: Vec2): number; + /** + * Project two 2D vectors onto another vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + static project(a: Vec2, b: Vec2, out?: Vec2): Vec2; + /** + * Project this vector onto a vector of unit length. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + static projectUnit(a: Vec2, b: Vec2, out?: Vec2): Vec2; + /** + * Right-hand normalize (make unit length) a 2D vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + static normalRightHand(a: Vec2, out?: Vec2): Vec2; + /** + * Normalize (make unit length) a 2D vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + static normalize(a: Vec2, out?: Vec2): Vec2; + /** + * The dot product of two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + static dot(a: Vec2, b: Vec2): number; + /** + * The cross product of two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + static cross(a: Vec2, b: Vec2): number; + /** + * The angle between two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + static angle(a: Vec2, b: Vec2): number; + /** + * The angle squared between two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + static angleSq(a: Vec2, b: Vec2): number; + /** + * Rotate a 2D vector around the origin to the given angle (theta). + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Number} theta The angle of rotation in radians. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + static rotate(a: Vec2, b: Vec2, theta: number, out?: Vec2): Vec2; + /** + * Clone a 2D vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is a copy of the source Vec2. + */ + static clone(a: Vec2, out?: Vec2): Vec2; + } +} +/** +* Phaser - Physics - Body +*/ +module Phaser.Physics { + class Body { + constructor(sprite: Sprite, type: number); + /** + * Reference to Phaser.Game + */ + public game: Game; + /** + * Reference to the sprite Sprite + */ + public sprite: Sprite; + /** + * The type of Body (disabled, dynamic, static or kinematic) + * Disabled = skips all physics operations / tests (default) + * Dynamic = gives and receives impacts + * Static = gives but doesn't receive impacts, cannot be moved by physics + * Kinematic = gives impacts, but never receives, can be moved by physics + * @type {number} + */ + public type: number; + public gravity: Vec2; + public bounce: Vec2; + public velocity: Vec2; + public acceleration: Vec2; + public drag: Vec2; + public maxVelocity: Vec2; + public angularVelocity: number; + public angularAcceleration: number; + public angularDrag: number; + public maxAngular: number; + /** + * Orientation of the object. + * @type {number} + */ + public facing: number; + public touching: number; + public allowCollisions: number; + public wasTouching: number; + public mass: number; + public position: Vec2; + public oldPosition: Vec2; + public offset: Vec2; + public bounds: Rectangle; + public preUpdate(): void; + public postUpdate(): void; + public hullWidth : number; + public hullHeight : number; + public hullX : number; + public hullY : number; + public deltaXAbs : number; + public deltaYAbs : number; + public deltaX : number; + public deltaY : number; + public render(context: CanvasRenderingContext2D): void; + /** + * Render debug infos. (including name, bounds info, position and some other properties) + * @param x {number} X position of the debug info to be rendered. + * @param y {number} Y position of the debug info to be rendered. + * @param [color] {number} color of the debug info to be rendered. (format is css color string) + */ + public renderDebugInfo(x: number, y: number, color?: string): void; + } +} +/** +* Phaser - Sprite +*/ +module Phaser { + class Sprite implements IGameObject { + /** + * Create a new Sprite. + * + * @param game {Phaser.Game} Current game instance. + * @param [x] {number} the initial x position of the sprite. + * @param [y] {number} the initial y position of the sprite. + * @param [key] {string} Key of the graphic you want to load for this sprite. + * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) + */ + constructor(game: Game, x?: number, y?: number, key?: string, frame?, bodyType?: number); + /** + * Reference to the main game object + */ + public game: Game; + /** + * The type of game object. + */ + public type: number; + /** + * The Group this Sprite belongs to. + */ + public group: Group; + /** + * Controls if both update and render are called by the core game loop. + */ + public exists: bool; + /** + * Controls if update() is automatically called by the core game loop. + */ + public active: bool; + /** + * Controls if this Sprite is rendered or skipped during the core game loop. + */ + public visible: bool; + /** + * A useful state for many game objects. Kill and revive both flip this switch. + */ + public alive: bool; + /** + * Sprite physics body. + */ + public body: Physics.Body; + /** + * The texture used to render the Sprite. + */ + public texture: Components.Texture; + /** + * The Sprite transform component. + */ + public transform: Components.Transform; + /** + * The Input component + */ + public input: Components.Sprite.Input; + /** + * The Events component + */ + public events: Components.Sprite.Events; + /** + * This manages animations of the sprite. You can modify animations though it. (see AnimationManager) + * @type AnimationManager + */ + public animations: Components.AnimationManager; + /** + * A Rectangle that defines the size and placement of the Sprite in the game world, + * after taking into consideration both scrollFactor and scaling. + */ + public worldView: Rectangle; + /** + * A boolean representing if the Sprite has been modified in any way via a scale, rotate, flip or skew. + */ + public modified: bool; + /** + * x value of the object. + */ + public x: number; + /** + * y value of the object. + */ + public y: number; + /** + * z order value of the object. + */ + public z: number; + /** + * Render iteration counter + */ + public renderOrderID: number; + /** + * The rotation of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + */ + /** + * Set the rotation of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + * The value is automatically wrapped to be between 0 and 360. + */ + 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; + public width : number; + public height : number; + /** + * Pre-update is called right before update() on each object in the game loop. + */ + public preUpdate(): void; + /** + * Override this function to update your class's position and appearance. + */ + public update(): void; + /** + * Automatically called after update() by the game loop. + */ + public postUpdate(): void; + /** + * Clean up memory. + */ + public destroy(): void; + /** + * Handy for "killing" game objects. + * Default behavior is to flag them as nonexistent AND dead. + * However, if you want the "corpse" to remain in the game, + * like to animate an effect or whatever, you should override this, + * setting only alive to false, and leaving exists true. + */ + public kill(removeFromGroup?: bool): void; + /** + * Handy for bringing game objects "back to life". Just sets alive and exists back to true. + * In practice, this is most often called by Object.reset(). + */ + public revive(): void; + } +} +/** +* Phaser - SpriteUtils +* +* A collection of methods useful for manipulating and checking Sprites. +*/ +module Phaser { + class SpriteUtils { + static _tempPoint: Point; + /** + * Check whether this object is visible in a specific camera Rectangle. + * @param camera {Rectangle} The Rectangle you want to check. + * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. + */ + static inCamera(camera: Camera, sprite: Sprite): bool; + static getAsPoints(sprite: Sprite): Point[]; + /** + * Checks to see if a point in 2D world space overlaps this GameObject. + * + * @param point {Point} The point in world space you want to check. + * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return Whether or not the point overlaps this object. + */ + static overlapsPoint(sprite: Sprite, point: Point, inScreenSpace?: bool, camera?: Camera): bool; + /** + * Check and see if this object is currently on screen. + * + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return {boolean} Whether the object is on screen or not. + */ + static onScreen(sprite: Sprite, camera?: Camera): bool; + /** + * Call this to figure out the on-screen position of the object. + * + * @param point {Point} Takes a Point object and assigns the post-scrolled X and Y values of this object to it. + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return {Point} The Point you passed in, or a new Point if you didn't pass one, containing the screen X and Y position of this object. + */ + static getScreenXY(sprite: Sprite, point?: Point, camera?: Camera): Point; + /** + * Handy for reviving game objects. + * Resets their existence flags and position. + * + * @param x {number} The new X position of this object. + * @param y {number} The new Y position of this object. + */ + static reset(sprite: Sprite, x: number, y: number): void; + static setOriginToCenter(sprite: Sprite, fromFrameBounds?: bool, fromBody?: bool): void; + /** + * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere + * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) + * it can be stopped from leaving the world, or a section of it. + * + * @param x {number} x position of the bound + * @param y {number} y position of the bound + * @param width {number} width of its bound + * @param height {number} height of its bound + */ + static setBounds(x: number, y: number, width: number, height: number): void; + } +} +/** +* Phaser - Components - Texture +* +* The Texture being used to render the object (Sprite, Group background, etc). Either Image based on a DynamicTexture. +*/ +module Phaser.Components { + class Texture { + /** + * Creates a new Texture component + * @param parent The object using this Texture to render. + * @param key An optional Game.Cache key to load an image from + */ + constructor(parent); + /** + * Private _width - use the width getter/setter instead + */ + private _width; + /** + * Private _height - use the height getter/setter instead + */ + private _height; + /** + * Reference to Phaser.Game + */ + public game: Game; + /** + * Reference to the parent object (Sprite, Group, etc) + */ + public parent; + /** + * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. + */ + public imageTexture; + /** + * Reference to the DynamicTexture that is used as the texture for the Sprite. + * @type {DynamicTexture} + */ + public dynamicTexture: DynamicTexture; + /** + * The load status of the texture image. + * @type {boolean} + */ + public loaded: bool; + /** + * An Array of Cameras to which this texture won't render + * @type {Array} + */ + public cameraBlacklist: number[]; + /** + * Whether the Sprite background is opaque or not. If set to true the Sprite is filled with + * the value of Texture.backgroundColor every frame. Normally you wouldn't enable this but + * for some effects it can be handy. + * @type {boolean} + */ + public opaque: bool; + /** + * Opacity of the Sprite texture where 1 is opaque (default) and 0 is fully transparent. + * @type {number} + */ + public alpha: number; + /** + * The Background Color of the Sprite if Texture.opaque is set to true. + * Given in css color string format, i.e. 'rgb(0,0,0)' or '#ff0000'. + * @type {string} + */ + public backgroundColor: string; + /** + * You can set a globalCompositeOperation that will be applied before the render method is called on this Sprite. + * This is useful if you wish to apply an effect like 'lighten'. + * If this value is set it will call a canvas context save and restore before and after the render pass, so use it sparingly. + * Set to null to disable. + */ + public globalCompositeOperation: string; + /** + * A reference to the Canvas this Sprite renders to. + * @type {HTMLCanvasElement} + */ + public canvas: HTMLCanvasElement; + /** + * A reference to the Canvas Context2D this Sprite renders to. + * @type {CanvasRenderingContext2D} + */ + public context: CanvasRenderingContext2D; + /** + * The Cache key used for the Image Texture. + */ + public cacheKey: string; + /** + * The Texture being used to render the Sprite. Either an Image Texture from the Cache or a DynamicTexture. + */ + public texture; + /** + * Controls if the Sprite is rendered rotated or not. + * If renderRotation is false then the object can still rotate but it will never be rendered rotated. + * @type {boolean} + */ + public renderRotation: bool; + /** + * Flip the graphic horizontally (defaults to false) + * @type {boolean} + */ + public flippedX: bool; + /** + * Flip the graphic vertically (defaults to false) + * @type {boolean} + */ + public flippedY: bool; + /** + * Is the texture a DynamicTexture? + * @type {boolean} + */ + public isDynamic: bool; + /** + * Updates the texture being used to render the Sprite. + * Called automatically by SpriteUtils.loadTexture and SpriteUtils.loadDynamicTexture. + */ + public setTo(image?, dynamic?: DynamicTexture); + /** + * Sets a new graphic from the game cache to use as the texture for this Sprite. + * The graphic can be SpriteSheet or Texture Atlas. If you need to use a DynamicTexture see loadDynamicTexture. + * @param key {string} Key of the graphic you want to load for this sprite. + * @param clearAnimations {boolean} If this Sprite has a set of animation data already loaded you can choose to keep or clear it with this boolean + * @param updateBody {boolean} Update the physics body dimensions to match the newly loaded texture/frame? + */ + public loadImage(key: string, clearAnimations?: bool, updateBody?: bool): void; + /** + * Load a DynamicTexture as its texture. + * @param texture {DynamicTexture} The texture object to be used by this sprite. + */ + public loadDynamicTexture(texture: DynamicTexture): void; + /** + * The width of the texture. If an animation it will be the frame width, not the width of the sprite sheet. + * If using a DynamicTexture it will be the width of the dynamic texture itself. + * @type {number} + */ + public width : number; + /** + * The height of the texture. If an animation it will be the frame height, not the height of the sprite sheet. + * If using a DynamicTexture it will be the height of the dynamic texture itself. + * @type {number} + */ + public height : number; + } +} +/** * Phaser - Group * * This class is used for organising, updating and sorting game objects. @@ -934,6 +2813,18 @@ module Phaser { */ public group: Group; /** + * Optional texture used in the background of the Camera. + */ + public texture: Components.Texture; + /** + * The transform component. + */ + public transform: Components.Transform; + /** + * A boolean representing if the Group has been modified in any way via a scale, rotate, flip or skew. + */ + public modified: bool; + /** * If this Group exists or not. Can be set to false to skip certain loop checks. */ public exists: bool; @@ -960,24 +2851,6 @@ module Phaser { */ public length: number; /** - * You can set a globalCompositeOperation that will be applied before the render method is called on this Groups children. - * This is useful if you wish to apply an effect like 'lighten' to a whole group of children as it saves doing it one-by-one. - * If this value is set it will call a canvas context save and restore before and after the render pass. - * Set to null to disable. - */ - public globalCompositeOperation: string; - /** - * You can set an alpha value on this Group that will be applied before the render method is called on this Groups children. - * This is useful if you wish to alpha a whole group of children as it saves doing it one-by-one. - * Set to 0 to disable. - */ - public alpha: number; - /** - * An Array of Cameras to which this Group, or any of its children, won't render - * @type {Array} - */ - public cameraBlacklist: number[]; - /** * Gets the next z index value for children of this Group */ public getNextZIndex(): number; @@ -1027,10 +2900,11 @@ module Phaser { * @param x {number} X position of the new sprite. * @param y {number} Y position of the new sprite. * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this sprite + * @param [frame] {string|number} If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name. * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) * @returns {Sprite} The newly created sprite object. */ - public addNewSprite(x: number, y: number, key?: string, bodyType?: number): Sprite; + public addNewSprite(x: number, y: number, key?: string, frame?, bodyType?: number): Sprite; /** * Sets all of the game object properties needed to exist within this Group. */ @@ -1085,7 +2959,7 @@ module Phaser { * State.update() override. To sort all existing objects after * a big explosion or bomb attack, you might call myGroup.sort("exists",Group.DESCENDING). * - * @param {string} index The string name of the member variable you want to sort on. Default value is "y". + * @param {string} index The string name of the member variable you want to sort on. Default value is "z". * @param {number} order A Group constant that defines the sort order. Possible values are Group.ASCENDING and Group.DESCENDING. Default value is Group.ASCENDING. */ public sort(index?: string, order?: number): void; @@ -1909,7 +3783,7 @@ module Phaser { */ public angleBetween(x1: number, y1: number, x2: number, y2: number): number; /** - * set an angle with in the bounds of -PI to PI + * set an angle within the bounds of -PI to PI */ public normalizeAngle(angle: number, radians?: bool): number; /** @@ -2233,16 +4107,16 @@ module Phaser { */ public vectorLength(dx: number, dy: number): number; /** - * Rotates the point around the x/y coordinates given to the desired angle and distance + * Rotates the point around the x/y coordinates given to the desired rotation and distance * @param point {Object} Any object with exposed x and y properties * @param x {number} The x coordinate of the anchor point * @param y {number} The y coordinate of the anchor point - * @param {Number} angle The angle in radians (unless asDegrees is true) to return the point from. - * @param {Boolean} asDegrees Is the given angle in radians (false) or degrees (true)? + * @param {Number} rotation The rotation in radians (unless asDegrees is true) to return the point from. + * @param {Boolean} asDegrees Is the given rotation in radians (false) or degrees (true)? * @param {Number} distance An optional distance constraint between the point and the anchor * @return The modified point object */ - public rotatePoint(point, x1: number, y1: number, angle: number, asDegrees?: bool, distance?: number); + public rotatePoint(point, x1: number, y1: number, rotation: number, asDegrees?: bool, distance?: number); } } /** @@ -2384,1830 +4258,6 @@ module Phaser { } } /** -* Phaser - AnimationLoader -* -* Responsible for parsing sprite sheet and JSON data into the internal FrameData format that Phaser uses for animations. -*/ -module Phaser { - class AnimationLoader { - /** - * Parse a sprite sheet from asset data. - * @param key {string} Asset key for the sprite sheet data. - * @param frameWidth {number} Width of animation frame. - * @param frameHeight {number} Height of animation frame. - * @param frameMax {number} Number of animation frames. - * @return {FrameData} Generated FrameData object. - */ - static parseSpriteSheet(game: Game, key: string, frameWidth: number, frameHeight: number, frameMax: number): FrameData; - /** - * Parse frame datas from json. - * @param json {object} Json data you want to parse. - * @return {FrameData} Generated FrameData object. - */ - static parseJSONData(game: Game, json): FrameData; - static parseXMLData(game: Game, xml, format: number): FrameData; - } -} -/** -* Phaser - Animation -* -* An Animation is a single animation. It is created by the AnimationManager and belongs to Sprite objects. -*/ -module Phaser { - class Animation { - /** - * Animation constructor - * Create a new Animation. - * - * @param parent {Sprite} Owner sprite of this animation. - * @param frameData {FrameData} The FrameData object contains animation data. - * @param name {string} Unique name of this animation. - * @param frames {number[]/string[]} An array of numbers or strings indicating what frames to play in what order. - * @param delay {number} Time between frames in ms. - * @param looped {boolean} Whether or not the animation is looped or just plays once. - */ - constructor(game: Game, parent: Sprite, frameData: FrameData, name: string, frames, delay: number, looped: bool); - /** - * Local private reference to game. - */ - private _game; - /** - * Local private reference to its owner sprite. - * @type {Sprite} - */ - private _parent; - /** - * Animation frame container. - * @type {number[]} - */ - private _frames; - /** - * Frame data of this animation.(parsed from sprite sheet) - * @type {FrameData} - */ - private _frameData; - /** - * Index of current frame. - * @type {number} - */ - private _frameIndex; - /** - * Time when switched to last frame (in ms). - * @type number - */ - private _timeLastFrame; - /** - * Time when this will switch to next frame (in ms). - * @type number - */ - private _timeNextFrame; - /** - * Name of this animation. - * @type {string} - */ - public name: string; - /** - * Currently played frame instance. - * @type {Frame} - */ - public currentFrame: Frame; - /** - * Whether or not this animation finished playing. - * @type {boolean} - */ - public isFinished: bool; - /** - * Whethor or not this animation is currently playing. - * @type {boolean} - */ - public isPlaying: bool; - /** - * Whether or not the animation is looped. - * @type {boolean} - */ - public looped: bool; - /** - * Time between frames in ms. - * @type {number} - */ - public delay: number; - public frameTotal : number; - public frame : number; - /** - * Play this animation. - * @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. - */ - public play(frameRate?: number, loop?: bool): void; - /** - * Play this animation from the first frame. - */ - public restart(): void; - /** - * Stop playing animation and set it finished. - */ - public stop(): void; - /** - * Update animation frames. - */ - public update(): bool; - /** - * Clean up animation memory. - */ - public destroy(): void; - /** - * Animation complete callback method. - */ - private onComplete(); - } -} -/** -* Phaser - Frame -* -* A Frame is a single frame of an animation and is part of a FrameData collection. -*/ -module Phaser { - class Frame { - /** - * Frame constructor - * Create a new Frame with specific position, size and name. - * - * @param x {number} X position within the image to cut from. - * @param y {number} Y position within the image to cut from. - * @param width {number} Width of the frame. - * @param height {number} Height of the frame. - * @param name {string} Name of this frame. - */ - constructor(x: number, y: number, width: number, height: number, name: string); - /** - * X position within the image to cut from. - * @type {number} - */ - public x: number; - /** - * Y position within the image to cut from. - * @type {number} - */ - public y: number; - /** - * Width of the frame. - * @type {number} - */ - public width: number; - /** - * Height of the frame. - * @type {number} - */ - public height: number; - /** - * Useful for Sprite Sheets. - * @type {number} - */ - public index: number; - /** - * Useful for Texture Atlas files. (is set to the filename value) - */ - public name: string; - /** - * Rotated? (not yet implemented) - */ - public rotated: bool; - /** - * Either cw or ccw, rotation is always 90 degrees. - */ - public rotationDirection: string; - /** - * Was it trimmed when packed? - * @type {boolean} - */ - public trimmed: bool; - /** - * Width of the original sprite. - * @type {number} - */ - public sourceSizeW: number; - /** - * Height of the original sprite. - * @type {number} - */ - public sourceSizeH: number; - /** - * X position of the trimmed sprite inside original sprite. - * @type {number} - */ - public spriteSourceSizeX: number; - /** - * Y position of the trimmed sprite inside original sprite. - * @type {number} - */ - public spriteSourceSizeY: number; - /** - * Width of the trimmed sprite. - * @type {number} - */ - public spriteSourceSizeW: number; - /** - * Height of the trimmed sprite. - * @type {number} - */ - public spriteSourceSizeH: number; - /** - * Set rotation of this frame. (Not yet supported!) - */ - public setRotation(rotated: bool, rotationDirection: string): void; - /** - * Set trim of the frame. - * @param trimmed {boolean} Whether this frame trimmed or not. - * @param actualWidth {number} Actual width of this frame. - * @param actualHeight {number} Actual height of this frame. - * @param destX {number} Destination x position. - * @param destY {number} Destination y position. - * @param destWidth {number} Destination draw width. - * @param destHeight {number} Destination draw height. - */ - public setTrim(trimmed: bool, actualWidth: number, actualHeight: number, destX: number, destY: number, destWidth: number, destHeight: number): void; - } -} -/** -* Phaser - FrameData -* -* FrameData is a container for Frame objects, the internal representation of animation data in Phaser. -*/ -module Phaser { - class FrameData { - /** - * FrameData constructor - */ - constructor(); - /** - * Local frame container. - */ - private _frames; - /** - * Local frameName<->index container. - */ - private _frameNames; - public total : number; - /** - * Add a new frame. - * @param frame {Frame} The frame you want to add. - * @return {Frame} The frame you just added. - */ - public addFrame(frame: Frame): Frame; - /** - * Get a frame by its index. - * @param index {number} Index of the frame you want to get. - * @return {Frame} The frame you want. - */ - public getFrame(index: number): Frame; - /** - * Get a frame by its name. - * @param name {string} Name of the frame you want to get. - * @return {Frame} The frame you want. - */ - public getFrameByName(name: string): Frame; - /** - * Check whether there's a frame with given name. - * @param name {string} Name of the frame you want to check. - * @return {boolean} True if frame with given name found, otherwise return false. - */ - public checkFrameName(name: string): bool; - /** - * Get ranges of frames in an array. - * @param start {number} Start index of frames you want. - * @param end {number} End index of frames you want. - * @param [output] {Frame[]} result will be added into this array. - * @return {Frame[]} Ranges of specific frames in an array. - */ - public getFrameRange(start: number, end: number, output?: Frame[]): Frame[]; - /** - * Get all indexes of frames by giving their name. - * @param [output] {number[]} result will be added into this array. - * @return {number[]} Indexes of specific frames in an array. - */ - public getFrameIndexes(output?: number[]): number[]; - /** - * Get the frame indexes by giving the frame names. - * @param [output] {number[]} result will be added into this array. - * @return {number[]} Names of specific frames in an array. - */ - public getFrameIndexesByName(input: string[]): number[]; - /** - * Get all frames in this frame data. - * @return {Frame[]} All the frames in an array. - */ - public getAllFrames(): Frame[]; - /** - * Get All frames with specific ranges. - * @param range {number[]} Ranges in an array. - * @return {Frame[]} All frames in an array. - */ - public getFrames(range: number[]): Frame[]; - } -} -/** -* Phaser - AnimationManager -* -* Any Sprite that has animation contains an instance of the AnimationManager, which is used to add, play and update -* sprite specific animations. -*/ -module Phaser.Components { - class AnimationManager { - /** - * AnimationManager constructor - * Create a new AnimationManager. - * - * @param parent {Sprite} Owner sprite of this manager. - */ - constructor(parent: Sprite); - /** - * Local private reference to game. - */ - private _game; - /** - * Local private reference to its owner sprite. - */ - private _parent; - /** - * Animation key-value container. - */ - private _anims; - /** - * Index of current frame. - * @type {number} - */ - private _frameIndex; - /** - * Data contains animation frames. - * @type {FrameData} - */ - private _frameData; - /** - * Keeps track of the current animation being played. - */ - public currentAnim: Animation; - /** - * Keeps track of the current frame of animation. - */ - public currentFrame: Frame; - /** - * Load animation frame data. - * @param frameData Data to be loaded. - */ - public loadFrameData(frameData: FrameData): void; - /** - * 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 - */ - public add(name: string, frames?: any[], frameRate?: number, loop?: bool, useNumericIndex?: bool): Animation; - /** - * 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. - */ - private validateFrames(frames, useNumericIndex); - /** - * 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. - */ - public play(name: string, frameRate?: number, loop?: bool): void; - /** - * Stop animation by name. - * Current animation will be automatically set to the stopped one. - */ - public stop(name: string): void; - /** - * Update animation and parent sprite's bounds. - */ - public update(): void; - public frameData : FrameData; - public frameTotal : number; - public frame : number; - public frameName : string; - /** - * Removes all related references - */ - public destroy(): void; - } -} -/** -* Phaser - RectangleUtils -* -* A collection of methods useful for manipulating and comparing Rectangle objects. -* -* TODO: Check docs + overlap + intersect + toPolygon? -*/ -module Phaser { - class RectangleUtils { - /** - * Get the location of the Rectangles top-left corner as a Point object. - * @method getTopLeftAsPoint - * @param {Rectangle} a - The Rectangle object. - * @param {Point} out - Optional Point to store the value in, if not supplied a new Point object will be created. - * @return {Point} The new Point object. - **/ - static getTopLeftAsPoint(a: Rectangle, out?: Point): Point; - /** - * Get the location of the Rectangles bottom-right corner as a Point object. - * @method getTopLeftAsPoint - * @param {Rectangle} a - The Rectangle object. - * @param {Point} out - Optional Point to store the value in, if not supplied a new Point object will be created. - * @return {Point} The new Point object. - **/ - static getBottomRightAsPoint(a: Rectangle, out?: Point): Point; - /** - * Increases the size of the Rectangle object by the specified amounts. The center point of the Rectangle object stays the same, and its size increases to the left and right by the dx value, and to the top and the bottom by the dy value. - * @method inflate - * @param {Rectangle} a - The Rectangle object. - * @param {Number} dx The amount to be added to the left side of the Rectangle. - * @param {Number} dy The amount to be added to the bottom side of the Rectangle. - * @return {Rectangle} This Rectangle object. - **/ - static inflate(a: Rectangle, dx: number, dy: number): Rectangle; - /** - * Increases the size of the Rectangle object. This method is similar to the Rectangle.inflate() method except it takes a Point object as a parameter. - * @method inflatePoint - * @param {Rectangle} a - The Rectangle object. - * @param {Point} point The x property of this Point object is used to increase the horizontal dimension of the Rectangle object. The y property is used to increase the vertical dimension of the Rectangle object. - * @return {Rectangle} The Rectangle object. - **/ - static inflatePoint(a: Rectangle, point: Point): Rectangle; - /** - * The size of the Rectangle object, expressed as a Point object with the values of the width and height properties. - * @method size - * @param {Rectangle} a - The Rectangle object. - * @param {Point} output Optional Point object. If given the values will be set into the object, otherwise a brand new Point object will be created and returned. - * @return {Point} The size of the Rectangle object - **/ - static size(a: Rectangle, output?: Point): Point; - /** - * Returns a new Rectangle object with the same values for the x, y, width, and height properties as the original Rectangle object. - * @method clone - * @param {Rectangle} a - The Rectangle object. - * @param {Rectangle} output Optional Rectangle object. If given the values will be set into the object, otherwise a brand new Rectangle object will be created and returned. - * @return {Rectangle} - **/ - static clone(a: Rectangle, output?: Rectangle): Rectangle; - /** - * Determines whether the specified coordinates are contained within the region defined by this Rectangle object. - * @method contains - * @param {Rectangle} a - The Rectangle object. - * @param {Number} x The x coordinate of the point to test. - * @param {Number} y The y coordinate of the point to test. - * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. - **/ - static contains(a: Rectangle, x: number, y: number): bool; - /** - * Determines whether the specified point is contained within the rectangular region defined by this Rectangle object. This method is similar to the Rectangle.contains() method, except that it takes a Point object as a parameter. - * @method containsPoint - * @param {Rectangle} a - The Rectangle object. - * @param {Point} point The point object being checked. Can be Point or any object with .x and .y values. - * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. - **/ - static containsPoint(a: Rectangle, point: Point): bool; - /** - * Determines whether the first Rectangle object is fully contained within the second Rectangle object. - * A Rectangle object is said to contain another if the second Rectangle object falls entirely within the boundaries of the first. - * @method containsRect - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. - **/ - static containsRect(a: Rectangle, b: Rectangle): bool; - /** - * Determines whether the two Rectangles are equal. - * This method compares the x, y, width and height properties of each Rectangle. - * @method equals - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @return {Boolean} A value of true if the two Rectangles have exactly the same values for the x, y, width and height properties; otherwise false. - **/ - static equals(a: Rectangle, b: Rectangle): bool; - /** - * If the Rectangle object specified in the toIntersect parameter intersects with this Rectangle object, returns the area of intersection as a Rectangle object. If the rectangles do not intersect, this method returns an empty Rectangle object with its properties set to 0. - * @method intersection - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @param {Rectangle} output Optional Rectangle object. If given the intersection values will be set into this object, otherwise a brand new Rectangle object will be created and returned. - * @return {Rectangle} A Rectangle object that equals the area of intersection. If the rectangles do not intersect, this method returns an empty Rectangle object; that is, a rectangle with its x, y, width, and height properties set to 0. - **/ - static intersection(a: Rectangle, b: Rectangle, out?: Rectangle): Rectangle; - /** - * Determines whether the two Rectangles intersect with each other. - * This method checks the x, y, width, and height properties of the Rectangles. - * @method intersects - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @param {Number} tolerance A tolerance value to allow for an intersection test with padding, default to 0 - * @return {Boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false. - **/ - static intersects(a: Rectangle, b: Rectangle, tolerance?: number): bool; - /** - * Determines whether the object specified intersects (overlaps) with the given values. - * @method intersectsRaw - * @param {Number} left - * @param {Number} right - * @param {Number} top - * @param {Number} bottomt - * @param {Number} tolerance A tolerance value to allow for an intersection test with padding, default to 0 - * @return {Boolean} A value of true if the specified object intersects with the Rectangle; otherwise false. - **/ - static intersectsRaw(a: Rectangle, left: number, right: number, top: number, bottom: number, tolerance?: number): bool; - /** - * Adds two rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two rectangles. - * @method union - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @param {Rectangle} output Optional Rectangle object. If given the new values will be set into this object, otherwise a brand new Rectangle object will be created and returned. - * @return {Rectangle} A Rectangle object that is the union of the two rectangles. - **/ - static union(a: Rectangle, b: Rectangle, out?: Rectangle): Rectangle; - } -} -/** -* Phaser - ColorUtils -* -* A collection of methods useful for manipulating color values. -*/ -module Phaser { - class ColorUtils { - static game: Game; - /** - * Given an alpha and 3 color values this will return an integer representation of it - * - * @param alpha {number} The Alpha value (between 0 and 255) - * @param red {number} The Red channel value (between 0 and 255) - * @param green {number} The Green channel value (between 0 and 255) - * @param blue {number} The Blue channel value (between 0 and 255) - * - * @return A native color value integer (format: 0xAARRGGBB) - */ - static getColor32(alpha: number, red: number, green: number, blue: number): number; - /** - * Given 3 color values this will return an integer representation of it - * - * @param red {number} The Red channel value (between 0 and 255) - * @param green {number} The Green channel value (between 0 and 255) - * @param blue {number} The Blue channel value (between 0 and 255) - * - * @return A native color value integer (format: 0xRRGGBB) - */ - static getColor(red: number, green: number, blue: number): number; - /** - * Get HSV color wheel values in an array which will be 360 elements in size - * - * @param alpha Alpha value for each color of the color wheel, between 0 (transparent) and 255 (opaque) - * - * @return Array - */ - static getHSVColorWheel(alpha?: number): any[]; - /** - * Returns a Complementary Color Harmony for the given color. - *

A complementary hue is one directly opposite the color given on the color wheel

- *

Value returned in 0xAARRGGBB format with Alpha set to 255.

- * - * @param color The color to base the harmony on - * - * @return 0xAARRGGBB format color value - */ - static getComplementHarmony(color: number): number; - /** - * Returns an Analogous Color Harmony for the given color. - *

An Analogous harmony are hues adjacent to each other on the color wheel

- *

Values returned in 0xAARRGGBB format with Alpha set to 255.

- * - * @param color The color to base the harmony on - * @param threshold Control how adjacent the colors will be (default +- 30 degrees) - * - * @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color) - */ - static getAnalogousHarmony(color: number, threshold?: number): { - color1: number; - color2: number; - color3: number; - hue1: any; - hue2: number; - hue3: number; - }; - /** - * Returns an Split Complement Color Harmony for the given color. - *

A Split Complement harmony are the two hues on either side of the color's Complement

- *

Values returned in 0xAARRGGBB format with Alpha set to 255.

- * - * @param color The color to base the harmony on - * @param threshold Control how adjacent the colors will be to the Complement (default +- 30 degrees) - * - * @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color) - */ - static getSplitComplementHarmony(color: number, threshold?: number): any; - /** - * Returns a Triadic Color Harmony for the given color. - *

A Triadic harmony are 3 hues equidistant from each other on the color wheel

- *

Values returned in 0xAARRGGBB format with Alpha set to 255.

- * - * @param color The color to base the harmony on - * - * @return Object containing 3 properties: color1 (the original color), color2 and color3 (the equidistant colors) - */ - static getTriadicHarmony(color: number): any; - /** - * Returns a string containing handy information about the given color including string hex value, - * RGB format information and HSL information. Each section starts on a newline, 3 lines in total. - * - * @param color A color value in the format 0xAARRGGBB - * - * @return string containing the 3 lines of information - */ - static getColorInfo(color: number): string; - /** - * Return a string representation of the color in the format 0xAARRGGBB - * - * @param color The color to get the string representation for - * - * @return A string of length 10 characters in the format 0xAARRGGBB - */ - static RGBtoHexstring(color: number): string; - /** - * Return a string representation of the color in the format #RRGGBB - * - * @param color The color to get the string representation for - * - * @return A string of length 10 characters in the format 0xAARRGGBB - */ - static RGBtoWebstring(color: number): string; - /** - * Return a string containing a hex representation of the given color - * - * @param color The color channel to get the hex value for, must be a value between 0 and 255) - * - * @return A string of length 2 characters, i.e. 255 = FF, 0 = 00 - */ - static colorToHexstring(color: number): string; - /** - * Convert a HSV (hue, saturation, lightness) color space value to an RGB color - * - * @param h Hue degree, between 0 and 359 - * @param s Saturation, between 0.0 (grey) and 1.0 - * @param v Value, between 0.0 (black) and 1.0 - * @param alpha Alpha value to set per color (between 0 and 255) - * - * @return 32-bit ARGB color value (0xAARRGGBB) - */ - static HSVtoRGB(h: number, s: number, v: number, alpha?: number): number; - /** - * Convert an RGB color value to an object containing the HSV color space values: Hue, Saturation and Lightness - * - * @param color In format 0xRRGGBB - * - * @return Object with the properties hue (from 0 to 360), saturation (from 0 to 1.0) and lightness (from 0 to 1.0, also available under .value) - */ - static RGBtoHSV(color: number): any; - /** - * - * @method interpolateColor - * @param {Number} color1 - * @param {Number} color2 - * @param {Number} steps - * @param {Number} currentStep - * @param {Number} alpha - * @return {Number} - * @static - */ - static interpolateColor(color1: number, color2: number, steps: number, currentStep: number, alpha?: number): number; - /** - * - * @method interpolateColorWithRGB - * @param {Number} color - * @param {Number} r2 - * @param {Number} g2 - * @param {Number} b2 - * @param {Number} steps - * @param {Number} currentStep - * @return {Number} - * @static - */ - static interpolateColorWithRGB(color: number, r2: number, g2: number, b2: number, steps: number, currentStep: number): number; - /** - * - * @method interpolateRGB - * @param {Number} r1 - * @param {Number} g1 - * @param {Number} b1 - * @param {Number} r2 - * @param {Number} g2 - * @param {Number} b2 - * @param {Number} steps - * @param {Number} currentStep - * @return {Number} - * @static - */ - static interpolateRGB(r1: number, g1: number, b1: number, r2: number, g2: number, b2: number, steps: number, currentStep: number): number; - /** - * Returns a random color value between black and white - *

Set the min value to start each channel from the given offset.

- *

Set the max value to restrict the maximum color used per channel

- * - * @param min The lowest value to use for the color - * @param max The highest value to use for the color - * @param alpha The alpha value of the returning color (default 255 = fully opaque) - * - * @return 32-bit color value with alpha - */ - static getRandomColor(min?: number, max?: number, alpha?: number): number; - /** - * Return the component parts of a color as an Object with the properties alpha, red, green, blue - * - *

Alpha will only be set if it exist in the given color (0xAARRGGBB)

- * - * @param color in RGB (0xRRGGBB) or ARGB format (0xAARRGGBB) - * - * @return Object with properties: alpha, red, green, blue - */ - static getRGB(color: number): any; - /** - * - * @method getWebRGB - * @param {Number} color - * @return {Any} - */ - static getWebRGB(color: number): any; - /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component, as a value between 0 and 255 - * - * @param color In the format 0xAARRGGBB - * - * @return The Alpha component of the color, will be between 0 and 255 (0 being no Alpha, 255 full Alpha) - */ - static getAlpha(color: number): number; - /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component as a value between 0 and 1 - * - * @param color In the format 0xAARRGGBB - * - * @return The Alpha component of the color, will be between 0 and 1 (0 being no Alpha (opaque), 1 full Alpha (transparent)) - */ - static getAlphaFloat(color: number): number; - /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Red component, as a value between 0 and 255 - * - * @param color In the format 0xAARRGGBB - * - * @return The Red component of the color, will be between 0 and 255 (0 being no color, 255 full Red) - */ - static getRed(color: number): number; - /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Green component, as a value between 0 and 255 - * - * @param color In the format 0xAARRGGBB - * - * @return The Green component of the color, will be between 0 and 255 (0 being no color, 255 full Green) - */ - static getGreen(color: number): number; - /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Blue component, as a value between 0 and 255 - * - * @param color In the format 0xAARRGGBB - * - * @return The Blue component of the color, will be between 0 and 255 (0 being no color, 255 full Blue) - */ - static getBlue(color: number): number; - } -} -/** -* Phaser - DynamicTexture -* -* A DynamicTexture can be thought of as a mini canvas into which you can draw anything. -* Game Objects can be assigned a DynamicTexture, so when they render in the world they do so -* based on the contents of the texture at the time. This allows you to create powerful effects -* once and have them replicated across as many game objects as you like. -*/ -module Phaser { - class DynamicTexture { - /** - * DynamicTexture constructor - * Create a new DynamicTexture. - * - * @param game {Phaser.Game} Current game instance. - * @param width {number} Init width of this texture. - * @param height {number} Init height of this texture. - */ - constructor(game: Game, width: number, height: number); - /** - * Reference to game. - */ - public game: Game; - /** - * The type of game object. - */ - public type: number; - private _sx; - private _sy; - private _sw; - private _sh; - private _dx; - private _dy; - private _dw; - private _dh; - /** - * Bound of this texture with width and height info. - * @type {Rectangle} - */ - public bounds: Rectangle; - /** - * This class is actually a wrapper of canvas. - * @type {HTMLCanvasElement} - */ - public canvas: HTMLCanvasElement; - /** - * Canvas context of this object. - * @type {CanvasRenderingContext2D} - */ - public context: CanvasRenderingContext2D; - /** - * Get a color of a specific pixel. - * @param x {number} X position of the pixel in this texture. - * @param y {number} Y position of the pixel in this texture. - * @return {number} A native color value integer (format: 0xRRGGBB) - */ - public getPixel(x: number, y: number): number; - /** - * Get a color of a specific pixel (including alpha value). - * @param x {number} X position of the pixel in this texture. - * @param y {number} Y position of the pixel in this texture. - * @return A native color value integer (format: 0xAARRGGBB) - */ - public getPixel32(x: number, y: number): number; - /** - * Get pixels in array in a specific rectangle. - * @param rect {Rectangle} The specific rectangle. - * @returns {array} CanvasPixelArray. - */ - public getPixels(rect: Rectangle): ImageData; - /** - * Set color of a specific pixel. - * @param x {number} X position of the target pixel. - * @param y {number} Y position of the target pixel. - * @param color {number} Native integer with color value. (format: 0xRRGGBB) - */ - public setPixel(x: number, y: number, color: string): void; - /** - * Set color (with alpha) of a specific pixel. - * @param x {number} X position of the target pixel. - * @param y {number} Y position of the target pixel. - * @param color {number} Native integer with color value. (format: 0xAARRGGBB) - */ - public setPixel32(x: number, y: number, color: number): void; - /** - * Set image data to a specific rectangle. - * @param rect {Rectangle} Target rectangle. - * @param input {object} Source image data. - */ - public setPixels(rect: Rectangle, input): void; - /** - * Fill a given rectangle with specific color. - * @param rect {Rectangle} Target rectangle you want to fill. - * @param color {number} A native number with color value. (format: 0xRRGGBB) - */ - public fillRect(rect: Rectangle, color: number): void; - /** - * - */ - public pasteImage(key: string, frame?: number, destX?: number, destY?: number, destWidth?: number, destHeight?: number): void; - /** - * Copy pixel from another DynamicTexture to this texture. - * @param sourceTexture {DynamicTexture} Source texture object. - * @param sourceRect {Rectangle} The specific region rectangle to be copied to this in the source. - * @param destPoint {Point} Top-left point the target image data will be paste at. - */ - public copyPixels(sourceTexture: DynamicTexture, sourceRect: Rectangle, destPoint: Point): void; - /** - * Given an array of Sprites it will update each of them so that their canvas/contexts reference this DynamicTexture - * @param objects {Array} An array of GameObjects, or objects that inherit from it such as Sprites - */ - public assignCanvasToGameObjects(objects: IGameObject[]): void; - /** - * Clear the whole canvas. - */ - public clear(): void; - /** - * Renders this DynamicTexture to the Stage at the given x/y coordinates - * - * @param x {number} The X coordinate to render on the stage to (given in screen coordinates, not world) - * @param y {number} The Y coordinate to render on the stage to (given in screen coordinates, not world) - */ - public render(x?: number, y?: number): void; - public width : number; - public height : number; - } -} -/** -* Phaser - SpriteUtils -* -* A collection of methods useful for manipulating and checking Sprites. -*/ -module Phaser { - class SpriteUtils { - static _tempPoint: Point; - /** - * Check whether this object is visible in a specific camera rectangle. - * @param camera {Rectangle} The rectangle you want to check. - * @return {boolean} Return true if bounds of this sprite intersects the given rectangle, otherwise return false. - */ - static inCamera(camera: Camera, sprite: Sprite): bool; - static getAsPoints(sprite: Sprite): Point[]; - /** - * Checks to see if a point in 2D world space overlaps this GameObject. - * - * @param point {Point} The point in world space you want to check. - * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return Whether or not the point overlaps this object. - */ - static overlapsPoint(sprite: Sprite, point: Point, inScreenSpace?: bool, camera?: Camera): bool; - /** - * Check and see if this object is currently on screen. - * - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {boolean} Whether the object is on screen or not. - */ - static onScreen(sprite: Sprite, camera?: Camera): bool; - /** - * Call this to figure out the on-screen position of the object. - * - * @param point {Point} Takes a Point object and assigns the post-scrolled X and Y values of this object to it. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {Point} The Point you passed in, or a new Point if you didn't pass one, containing the screen X and Y position of this object. - */ - static getScreenXY(sprite: Sprite, point?: Point, camera?: Camera): Point; - /** - * Handy for reviving game objects. - * Resets their existence flags and position. - * - * @param x {number} The new X position of this object. - * @param y {number} The new Y position of this object. - */ - static reset(sprite: Sprite, x: number, y: number): void; - static setOriginToCenter(sprite: Sprite, fromFrameBounds?: bool, fromBody?: bool): void; - /** - * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere - * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) - * it can be stopped from leaving the world, or a section of it. - * - * @param x {number} x position of the bound - * @param y {number} y position of the bound - * @param width {number} width of its bound - * @param height {number} height of its bound - */ - static setBounds(x: number, y: number, width: number, height: number): void; - } -} -/** -* Phaser - Components - Texture -* -* The Texture being used to render the Sprite. Either Image based on a DynamicTexture. -*/ -module Phaser.Components { - class Texture { - /** - * Creates a new Sprite Texture component - * @param parent The Sprite using this Texture to render - * @param key An optional Game.Cache key to load an image from - */ - constructor(parent: Sprite, key?: string); - /** - * Reference to Phaser.Game - */ - public game: Game; - /** - * Reference to the parent Sprite - */ - private _sprite; - /** - * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. - */ - public imageTexture; - /** - * Reference to the DynamicTexture that is used as the texture for the Sprite. - * @type {DynamicTexture} - */ - public dynamicTexture: DynamicTexture; - /** - * The load status of the texture image. - * @type {boolean} - */ - public loaded: bool; - /** - * Opacity of the Sprite texture where 1 is opaque and 0 is fully transparent. - * @type {number} - */ - public alpha: number; - /** - * A reference to the Canvas this Sprite renders to. - * @type {HTMLCanvasElement} - */ - public canvas: HTMLCanvasElement; - /** - * A reference to the Canvas Context2D this Sprite renders to. - * @type {CanvasRenderingContext2D} - */ - public context: CanvasRenderingContext2D; - /** - * The Cache key used for the Image Texture. - */ - public cacheKey: string; - /** - * The Texture being used to render the Sprite. Either an Image Texture from the Cache or a DynamicTexture. - */ - public texture; - /** - * Controls if the Sprite is rendered rotated or not. - * If renderRotation is false then the object can still rotate but it will never be rendered rotated. - * @type {boolean} - */ - public renderRotation: bool; - /** - * Flip the graphic horizontally (defaults to false) - * @type {boolean} - */ - public flippedX: bool; - /** - * Flip the graphic vertically (defaults to false) - * @type {boolean} - */ - public flippedY: bool; - /** - * Is the texture a DynamicTexture? - * @type {boolean} - */ - public isDynamic: bool; - /** - * Updates the texture being used to render the Sprite. - * Called automatically by SpriteUtils.loadTexture and SpriteUtils.loadDynamicTexture. - */ - public setTo(image?, dynamic?: DynamicTexture): Sprite; - /** - * Sets a new graphic from the game cache to use as the texture for this Sprite. - * The graphic can be SpriteSheet or Texture Atlas. If you need to use a DynamicTexture see loadDynamicTexture. - * @param key {string} Key of the graphic you want to load for this sprite. - * @param clearAnimations {boolean} If this Sprite has a set of animation data already loaded you can choose to keep or clear it with this boolean - */ - public loadImage(key: string, clearAnimations?: bool, updateBody?: bool): void; - /** - * Load a DynamicTexture as its texture. - * @param texture {DynamicTexture} The texture object to be used by this sprite. - */ - public loadDynamicTexture(texture: DynamicTexture): void; - /** - * Getter only. The width of the texture. - * @type {number} - */ - public width : number; - /** - * Getter only. The height of the texture. - * @type {number} - */ - public height : number; - } -} -/** -* Phaser - Components - Input -* -* Input detection component -*/ -module Phaser.Components { - class Input { - /** - * Sprite Input component constructor - * @param parent The Sprite using this Input component - */ - constructor(parent: Sprite); - /** - * Reference to Phaser.Game - */ - public game: Game; - /** - * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. - */ - private _sprite; - private _pointerData; - /** - * If enabled the Input component will be updated by the parent Sprite - * @type {Boolean} - */ - public enabled: bool; - /** - * The PriorityID controls which Sprite receives an Input event first if they should overlap. - */ - public priorityID: number; - private _dragPoint; - private _draggedPointerID; - public dragOffset: Point; - public isDragged: bool; - public dragFromCenter: bool; - public dragPixelPerfect: bool; - public dragPixelPerfectAlpha: number; - public allowHorizontalDrag: bool; - public allowVerticalDrag: bool; - public snapOnDrag: bool; - public snapOnRelease: bool; - public snapOffset: Point; - public snapX: number; - public snapY: number; - /** - * Is this sprite allowed to be dragged by the mouse? true = yes, false = no - * @default false - */ - public draggable: bool; - /** - * A region of the game world within which the sprite is restricted during drag - * @default null - */ - public boundsRect: Rectangle; - /** - * An Sprite the bounds of which this sprite is restricted during drag - * @default null - */ - public boundsSprite: Sprite; - /** - * The Input component can monitor either the physics body of the Sprite or the frameBounds - * If checkBody is set to true it will monitor the bounds of the physics body. - * @type {Boolean} - */ - public checkBody: bool; - /** - * Turn the mouse pointer into a hand image by temporarily setting the CSS style of the Game canvas - * on Input over. Only works on desktop browsers or browsers with a visible input pointer. - * @type {Boolean} - */ - public useHandCursor: bool; - /** - * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. - * This value is only set when the pointer is over this Sprite. - * @type {number} - */ - public pointerX(pointer?: number): number; - /** - * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite - * This value is only set when the pointer is over this Sprite. - * @type {number} - */ - public pointerY(pointer?: number): number; - /** - * If the Pointer is touching the touchscreen, or the mouse button is held down, isDown is set to true - * @property isDown - * @type {Boolean} - **/ - public pointerDown(pointer?: number): bool; - /** - * If the Pointer is not touching the touchscreen, or the mouse button is up, isUp is set to true - * @property isUp - * @type {Boolean} - **/ - public pointerUp(pointer?: number): bool; - /** - * A timestamp representing when the Pointer first touched the touchscreen. - * @property timeDown - * @type {Number} - **/ - public pointerTimeDown(pointer?: number): bool; - /** - * A timestamp representing when the Pointer left the touchscreen. - * @property timeUp - * @type {Number} - **/ - public pointerTimeUp(pointer?: number): bool; - /** - * Is the Pointer over this Sprite - * @property isOver - * @type {Boolean} - **/ - public pointerOver(pointer?: number): bool; - /** - * Is the Pointer outside of this Sprite - * @property isOut - * @type {Boolean} - **/ - public pointerOut(pointer?: number): bool; - /** - * A timestamp representing when the Pointer first touched the touchscreen. - * @property timeDown - * @type {Number} - **/ - public pointerTimeOver(pointer?: number): bool; - /** - * A timestamp representing when the Pointer left the touchscreen. - * @property timeUp - * @type {Number} - **/ - public pointerTimeOut(pointer?: number): bool; - /** - * Is this sprite being dragged by the mouse or not? - * @default false - */ - public pointerDragged(pointer?: number): bool; - public start(priority?: number, checkBody?: bool, useHandCursor?: bool): Sprite; - public reset(): void; - public stop(): void; - public checkPointerOver(pointer: Pointer): bool; - /** - * Update - */ - public update(pointer: Pointer): bool; - public _pointerOverHandler(pointer: Pointer): void; - public _pointerOutHandler(pointer: Pointer): void; - public consumePointerEvent: bool; - public _touchedHandler(pointer: Pointer): bool; - public _releasedHandler(pointer: Pointer): void; - /** - * Updates the Pointer drag on this Sprite. - */ - private updateDrag(pointer); - /** - * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) - * @param delay The time below which the pointer is considered as just over. - * @returns {boolean} - */ - public justOver(pointer?: number, delay?: number): bool; - /** - * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) - * @param delay The time below which the pointer is considered as just out. - * @returns {boolean} - */ - public justOut(pointer?: number, delay?: number): bool; - /** - * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) - * @param delay The time below which the pointer is considered as just over. - * @returns {boolean} - */ - public justPressed(pointer?: number, delay?: number): bool; - /** - * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) - * @param delay The time below which the pointer is considered as just out. - * @returns {boolean} - */ - public justReleased(pointer?: number, delay?: number): bool; - /** - * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. - * @returns {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over. - */ - public overDuration(pointer?: number): number; - /** - * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. - * @returns {number} The number of milliseconds the pointer has been pressed down on the Sprite, or -1 if not over. - */ - public downDuration(pointer?: number): number; - /** - * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback - * - * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. - * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. - * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) - * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere - * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here - */ - public enableDrag(lockCenter?: bool, pixelPerfect?: bool, alphaThreshold?: number, boundsRect?: Rectangle, boundsSprite?: Sprite): void; - /** - * Stops this sprite from being able to be dragged. If it is currently the target of an active drag it will be stopped immediately. Also disables any set callbacks. - */ - public disableDrag(): void; - /** - * Called by Pointer when drag starts on this Sprite. Should not usually be called directly. - */ - public startDrag(pointer: Pointer): void; - /** - * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. - */ - public stopDrag(pointer: Pointer): void; - /** - * Restricts this sprite to drag movement only on the given axis. Note: If both are set to false the sprite will never move! - * - * @param allowHorizontal To enable the sprite to be dragged horizontally set to true, otherwise false - * @param allowVertical To enable the sprite to be dragged vertically set to true, otherwise false - */ - public setDragLock(allowHorizontal?: bool, allowVertical?: bool): void; - /** - * Make this Sprite snap to the given grid either during drag or when it's released. - * For example 16x16 as the snapX and snapY would make the sprite snap to every 16 pixels. - * - * @param snapX The width of the grid cell in pixels - * @param snapY The height of the grid cell in pixels - * @param onDrag If true the sprite will snap to the grid while being dragged - * @param onRelease If true the sprite will snap to the grid when released - */ - public enableSnap(snapX: number, snapY: number, onDrag?: bool, onRelease?: bool): void; - /** - * Stops the sprite from snapping to a grid during drag or release. - */ - public disableSnap(): void; - /** - * Bounds Rect check for the sprite drag - */ - private checkBoundsRect(); - /** - * Parent Sprite Bounds check for the sprite drag - */ - private checkBoundsSprite(); - /** - * Render debug infos. (including name, bounds info, position and some other properties) - * @param x {number} X position of the debug info to be rendered. - * @param y {number} Y position of the debug info to be rendered. - * @param [color] {number} color of the debug info to be rendered. (format is css color string) - */ - public renderDebugInfo(x: number, y: number, color?: string): void; - } -} -/** -* Phaser - Components - Events -* -* Signals that are dispatched by the Sprite and its various components -*/ -module Phaser.Components { - class Events { - /** - * The Events component is a collection of events fired by the parent Sprite and its other components. - * @param parent The Sprite using this Input component - */ - constructor(parent: Sprite); - /** - * Reference to Phaser.Game - */ - public game: Game; - /** - * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. - */ - private _sprite; - /** - * Dispatched by the Group this Sprite is added to. - */ - public onAddedToGroup: Signal; - /** - * Dispatched by the Group this Sprite is removed from. - */ - public onRemovedFromGroup: Signal; - /** - * Dispatched when this Sprite is killed. - */ - public onKilled: Signal; - /** - * Dispatched when this Sprite is revived. - */ - public onRevived: Signal; - /** - * Dispatched by the Input component when a pointer moves over an Input enabled sprite. - */ - public onInputOver: Signal; - /** - * Dispatched by the Input component when a pointer moves out of an Input enabled sprite. - */ - public onInputOut: Signal; - /** - * Dispatched by the Input component when a pointer is pressed down on an Input enabled sprite. - */ - public onInputDown: Signal; - /** - * Dispatched by the Input component when a pointer is released over an Input enabled sprite - */ - public onInputUp: Signal; - public onOutOfBounds: Signal; - } -} -/** -* Phaser - Vec2Utils -* -* A collection of methods useful for manipulating and performing operations on 2D vectors. -* -*/ -module Phaser { - class Vec2Utils { - /** - * Adds two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the sum of the two vectors. - */ - static add(a: Vec2, b: Vec2, out?: Vec2): Vec2; - /** - * Subtracts two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the difference of the two vectors. - */ - static subtract(a: Vec2, b: Vec2, out?: Vec2): Vec2; - /** - * Multiplies two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the sum of the two vectors multiplied. - */ - static multiply(a: Vec2, b: Vec2, out?: Vec2): Vec2; - /** - * Divides two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the sum of the two vectors divided. - */ - static divide(a: Vec2, b: Vec2, out?: Vec2): Vec2; - /** - * Scales a 2D vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {number} s Scaling value. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the scaled vector. - */ - static scale(a: Vec2, s: number, out?: Vec2): Vec2; - /** - * Rotate a 2D vector by 90 degrees. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the scaled vector. - */ - static perp(a: Vec2, out?: Vec2): Vec2; - /** - * Checks if two 2D vectors are equal. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Boolean} - */ - static equals(a: Vec2, b: Vec2): bool; - /** - * - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} epsilon - * @return {Boolean} - */ - static epsilonEquals(a: Vec2, b: Vec2, epsilon: number): bool; - /** - * Get the distance between two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - static distance(a: Vec2, b: Vec2): number; - /** - * Get the distance squared between two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - static distanceSq(a: Vec2, b: Vec2): number; - /** - * Project two 2D vectors onto another vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - static project(a: Vec2, b: Vec2, out?: Vec2): Vec2; - /** - * Project this vector onto a vector of unit length. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - static projectUnit(a: Vec2, b: Vec2, out?: Vec2): Vec2; - /** - * Right-hand normalize (make unit length) a 2D vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - static normalRightHand(a: Vec2, out?: Vec2): Vec2; - /** - * Normalize (make unit length) a 2D vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - static normalize(a: Vec2, out?: Vec2): Vec2; - /** - * The dot product of two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - static dot(a: Vec2, b: Vec2): number; - /** - * The cross product of two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - static cross(a: Vec2, b: Vec2): number; - /** - * The angle between two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - static angle(a: Vec2, b: Vec2): number; - /** - * The angle squared between two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - static angleSq(a: Vec2, b: Vec2): number; - /** - * Rotate a 2D vector around the origin to the given angle (theta). - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Number} theta The angle of rotation in radians. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - static rotate(a: Vec2, b: Vec2, theta: number, out?: Vec2): Vec2; - /** - * Clone a 2D vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is a copy of the source Vec2. - */ - static clone(a: Vec2, out?: Vec2): Vec2; - } -} -/** -* Phaser - Physics - Body -*/ -module Phaser.Physics { - class Body { - constructor(parent: Sprite, type: number); - public game: Game; - public parent: Sprite; - /** - * The type of Body (disabled, dynamic, static or kinematic) - * Disabled = skips all physics operations / tests (default) - * Dynamic = gives and receives impacts - * Static = gives but doesn't receive impacts, cannot be moved by physics - * Kinematic = gives impacts, but never receives, can be moved by physics - * @type {number} - */ - public type: number; - public gravity: Vec2; - public bounce: Vec2; - public velocity: Vec2; - public acceleration: Vec2; - public drag: Vec2; - public maxVelocity: Vec2; - public angularVelocity: number; - public angularAcceleration: number; - public angularDrag: number; - public maxAngular: number; - /** - * Angle of rotation of this body. - * @type {number} - */ - public angle: number; - /** - * Orientation of the object. - * @type {number} - */ - public facing: number; - public touching: number; - public allowCollisions: number; - public wasTouching: number; - public mass: number; - public position: Vec2; - public oldPosition: Vec2; - public offset: Vec2; - public bounds: Rectangle; - public preUpdate(): void; - public postUpdate(): void; - public hullWidth : number; - public hullHeight : number; - public hullX : number; - public hullY : number; - public deltaXAbs : number; - public deltaYAbs : number; - public deltaX : number; - public deltaY : number; - public render(context: CanvasRenderingContext2D): void; - /** - * Render debug infos. (including name, bounds info, position and some other properties) - * @param x {number} X position of the debug info to be rendered. - * @param y {number} Y position of the debug info to be rendered. - * @param [color] {number} color of the debug info to be rendered. (format is css color string) - */ - public renderDebugInfo(x: number, y: number, color?: string): void; - } -} -/** -* Phaser - Sprite -* -*/ -module Phaser { - class Sprite implements IGameObject { - /** - * Create a new Sprite. - * - * @param game {Phaser.Game} Current game instance. - * @param [x] {number} the initial x position of the sprite. - * @param [y] {number} the initial y position of the sprite. - * @param [key] {string} Key of the graphic you want to load for this sprite. - * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) - */ - constructor(game: Game, x?: number, y?: number, key?: string, bodyType?: number); - /** - * Reference to the main game object - */ - public game: Game; - /** - * The type of game object. - */ - public type: number; - /** - * The Group this Sprite belongs to. - */ - public group: Group; - /** - * Controls if both update and render are called by the core game loop. - */ - public exists: bool; - /** - * Controls if update() is automatically called by the core game loop. - */ - public active: bool; - /** - * Controls if this Sprite is rendered or skipped during the core game loop. - */ - public visible: bool; - /** - * - */ - public alive: bool; - /** - * Sprite physics body. - */ - public body: Physics.Body; - /** - * The texture used to render the Sprite. - */ - public texture: Components.Texture; - /** - * The Input component - */ - public input: Components.Input; - /** - * The Events component - */ - public events: Components.Events; - /** - * This manages animations of the sprite. You can modify animations though it. (see AnimationManager) - * @type AnimationManager - */ - public animations: Components.AnimationManager; - /** - * An Array of Cameras to which this GameObject won't render - * @type {Array} - */ - public cameraBlacklist: number[]; - /** - * 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. - */ - public frameBounds: Rectangle; - /** - * Scale of the Sprite. A scale of 1.0 is the original size. 0.5 half size. 2.0 double sized. - */ - 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; - /** - * The Sprite origin is the point around which scale and rotation takes place. - */ - public origin: Vec2; - /** - * A Point holding the x/y coordinate of this Sprite relative to the screen. It uses the default created world - * camera to calculate its values. If you have changed the default camera (i.e. resized it, deleted it) this value - * will be incorrect and should be ignored. - */ - public screen: Point; - /** - * x value of the object. - */ - public x: number; - /** - * y value of the object. - */ - public y: number; - /** - * z order value of the object. - */ - public z: number; - /** - * Render iteration - */ - public renderOrderID: number; - /** - * This value is added to the angle of the Sprite. - * For example if you had a sprite graphic drawn facing straight up then you could set - * angleOffset to 90 and it would correspond correctly with Phasers right-handed coordinate system. - * @type {number} - */ - public angleOffset: number; - /** - * The angle of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. - */ - /** - * Set the angle of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. - * The value is automatically wrapped to be between 0 and 360. - */ - public angle : 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; - public width : number; - public height : number; - /** - * Pre-update is called right before update() on each object in the game loop. - */ - public preUpdate(): void; - /** - * Override this function to update your class's position and appearance. - */ - public update(): void; - /** - * Automatically called after update() by the game loop. - */ - public postUpdate(): void; - /** - * Clean up memory. - */ - public destroy(): void; - /** - * Handy for "killing" game objects. - * Default behavior is to flag them as nonexistent AND dead. - * However, if you want the "corpse" to remain in the game, - * like to animate an effect or whatever, you should override this, - * setting only alive to false, and leaving exists true. - */ - public kill(removeFromGroup?: bool): void; - /** - * Handy for bringing game objects "back to life". Just sets alive and exists back to true. - * In practice, this is most often called by Object.reset(). - */ - public revive(): void; - } -} -/** * Phaser - CameraFX * * CameraFX controls all special effects applied to game Cameras. @@ -4305,17 +4355,19 @@ module Phaser { * @param height {number} The height of the camera display in pixels. */ constructor(game: Game, id: number, x: number, y: number, width: number, height: number); + private _target; /** * Local private reference to Game. */ - private _game; - private _clip; - private _stageX; - private _stageY; - private _rotation; - private _target; - public scaledX: number; - public scaledY: number; + public game: Game; + /** + * Optional texture used in the background of the Camera. + */ + public texture: Components.Texture; + /** + * The transform component. + */ + public transform: Components.Transform; /** * Camera "follow" style preset: camera has no deadzone, just tracks the focus object directly. * @type {number} @@ -4341,27 +4393,30 @@ module Phaser { */ public ID: number; /** - * Camera view rectangle in world coordinate. + * Controls if this camera is clipped or not when rendering. You shouldn't usually set this value directly. + */ + public clip: bool; + /** + * Camera view Rectangle in world coordinate. * @type {Rectangle} */ public worldView: Rectangle; /** - * Scale factor of the camera. - * @type {Vec2} - */ - public scale: Vec2; - /** - * Scrolling factor. - * @type {MicroPoint} - */ - public scroll: Vec2; - /** - * Camera bounds. + * Visible / renderable area (changes if the camera resizes/moves around the stage) * @type {Rectangle} */ - public bounds: Rectangle; + public screenView: Rectangle; /** - * Sprite moving inside this rectangle will not cause camera moving. + * Camera worldBounds. + * @type {Rectangle} + */ + public worldBounds: Rectangle; + /** + * A boolean representing if the Camera has been modified in any way via a scale, rotate, flip or skew. + */ + public modified: bool; + /** + * Sprite moving inside this Rectangle will not cause camera moving. * @type {Rectangle} */ public deadzone: Rectangle; @@ -4371,39 +4426,14 @@ module Phaser { */ public disableClipping: bool; /** - * Whether the camera background is opaque or not. If set to true the Camera is filled with - * the value of Camera.backgroundColor every frame. Normally you wouldn't enable this if the - * Camera is the full Stage size, as the Stage.backgroundColor has the same effect. But for - * multiple or mini cameras it can be very useful. - * @type {boolean} - */ - public opaque: bool; - /** - * The Background Color of the camera in css color string format, i.e. 'rgb(0,0,0)' or '#ff0000'. - * Not used if the Camera.opaque property is false. - * @type {string} - */ - public backgroundColor: string; - /** - * Whether this camera visible or not. (default is true) + * Whether this camera is visible or not. (default is true) * @type {boolean} */ public visible: bool; /** - * Alpha of the camera. (everything rendered to this camera will be affected) - * @type {number} + * The z value of this Camera. Cameras are rendered in z-index order by the Renderer. */ - public alpha: number; - /** - * The x position of the current input event in world coordinates. - * @type {number} - */ - public inputX: number; - /** - * The y position of the current input event in world coordinates. - * @type {number} - */ - public inputY: number; + public z: number; /** * Effects manager. * @type {CameraFX} @@ -4460,27 +4490,7 @@ module Phaser { */ public update(): void; /** - * Camera preRender - */ - public preRender(): void; - /** - * Camera postRender - */ - public postRender(): void; - /** - * Set position of this camera. - * @param x {number} X position. - * @param y {number} Y position. - */ - public setPosition(x: number, y: number): void; - /** - * Give this camera a new size. - * @param width {number} Width of new size. - * @param height {number} Height of new size. - */ - public setSize(width: number, height: number): void; - /** - * Render debug infos. (including id, position, rotation, scrolling factor, bounds and some other properties) + * Render debug infos. (including id, position, rotation, scrolling factor, worldBounds and some other properties) * @param x {number} X position of the debug info to be rendered. * @param y {number} Y position of the debug info to be rendered. * @param [color] {number} color of the debug info to be rendered. (format is css color string) @@ -4494,6 +4504,15 @@ module Phaser { public y : number; public width : number; public height : number; + public setPosition(x: number, y: number): void; + public setSize(width: number, height: number): void; + /** + * The angle of the Camera in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + */ + /** + * Set the angle of the Camera in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + * The value is automatically wrapped to be between 0 and 360. + */ public rotation : number; private checkClip(); } @@ -4528,6 +4547,14 @@ module Phaser { * Local helper stores index of next created camera. */ private _cameraInstance; + /** + * Helper for sort. + */ + private _sortIndex; + /** + * Helper for sort. + */ + private _sortOrder; static CAMERA_TYPE_ORTHOGRAPHIC: number; static CAMERA_TYPE_ISOMETRIC: number; /** @@ -4565,6 +4592,24 @@ module Phaser { * @returns {boolean} True if successfully removed the camera, otherwise return false. */ public removeCamera(id: number): bool; + public swap(camera1: Camera, camera2: Camera, sort?: bool): bool; + /** + * Call this function to sort the Cameras according to a particular value and order (default is their Z value). + * The order in which they are sorted determines the render order. If sorted on z then Cameras with a lower z-index value render first. + * + * @param {string} index The string name of the Camera variable you want to sort on. Default value is "z". + * @param {number} order A Group constant that defines the sort order. Possible values are Group.ASCENDING and Group.DESCENDING. Default value is Group.ASCENDING. + */ + public sort(index?: string, order?: number): void; + /** + * Helper function for the sort process. + * + * @param {Basic} Obj1 The first object being sorted. + * @param {Basic} Obj2 The second object being sorted. + * + * @return {number} An integer value: -1 (Obj1 before Obj2), 0 (same), or 1 (Obj1 after Obj2). + */ + public sortHandler(obj1, obj2): number; /** * Clean up memory. */ @@ -5347,10 +5392,10 @@ module Phaser { * Swap tiles with 2 kinds of indexes. * @param tileA {number} First tile index. * @param tileB {number} Second tile index. - * @param [x] {number} specify a rectangle of tiles to operate. The x position in tiles of rectangle's left-top corner. - * @param [y] {number} specify a rectangle of tiles to operate. The y position in tiles of rectangle's left-top corner. - * @param [width] {number} specify a rectangle of tiles to operate. The width in tiles. - * @param [height] {number} specify a rectangle of tiles to operate. The height in tiles. + * @param [x] {number} specify a Rectangle of tiles to operate. The x position in tiles of Rectangle's left-top corner. + * @param [y] {number} specify a Rectangle of tiles to operate. The y position in tiles of Rectangle's left-top corner. + * @param [width] {number} specify a Rectangle of tiles to operate. The width in tiles. + * @param [height] {number} specify a Rectangle of tiles to operate. The height in tiles. */ public swapTile(tileA: number, tileB: number, x?: number, y?: number, width?: number, height?: number): void; /** @@ -5800,10 +5845,11 @@ module Phaser { * @param x {number} X position of the new sprite. * @param y {number} Y position of the new sprite. * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this sprite + * @param [frame] {string|number} If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name. * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) * @returns {Sprite} The newly created sprite object. */ - public sprite(x: number, y: number, key?: string, bodyType?: number): Sprite; + public sprite(x: number, y: number, key?: string, frame?, bodyType?: number): Sprite; /** * Create a new DynamicTexture with specific size. * @@ -6056,7 +6102,7 @@ module Phaser { /** * StageScaleMode constructor */ - constructor(game: Game); + constructor(game: Game, width: number, height: number); /** * Local private reference to game. */ @@ -6099,6 +6145,20 @@ module Phaser { */ public incorrectOrientation: bool; /** + * If you wish to align your game in the middle of the page then you can set this value to true. + * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing. + * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin. + * @type {Boolean} + */ + public pageAlignHorizontally: bool; + /** + * If you wish to align your game in the middle of the page then you can set this value to true. + * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing. + * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin. + * @type {Boolean} + */ + public pageAlignVeritcally: bool; + /** * Minimum width the canvas should be scaled to (in pixels) * @type {number} */ @@ -6180,7 +6240,7 @@ module Phaser { /** * Set screen size automatically based on the scaleMode. */ - private setScreenSize(); + public setScreenSize(force?: bool): void; private setSize(); private setMaximum(); private setShowAll(); @@ -6458,6 +6518,7 @@ module Phaser { */ private visibilityChange(event); public enableOrientationCheck(forceLandscape: bool, forcePortrait: bool, imageKey?: string): void; + public setImageRenderingCrisp(): void; public pauseGame(): void; public resumeGame(): void; /** @@ -7629,7 +7690,7 @@ module Phaser { **/ public targetObject; /** - * Gets the X value of this Pointer in world coordinate space + * Gets the X value of this Pointer in world coordinate space (is it properly scaled?) * @param {Camera} [camera] */ public getWorldX(camera?: Camera): number; @@ -8489,6 +8550,10 @@ module Phaser { renderSprite(camera: Camera, sprite: Sprite): bool; renderScrollZone(camera: Camera, sprite: ScrollZone): bool; renderCircle(camera: Camera, circle: Circle, context, outline?: bool, fill?: bool, lineColor?: string, fillColor?: string, lineWidth?: number); + preRenderGroup(camera: Camera, group: Group); + postRenderGroup(camera: Camera, group: Group); + preRenderCamera(camera: Camera); + postRenderCamera(camera: Camera); } } module Phaser { @@ -8503,6 +8568,10 @@ module Phaser { public renderSprite(camera: Camera, sprite: Sprite): bool; public renderScrollZone(camera: Camera, scrollZone: ScrollZone): bool; public renderCircle(camera: Camera, circle: Circle, context, outline?: bool, fill?: bool, lineColor?: string, fillColor?: string, lineWidth?: number): bool; + public preRenderCamera(camera: Camera): void; + public postRenderCamera(camera: Camera): void; + public preRenderGroup(camera: Camera, group: Group): void; + public postRenderGroup(camera: Camera, group: Group): void; } } module Phaser { @@ -8532,12 +8601,22 @@ module Phaser { public renderTotal: number; public render(): void; public renderGameObject(object): void; + public preRenderGroup(camera: Camera, group: Group): bool; + public postRenderGroup(camera: Camera, group: Group): void; /** - * Check whether this object is visible in a specific camera rectangle. - * @param camera {Rectangle} The rectangle you want to check. - * @return {boolean} Return true if bounds of this sprite intersects the given rectangle, otherwise return false. + * Check whether this object is visible in a specific camera Rectangle. + * @param camera {Rectangle} The Rectangle you want to check. + * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. */ public inCamera(camera: Camera, sprite: Sprite): bool; + public inScreen(camera: Camera): bool; + /** + * Render this sprite to specific camera. Called by game loop after update(). + * @param camera {Camera} Camera this sprite will be rendered to. + * @return {boolean} Return false if not rendered, otherwise return true. + */ + public preRenderCamera(camera: Camera): bool; + public postRenderCamera(camera: Camera): void; public renderCircle(camera: Camera, circle: Circle, context, outline?: bool, fill?: bool, lineColor?: string, fillColor?: string, lineWidth?: number): bool; /** * Render this sprite to specific camera. Called by game loop after update(). diff --git a/build/phaser.js b/build/phaser.js index 92335948..4839d5cb 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -74,14 +74,14 @@ var Phaser; (function (Phaser) { var Rectangle = (function () { /** - * Creates a new Rectangle object with the top-left corner specified by the x and y parameters and with the specified width and height parameters. If you call this function without parameters, a rectangle with x, y, width, and height properties set to 0 is created. + * Creates a new Rectangle object with the top-left corner specified by the x and y parameters and with the specified width and height parameters. If you call this function without parameters, a Rectangle with x, y, width, and height properties set to 0 is created. * @class Rectangle * @constructor - * @param {Number} x The x coordinate of the top-left corner of the rectangle. - * @param {Number} y The y coordinate of the top-left corner of the rectangle. - * @param {Number} width The width of the rectangle in pixels. - * @param {Number} height The height of the rectangle in pixels. - * @return {Rectangle} This rectangle object + * @param {Number} x The x coordinate of the top-left corner of the Rectangle. + * @param {Number} y The y coordinate of the top-left corner of the Rectangle. + * @param {Number} width The width of the Rectangle in pixels. + * @param {Number} height The height of the Rectangle in pixels. + * @return {Rectangle} This Rectangle object **/ function Rectangle(x, y, width, height) { if (typeof x === "undefined") { x = 0; } @@ -95,7 +95,7 @@ var Phaser; } Object.defineProperty(Rectangle.prototype, "halfWidth", { get: /** - * Half of the width of the rectangle + * Half of the width of the Rectangle * @property halfWidth * @type Number **/ @@ -107,7 +107,7 @@ var Phaser; }); Object.defineProperty(Rectangle.prototype, "halfHeight", { get: /** - * Half of the height of the rectangle + * Half of the height of the Rectangle * @property halfHeight * @type Number **/ @@ -282,7 +282,7 @@ var Phaser; set: /** * Sets all of the Rectangle object's properties to 0. A Rectangle object is empty if its width or height is less than or equal to 0. * @method setEmpty - * @return {Rectangle} This rectangle object + * @return {Rectangle} This Rectangle object **/ function (value) { return this.setTo(0, 0, 0, 0); @@ -314,11 +314,11 @@ var Phaser; Rectangle.prototype.setTo = /** * Sets the members of Rectangle to the specified values. * @method setTo - * @param {Number} x The x coordinate of the top-left corner of the rectangle. - * @param {Number} y The y coordinate of the top-left corner of the rectangle. - * @param {Number} width The width of the rectangle in pixels. - * @param {Number} height The height of the rectangle in pixels. - * @return {Rectangle} This rectangle object + * @param {Number} x The x coordinate of the top-left corner of the Rectangle. + * @param {Number} y The y coordinate of the top-left corner of the Rectangle. + * @param {Number} width The width of the Rectangle in pixels. + * @param {Number} height The height of the Rectangle in pixels. + * @return {Rectangle} This Rectangle object **/ function (x, y, width, height) { this.x = x; @@ -1243,7 +1243,7 @@ var Phaser; Types.SCROLLZONE = 6; Types.GEOM_POINT = 0; Types.GEOM_CIRCLE = 1; - Types.GEOM_RECTANGLE = 2; + Types.GEOM_Rectangle = 2; Types.GEOM_LINE = 3; Types.GEOM_POLYGON = 4; Types.BODY_DISABLED = 0; @@ -1264,7 +1264,3364 @@ var Phaser; Phaser.Types = Types; })(Phaser || (Phaser = {})); /// +/// +/// +/** +* Phaser - RectangleUtils +* +* A collection of methods useful for manipulating and comparing Rectangle objects. +* +* TODO: Check docs + overlap + intersect + toPolygon? +*/ +var Phaser; +(function (Phaser) { + var RectangleUtils = (function () { + function RectangleUtils() { } + RectangleUtils.getTopLeftAsPoint = /** + * Get the location of the Rectangles top-left corner as a Point object. + * @method getTopLeftAsPoint + * @param {Rectangle} a - The Rectangle object. + * @param {Point} out - Optional Point to store the value in, if not supplied a new Point object will be created. + * @return {Point} The new Point object. + **/ + function getTopLeftAsPoint(a, out) { + if (typeof out === "undefined") { out = new Phaser.Point(); } + return out.setTo(a.x, a.y); + }; + RectangleUtils.getBottomRightAsPoint = /** + * Get the location of the Rectangles bottom-right corner as a Point object. + * @method getTopLeftAsPoint + * @param {Rectangle} a - The Rectangle object. + * @param {Point} out - Optional Point to store the value in, if not supplied a new Point object will be created. + * @return {Point} The new Point object. + **/ + function getBottomRightAsPoint(a, out) { + if (typeof out === "undefined") { out = new Phaser.Point(); } + return out.setTo(a.right, a.bottom); + }; + RectangleUtils.inflate = /** + * Increases the size of the Rectangle object by the specified amounts. The center point of the Rectangle object stays the same, and its size increases to the left and right by the dx value, and to the top and the bottom by the dy value. + * @method inflate + * @param {Rectangle} a - The Rectangle object. + * @param {Number} dx The amount to be added to the left side of the Rectangle. + * @param {Number} dy The amount to be added to the bottom side of the Rectangle. + * @return {Rectangle} This Rectangle object. + **/ + function inflate(a, dx, dy) { + a.x -= dx; + a.width += 2 * dx; + a.y -= dy; + a.height += 2 * dy; + return a; + }; + RectangleUtils.inflatePoint = /** + * Increases the size of the Rectangle object. This method is similar to the Rectangle.inflate() method except it takes a Point object as a parameter. + * @method inflatePoint + * @param {Rectangle} a - The Rectangle object. + * @param {Point} point The x property of this Point object is used to increase the horizontal dimension of the Rectangle object. The y property is used to increase the vertical dimension of the Rectangle object. + * @return {Rectangle} The Rectangle object. + **/ + function inflatePoint(a, point) { + return RectangleUtils.inflate(a, point.x, point.y); + }; + RectangleUtils.size = /** + * The size of the Rectangle object, expressed as a Point object with the values of the width and height properties. + * @method size + * @param {Rectangle} a - The Rectangle object. + * @param {Point} output Optional Point object. If given the values will be set into the object, otherwise a brand new Point object will be created and returned. + * @return {Point} The size of the Rectangle object + **/ + function size(a, output) { + if (typeof output === "undefined") { output = new Phaser.Point(); } + return output.setTo(a.width, a.height); + }; + RectangleUtils.clone = /** + * Returns a new Rectangle object with the same values for the x, y, width, and height properties as the original Rectangle object. + * @method clone + * @param {Rectangle} a - The Rectangle object. + * @param {Rectangle} output Optional Rectangle object. If given the values will be set into the object, otherwise a brand new Rectangle object will be created and returned. + * @return {Rectangle} + **/ + function clone(a, output) { + if (typeof output === "undefined") { output = new Phaser.Rectangle(); } + return output.setTo(a.x, a.y, a.width, a.height); + }; + RectangleUtils.contains = /** + * Determines whether the specified coordinates are contained within the region defined by this Rectangle object. + * @method contains + * @param {Rectangle} a - The Rectangle object. + * @param {Number} x The x coordinate of the point to test. + * @param {Number} y The y coordinate of the point to test. + * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. + **/ + function contains(a, x, y) { + return (x >= a.x && x <= a.right && y >= a.y && y <= a.bottom); + }; + RectangleUtils.containsPoint = /** + * Determines whether the specified point is contained within the rectangular region defined by this Rectangle object. This method is similar to the Rectangle.contains() method, except that it takes a Point object as a parameter. + * @method containsPoint + * @param {Rectangle} a - The Rectangle object. + * @param {Point} point The point object being checked. Can be Point or any object with .x and .y values. + * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. + **/ + function containsPoint(a, point) { + return RectangleUtils.contains(a, point.x, point.y); + }; + RectangleUtils.containsRect = /** + * Determines whether the first Rectangle object is fully contained within the second Rectangle object. + * A Rectangle object is said to contain another if the second Rectangle object falls entirely within the boundaries of the first. + * @method containsRect + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. + **/ + function containsRect(a, b) { + // If the given rect has a larger volume than this one then it can never contain it + if(a.volume > b.volume) { + return false; + } + return (a.x >= b.x && a.y >= b.y && a.right <= b.right && a.bottom <= b.bottom); + }; + RectangleUtils.equals = /** + * Determines whether the two Rectangles are equal. + * This method compares the x, y, width and height properties of each Rectangle. + * @method equals + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @return {Boolean} A value of true if the two Rectangles have exactly the same values for the x, y, width and height properties; otherwise false. + **/ + function equals(a, b) { + return (a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height); + }; + RectangleUtils.intersection = /** + * If the Rectangle object specified in the toIntersect parameter intersects with this Rectangle object, returns the area of intersection as a Rectangle object. If the Rectangles do not intersect, this method returns an empty Rectangle object with its properties set to 0. + * @method intersection + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @param {Rectangle} output Optional Rectangle object. If given the intersection values will be set into this object, otherwise a brand new Rectangle object will be created and returned. + * @return {Rectangle} A Rectangle object that equals the area of intersection. If the Rectangles do not intersect, this method returns an empty Rectangle object; that is, a Rectangle with its x, y, width, and height properties set to 0. + **/ + function intersection(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Rectangle(); } + if(RectangleUtils.intersects(a, b)) { + out.x = Math.max(a.x, b.x); + out.y = Math.max(a.y, b.y); + out.width = Math.min(a.right, b.right) - out.x; + out.height = Math.min(a.bottom, b.bottom) - out.y; + } + return out; + }; + RectangleUtils.intersects = /** + * Determines whether the two Rectangles intersect with each other. + * This method checks the x, y, width, and height properties of the Rectangles. + * @method intersects + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @param {Number} tolerance A tolerance value to allow for an intersection test with padding, default to 0 + * @return {Boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false. + **/ + function intersects(a, b, tolerance) { + if (typeof tolerance === "undefined") { tolerance = 0; } + return !(a.left > b.right + tolerance || a.right < b.left - tolerance || a.top > b.bottom + tolerance || a.bottom < b.top - tolerance); + }; + RectangleUtils.intersectsRaw = /** + * Determines whether the object specified intersects (overlaps) with the given values. + * @method intersectsRaw + * @param {Number} left + * @param {Number} right + * @param {Number} top + * @param {Number} bottomt + * @param {Number} tolerance A tolerance value to allow for an intersection test with padding, default to 0 + * @return {Boolean} A value of true if the specified object intersects with the Rectangle; otherwise false. + **/ + function intersectsRaw(a, left, right, top, bottom, tolerance) { + if (typeof tolerance === "undefined") { tolerance = 0; } + return !(left > a.right + tolerance || right < a.left - tolerance || top > a.bottom + tolerance || bottom < a.top - tolerance); + }; + RectangleUtils.union = /** + * Adds two Rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two Rectangles. + * @method union + * @param {Rectangle} a - The first Rectangle object. + * @param {Rectangle} b - The second Rectangle object. + * @param {Rectangle} output Optional Rectangle object. If given the new values will be set into this object, otherwise a brand new Rectangle object will be created and returned. + * @return {Rectangle} A Rectangle object that is the union of the two Rectangles. + **/ + function union(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Rectangle(); } + return out.setTo(Math.min(a.x, b.x), Math.min(a.y, b.y), Math.max(a.right, b.right), Math.max(a.bottom, b.bottom)); + }; + return RectangleUtils; + })(); + Phaser.RectangleUtils = RectangleUtils; +})(Phaser || (Phaser = {})); +/// +/// +/// +/// +/** +* Phaser - ColorUtils +* +* A collection of methods useful for manipulating color values. +*/ +var Phaser; +(function (Phaser) { + var ColorUtils = (function () { + function ColorUtils() { } + ColorUtils.getColor32 = /** + * Given an alpha and 3 color values this will return an integer representation of it + * + * @param alpha {number} The Alpha value (between 0 and 255) + * @param red {number} The Red channel value (between 0 and 255) + * @param green {number} The Green channel value (between 0 and 255) + * @param blue {number} The Blue channel value (between 0 and 255) + * + * @return A native color value integer (format: 0xAARRGGBB) + */ + function getColor32(alpha, red, green, blue) { + return alpha << 24 | red << 16 | green << 8 | blue; + }; + ColorUtils.getColor = /** + * Given 3 color values this will return an integer representation of it + * + * @param red {number} The Red channel value (between 0 and 255) + * @param green {number} The Green channel value (between 0 and 255) + * @param blue {number} The Blue channel value (between 0 and 255) + * + * @return A native color value integer (format: 0xRRGGBB) + */ + function getColor(red, green, blue) { + return red << 16 | green << 8 | blue; + }; + ColorUtils.getHSVColorWheel = /** + * Get HSV color wheel values in an array which will be 360 elements in size + * + * @param alpha Alpha value for each color of the color wheel, between 0 (transparent) and 255 (opaque) + * + * @return Array + */ + function getHSVColorWheel(alpha) { + if (typeof alpha === "undefined") { alpha = 255; } + var colors = []; + for(var c = 0; c <= 359; c++) { + //colors[c] = HSVtoRGB(c, 1.0, 1.0, alpha); + colors[c] = ColorUtils.getWebRGB(ColorUtils.HSVtoRGB(c, 1.0, 1.0, alpha)); + } + return colors; + }; + ColorUtils.getComplementHarmony = /** + * Returns a Complementary Color Harmony for the given color. + *

A complementary hue is one directly opposite the color given on the color wheel

+ *

Value returned in 0xAARRGGBB format with Alpha set to 255.

+ * + * @param color The color to base the harmony on + * + * @return 0xAARRGGBB format color value + */ + function getComplementHarmony(color) { + var hsv = ColorUtils.RGBtoHSV(color); + var opposite = ColorUtils.game.math.wrapValue(hsv.hue, 180, 359); + return ColorUtils.HSVtoRGB(opposite, 1.0, 1.0); + }; + ColorUtils.getAnalogousHarmony = /** + * Returns an Analogous Color Harmony for the given color. + *

An Analogous harmony are hues adjacent to each other on the color wheel

+ *

Values returned in 0xAARRGGBB format with Alpha set to 255.

+ * + * @param color The color to base the harmony on + * @param threshold Control how adjacent the colors will be (default +- 30 degrees) + * + * @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color) + */ + function getAnalogousHarmony(color, threshold) { + if (typeof threshold === "undefined") { threshold = 30; } + var hsv = ColorUtils.RGBtoHSV(color); + if(threshold > 359 || threshold < 0) { + throw Error("Color Warning: Invalid threshold given to getAnalogousHarmony()"); + } + var warmer = ColorUtils.game.math.wrapValue(hsv.hue, 359 - threshold, 359); + var colder = ColorUtils.game.math.wrapValue(hsv.hue, threshold, 359); + return { + color1: color, + color2: ColorUtils.HSVtoRGB(warmer, 1.0, 1.0), + color3: ColorUtils.HSVtoRGB(colder, 1.0, 1.0), + hue1: hsv.hue, + hue2: warmer, + hue3: colder + }; + }; + ColorUtils.getSplitComplementHarmony = /** + * Returns an Split Complement Color Harmony for the given color. + *

A Split Complement harmony are the two hues on either side of the color's Complement

+ *

Values returned in 0xAARRGGBB format with Alpha set to 255.

+ * + * @param color The color to base the harmony on + * @param threshold Control how adjacent the colors will be to the Complement (default +- 30 degrees) + * + * @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color) + */ + function getSplitComplementHarmony(color, threshold) { + if (typeof threshold === "undefined") { threshold = 30; } + var hsv = ColorUtils.RGBtoHSV(color); + if(threshold >= 359 || threshold <= 0) { + throw Error("FlxColor Warning: Invalid threshold given to getSplitComplementHarmony()"); + } + var opposite = ColorUtils.game.math.wrapValue(hsv.hue, 180, 359); + var warmer = ColorUtils.game.math.wrapValue(hsv.hue, opposite - threshold, 359); + var colder = ColorUtils.game.math.wrapValue(hsv.hue, opposite + threshold, 359); + return { + color1: color, + color2: ColorUtils.HSVtoRGB(warmer, hsv.saturation, hsv.value), + color3: ColorUtils.HSVtoRGB(colder, hsv.saturation, hsv.value), + hue1: hsv.hue, + hue2: warmer, + hue3: colder + }; + }; + ColorUtils.getTriadicHarmony = /** + * Returns a Triadic Color Harmony for the given color. + *

A Triadic harmony are 3 hues equidistant from each other on the color wheel

+ *

Values returned in 0xAARRGGBB format with Alpha set to 255.

+ * + * @param color The color to base the harmony on + * + * @return Object containing 3 properties: color1 (the original color), color2 and color3 (the equidistant colors) + */ + function getTriadicHarmony(color) { + var hsv = ColorUtils.RGBtoHSV(color); + var triadic1 = ColorUtils.game.math.wrapValue(hsv.hue, 120, 359); + var triadic2 = ColorUtils.game.math.wrapValue(triadic1, 120, 359); + return { + color1: color, + color2: ColorUtils.HSVtoRGB(triadic1, 1.0, 1.0), + color3: ColorUtils.HSVtoRGB(triadic2, 1.0, 1.0) + }; + }; + ColorUtils.getColorInfo = /** + * Returns a string containing handy information about the given color including string hex value, + * RGB format information and HSL information. Each section starts on a newline, 3 lines in total. + * + * @param color A color value in the format 0xAARRGGBB + * + * @return string containing the 3 lines of information + */ + function getColorInfo(color) { + var argb = ColorUtils.getRGB(color); + var hsl = ColorUtils.RGBtoHSV(color); + // Hex format + var result = ColorUtils.RGBtoHexstring(color) + "\n"; + // RGB format + result = result.concat("Alpha: " + argb.alpha + " Red: " + argb.red + " Green: " + argb.green + " Blue: " + argb.blue) + "\n"; + // HSL info + result = result.concat("Hue: " + hsl.hue + " Saturation: " + hsl.saturation + " Lightnes: " + hsl.lightness); + return result; + }; + ColorUtils.RGBtoHexstring = /** + * Return a string representation of the color in the format 0xAARRGGBB + * + * @param color The color to get the string representation for + * + * @return A string of length 10 characters in the format 0xAARRGGBB + */ + function RGBtoHexstring(color) { + var argb = ColorUtils.getRGB(color); + return "0x" + ColorUtils.colorToHexstring(argb.alpha) + ColorUtils.colorToHexstring(argb.red) + ColorUtils.colorToHexstring(argb.green) + ColorUtils.colorToHexstring(argb.blue); + }; + ColorUtils.RGBtoWebstring = /** + * Return a string representation of the color in the format #RRGGBB + * + * @param color The color to get the string representation for + * + * @return A string of length 10 characters in the format 0xAARRGGBB + */ + function RGBtoWebstring(color) { + var argb = ColorUtils.getRGB(color); + return "#" + ColorUtils.colorToHexstring(argb.red) + ColorUtils.colorToHexstring(argb.green) + ColorUtils.colorToHexstring(argb.blue); + }; + ColorUtils.colorToHexstring = /** + * Return a string containing a hex representation of the given color + * + * @param color The color channel to get the hex value for, must be a value between 0 and 255) + * + * @return A string of length 2 characters, i.e. 255 = FF, 0 = 00 + */ + function colorToHexstring(color) { + var digits = "0123456789ABCDEF"; + var lsd = color % 16; + var msd = (color - lsd) / 16; + var hexified = digits.charAt(msd) + digits.charAt(lsd); + return hexified; + }; + ColorUtils.HSVtoRGB = /** + * Convert a HSV (hue, saturation, lightness) color space value to an RGB color + * + * @param h Hue degree, between 0 and 359 + * @param s Saturation, between 0.0 (grey) and 1.0 + * @param v Value, between 0.0 (black) and 1.0 + * @param alpha Alpha value to set per color (between 0 and 255) + * + * @return 32-bit ARGB color value (0xAARRGGBB) + */ + function HSVtoRGB(h, s, v, alpha) { + if (typeof alpha === "undefined") { alpha = 255; } + var result; + if(s == 0.0) { + result = ColorUtils.getColor32(alpha, v * 255, v * 255, v * 255); + } else { + h = h / 60.0; + var f = h - Math.floor(h); + var p = v * (1.0 - s); + var q = v * (1.0 - s * f); + var t = v * (1.0 - s * (1.0 - f)); + switch(Math.floor(h)) { + case 0: + result = ColorUtils.getColor32(alpha, v * 255, t * 255, p * 255); + break; + case 1: + result = ColorUtils.getColor32(alpha, q * 255, v * 255, p * 255); + break; + case 2: + result = ColorUtils.getColor32(alpha, p * 255, v * 255, t * 255); + break; + case 3: + result = ColorUtils.getColor32(alpha, p * 255, q * 255, v * 255); + break; + case 4: + result = ColorUtils.getColor32(alpha, t * 255, p * 255, v * 255); + break; + case 5: + result = ColorUtils.getColor32(alpha, v * 255, p * 255, q * 255); + break; + default: + throw new Error("ColorUtils.HSVtoRGB : Unknown color"); + } + } + return result; + }; + ColorUtils.RGBtoHSV = /** + * Convert an RGB color value to an object containing the HSV color space values: Hue, Saturation and Lightness + * + * @param color In format 0xRRGGBB + * + * @return Object with the properties hue (from 0 to 360), saturation (from 0 to 1.0) and lightness (from 0 to 1.0, also available under .value) + */ + function RGBtoHSV(color) { + var rgb = ColorUtils.getRGB(color); + var red = rgb.red / 255; + var green = rgb.green / 255; + var blue = rgb.blue / 255; + var min = Math.min(red, green, blue); + var max = Math.max(red, green, blue); + var delta = max - min; + var lightness = (max + min) / 2; + var hue; + var saturation; + // Grey color, no chroma + if(delta == 0) { + hue = 0; + saturation = 0; + } else { + if(lightness < 0.5) { + saturation = delta / (max + min); + } else { + saturation = delta / (2 - max - min); + } + var delta_r = (((max - red) / 6) + (delta / 2)) / delta; + var delta_g = (((max - green) / 6) + (delta / 2)) / delta; + var delta_b = (((max - blue) / 6) + (delta / 2)) / delta; + if(red == max) { + hue = delta_b - delta_g; + } else if(green == max) { + hue = (1 / 3) + delta_r - delta_b; + } else if(blue == max) { + hue = (2 / 3) + delta_g - delta_r; + } + if(hue < 0) { + hue += 1; + } + if(hue > 1) { + hue -= 1; + } + } + // Keep the value with 0 to 359 + hue *= 360; + hue = Math.round(hue); + return { + hue: hue, + saturation: saturation, + lightness: lightness, + value: lightness + }; + }; + ColorUtils.interpolateColor = /** + * + * @method interpolateColor + * @param {Number} color1 + * @param {Number} color2 + * @param {Number} steps + * @param {Number} currentStep + * @param {Number} alpha + * @return {Number} + * @static + */ + function interpolateColor(color1, color2, steps, currentStep, alpha) { + if (typeof alpha === "undefined") { alpha = 255; } + var src1 = ColorUtils.getRGB(color1); + var src2 = ColorUtils.getRGB(color2); + var r = (((src2.red - src1.red) * currentStep) / steps) + src1.red; + var g = (((src2.green - src1.green) * currentStep) / steps) + src1.green; + var b = (((src2.blue - src1.blue) * currentStep) / steps) + src1.blue; + return ColorUtils.getColor32(alpha, r, g, b); + }; + ColorUtils.interpolateColorWithRGB = /** + * + * @method interpolateColorWithRGB + * @param {Number} color + * @param {Number} r2 + * @param {Number} g2 + * @param {Number} b2 + * @param {Number} steps + * @param {Number} currentStep + * @return {Number} + * @static + */ + function interpolateColorWithRGB(color, r2, g2, b2, steps, currentStep) { + var src = ColorUtils.getRGB(color); + var r = (((r2 - src.red) * currentStep) / steps) + src.red; + var g = (((g2 - src.green) * currentStep) / steps) + src.green; + var b = (((b2 - src.blue) * currentStep) / steps) + src.blue; + return ColorUtils.getColor(r, g, b); + }; + ColorUtils.interpolateRGB = /** + * + * @method interpolateRGB + * @param {Number} r1 + * @param {Number} g1 + * @param {Number} b1 + * @param {Number} r2 + * @param {Number} g2 + * @param {Number} b2 + * @param {Number} steps + * @param {Number} currentStep + * @return {Number} + * @static + */ + function interpolateRGB(r1, g1, b1, r2, g2, b2, steps, currentStep) { + var r = (((r2 - r1) * currentStep) / steps) + r1; + var g = (((g2 - g1) * currentStep) / steps) + g1; + var b = (((b2 - b1) * currentStep) / steps) + b1; + return ColorUtils.getColor(r, g, b); + }; + ColorUtils.getRandomColor = /** + * Returns a random color value between black and white + *

Set the min value to start each channel from the given offset.

+ *

Set the max value to restrict the maximum color used per channel

+ * + * @param min The lowest value to use for the color + * @param max The highest value to use for the color + * @param alpha The alpha value of the returning color (default 255 = fully opaque) + * + * @return 32-bit color value with alpha + */ + function getRandomColor(min, max, alpha) { + if (typeof min === "undefined") { min = 0; } + if (typeof max === "undefined") { max = 255; } + if (typeof alpha === "undefined") { alpha = 255; } + // Sanity checks + if(max > 255) { + return ColorUtils.getColor(255, 255, 255); + } + if(min > max) { + return ColorUtils.getColor(255, 255, 255); + } + var red = min + Math.round(Math.random() * (max - min)); + var green = min + Math.round(Math.random() * (max - min)); + var blue = min + Math.round(Math.random() * (max - min)); + return ColorUtils.getColor32(alpha, red, green, blue); + }; + ColorUtils.getRGB = /** + * Return the component parts of a color as an Object with the properties alpha, red, green, blue + * + *

Alpha will only be set if it exist in the given color (0xAARRGGBB)

+ * + * @param color in RGB (0xRRGGBB) or ARGB format (0xAARRGGBB) + * + * @return Object with properties: alpha, red, green, blue + */ + function getRGB(color) { + return { + alpha: color >>> 24, + red: color >> 16 & 0xFF, + green: color >> 8 & 0xFF, + blue: color & 0xFF + }; + }; + ColorUtils.getWebRGB = /** + * + * @method getWebRGB + * @param {Number} color + * @return {Any} + */ + function getWebRGB(color) { + var alpha = (color >>> 24) / 255; + var red = color >> 16 & 0xFF; + var green = color >> 8 & 0xFF; + var blue = color & 0xFF; + return 'rgba(' + red.toString() + ',' + green.toString() + ',' + blue.toString() + ',' + alpha.toString() + ')'; + }; + ColorUtils.getAlpha = /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component, as a value between 0 and 255 + * + * @param color In the format 0xAARRGGBB + * + * @return The Alpha component of the color, will be between 0 and 255 (0 being no Alpha, 255 full Alpha) + */ + function getAlpha(color) { + return color >>> 24; + }; + ColorUtils.getAlphaFloat = /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component as a value between 0 and 1 + * + * @param color In the format 0xAARRGGBB + * + * @return The Alpha component of the color, will be between 0 and 1 (0 being no Alpha (opaque), 1 full Alpha (transparent)) + */ + function getAlphaFloat(color) { + return (color >>> 24) / 255; + }; + ColorUtils.getRed = /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Red component, as a value between 0 and 255 + * + * @param color In the format 0xAARRGGBB + * + * @return The Red component of the color, will be between 0 and 255 (0 being no color, 255 full Red) + */ + function getRed(color) { + return color >> 16 & 0xFF; + }; + ColorUtils.getGreen = /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Green component, as a value between 0 and 255 + * + * @param color In the format 0xAARRGGBB + * + * @return The Green component of the color, will be between 0 and 255 (0 being no color, 255 full Green) + */ + function getGreen(color) { + return color >> 8 & 0xFF; + }; + ColorUtils.getBlue = /** + * Given a native color value (in the format 0xAARRGGBB) this will return the Blue component, as a value between 0 and 255 + * + * @param color In the format 0xAARRGGBB + * + * @return The Blue component of the color, will be between 0 and 255 (0 being no color, 255 full Blue) + */ + function getBlue(color) { + return color & 0xFF; + }; + return ColorUtils; + })(); + Phaser.ColorUtils = ColorUtils; +})(Phaser || (Phaser = {})); +/// +/// +/// +/// +/** +* Phaser - DynamicTexture +* +* A DynamicTexture can be thought of as a mini canvas into which you can draw anything. +* Game Objects can be assigned a DynamicTexture, so when they render in the world they do so +* based on the contents of the texture at the time. This allows you to create powerful effects +* once and have them replicated across as many game objects as you like. +*/ +var Phaser; +(function (Phaser) { + var DynamicTexture = (function () { + /** + * DynamicTexture constructor + * Create a new DynamicTexture. + * + * @param game {Phaser.Game} Current game instance. + * @param width {number} Init width of this texture. + * @param height {number} Init height of this texture. + */ + function DynamicTexture(game, width, height) { + this._sx = 0; + this._sy = 0; + this._sw = 0; + this._sh = 0; + this._dx = 0; + this._dy = 0; + this._dw = 0; + this._dh = 0; + this.game = game; + this.type = Phaser.Types.GEOMSPRITE; + this.canvas = document.createElement('canvas'); + this.canvas.width = width; + this.canvas.height = height; + this.context = this.canvas.getContext('2d'); + this.bounds = new Phaser.Rectangle(0, 0, width, height); + } + DynamicTexture.prototype.getPixel = /** + * Get a color of a specific pixel. + * @param x {number} X position of the pixel in this texture. + * @param y {number} Y position of the pixel in this texture. + * @return {number} A native color value integer (format: 0xRRGGBB) + */ + function (x, y) { + //r = imageData.data[0]; + //g = imageData.data[1]; + //b = imageData.data[2]; + //a = imageData.data[3]; + var imageData = this.context.getImageData(x, y, 1, 1); + return Phaser.ColorUtils.getColor(imageData.data[0], imageData.data[1], imageData.data[2]); + }; + DynamicTexture.prototype.getPixel32 = /** + * Get a color of a specific pixel (including alpha value). + * @param x {number} X position of the pixel in this texture. + * @param y {number} Y position of the pixel in this texture. + * @return A native color value integer (format: 0xAARRGGBB) + */ + function (x, y) { + var imageData = this.context.getImageData(x, y, 1, 1); + return Phaser.ColorUtils.getColor32(imageData.data[3], imageData.data[0], imageData.data[1], imageData.data[2]); + }; + DynamicTexture.prototype.getPixels = /** + * Get pixels in array in a specific Rectangle. + * @param rect {Rectangle} The specific Rectangle. + * @returns {array} CanvasPixelArray. + */ + function (rect) { + return this.context.getImageData(rect.x, rect.y, rect.width, rect.height); + }; + DynamicTexture.prototype.setPixel = /** + * Set color of a specific pixel. + * @param x {number} X position of the target pixel. + * @param y {number} Y position of the target pixel. + * @param color {number} Native integer with color value. (format: 0xRRGGBB) + */ + function (x, y, color) { + this.context.fillStyle = color; + this.context.fillRect(x, y, 1, 1); + }; + DynamicTexture.prototype.setPixel32 = /** + * Set color (with alpha) of a specific pixel. + * @param x {number} X position of the target pixel. + * @param y {number} Y position of the target pixel. + * @param color {number} Native integer with color value. (format: 0xAARRGGBB) + */ + function (x, y, color) { + this.context.fillStyle = color; + this.context.fillRect(x, y, 1, 1); + }; + DynamicTexture.prototype.setPixels = /** + * Set image data to a specific Rectangle. + * @param rect {Rectangle} Target Rectangle. + * @param input {object} Source image data. + */ + function (rect, input) { + this.context.putImageData(input, rect.x, rect.y); + }; + DynamicTexture.prototype.fillRect = /** + * Fill a given Rectangle with specific color. + * @param rect {Rectangle} Target Rectangle you want to fill. + * @param color {number} A native number with color value. (format: 0xRRGGBB) + */ + function (rect, color) { + this.context.fillStyle = color; + this.context.fillRect(rect.x, rect.y, rect.width, rect.height); + }; + DynamicTexture.prototype.pasteImage = /** + * + */ + function (key, frame, destX, destY, destWidth, destHeight) { + if (typeof frame === "undefined") { frame = -1; } + if (typeof destX === "undefined") { destX = 0; } + if (typeof destY === "undefined") { destY = 0; } + if (typeof destWidth === "undefined") { destWidth = null; } + if (typeof destHeight === "undefined") { destHeight = null; } + var texture = null; + var frameData; + this._sx = 0; + this._sy = 0; + this._dx = destX; + this._dy = destY; + // TODO - Load a frame from a sprite sheet, otherwise we'll draw the whole lot + if(frame > -1) { + //if (this.game.cache.isSpriteSheet(key)) + //{ + // texture = this.game.cache.getImage(key); + //this.animations.loadFrameData(this.game.cache.getFrameData(key)); + //} + } else { + texture = this.game.cache.getImage(key); + this._sw = texture.width; + this._sh = texture.height; + this._dw = texture.width; + this._dh = texture.height; + } + if(destWidth !== null) { + this._dw = destWidth; + } + if(destHeight !== null) { + this._dh = destHeight; + } + if(texture != null) { + this.context.drawImage(texture, // Source Image + this._sx, // Source X (location within the source image) + this._sy, // Source Y + this._sw, // Source Width + this._sh, // Source Height + this._dx, // Destination X (where on the canvas it'll be drawn) + this._dy, // Destination Y + this._dw, // Destination Width (always same as Source Width unless scaled) + this._dh); + // Destination Height (always same as Source Height unless scaled) + } + }; + DynamicTexture.prototype.copyPixels = // TODO - Add in support for: alphaBitmapData: BitmapData = null, alphaPoint: Point = null, mergeAlpha: bool = false + /** + * Copy pixel from another DynamicTexture to this texture. + * @param sourceTexture {DynamicTexture} Source texture object. + * @param sourceRect {Rectangle} The specific region Rectangle to be copied to this in the source. + * @param destPoint {Point} Top-left point the target image data will be paste at. + */ + function (sourceTexture, sourceRect, destPoint) { + // Swap for drawImage if the sourceRect is the same size as the sourceTexture to avoid a costly getImageData call + if(Phaser.RectangleUtils.equals(sourceRect, this.bounds) == true) { + this.context.drawImage(sourceTexture.canvas, destPoint.x, destPoint.y); + } else { + this.context.putImageData(sourceTexture.getPixels(sourceRect), destPoint.x, destPoint.y); + } + }; + DynamicTexture.prototype.assignCanvasToGameObjects = /** + * Given an array of Sprites it will update each of them so that their canvas/contexts reference this DynamicTexture + * @param objects {Array} An array of GameObjects, or objects that inherit from it such as Sprites + */ + function (objects) { + for(var i = 0; i < objects.length; i++) { + objects[i].texture.canvas = this.canvas; + objects[i].texture.context = this.context; + } + }; + DynamicTexture.prototype.clear = /** + * Clear the whole canvas. + */ + function () { + this.context.clearRect(0, 0, this.bounds.width, this.bounds.height); + }; + DynamicTexture.prototype.render = /** + * Renders this DynamicTexture to the Stage at the given x/y coordinates + * + * @param x {number} The X coordinate to render on the stage to (given in screen coordinates, not world) + * @param y {number} The Y coordinate to render on the stage to (given in screen coordinates, not world) + */ + function (x, y) { + if (typeof x === "undefined") { x = 0; } + if (typeof y === "undefined") { y = 0; } + this.game.stage.context.drawImage(this.canvas, x, y); + }; + Object.defineProperty(DynamicTexture.prototype, "width", { + get: function () { + return this.bounds.width; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(DynamicTexture.prototype, "height", { + get: function () { + return this.bounds.height; + }, + enumerable: true, + configurable: true + }); + return DynamicTexture; + })(); + Phaser.DynamicTexture = DynamicTexture; +})(Phaser || (Phaser = {})); +/// +/** +* Phaser - AnimationLoader +* +* Responsible for parsing sprite sheet and JSON data into the internal FrameData format that Phaser uses for animations. +*/ +var Phaser; +(function (Phaser) { + var AnimationLoader = (function () { + function AnimationLoader() { } + AnimationLoader.parseSpriteSheet = /** + * Parse a sprite sheet from asset data. + * @param key {string} Asset key for the sprite sheet data. + * @param frameWidth {number} Width of animation frame. + * @param frameHeight {number} Height of animation frame. + * @param frameMax {number} Number of animation frames. + * @return {FrameData} Generated FrameData object. + */ + function parseSpriteSheet(game, key, frameWidth, frameHeight, frameMax) { + // How big is our image? + var img = game.cache.getImage(key); + if(img == null) { + return null; + } + var width = img.width; + var height = img.height; + var row = Math.round(width / frameWidth); + var column = Math.round(height / frameHeight); + var total = row * column; + if(frameMax !== -1) { + total = frameMax; + } + // Zero or smaller than frame sizes? + if(width == 0 || height == 0 || width < frameWidth || height < frameHeight || total === 0) { + return null; + } + // Let's create some frames then + var data = new Phaser.FrameData(); + var x = 0; + var y = 0; + for(var i = 0; i < total; i++) { + data.addFrame(new Phaser.Frame(x, y, frameWidth, frameHeight, '')); + x += frameWidth; + if(x === width) { + x = 0; + y += frameHeight; + } + } + return data; + }; + AnimationLoader.parseJSONData = /** + * Parse frame datas from json. + * @param json {object} Json data you want to parse. + * @return {FrameData} Generated FrameData object. + */ + function parseJSONData(game, json) { + // Malformed? + if(!json['frames']) { + console.log(json); + throw new Error("Phaser.AnimationLoader.parseJSONData: Invalid Texture Atlas JSON given, missing 'frames' array"); + } + // Let's create some frames then + var data = new Phaser.FrameData(); + // By this stage frames is a fully parsed array + var frames = json['frames']; + var newFrame; + for(var i = 0; i < frames.length; i++) { + newFrame = data.addFrame(new Phaser.Frame(frames[i].frame.x, frames[i].frame.y, frames[i].frame.w, frames[i].frame.h, frames[i].filename)); + newFrame.setTrim(frames[i].trimmed, frames[i].sourceSize.w, frames[i].sourceSize.h, frames[i].spriteSourceSize.x, frames[i].spriteSourceSize.y, frames[i].spriteSourceSize.w, frames[i].spriteSourceSize.h); + } + return data; + }; + AnimationLoader.parseXMLData = function parseXMLData(game, xml, format) { + // Malformed? + if(!xml.getElementsByTagName('TextureAtlas')) { + throw new Error("Phaser.AnimationLoader.parseXMLData: Invalid Texture Atlas XML given, missing tag"); + } + // Let's create some frames then + var data = new Phaser.FrameData(); + var frames = xml.getElementsByTagName('SubTexture'); + var newFrame; + for(var i = 0; i < frames.length; i++) { + var frame = frames[i].attributes; + newFrame = data.addFrame(new Phaser.Frame(frame.x.nodeValue, frame.y.nodeValue, frame.width.nodeValue, frame.height.nodeValue, frame.name.nodeValue)); + // Trimmed? + if(frame.frameX.nodeValue != '-0' || frame.frameY.nodeValue != '-0') { + newFrame.setTrim(true, frame.width.nodeValue, frame.height.nodeValue, Math.abs(frame.frameX.nodeValue), Math.abs(frame.frameY.nodeValue), frame.frameWidth.nodeValue, frame.frameHeight.nodeValue); + } + } + return data; + }; + return AnimationLoader; + })(); + Phaser.AnimationLoader = AnimationLoader; +})(Phaser || (Phaser = {})); +/// +/** +* Phaser - Animation +* +* An Animation is a single animation. It is created by the AnimationManager and belongs to Sprite objects. +*/ +var Phaser; +(function (Phaser) { + var Animation = (function () { + /** + * Animation constructor + * Create a new Animation. + * + * @param parent {Sprite} Owner sprite of this animation. + * @param frameData {FrameData} The FrameData object contains animation data. + * @param name {string} Unique name of this animation. + * @param frames {number[]/string[]} An array of numbers or strings indicating what frames to play in what order. + * @param delay {number} Time between frames in ms. + * @param looped {boolean} Whether or not the animation is looped or just plays once. + */ + function Animation(game, parent, frameData, name, frames, delay, looped) { + this._game = game; + this._parent = parent; + this._frames = frames; + this._frameData = frameData; + this.name = name; + this.delay = 1000 / delay; + this.looped = looped; + this.isFinished = false; + this.isPlaying = false; + this._frameIndex = 0; + this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); + } + Object.defineProperty(Animation.prototype, "frameTotal", { + get: function () { + return this._frames.length; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Animation.prototype, "frame", { + get: function () { + if(this.currentFrame !== null) { + return this.currentFrame.index; + } else { + return this._frameIndex; + } + }, + set: function (value) { + this.currentFrame = this._frameData.getFrame(value); + if(this.currentFrame !== null) { + this._parent.texture.width = this.currentFrame.width; + this._parent.texture.height = this.currentFrame.height; + this._frameIndex = value; + } + }, + enumerable: true, + configurable: true + }); + Animation.prototype.play = /** + * Play this animation. + * @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 (frameRate, loop) { + if (typeof frameRate === "undefined") { frameRate = null; } + if(frameRate !== null) { + this.delay = 1000 / frameRate; + } + if(loop !== undefined) { + this.looped = loop; + } + this.isPlaying = true; + this.isFinished = false; + this._timeLastFrame = this._game.time.now; + this._timeNextFrame = this._game.time.now + this.delay; + this._frameIndex = 0; + this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); + }; + Animation.prototype.restart = /** + * Play this animation from the first frame. + */ + function () { + this.isPlaying = true; + this.isFinished = false; + this._timeLastFrame = this._game.time.now; + this._timeNextFrame = this._game.time.now + this.delay; + this._frameIndex = 0; + this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); + }; + Animation.prototype.stop = /** + * Stop playing animation and set it finished. + */ + function () { + this.isPlaying = false; + this.isFinished = true; + }; + Animation.prototype.update = /** + * Update animation frames. + */ + function () { + if(this.isPlaying == true && this._game.time.now >= this._timeNextFrame) { + this._frameIndex++; + if(this._frameIndex == this._frames.length) { + if(this.looped) { + this._frameIndex = 0; + this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); + } else { + this.onComplete(); + } + } else { + this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); + } + this._timeLastFrame = this._game.time.now; + this._timeNextFrame = this._game.time.now + this.delay; + return true; + } + return false; + }; + Animation.prototype.destroy = /** + * Clean up animation memory. + */ + function () { + this._game = null; + this._parent = null; + this._frames = null; + this._frameData = null; + this.currentFrame = null; + this.isPlaying = false; + }; + Animation.prototype.onComplete = /** + * Animation complete callback method. + */ + function () { + this.isPlaying = false; + this.isFinished = true; + // callback goes here + }; + return Animation; + })(); + Phaser.Animation = Animation; +})(Phaser || (Phaser = {})); +/// +/** +* Phaser - Frame +* +* A Frame is a single frame of an animation and is part of a FrameData collection. +*/ +var Phaser; +(function (Phaser) { + var Frame = (function () { + /** + * Frame constructor + * Create a new Frame with specific position, size and name. + * + * @param x {number} X position within the image to cut from. + * @param y {number} Y position within the image to cut from. + * @param width {number} Width of the frame. + * @param height {number} Height of the frame. + * @param name {string} Name of this frame. + */ + function Frame(x, y, width, height, name) { + /** + * Useful for Texture Atlas files. (is set to the filename value) + */ + this.name = ''; + /** + * Rotated? (not yet implemented) + */ + this.rotated = false; + /** + * Either cw or ccw, rotation is always 90 degrees. + */ + this.rotationDirection = 'cw'; + //console.log('Creating Frame', name, 'x', x, 'y', y, 'width', width, 'height', height); + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.name = name; + this.rotated = false; + this.trimmed = false; + } + Frame.prototype.setRotation = /** + * Set rotation of this frame. (Not yet supported!) + */ + function (rotated, rotationDirection) { + // Not yet supported + }; + Frame.prototype.setTrim = /** + * Set trim of the frame. + * @param trimmed {boolean} Whether this frame trimmed or not. + * @param actualWidth {number} Actual width of this frame. + * @param actualHeight {number} Actual height of this frame. + * @param destX {number} Destination x position. + * @param destY {number} Destination y position. + * @param destWidth {number} Destination draw width. + * @param destHeight {number} Destination draw height. + */ + function (trimmed, actualWidth, actualHeight, destX, destY, destWidth, destHeight) { + //console.log('setTrim', trimmed, 'aw', actualWidth, 'ah', actualHeight, 'dx', destX, 'dy', destY, 'dw', destWidth, 'dh', destHeight); + this.trimmed = trimmed; + if(trimmed) { + this.width = actualWidth; + this.height = actualHeight; + this.sourceSizeW = actualWidth; + this.sourceSizeH = actualHeight; + this.spriteSourceSizeX = destX; + this.spriteSourceSizeY = destY; + this.spriteSourceSizeW = destWidth; + this.spriteSourceSizeH = destHeight; + } + }; + return Frame; + })(); + Phaser.Frame = Frame; +})(Phaser || (Phaser = {})); +/// +/** +* Phaser - FrameData +* +* FrameData is a container for Frame objects, the internal representation of animation data in Phaser. +*/ +var Phaser; +(function (Phaser) { + var FrameData = (function () { + /** + * FrameData constructor + */ + function FrameData() { + this._frames = []; + this._frameNames = []; + } + Object.defineProperty(FrameData.prototype, "total", { + get: function () { + return this._frames.length; + }, + enumerable: true, + configurable: true + }); + FrameData.prototype.addFrame = /** + * Add a new frame. + * @param frame {Frame} The frame you want to add. + * @return {Frame} The frame you just added. + */ + function (frame) { + frame.index = this._frames.length; + this._frames.push(frame); + if(frame.name !== '') { + this._frameNames[frame.name] = frame.index; + } + return frame; + }; + FrameData.prototype.getFrame = /** + * Get a frame by its index. + * @param index {number} Index of the frame you want to get. + * @return {Frame} The frame you want. + */ + function (index) { + if(this._frames[index]) { + return this._frames[index]; + } + return null; + }; + FrameData.prototype.getFrameByName = /** + * Get a frame by its name. + * @param name {string} Name of the frame you want to get. + * @return {Frame} The frame you want. + */ + function (name) { + if(this._frameNames[name] !== '') { + return this._frames[this._frameNames[name]]; + } + return null; + }; + FrameData.prototype.checkFrameName = /** + * Check whether there's a frame with given name. + * @param name {string} Name of the frame you want to check. + * @return {boolean} True if frame with given name found, otherwise return false. + */ + function (name) { + if(this._frameNames[name]) { + return true; + } + return false; + }; + FrameData.prototype.getFrameRange = /** + * Get ranges of frames in an array. + * @param start {number} Start index of frames you want. + * @param end {number} End index of frames you want. + * @param [output] {Frame[]} result will be added into this array. + * @return {Frame[]} Ranges of specific frames in an array. + */ + function (start, end, output) { + if (typeof output === "undefined") { output = []; } + for(var i = start; i <= end; i++) { + output.push(this._frames[i]); + } + return output; + }; + FrameData.prototype.getFrameIndexes = /** + * Get all indexes of frames by giving their name. + * @param [output] {number[]} result will be added into this array. + * @return {number[]} Indexes of specific frames in an array. + */ + function (output) { + if (typeof output === "undefined") { output = []; } + output.length = 0; + for(var i = 0; i < this._frames.length; i++) { + output.push(i); + } + return output; + }; + FrameData.prototype.getFrameIndexesByName = /** + * Get the frame indexes by giving the frame names. + * @param [output] {number[]} result will be added into this array. + * @return {number[]} Names of specific frames in an array. + */ + function (input) { + var output = []; + for(var i = 0; i < input.length; i++) { + if(this.getFrameByName(input[i])) { + output.push(this.getFrameByName(input[i]).index); + } + } + return output; + }; + FrameData.prototype.getAllFrames = /** + * Get all frames in this frame data. + * @return {Frame[]} All the frames in an array. + */ + function () { + return this._frames; + }; + FrameData.prototype.getFrames = /** + * Get All frames with specific ranges. + * @param range {number[]} Ranges in an array. + * @return {Frame[]} All frames in an array. + */ + function (range) { + var output = []; + for(var i = 0; i < range.length; i++) { + output.push(this._frames[i]); + } + return output; + }; + return FrameData; + })(); + Phaser.FrameData = FrameData; +})(Phaser || (Phaser = {})); +var Phaser; +(function (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. + */ + (function (Components) { + var AnimationManager = (function () { + /** + * AnimationManager constructor + * Create a new AnimationManager. + * + * @param parent {Sprite} Owner sprite of this manager. + */ + function AnimationManager(parent) { + /** + * Data contains animation frames. + * @type {FrameData} + */ + this._frameData = null; + /** + * When an animation frame changes you can choose to automatically update the physics bounds of the parent Sprite + * to the width and height of the new frame. If you've set a specific physics bounds that you don't want changed during + * animation then set this to false, otherwise leave it set to true. + * @type {boolean} + */ + this.autoUpdateBounds = true; + /** + * Keeps track of the current frame of animation. + */ + this.currentFrame = null; + this._parent = parent; + this._game = parent.game; + 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; + } + if(frames == null) { + frames = this._frameData.getFrameIndexes(); + } else { + if(this.validateFrames(frames, useNumericIndex) == false) { + throw Error('Invalid frames given to Animation ' + name); + 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; + } + } 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); + } + } + }; + 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.texture.width = this.currentFrame.width; + this._parent.texture.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.texture.width = this.currentFrame.width; + this._parent.texture.height = this.currentFrame.height; + if(this.autoUpdateBounds && this._parent['body']) { + this._parent.body.bounds.width = this.currentFrame.width; + this._parent.body.bounds.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.texture.width = this.currentFrame.width; + this._parent.texture.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 = {})); +var Phaser; +(function (Phaser) { + /// + /** + * Phaser - Components - Transform + */ + (function (Components) { + var Transform = (function () { + /** + * Creates a new Sprite Transform component + * @param parent The Sprite using this transform + */ + function Transform(parent) { + /** + * This value is added to the rotation of the object. + * For example if you had a texture drawn facing straight up then you could set + * rotationOffset to 90 and it would correspond correctly with Phasers right-handed coordinate system. + * @type {number} + */ + this.rotationOffset = 0; + /** + * The rotation of the object in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + */ + this.rotation = 0; + this.game = parent.game; + this.parent = parent; + this.scrollFactor = new Phaser.Vec2(1, 1); + this.origin = new Phaser.Vec2(); + this.scale = new Phaser.Vec2(1, 1); + this.skew = new Phaser.Vec2(); + } + return Transform; + })(); + Components.Transform = Transform; + })(Phaser.Components || (Phaser.Components = {})); + var Components = Phaser.Components; +})(Phaser || (Phaser = {})); +var Phaser; +(function (Phaser) { + (function (Components) { + /// + /// + /// + /// + /** + * Phaser - Components - Input + * + * Input detection component + */ + (function (Sprite) { + var Input = (function () { + /** + * Sprite Input component constructor + * @param parent The Sprite using this Input component + */ + function Input(parent) { + /** + * The PriorityID controls which Sprite receives an Input event first if they should overlap. + */ + this.priorityID = 0; + this.isDragged = false; + this.dragPixelPerfect = false; + this.allowHorizontalDrag = true; + this.allowVerticalDrag = true; + this.snapOnDrag = false; + this.snapOnRelease = false; + this.snapX = 0; + this.snapY = 0; + /** + * Is this sprite allowed to be dragged by the mouse? true = yes, false = no + * @default false + */ + this.draggable = false; + /** + * A region of the game world within which the sprite is restricted during drag + * @default null + */ + this.boundsRect = null; + /** + * An Sprite the bounds of which this sprite is restricted during drag + * @default null + */ + this.boundsSprite = null; + this.consumePointerEvent = false; + this.game = parent.game; + this.sprite = parent; + this.enabled = false; + } + Input.prototype.pointerX = /** + * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. + * This value is only set when the pointer is over this Sprite. + * @type {number} + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].x; + }; + Input.prototype.pointerY = /** + * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite + * This value is only set when the pointer is over this Sprite. + * @type {number} + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].y; + }; + Input.prototype.pointerDown = /** + * If the Pointer is touching the touchscreen, or the mouse button is held down, isDown is set to true + * @property isDown + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isDown; + }; + Input.prototype.pointerUp = /** + * If the Pointer is not touching the touchscreen, or the mouse button is up, isUp is set to true + * @property isUp + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isUp; + }; + Input.prototype.pointerTimeDown = /** + * A timestamp representing when the Pointer first touched the touchscreen. + * @property timeDown + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeDown; + }; + Input.prototype.pointerTimeUp = /** + * A timestamp representing when the Pointer left the touchscreen. + * @property timeUp + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeUp; + }; + Input.prototype.pointerOver = /** + * Is the Pointer over this Sprite + * @property isOver + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isOver; + }; + Input.prototype.pointerOut = /** + * Is the Pointer outside of this Sprite + * @property isOut + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isOut; + }; + Input.prototype.pointerTimeOver = /** + * A timestamp representing when the Pointer first touched the touchscreen. + * @property timeDown + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeOver; + }; + Input.prototype.pointerTimeOut = /** + * A timestamp representing when the Pointer left the touchscreen. + * @property timeUp + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeOut; + }; + Input.prototype.pointerDragged = /** + * Is this sprite being dragged by the mouse or not? + * @default false + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isDragged; + }; + Input.prototype.start = function (priority, checkBody, useHandCursor) { + if (typeof priority === "undefined") { priority = 0; } + if (typeof checkBody === "undefined") { checkBody = false; } + if (typeof useHandCursor === "undefined") { useHandCursor = false; } + // Turning on + if(this.enabled == false) { + // Register, etc + this.checkBody = checkBody; + this.useHandCursor = useHandCursor; + this.priorityID = priority; + this._pointerData = []; + for(var i = 0; i < 10; i++) { + this._pointerData.push({ + id: i, + x: 0, + y: 0, + isDown: false, + isUp: false, + isOver: false, + isOut: false, + timeOver: 0, + timeOut: 0, + timeDown: 0, + timeUp: 0, + downDuration: 0, + isDragged: false + }); + } + this.snapOffset = new Phaser.Point(); + this.enabled = true; + this.game.input.addGameObject(this.sprite); + } + return this.sprite; + }; + Input.prototype.reset = function () { + this.enabled = false; + for(var i = 0; i < 10; i++) { + this._pointerData[i] = { + id: i, + x: 0, + y: 0, + isDown: false, + isUp: false, + isOver: false, + isOut: false, + timeOver: 0, + timeOut: 0, + timeDown: 0, + timeUp: 0, + downDuration: 0, + isDragged: false + }; + } + }; + Input.prototype.stop = function () { + // Turning off + if(this.enabled == false) { + return; + } else { + // De-register, etc + this.enabled = false; + this.game.input.removeGameObject(this.sprite); + } + }; + Input.prototype.checkPointerOver = function (pointer) { + if(this.enabled == false || this.sprite.visible == false) { + return false; + } else { + return Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.scaledX, pointer.scaledY); + } + }; + Input.prototype.update = /** + * Update + */ + function (pointer) { + if(this.enabled == false || this.sprite.visible == false) { + return false; + } + if(this.draggable && this._draggedPointerID == pointer.id) { + return this.updateDrag(pointer); + } else if(this._pointerData[pointer.id].isOver == true) { + if(Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.scaledX, pointer.scaledY)) { + this._pointerData[pointer.id].x = pointer.scaledX - this.sprite.x; + this._pointerData[pointer.id].y = pointer.scaledY - this.sprite.y; + return true; + } else { + this._pointerOutHandler(pointer); + return false; + } + } + }; + Input.prototype._pointerOverHandler = function (pointer) { + // { id: i, x: 0, y: 0, isDown: false, isUp: false, isOver: false, isOut: false, timeOver: 0, timeOut: 0, isDragged: false } + if(this._pointerData[pointer.id].isOver == false) { + this._pointerData[pointer.id].isOver = true; + this._pointerData[pointer.id].isOut = false; + this._pointerData[pointer.id].timeOver = this.game.time.now; + this._pointerData[pointer.id].x = pointer.x - this.sprite.x; + this._pointerData[pointer.id].y = pointer.y - this.sprite.y; + if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { + this.game.stage.canvas.style.cursor = "pointer"; + } + this.sprite.events.onInputOver.dispatch(this.sprite, pointer); + } + }; + Input.prototype._pointerOutHandler = function (pointer) { + this._pointerData[pointer.id].isOver = false; + this._pointerData[pointer.id].isOut = true; + this._pointerData[pointer.id].timeOut = this.game.time.now; + if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { + this.game.stage.canvas.style.cursor = "default"; + } + this.sprite.events.onInputOut.dispatch(this.sprite, pointer); + }; + Input.prototype._touchedHandler = function (pointer) { + if(this._pointerData[pointer.id].isDown == false && this._pointerData[pointer.id].isOver == true) { + this._pointerData[pointer.id].isDown = true; + this._pointerData[pointer.id].isUp = false; + this._pointerData[pointer.id].timeDown = this.game.time.now; + this.sprite.events.onInputDown.dispatch(this.sprite, pointer); + // Start drag + //if (this.draggable && this.isDragged == false && pointer.targetObject == null) + if(this.draggable && this.isDragged == false) { + this.startDrag(pointer); + } + } + // Consume the event? + return this.consumePointerEvent; + }; + Input.prototype._releasedHandler = function (pointer) { + // If was previously touched by this Pointer, check if still is + if(this._pointerData[pointer.id].isDown && pointer.isUp) { + this._pointerData[pointer.id].isDown = false; + this._pointerData[pointer.id].isUp = true; + this._pointerData[pointer.id].timeUp = this.game.time.now; + this._pointerData[pointer.id].downDuration = this._pointerData[pointer.id].timeUp - this._pointerData[pointer.id].timeDown; + this.sprite.events.onInputUp.dispatch(this.sprite, pointer); + // Stop drag + if(this.draggable && this.isDragged && this._draggedPointerID == pointer.id) { + this.stopDrag(pointer); + } + if(this.useHandCursor) { + this.game.stage.canvas.style.cursor = "default"; + } + } + }; + Input.prototype.updateDrag = /** + * Updates the Pointer drag on this Sprite. + */ + function (pointer) { + if(pointer.isUp) { + this.stopDrag(pointer); + return false; + } + if(this.allowHorizontalDrag) { + this.sprite.x = pointer.x + this._dragPoint.x + this.dragOffset.x; + } + if(this.allowVerticalDrag) { + this.sprite.y = pointer.y + this._dragPoint.y + this.dragOffset.y; + } + if(this.boundsRect) { + this.checkBoundsRect(); + } + if(this.boundsSprite) { + this.checkBoundsSprite(); + } + if(this.snapOnDrag) { + this.sprite.x = Math.floor(this.sprite.x / this.snapX) * this.snapX; + this.sprite.y = Math.floor(this.sprite.y / this.snapY) * this.snapY; + } + return true; + }; + Input.prototype.justOver = /** + * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just over. + * @returns {boolean} + */ + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } + if (typeof delay === "undefined") { delay = 500; } + return (this._pointerData[pointer].isOver && this.overDuration(pointer) < delay); + }; + Input.prototype.justOut = /** + * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just out. + * @returns {boolean} + */ + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } + if (typeof delay === "undefined") { delay = 500; } + return (this._pointerData[pointer].isOut && (this.game.time.now - this._pointerData[pointer].timeOut < delay)); + }; + Input.prototype.justPressed = /** + * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just over. + * @returns {boolean} + */ + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } + if (typeof delay === "undefined") { delay = 500; } + return (this._pointerData[pointer].isDown && this.downDuration(pointer) < delay); + }; + Input.prototype.justReleased = /** + * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just out. + * @returns {boolean} + */ + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } + if (typeof delay === "undefined") { delay = 500; } + return (this._pointerData[pointer].isUp && (this.game.time.now - this._pointerData[pointer].timeUp < delay)); + }; + Input.prototype.overDuration = /** + * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. + * @returns {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over. + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + if(this._pointerData[pointer].isOver) { + return this.game.time.now - this._pointerData[pointer].timeOver; + } + return -1; + }; + Input.prototype.downDuration = /** + * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. + * @returns {number} The number of milliseconds the pointer has been pressed down on the Sprite, or -1 if not over. + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + if(this._pointerData[pointer].isDown) { + return this.game.time.now - this._pointerData[pointer].timeDown; + } + return -1; + }; + Input.prototype.enableDrag = /** + * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback + * + * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. + * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. + * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) + * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere + * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here + */ + function (lockCenter, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) { + if (typeof lockCenter === "undefined") { lockCenter = false; } + if (typeof pixelPerfect === "undefined") { pixelPerfect = false; } + if (typeof alphaThreshold === "undefined") { alphaThreshold = 255; } + if (typeof boundsRect === "undefined") { boundsRect = null; } + if (typeof boundsSprite === "undefined") { boundsSprite = null; } + this._dragPoint = new Phaser.Point(); + this.draggable = true; + this.dragOffset = new Phaser.Point(); + this.dragFromCenter = lockCenter; + this.dragPixelPerfect = pixelPerfect; + this.dragPixelPerfectAlpha = alphaThreshold; + if(boundsRect) { + this.boundsRect = boundsRect; + } + if(boundsSprite) { + this.boundsSprite = boundsSprite; + } + }; + Input.prototype.disableDrag = /** + * Stops this sprite from being able to be dragged. If it is currently the target of an active drag it will be stopped immediately. Also disables any set callbacks. + */ + function () { + if(this._pointerData) { + for(var i = 0; i < 10; i++) { + this._pointerData[i].isDragged = false; + } + } + this.draggable = false; + this.isDragged = false; + this._draggedPointerID = -1; + }; + Input.prototype.startDrag = /** + * Called by Pointer when drag starts on this Sprite. Should not usually be called directly. + */ + function (pointer) { + this.isDragged = true; + this._draggedPointerID = pointer.id; + this._pointerData[pointer.id].isDragged = true; + if(this.dragFromCenter) { + // Move the sprite to the middle of the pointer + this._dragPoint.setTo(-this.sprite.worldView.halfWidth, -this.sprite.worldView.halfHeight); + } else { + this._dragPoint.setTo(this.sprite.x - pointer.x, this.sprite.y - pointer.y); + } + this.updateDrag(pointer); + }; + Input.prototype.stopDrag = /** + * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. + */ + function (pointer) { + this.isDragged = false; + this._draggedPointerID = -1; + this._pointerData[pointer.id].isDragged = false; + if(this.snapOnRelease) { + this.sprite.x = Math.floor(this.sprite.x / this.snapX) * this.snapX; + this.sprite.y = Math.floor(this.sprite.y / this.snapY) * this.snapY; + } + //pointer.draggedObject = null; + }; + Input.prototype.setDragLock = /** + * Restricts this sprite to drag movement only on the given axis. Note: If both are set to false the sprite will never move! + * + * @param allowHorizontal To enable the sprite to be dragged horizontally set to true, otherwise false + * @param allowVertical To enable the sprite to be dragged vertically set to true, otherwise false + */ + function (allowHorizontal, allowVertical) { + if (typeof allowHorizontal === "undefined") { allowHorizontal = true; } + if (typeof allowVertical === "undefined") { allowVertical = true; } + this.allowHorizontalDrag = allowHorizontal; + this.allowVerticalDrag = allowVertical; + }; + Input.prototype.enableSnap = /** + * Make this Sprite snap to the given grid either during drag or when it's released. + * For example 16x16 as the snapX and snapY would make the sprite snap to every 16 pixels. + * + * @param snapX The width of the grid cell in pixels + * @param snapY The height of the grid cell in pixels + * @param onDrag If true the sprite will snap to the grid while being dragged + * @param onRelease If true the sprite will snap to the grid when released + */ + function (snapX, snapY, onDrag, onRelease) { + if (typeof onDrag === "undefined") { onDrag = true; } + if (typeof onRelease === "undefined") { onRelease = false; } + this.snapOnDrag = onDrag; + this.snapOnRelease = onRelease; + this.snapX = snapX; + this.snapY = snapY; + }; + Input.prototype.disableSnap = /** + * Stops the sprite from snapping to a grid during drag or release. + */ + function () { + this.snapOnDrag = false; + this.snapOnRelease = false; + }; + Input.prototype.checkBoundsRect = /** + * Bounds Rect check for the sprite drag + */ + function () { + if(this.sprite.x < this.boundsRect.left) { + this.sprite.x = this.boundsRect.x; + } else if((this.sprite.x + this.sprite.width) > this.boundsRect.right) { + this.sprite.x = this.boundsRect.right - this.sprite.width; + } + if(this.sprite.y < this.boundsRect.top) { + this.sprite.y = this.boundsRect.top; + } else if((this.sprite.y + this.sprite.height) > this.boundsRect.bottom) { + this.sprite.y = this.boundsRect.bottom - this.sprite.height; + } + }; + Input.prototype.checkBoundsSprite = /** + * Parent Sprite Bounds check for the sprite drag + */ + function () { + if(this.sprite.x < this.boundsSprite.x) { + this.sprite.x = this.boundsSprite.x; + } else if((this.sprite.x + this.sprite.width) > (this.boundsSprite.x + this.boundsSprite.width)) { + this.sprite.x = (this.boundsSprite.x + this.boundsSprite.width) - this.sprite.width; + } + if(this.sprite.y < this.boundsSprite.y) { + this.sprite.y = this.boundsSprite.y; + } else if((this.sprite.y + this.sprite.height) > (this.boundsSprite.y + this.boundsSprite.height)) { + this.sprite.y = (this.boundsSprite.y + this.boundsSprite.height) - this.sprite.height; + } + }; + Input.prototype.renderDebugInfo = /** + * Render debug infos. (including name, bounds info, position and some other properties) + * @param x {number} X position of the debug info to be rendered. + * @param y {number} Y position of the debug info to be rendered. + * @param [color] {number} color of the debug info to be rendered. (format is css color string) + */ + function (x, y, color) { + if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } + this.sprite.texture.context.font = '14px Courier'; + this.sprite.texture.context.fillStyle = color; + this.sprite.texture.context.fillText('Sprite Input: (' + this.sprite.worldView.width + ' x ' + this.sprite.worldView.height + ')', x, y); + this.sprite.texture.context.fillText('x: ' + this.pointerX().toFixed(1) + ' y: ' + this.pointerY().toFixed(1), x, y + 14); + this.sprite.texture.context.fillText('over: ' + this.pointerOver() + ' duration: ' + this.overDuration().toFixed(0), x, y + 28); + this.sprite.texture.context.fillText('down: ' + this.pointerDown() + ' duration: ' + this.downDuration().toFixed(0), x, y + 42); + this.sprite.texture.context.fillText('just over: ' + this.justOver() + ' just out: ' + this.justOut(), x, y + 56); + }; + return Input; + })(); + Sprite.Input = Input; + })(Components.Sprite || (Components.Sprite = {})); + var Sprite = Components.Sprite; + })(Phaser.Components || (Phaser.Components = {})); + var Components = Phaser.Components; +})(Phaser || (Phaser = {})); +var Phaser; +(function (Phaser) { + (function (Components) { + /// + /** + * Phaser - Components - Events + * + * Signals that are dispatched by the Sprite and its various components + */ + (function (Sprite) { + var Events = (function () { + /** + * The Events component is a collection of events fired by the parent Sprite and its other components. + * @param parent The Sprite using this Input component + */ + function Events(parent) { + this.game = parent.game; + this.sprite = parent; + this.onAddedToGroup = new Phaser.Signal(); + this.onRemovedFromGroup = new Phaser.Signal(); + this.onKilled = new Phaser.Signal(); + this.onRevived = new Phaser.Signal(); + this.onInputOver = new Phaser.Signal(); + this.onInputOut = new Phaser.Signal(); + this.onInputDown = new Phaser.Signal(); + this.onInputUp = new Phaser.Signal(); + } + return Events; + })(); + Sprite.Events = Events; + })(Components.Sprite || (Components.Sprite = {})); + var Sprite = Components.Sprite; + })(Phaser.Components || (Phaser.Components = {})); + var Components = Phaser.Components; +})(Phaser || (Phaser = {})); +/// +/// +/** +* Phaser - Vec2Utils +* +* A collection of methods useful for manipulating and performing operations on 2D vectors. +* +*/ +var Phaser; +(function (Phaser) { + var Vec2Utils = (function () { + function Vec2Utils() { } + Vec2Utils.add = /** + * Adds two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the sum of the two vectors. + */ + function add(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.x + b.x, a.y + b.y); + }; + Vec2Utils.subtract = /** + * Subtracts two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the difference of the two vectors. + */ + function subtract(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.x - b.x, a.y - b.y); + }; + Vec2Utils.multiply = /** + * Multiplies two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the sum of the two vectors multiplied. + */ + function multiply(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.x * b.x, a.y * b.y); + }; + Vec2Utils.divide = /** + * Divides two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the sum of the two vectors divided. + */ + function divide(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.x / b.x, a.y / b.y); + }; + Vec2Utils.scale = /** + * Scales a 2D vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {number} s Scaling value. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the scaled vector. + */ + function scale(a, s, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.x * s, a.y * s); + }; + Vec2Utils.perp = /** + * Rotate a 2D vector by 90 degrees. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is the scaled vector. + */ + function perp(a, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.y, -a.x); + }; + Vec2Utils.equals = /** + * Checks if two 2D vectors are equal. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Boolean} + */ + function equals(a, b) { + return a.x == b.x && a.y == b.y; + }; + Vec2Utils.epsilonEquals = /** + * + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} epsilon + * @return {Boolean} + */ + function epsilonEquals(a, b, epsilon) { + return Math.abs(a.x - b.x) <= epsilon && Math.abs(a.y - b.y) <= epsilon; + }; + Vec2Utils.distance = /** + * Get the distance between two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + function distance(a, b) { + return Math.sqrt(Vec2Utils.distanceSq(a, b)); + }; + Vec2Utils.distanceSq = /** + * Get the distance squared between two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + function distanceSq(a, b) { + return ((a.x - b.x) * (a.x - b.x)) + ((a.y - b.y) * (a.y - b.y)); + }; + Vec2Utils.project = /** + * Project two 2D vectors onto another vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + function project(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + var amt = a.dot(b) / b.lengthSq(); + if(amt != 0) { + out.setTo(amt * b.x, amt * b.y); + } + return out; + }; + Vec2Utils.projectUnit = /** + * Project this vector onto a vector of unit length. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + function projectUnit(a, b, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + var amt = a.dot(b); + if(amt != 0) { + out.setTo(amt * b.x, amt * b.y); + } + return out; + }; + Vec2Utils.normalRightHand = /** + * Right-hand normalize (make unit length) a 2D vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + function normalRightHand(a, out) { + if (typeof out === "undefined") { out = this; } + return out.setTo(a.y * -1, a.x); + }; + Vec2Utils.normalize = /** + * Normalize (make unit length) a 2D vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + function normalize(a, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + var m = a.length(); + if(m != 0) { + out.setTo(a.x / m, a.y / m); + } + return out; + }; + Vec2Utils.dot = /** + * The dot product of two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + function dot(a, b) { + return ((a.x * b.x) + (a.y * b.y)); + }; + Vec2Utils.cross = /** + * The cross product of two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + function cross(a, b) { + return ((a.x * b.y) - (a.y * b.x)); + }; + Vec2Utils.angle = /** + * The angle between two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + function angle(a, b) { + return Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y); + }; + Vec2Utils.angleSq = /** + * The angle squared between two 2D vectors. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @return {Number} + */ + function angleSq(a, b) { + return a.subtract(b).angle(b.subtract(a)); + }; + Vec2Utils.rotate = /** + * Rotate a 2D vector around the origin to the given angle (theta). + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} b Reference to a source Vec2 object. + * @param {Number} theta The angle of rotation in radians. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2. + */ + function rotate(a, b, theta, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + var x = a.x - b.x; + var y = a.y - b.y; + return out.setTo(x * Math.cos(theta) - y * Math.sin(theta) + b.x, x * Math.sin(theta) + y * Math.cos(theta) + b.y); + }; + Vec2Utils.clone = /** + * Clone a 2D vector. + * + * @param {Vec2} a Reference to a source Vec2 object. + * @param {Vec2} out The output Vec2 that is the result of the operation. + * @return {Vec2} A Vec2 that is a copy of the source Vec2. + */ + function clone(a, out) { + if (typeof out === "undefined") { out = new Phaser.Vec2(); } + return out.setTo(a.x, a.y); + }; + return Vec2Utils; + })(); + Phaser.Vec2Utils = Vec2Utils; + /** + * Reflect this vector on an arbitrary axis. + * + * @param {Vec2} axis The vector representing the axis. + * @return {Vec2} This for chaining. + */ + /* + static reflect(axis): Vec2 { + + var x = this.x; + var y = this.y; + this.project(axis).scale(2); + this.x -= x; + this.y -= y; + + return this; + + } + */ + /** + * Reflect this vector on an arbitrary axis (represented by a unit vector) + * + * @param {Vec2} axis The unit vector representing the axis. + * @return {Vec2} This for chaining. + */ + /* + static reflectN(axis): Vec2 { + + var x = this.x; + var y = this.y; + this.projectN(axis).scale(2); + this.x -= x; + this.y -= y; + + return this; + + } + + static getMagnitude(): number { + return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)); + } + */ + })(Phaser || (Phaser = {})); +var Phaser; +(function (Phaser) { + /// + /// + /// + /** + * Phaser - Physics - Body + */ + (function (Physics) { + var Body = (function () { + function Body(sprite, type) { + this.angularVelocity = 0; + this.angularAcceleration = 0; + this.angularDrag = 0; + this.maxAngular = 10000; + this.mass = 1; + this.sprite = sprite; + this.game = sprite.game; + this.type = type; + // Fixture properties + // Will extend into its own class at a later date - can move the fixture defs there and add shape support, but this will do for 1.0 release + this.bounds = new Phaser.Rectangle(sprite.x + Math.round(sprite.width / 2), sprite.y + Math.round(sprite.height / 2), sprite.width, sprite.height); + this.bounce = Phaser.Vec2Utils.clone(this.game.world.physics.bounce); + // Body properties + this.gravity = Phaser.Vec2Utils.clone(this.game.world.physics.gravity); + this.velocity = new Phaser.Vec2(); + this.acceleration = new Phaser.Vec2(); + this.drag = Phaser.Vec2Utils.clone(this.game.world.physics.drag); + this.maxVelocity = new Phaser.Vec2(10000, 10000); + this.angularVelocity = 0; + this.angularAcceleration = 0; + this.angularDrag = 0; + this.touching = Phaser.Types.NONE; + this.wasTouching = Phaser.Types.NONE; + this.allowCollisions = Phaser.Types.ANY; + this.position = new Phaser.Vec2(sprite.x + this.bounds.halfWidth, sprite.y + this.bounds.halfHeight); + this.oldPosition = new Phaser.Vec2(sprite.x + this.bounds.halfWidth, sprite.y + this.bounds.halfHeight); + this.offset = new Phaser.Vec2(); + } + Body.prototype.preUpdate = function () { + this.oldPosition.copyFrom(this.position); + this.bounds.x = this.position.x - this.bounds.halfWidth; + this.bounds.y = this.position.y - this.bounds.halfHeight; + if(this.sprite.transform.scale.equals(1) == false) { + } + }; + Body.prototype.postUpdate = // Shall we do this? Or just update the values directly in the separate functions? But then the bounds will be out of sync - as long as + // the bounds are updated and used in calculations then we can do one final sprite movement here I guess? + function () { + // if this is all it does maybe move elsewhere? Sprite postUpdate? + if(this.type !== Phaser.Types.BODY_DISABLED) { + this.game.world.physics.updateMotion(this); + this.sprite.x = (this.position.x - this.bounds.halfWidth) - this.offset.x; + this.sprite.y = (this.position.y - this.bounds.halfHeight) - this.offset.y; + this.wasTouching = this.touching; + this.touching = Phaser.Types.NONE; + } + }; + Object.defineProperty(Body.prototype, "hullWidth", { + get: function () { + if(this.deltaX > 0) { + return this.bounds.width + this.deltaX; + } else { + return this.bounds.width - this.deltaX; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "hullHeight", { + get: function () { + if(this.deltaY > 0) { + return this.bounds.height + this.deltaY; + } else { + return this.bounds.height - this.deltaY; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "hullX", { + get: function () { + if(this.position.x < this.oldPosition.x) { + return this.position.x; + } else { + return this.oldPosition.x; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "hullY", { + get: function () { + if(this.position.y < this.oldPosition.y) { + return this.position.y; + } else { + return this.oldPosition.y; + } + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "deltaXAbs", { + get: function () { + return (this.deltaX > 0 ? this.deltaX : -this.deltaX); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "deltaYAbs", { + get: function () { + return (this.deltaY > 0 ? this.deltaY : -this.deltaY); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "deltaX", { + get: function () { + return this.position.x - this.oldPosition.x; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "deltaY", { + get: function () { + return this.position.y - this.oldPosition.y; + }, + enumerable: true, + configurable: true + }); + Body.prototype.render = // MOVE THESE TO A UTIL + function (context) { + context.beginPath(); + context.strokeStyle = 'rgb(0,255,0)'; + context.strokeRect(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight, this.bounds.width, this.bounds.height); + context.stroke(); + context.closePath(); + // center point + context.fillStyle = 'rgb(0,255,0)'; + context.fillRect(this.position.x, this.position.y, 2, 2); + if(this.touching & Phaser.Types.LEFT) { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); + context.lineTo(this.position.x - this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); + context.stroke(); + context.closePath(); + } + if(this.touching & Phaser.Types.RIGHT) { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.position.x + this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); + context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); + context.stroke(); + context.closePath(); + } + if(this.touching & Phaser.Types.UP) { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); + context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); + context.stroke(); + context.closePath(); + } + if(this.touching & Phaser.Types.DOWN) { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); + context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); + context.stroke(); + context.closePath(); + } + }; + Body.prototype.renderDebugInfo = /** + * Render debug infos. (including name, bounds info, position and some other properties) + * @param x {number} X position of the debug info to be rendered. + * @param y {number} Y position of the debug info to be rendered. + * @param [color] {number} color of the debug info to be rendered. (format is css color string) + */ + function (x, y, color) { + if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } + this.sprite.texture.context.fillStyle = color; + this.sprite.texture.context.fillText('Sprite: (' + this.sprite.width + ' x ' + this.sprite.height + ')', x, y); + //this.sprite.texture.context.fillText('x: ' + this._sprite.frameBounds.x.toFixed(1) + ' y: ' + this._sprite.frameBounds.y.toFixed(1) + ' rotation: ' + this._sprite.rotation.toFixed(1), x, y + 14); + this.sprite.texture.context.fillText('x: ' + this.bounds.x.toFixed(1) + ' y: ' + this.bounds.y.toFixed(1) + ' rotation: ' + this.sprite.transform.rotation.toFixed(0), x, y + 14); + this.sprite.texture.context.fillText('vx: ' + this.velocity.x.toFixed(1) + ' vy: ' + this.velocity.y.toFixed(1), x, y + 28); + this.sprite.texture.context.fillText('acx: ' + this.acceleration.x.toFixed(1) + ' acy: ' + this.acceleration.y.toFixed(1), x, y + 42); + this.sprite.texture.context.fillText('angVx: ' + this.angularVelocity.toFixed(1) + ' angAc: ' + this.angularAcceleration.toFixed(1), x, y + 56); + }; + return Body; + })(); + Physics.Body = Body; + })(Phaser.Physics || (Phaser.Physics = {})); + var Physics = Phaser.Physics; +})(Phaser || (Phaser = {})); +/// +/// +/// +/// +/// +/// +/// +/// +/// +/** +* Phaser - Sprite +*/ +var Phaser; +(function (Phaser) { + var Sprite = (function () { + /** + * Create a new Sprite. + * + * @param game {Phaser.Game} Current game instance. + * @param [x] {number} the initial x position of the sprite. + * @param [y] {number} the initial y position of the sprite. + * @param [key] {string} Key of the graphic you want to load for this sprite. + * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) + */ + function Sprite(game, x, y, key, frame, bodyType) { + if (typeof x === "undefined") { x = 0; } + if (typeof y === "undefined") { y = 0; } + if (typeof key === "undefined") { key = null; } + if (typeof frame === "undefined") { frame = null; } + if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } + /** + * 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; + /** + * y value of the object. + */ + this.y = 0; + /** + * z order value of the object. + */ + this.z = 0; + /** + * Render iteration counter + */ + this.renderOrderID = 0; + this.game = game; + this.type = Phaser.Types.SPRITE; + this.exists = true; + this.active = true; + this.visible = true; + this.alive = true; + this.x = x; + this.y = y; + this.z = -1; + this.group = null; + this.transform = new Phaser.Components.Transform(this); + this.animations = new Phaser.Components.AnimationManager(this); + this.texture = new Phaser.Components.Texture(this); + this.body = new Phaser.Physics.Body(this, bodyType); + this.input = new Phaser.Components.Sprite.Input(this); + this.events = new Phaser.Components.Sprite.Events(this); + if(key !== null) { + this.texture.loadImage(key, false); + } else { + this.texture.opaque = true; + } + if(frame !== null) { + if(typeof frame == 'string') { + this.frameName = frame; + } else { + this.frame = frame; + } + } + this.worldView = new Phaser.Rectangle(x, y, this.width, this.height); + } + Object.defineProperty(Sprite.prototype, "rotation", { + get: /** + * The rotation of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + */ + function () { + return this.transform.rotation; + }, + set: /** + * Set the rotation of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + * The value is automatically wrapped to be between 0 and 360. + */ + function (value) { + this.transform.rotation = this.game.math.wrap(value, 360, 0); + }, + 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 + }); + Object.defineProperty(Sprite.prototype, "width", { + get: function () { + return this.texture.width * this.transform.scale.x; + }, + set: function (value) { + this.transform.scale.x = value / this.texture.width; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Sprite.prototype, "height", { + get: function () { + return this.texture.height * this.transform.scale.y; + }, + set: function (value) { + this.transform.scale.y = value / this.texture.height; + }, + enumerable: true, + configurable: true + }); + Sprite.prototype.preUpdate = /** + * Pre-update is called right before update() on each object in the game loop. + */ + function () { + this.worldView.x = this.x - (this.game.world.cameras.default.worldView.x * this.transform.scrollFactor.x); + this.worldView.y = this.y - (this.game.world.cameras.default.worldView.y * this.transform.scrollFactor.y); + this.worldView.width = this.width; + this.worldView.height = this.height; + if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.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. + */ + function () { + }; + Sprite.prototype.postUpdate = /** + * Automatically called after update() by the game loop. + */ + function () { + this.animations.update(); + this.body.postUpdate(); + /* + if (this.worldBounds != null) + { + if (this.outOfBoundsAction == GameObject.OUT_OF_BOUNDS_KILL) + { + if (this.x < this.worldBounds.x || this.x > this.worldBounds.right || this.y < this.worldBounds.y || this.y > this.worldBounds.bottom) + { + this.kill(); + } + } + else + { + if (this.x < this.worldBounds.x) + { + this.x = this.worldBounds.x; + } + else if (this.x > this.worldBounds.right) + { + this.x = this.worldBounds.right; + } + + if (this.y < this.worldBounds.y) + { + this.y = this.worldBounds.y; + } + else if (this.y > this.worldBounds.bottom) + { + this.y = this.worldBounds.bottom; + } + } + } + */ + if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { + this.modified = false; + } + }; + Sprite.prototype.destroy = /** + * Clean up memory. + */ + function () { + //this.input.destroy(); + }; + Sprite.prototype.kill = /** + * Handy for "killing" game objects. + * Default behavior is to flag them as nonexistent AND dead. + * However, if you want the "corpse" to remain in the game, + * like to animate an effect or whatever, you should override this, + * setting only alive to false, and leaving exists true. + */ + function (removeFromGroup) { + if (typeof removeFromGroup === "undefined") { removeFromGroup = false; } + this.alive = false; + this.exists = false; + if(removeFromGroup && this.group) { + this.group.remove(this); + } + this.events.onKilled.dispatch(this); + }; + Sprite.prototype.revive = /** + * Handy for bringing game objects "back to life". Just sets alive and exists back to true. + * In practice, this is most often called by Object.reset(). + */ + function () { + this.alive = true; + this.exists = true; + this.events.onRevived.dispatch(this); + }; + return Sprite; + })(); + Phaser.Sprite = Sprite; +})(Phaser || (Phaser = {})); +/// +/// +/// +/// +/// +/// +/** +* Phaser - SpriteUtils +* +* A collection of methods useful for manipulating and checking Sprites. +*/ +var Phaser; +(function (Phaser) { + var SpriteUtils = (function () { + function SpriteUtils() { } + SpriteUtils.inCamera = /** + * Check whether this object is visible in a specific camera Rectangle. + * @param camera {Rectangle} The Rectangle you want to check. + * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. + */ + function inCamera(camera, sprite) { + // Object fixed in place regardless of the camera scrolling? Then it's always visible + if(sprite.transform.scrollFactor.x == 0 && sprite.transform.scrollFactor.y == 0) { + return true; + } + var dx = sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + var dy = sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + var dw = sprite.width * sprite.transform.scale.x; + var dh = sprite.height * sprite.transform.scale.y; + return (camera.screenView.x + camera.worldView.width > this._dx) && (camera.screenView.x < this._dx + this._dw) && (camera.screenView.y + camera.worldView.height > this._dy) && (camera.screenView.y < this._dy + this._dh); + }; + SpriteUtils.getAsPoints = function getAsPoints(sprite) { + var out = []; + // top left + out.push(new Phaser.Point(sprite.x, sprite.y)); + // top right + out.push(new Phaser.Point(sprite.x + sprite.width, sprite.y)); + // bottom right + out.push(new Phaser.Point(sprite.x + sprite.width, sprite.y + sprite.height)); + // bottom left + out.push(new Phaser.Point(sprite.x, sprite.y + sprite.height)); + return out; + }; + SpriteUtils.overlapsPoint = /** + * Checks to see if some GameObject overlaps this GameObject or Group. + * If the group has a LOT of things in it, it might be faster to use Collision.overlaps(). + * WARNING: Currently tilemaps do NOT support screen space overlap checks! + * + * @param objectOrGroup {object} The object or group being tested. + * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return {boolean} Whether or not the objects overlap this. + */ + /* + static overlaps(objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { + + if (objectOrGroup.isGroup) + { + var results: bool = false; + var i: number = 0; + var members = objectOrGroup.members; + + while (i < length) + { + if (this.overlaps(members[i++], inScreenSpace, camera)) + { + results = true; + } + } + + return results; + + } + + if (!inScreenSpace) + { + return (objectOrGroup.x + objectOrGroup.width > this.x) && (objectOrGroup.x < this.x + this.width) && + (objectOrGroup.y + objectOrGroup.height > this.y) && (objectOrGroup.y < this.y + this.height); + } + + if (camera == null) + { + camera = this._game.camera; + } + + var objectScreenPos: Point = objectOrGroup.getScreenXY(null, camera); + + this.getScreenXY(this._point, camera); + + return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && + (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); + } + */ + /** + * Checks to see if this GameObject were located at the given position, would it overlap the GameObject or Group? + * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size numbero account. + * WARNING: Currently tilemaps do NOT support screen space overlap checks! + * + * @param X {number} The X position you want to check. Pretends this object (the caller, not the parameter) is located here. + * @param Y {number} The Y position you want to check. Pretends this object (the caller, not the parameter) is located here. + * @param objectOrGroup {object} The object or group being tested. + * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return {boolean} Whether or not the two objects overlap. + */ + /* + static overlapsAt(X: number, Y: number, objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { + + if (objectOrGroup.isGroup) + { + var results: bool = false; + var basic; + var i: number = 0; + var members = objectOrGroup.members; + + while (i < length) + { + if (this.overlapsAt(X, Y, members[i++], inScreenSpace, camera)) + { + results = true; + } + } + + return results; + } + + if (!inScreenSpace) + { + return (objectOrGroup.x + objectOrGroup.width > X) && (objectOrGroup.x < X + this.width) && + (objectOrGroup.y + objectOrGroup.height > Y) && (objectOrGroup.y < Y + this.height); + } + + if (camera == null) + { + camera = this._game.camera; + } + + var objectScreenPos: Point = objectOrGroup.getScreenXY(null, Camera); + + this._point.x = X - camera.scroll.x * this.transform.scrollFactor.x; //copied from getScreenXY() + this._point.y = Y - camera.scroll.y * this.transform.scrollFactor.y; + this._point.x += (this._point.x > 0) ? 0.0000001 : -0.0000001; + this._point.y += (this._point.y > 0) ? 0.0000001 : -0.0000001; + + return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && + (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); + } + */ + /** + * Checks to see if a point in 2D world space overlaps this GameObject. + * + * @param point {Point} The point in world space you want to check. + * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return Whether or not the point overlaps this object. + */ + function overlapsPoint(sprite, point, inScreenSpace, camera) { + if (typeof inScreenSpace === "undefined") { inScreenSpace = false; } + if (typeof camera === "undefined") { camera = null; } + if(!inScreenSpace) { + return Phaser.RectangleUtils.containsPoint(sprite.body.bounds, point); + //return (point.x > sprite.x) && (point.x < sprite.x + sprite.width) && (point.y > sprite.y) && (point.y < sprite.y + sprite.height); + } + if(camera == null) { + camera = sprite.game.camera; + } + //var x: number = point.x - camera.scroll.x; + //var y: number = point.y - camera.scroll.y; + //this.getScreenXY(this._point, camera); + //return (x > this._point.x) && (X < this._point.x + this.width) && (Y > this._point.y) && (Y < this._point.y + this.height); + }; + SpriteUtils.onScreen = /** + * Check and see if this object is currently on screen. + * + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return {boolean} Whether the object is on screen or not. + */ + function onScreen(sprite, camera) { + if (typeof camera === "undefined") { camera = null; } + if(camera == null) { + camera = sprite.game.camera; + } + SpriteUtils.getScreenXY(sprite, SpriteUtils._tempPoint, camera); + return (SpriteUtils._tempPoint.x + sprite.width > 0) && (SpriteUtils._tempPoint.x < camera.width) && (SpriteUtils._tempPoint.y + sprite.height > 0) && (SpriteUtils._tempPoint.y < camera.height); + }; + SpriteUtils.getScreenXY = /** + * Call this to figure out the on-screen position of the object. + * + * @param point {Point} Takes a Point object and assigns the post-scrolled X and Y values of this object to it. + * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * + * @return {Point} The Point you passed in, or a new Point if you didn't pass one, containing the screen X and Y position of this object. + */ + function getScreenXY(sprite, point, camera) { + if (typeof point === "undefined") { point = null; } + if (typeof camera === "undefined") { camera = null; } + if(point == null) { + point = new Phaser.Point(); + } + if(camera == null) { + camera = this._game.camera; + } + point.x = sprite.x - camera.x * sprite.transform.scrollFactor.x; + point.y = sprite.y - camera.y * sprite.transform.scrollFactor.y; + point.x += (point.x > 0) ? 0.0000001 : -0.0000001; + point.y += (point.y > 0) ? 0.0000001 : -0.0000001; + return point; + }; + SpriteUtils.reset = /** + * Set the world bounds that this GameObject can exist within based on the size of the current game world. + * + * @param action {number} The action to take if the object hits the world bounds, either OUT_OF_BOUNDS_KILL or OUT_OF_BOUNDS_STOP + */ + /* + static setBoundsFromWorld(action?: number = GameObject.OUT_OF_BOUNDS_STOP) { + + this.setBounds(this._game.world.bounds.x, this._game.world.bounds.y, this._game.world.bounds.width, this._game.world.bounds.height); + this.outOfBoundsAction = action; + + } + */ + /** + * Handy for reviving game objects. + * Resets their existence flags and position. + * + * @param x {number} The new X position of this object. + * @param y {number} The new Y position of this object. + */ + function reset(sprite, x, y) { + sprite.revive(); + sprite.body.touching = Phaser.Types.NONE; + sprite.body.wasTouching = Phaser.Types.NONE; + sprite.x = x; + sprite.y = y; + sprite.body.velocity.x = 0; + sprite.body.velocity.y = 0; + sprite.body.position.x = x; + sprite.body.position.y = y; + }; + SpriteUtils.setOriginToCenter = function setOriginToCenter(sprite, fromFrameBounds, fromBody) { + if (typeof fromFrameBounds === "undefined") { fromFrameBounds = true; } + if (typeof fromBody === "undefined") { fromBody = false; } + if(fromFrameBounds) { + sprite.transform.origin.setTo(sprite.width / 2, sprite.height / 2); + } else if(fromBody) { + sprite.transform.origin.setTo(sprite.body.bounds.halfWidth, sprite.body.bounds.halfHeight); + } + }; + SpriteUtils.setBounds = /** + * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere + * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) + * it can be stopped from leaving the world, or a section of it. + * + * @param x {number} x position of the bound + * @param y {number} y position of the bound + * @param width {number} width of its bound + * @param height {number} height of its bound + */ + function setBounds(x, y, width, height) { + //this.worldBounds = new Quad(x, y, width, height); + }; + return SpriteUtils; + })(); + Phaser.SpriteUtils = SpriteUtils; + /** + * This function creates a flat colored square image dynamically. + * @param width {number} The width of the sprite you want to generate. + * @param height {number} The height of the sprite you want to generate. + * @param [color] {number} specifies the color of the generated block. (format is 0xAARRGGBB) + * @return {Sprite} Sprite instance itself. + */ + /* + static makeGraphic(width: number, height: number, color: string = 'rgb(255,255,255)'): Sprite { + + this._texture = null; + this.width = width; + this.height = height; + this.fillColor = color; + this._dynamicTexture = false; + + return this; + } + */ + })(Phaser || (Phaser = {})); +var Phaser; +(function (Phaser) { + /// + /// + /// + /** + * Phaser - Components - Texture + * + * The Texture being used to render the object (Sprite, Group background, etc). Either Image based on a DynamicTexture. + */ + (function (Components) { + var Texture = (function () { + /** + * Creates a new Texture component + * @param parent The object using this Texture to render. + * @param key An optional Game.Cache key to load an image from + */ + function Texture(parent) { + /** + * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. + */ + this.imageTexture = null; + /** + * Reference to the DynamicTexture that is used as the texture for the Sprite. + * @type {DynamicTexture} + */ + this.dynamicTexture = null; + /** + * The load status of the texture image. + * @type {boolean} + */ + this.loaded = false; + /** + * Whether the Sprite background is opaque or not. If set to true the Sprite is filled with + * the value of Texture.backgroundColor every frame. Normally you wouldn't enable this but + * for some effects it can be handy. + * @type {boolean} + */ + this.opaque = false; + /** + * The Background Color of the Sprite if Texture.opaque is set to true. + * Given in css color string format, i.e. 'rgb(0,0,0)' or '#ff0000'. + * @type {string} + */ + this.backgroundColor = 'rgb(255,255,255)'; + /** + * You can set a globalCompositeOperation that will be applied before the render method is called on this Sprite. + * This is useful if you wish to apply an effect like 'lighten'. + * If this value is set it will call a canvas context save and restore before and after the render pass, so use it sparingly. + * Set to null to disable. + */ + this.globalCompositeOperation = null; + /** + * Controls if the Sprite is rendered rotated or not. + * If renderRotation is false then the object can still rotate but it will never be rendered rotated. + * @type {boolean} + */ + this.renderRotation = true; + /** + * Flip the graphic horizontally (defaults to false) + * @type {boolean} + */ + this.flippedX = false; + /** + * Flip the graphic vertically (defaults to false) + * @type {boolean} + */ + this.flippedY = false; + /** + * Is the texture a DynamicTexture? + * @type {boolean} + */ + this.isDynamic = false; + this.game = parent.game; + this.parent = parent; + this.canvas = parent.game.stage.canvas; + this.context = parent.game.stage.context; + this.alpha = 1; + this.flippedX = false; + this.flippedY = false; + this._width = 16; + this._height = 16; + this.cameraBlacklist = []; + } + Texture.prototype.setTo = /** + * Updates the texture being used to render the Sprite. + * Called automatically by SpriteUtils.loadTexture and SpriteUtils.loadDynamicTexture. + */ + function (image, dynamic) { + if (typeof image === "undefined") { image = null; } + if (typeof dynamic === "undefined") { dynamic = null; } + if(dynamic) { + this.isDynamic = true; + this.dynamicTexture = dynamic; + this.texture = this.dynamicTexture.canvas; + } else { + this.isDynamic = false; + this.imageTexture = image; + this.texture = this.imageTexture; + this._width = image.width; + this._height = image.height; + } + this.loaded = true; + return this.parent; + }; + Texture.prototype.loadImage = /** + * Sets a new graphic from the game cache to use as the texture for this Sprite. + * The graphic can be SpriteSheet or Texture Atlas. If you need to use a DynamicTexture see loadDynamicTexture. + * @param key {string} Key of the graphic you want to load for this sprite. + * @param clearAnimations {boolean} If this Sprite has a set of animation data already loaded you can choose to keep or clear it with this boolean + * @param updateBody {boolean} Update the physics body dimensions to match the newly loaded texture/frame? + */ + function (key, clearAnimations, updateBody) { + if (typeof clearAnimations === "undefined") { clearAnimations = true; } + if (typeof updateBody === "undefined") { updateBody = true; } + if(clearAnimations && this.parent['animations'] && this.parent['animations'].frameData !== null) { + this.parent.animations.destroy(); + } + if(this.game.cache.getImage(key) !== null) { + this.setTo(this.game.cache.getImage(key), null); + this.cacheKey = key; + if(this.game.cache.isSpriteSheet(key) && this.parent['animations']) { + this.parent.animations.loadFrameData(this.parent.game.cache.getFrameData(key)); + } else { + if(updateBody && this.parent['body']) { + this.parent.body.bounds.width = this.width; + this.parent.body.bounds.height = this.height; + } + } + } + }; + Texture.prototype.loadDynamicTexture = /** + * Load a DynamicTexture as its texture. + * @param texture {DynamicTexture} The texture object to be used by this sprite. + */ + function (texture) { + if(this.parent.animations.frameData !== null) { + this.parent.animations.destroy(); + } + this.setTo(null, texture); + this.parent.texture.width = this.width; + this.parent.texture.height = this.height; + }; + Object.defineProperty(Texture.prototype, "width", { + get: /** + * The width of the texture. If an animation it will be the frame width, not the width of the sprite sheet. + * If using a DynamicTexture it will be the width of the dynamic texture itself. + * @type {number} + */ + function () { + if(this.isDynamic) { + return this.dynamicTexture.width; + } else { + return this._width; + } + }, + set: function (value) { + this._width = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Texture.prototype, "height", { + get: /** + * The height of the texture. If an animation it will be the frame height, not the height of the sprite sheet. + * If using a DynamicTexture it will be the height of the dynamic texture itself. + * @type {number} + */ + function () { + if(this.isDynamic) { + return this.dynamicTexture.height; + } else { + return this._height; + } + }, + set: function (value) { + this._height = value; + }, + enumerable: true, + configurable: true + }); + return Texture; + })(); + Components.Texture = Texture; + })(Phaser.Components || (Phaser.Components = {})); + var Components = Phaser.Components; +})(Phaser || (Phaser = {})); +/// /// +/// +/// /** * Phaser - Group * @@ -1296,18 +4653,9 @@ var Phaser; */ this.group = null; /** - * You can set a globalCompositeOperation that will be applied before the render method is called on this Groups children. - * This is useful if you wish to apply an effect like 'lighten' to a whole group of children as it saves doing it one-by-one. - * If this value is set it will call a canvas context save and restore before and after the render pass. - * Set to null to disable. + * A boolean representing if the Group has been modified in any way via a scale, rotate, flip or skew. */ - this.globalCompositeOperation = null; - /** - * You can set an alpha value on this Group that will be applied before the render method is called on this Groups children. - * This is useful if you wish to alpha a whole group of children as it saves doing it one-by-one. - * Set to 0 to disable. - */ - this.alpha = 0; + this.modified = false; this.game = game; this.type = Phaser.Types.GROUP; this.exists = true; @@ -1317,8 +4665,10 @@ var Phaser; this._maxSize = maxSize; this._marker = 0; this._sortIndex = null; - this.cameraBlacklist = []; this.ID = this.game.world.getNextGroupID(); + this.transform = new Phaser.Components.Transform(this); + this.texture = new Phaser.Components.Texture(this); + this.texture.opaque = false; } Group.ASCENDING = -1; Group.DESCENDING = 1; @@ -1350,6 +4700,11 @@ var Phaser; * You can also call Object.update directly, which will bypass the active/exists check. */ function () { + if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { + this.modified = true; + } else if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { + this.modified = false; + } this._i = 0; while(this._i < this.length) { this._member = this.members[this._i++]; @@ -1368,14 +4723,7 @@ var Phaser; if(camera.isHidden(this) == true) { return; } - if(this.globalCompositeOperation) { - this.game.stage.context.save(); - this.game.stage.context.globalCompositeOperation = this.globalCompositeOperation; - } - if(this.alpha > 0) { - this._prevAlpha = this.game.stage.context.globalAlpha; - this.game.stage.context.globalAlpha = this.alpha; - } + this.game.renderer.preRenderGroup(camera, this); this._i = 0; while(this._i < this.length) { this._member = this.members[this._i++]; @@ -1387,26 +4735,14 @@ var Phaser; } } } - if(this.alpha > 0) { - this.game.stage.context.globalAlpha = this._prevAlpha; - } - if(this.globalCompositeOperation) { - this.game.stage.context.restore(); - } + this.game.renderer.postRenderGroup(camera, this); }; Group.prototype.directRender = /** * Calls render on all members of this Group regardless of their visible status and also ignores the camera blacklist. * Use this when the Group objects render to hidden canvases for example. */ function (camera) { - if(this.globalCompositeOperation) { - this.game.stage.context.save(); - this.game.stage.context.globalCompositeOperation = this.globalCompositeOperation; - } - if(this.alpha > 0) { - this._prevAlpha = this.game.stage.context.globalAlpha; - this.game.stage.context.globalAlpha = this.alpha; - } + this.game.renderer.preRenderGroup(camera, this); this._i = 0; while(this._i < this.length) { this._member = this.members[this._i++]; @@ -1418,12 +4754,7 @@ var Phaser; } } } - if(this.alpha > 0) { - this.game.stage.context.globalAlpha = this._prevAlpha; - } - if(this.globalCompositeOperation) { - this.game.stage.context.restore(); - } + this.game.renderer.postRenderGroup(camera, this); }; Object.defineProperty(Group.prototype, "maxSize", { get: /** @@ -1514,13 +4845,15 @@ var Phaser; * @param x {number} X position of the new sprite. * @param y {number} Y position of the new sprite. * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this sprite + * @param [frame] {string|number} If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name. * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) * @returns {Sprite} The newly created sprite object. */ - function (x, y, key, bodyType) { + function (x, y, key, frame, bodyType) { if (typeof key === "undefined") { key = ''; } + if (typeof frame === "undefined") { frame = null; } if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } - return this.add(new Phaser.Sprite(this.game, x, y, key, bodyType)); + return this.add(new Phaser.Sprite(this.game, x, y, key, frame, bodyType)); }; Group.prototype.setObjectIDs = /** * Sets all of the game object properties needed to exist within this Group. @@ -1655,7 +4988,7 @@ var Phaser; * State.update() override. To sort all existing objects after * a big explosion or bomb attack, you might call myGroup.sort("exists",Group.DESCENDING). * - * @param {string} index The string name of the member variable you want to sort on. Default value is "y". + * @param {string} index The string name of the member variable you want to sort on. Default value is "z". * @param {number} order A Group constant that defines the sort order. Possible values are Group.ASCENDING and Group.DESCENDING. Default value is Group.ASCENDING. */ function (index, order) { @@ -2422,7 +5755,7 @@ var Phaser; url: textureURL, data: null, atlasURL: null, - atlasData: atlasData['frames'], + atlasData: atlasData, format: format, error: false, loaded: false @@ -3261,7 +6594,7 @@ var Phaser; return Math.atan2(y2 - y1, x2 - x1); }; GameMath.prototype.normalizeAngle = /** - * set an angle with in the bounds of -PI to PI + * set an angle within the bounds of -PI to PI */ function (angle, radians) { if (typeof radians === "undefined") { radians = true; } @@ -3835,27 +7168,27 @@ var Phaser; return Math.sqrt(dx * dx + dy * dy); }; GameMath.prototype.rotatePoint = /** - * Rotates the point around the x/y coordinates given to the desired angle and distance + * Rotates the point around the x/y coordinates given to the desired rotation and distance * @param point {Object} Any object with exposed x and y properties * @param x {number} The x coordinate of the anchor point * @param y {number} The y coordinate of the anchor point - * @param {Number} angle The angle in radians (unless asDegrees is true) to return the point from. - * @param {Boolean} asDegrees Is the given angle in radians (false) or degrees (true)? + * @param {Number} rotation The rotation in radians (unless asDegrees is true) to return the point from. + * @param {Boolean} asDegrees Is the given rotation in radians (false) or degrees (true)? * @param {Number} distance An optional distance constraint between the point and the anchor * @return The modified point object */ - function (point, x1, y1, angle, asDegrees, distance) { + function (point, x1, y1, rotation, asDegrees, distance) { if (typeof asDegrees === "undefined") { asDegrees = false; } if (typeof distance === "undefined") { distance = null; } if(asDegrees) { - angle = angle * GameMath.DEG_TO_RAD; + rotation = rotation * GameMath.DEG_TO_RAD; } // Get distance from origin to the point if(distance === null) { distance = Math.sqrt(((x1 - point.x) * (x1 - point.x)) + ((y1 - point.y) * (y1 - point.y))); } - point.x = x1 + distance * Math.cos(angle); - point.y = y1 + distance * Math.sin(angle); + point.x = x1 + distance * Math.cos(rotation); + point.y = y1 + distance * Math.sin(rotation); return point; }; return GameMath; @@ -4089,3278 +7422,6 @@ var Phaser; })(); Phaser.RandomDataGenerator = RandomDataGenerator; })(Phaser || (Phaser = {})); -/// -/** -* Phaser - AnimationLoader -* -* Responsible for parsing sprite sheet and JSON data into the internal FrameData format that Phaser uses for animations. -*/ -var Phaser; -(function (Phaser) { - var AnimationLoader = (function () { - function AnimationLoader() { } - AnimationLoader.parseSpriteSheet = /** - * Parse a sprite sheet from asset data. - * @param key {string} Asset key for the sprite sheet data. - * @param frameWidth {number} Width of animation frame. - * @param frameHeight {number} Height of animation frame. - * @param frameMax {number} Number of animation frames. - * @return {FrameData} Generated FrameData object. - */ - function parseSpriteSheet(game, key, frameWidth, frameHeight, frameMax) { - // How big is our image? - var img = game.cache.getImage(key); - if(img == null) { - return null; - } - var width = img.width; - var height = img.height; - var row = Math.round(width / frameWidth); - var column = Math.round(height / frameHeight); - var total = row * column; - if(frameMax !== -1) { - total = frameMax; - } - // Zero or smaller than frame sizes? - if(width == 0 || height == 0 || width < frameWidth || height < frameHeight || total === 0) { - return null; - } - // Let's create some frames then - var data = new Phaser.FrameData(); - var x = 0; - var y = 0; - for(var i = 0; i < total; i++) { - data.addFrame(new Phaser.Frame(x, y, frameWidth, frameHeight, '')); - x += frameWidth; - if(x === width) { - x = 0; - y += frameHeight; - } - } - return data; - }; - AnimationLoader.parseJSONData = /** - * Parse frame datas from json. - * @param json {object} Json data you want to parse. - * @return {FrameData} Generated FrameData object. - */ - function parseJSONData(game, json) { - // Malformed? - if(!json['frames']) { - throw new Error("Phaser.AnimationLoader.parseJSONData: Invalid Texture Atlas JSON given, missing 'frames' array"); - } - // Let's create some frames then - var data = new Phaser.FrameData(); - // By this stage frames is a fully parsed array - var frames = json['frames']; - var newFrame; - for(var i = 0; i < frames.length; i++) { - newFrame = data.addFrame(new Phaser.Frame(frames[i].frame.x, frames[i].frame.y, frames[i].frame.w, frames[i].frame.h, frames[i].filename)); - newFrame.setTrim(frames[i].trimmed, frames[i].sourceSize.w, frames[i].sourceSize.h, frames[i].spriteSourceSize.x, frames[i].spriteSourceSize.y, frames[i].spriteSourceSize.w, frames[i].spriteSourceSize.h); - } - return data; - }; - AnimationLoader.parseXMLData = function parseXMLData(game, xml, format) { - // Malformed? - if(!xml.getElementsByTagName('TextureAtlas')) { - throw new Error("Phaser.AnimationLoader.parseXMLData: Invalid Texture Atlas XML given, missing tag"); - } - // Let's create some frames then - var data = new Phaser.FrameData(); - var frames = xml.getElementsByTagName('SubTexture'); - var newFrame; - for(var i = 0; i < frames.length; i++) { - var frame = frames[i].attributes; - newFrame = data.addFrame(new Phaser.Frame(frame.x.nodeValue, frame.y.nodeValue, frame.width.nodeValue, frame.height.nodeValue, frame.name.nodeValue)); - // Trimmed? - if(frame.frameX.nodeValue != '-0' || frame.frameY.nodeValue != '-0') { - newFrame.setTrim(true, frame.width.nodeValue, frame.height.nodeValue, Math.abs(frame.frameX.nodeValue), Math.abs(frame.frameY.nodeValue), frame.frameWidth.nodeValue, frame.frameHeight.nodeValue); - } - } - return data; - }; - return AnimationLoader; - })(); - Phaser.AnimationLoader = AnimationLoader; -})(Phaser || (Phaser = {})); -/// -/** -* Phaser - Animation -* -* An Animation is a single animation. It is created by the AnimationManager and belongs to Sprite objects. -*/ -var Phaser; -(function (Phaser) { - var Animation = (function () { - /** - * Animation constructor - * Create a new Animation. - * - * @param parent {Sprite} Owner sprite of this animation. - * @param frameData {FrameData} The FrameData object contains animation data. - * @param name {string} Unique name of this animation. - * @param frames {number[]/string[]} An array of numbers or strings indicating what frames to play in what order. - * @param delay {number} Time between frames in ms. - * @param looped {boolean} Whether or not the animation is looped or just plays once. - */ - function Animation(game, parent, frameData, name, frames, delay, looped) { - this._game = game; - this._parent = parent; - this._frames = frames; - this._frameData = frameData; - this.name = name; - this.delay = 1000 / delay; - this.looped = looped; - this.isFinished = false; - this.isPlaying = false; - this._frameIndex = 0; - this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); - } - Object.defineProperty(Animation.prototype, "frameTotal", { - get: function () { - return this._frames.length; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Animation.prototype, "frame", { - get: function () { - if(this.currentFrame !== null) { - return this.currentFrame.index; - } else { - return this._frameIndex; - } - }, - set: function (value) { - this.currentFrame = this._frameData.getFrame(value); - if(this.currentFrame !== null) { - this._parent.frameBounds.width = this.currentFrame.width; - this._parent.frameBounds.height = this.currentFrame.height; - this._frameIndex = value; - } - }, - enumerable: true, - configurable: true - }); - Animation.prototype.play = /** - * Play this animation. - * @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 (frameRate, loop) { - if (typeof frameRate === "undefined") { frameRate = null; } - if(frameRate !== null) { - this.delay = 1000 / frameRate; - } - if(loop !== undefined) { - this.looped = loop; - } - this.isPlaying = true; - this.isFinished = false; - this._timeLastFrame = this._game.time.now; - this._timeNextFrame = this._game.time.now + this.delay; - this._frameIndex = 0; - this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); - }; - Animation.prototype.restart = /** - * Play this animation from the first frame. - */ - function () { - this.isPlaying = true; - this.isFinished = false; - this._timeLastFrame = this._game.time.now; - this._timeNextFrame = this._game.time.now + this.delay; - this._frameIndex = 0; - this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); - }; - Animation.prototype.stop = /** - * Stop playing animation and set it finished. - */ - function () { - this.isPlaying = false; - this.isFinished = true; - }; - Animation.prototype.update = /** - * Update animation frames. - */ - function () { - if(this.isPlaying == true && this._game.time.now >= this._timeNextFrame) { - this._frameIndex++; - if(this._frameIndex == this._frames.length) { - if(this.looped) { - this._frameIndex = 0; - this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); - } else { - this.onComplete(); - } - } else { - this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); - } - this._timeLastFrame = this._game.time.now; - this._timeNextFrame = this._game.time.now + this.delay; - return true; - } - return false; - }; - Animation.prototype.destroy = /** - * Clean up animation memory. - */ - function () { - this._game = null; - this._parent = null; - this._frames = null; - this._frameData = null; - this.currentFrame = null; - this.isPlaying = false; - }; - Animation.prototype.onComplete = /** - * Animation complete callback method. - */ - function () { - this.isPlaying = false; - this.isFinished = true; - // callback goes here - }; - return Animation; - })(); - Phaser.Animation = Animation; -})(Phaser || (Phaser = {})); -/// -/** -* Phaser - Frame -* -* A Frame is a single frame of an animation and is part of a FrameData collection. -*/ -var Phaser; -(function (Phaser) { - var Frame = (function () { - /** - * Frame constructor - * Create a new Frame with specific position, size and name. - * - * @param x {number} X position within the image to cut from. - * @param y {number} Y position within the image to cut from. - * @param width {number} Width of the frame. - * @param height {number} Height of the frame. - * @param name {string} Name of this frame. - */ - function Frame(x, y, width, height, name) { - /** - * Useful for Texture Atlas files. (is set to the filename value) - */ - this.name = ''; - /** - * Rotated? (not yet implemented) - */ - this.rotated = false; - /** - * Either cw or ccw, rotation is always 90 degrees. - */ - this.rotationDirection = 'cw'; - //console.log('Creating Frame', name, 'x', x, 'y', y, 'width', width, 'height', height); - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.name = name; - this.rotated = false; - this.trimmed = false; - } - Frame.prototype.setRotation = /** - * Set rotation of this frame. (Not yet supported!) - */ - function (rotated, rotationDirection) { - // Not yet supported - }; - Frame.prototype.setTrim = /** - * Set trim of the frame. - * @param trimmed {boolean} Whether this frame trimmed or not. - * @param actualWidth {number} Actual width of this frame. - * @param actualHeight {number} Actual height of this frame. - * @param destX {number} Destination x position. - * @param destY {number} Destination y position. - * @param destWidth {number} Destination draw width. - * @param destHeight {number} Destination draw height. - */ - function (trimmed, actualWidth, actualHeight, destX, destY, destWidth, destHeight) { - this.trimmed = trimmed; - this.sourceSizeW = actualWidth; - this.sourceSizeH = actualHeight; - this.spriteSourceSizeX = destX; - this.spriteSourceSizeY = destY; - this.spriteSourceSizeW = destWidth; - this.spriteSourceSizeH = destHeight; - }; - return Frame; - })(); - Phaser.Frame = Frame; -})(Phaser || (Phaser = {})); -/// -/** -* Phaser - FrameData -* -* FrameData is a container for Frame objects, the internal representation of animation data in Phaser. -*/ -var Phaser; -(function (Phaser) { - var FrameData = (function () { - /** - * FrameData constructor - */ - function FrameData() { - this._frames = []; - this._frameNames = []; - } - Object.defineProperty(FrameData.prototype, "total", { - get: function () { - return this._frames.length; - }, - enumerable: true, - configurable: true - }); - FrameData.prototype.addFrame = /** - * Add a new frame. - * @param frame {Frame} The frame you want to add. - * @return {Frame} The frame you just added. - */ - function (frame) { - frame.index = this._frames.length; - this._frames.push(frame); - if(frame.name !== '') { - this._frameNames[frame.name] = frame.index; - } - return frame; - }; - FrameData.prototype.getFrame = /** - * Get a frame by its index. - * @param index {number} Index of the frame you want to get. - * @return {Frame} The frame you want. - */ - function (index) { - if(this._frames[index]) { - return this._frames[index]; - } - return null; - }; - FrameData.prototype.getFrameByName = /** - * Get a frame by its name. - * @param name {string} Name of the frame you want to get. - * @return {Frame} The frame you want. - */ - function (name) { - if(this._frameNames[name] !== '') { - return this._frames[this._frameNames[name]]; - } - return null; - }; - FrameData.prototype.checkFrameName = /** - * Check whether there's a frame with given name. - * @param name {string} Name of the frame you want to check. - * @return {boolean} True if frame with given name found, otherwise return false. - */ - function (name) { - if(this._frameNames[name]) { - return true; - } - return false; - }; - FrameData.prototype.getFrameRange = /** - * Get ranges of frames in an array. - * @param start {number} Start index of frames you want. - * @param end {number} End index of frames you want. - * @param [output] {Frame[]} result will be added into this array. - * @return {Frame[]} Ranges of specific frames in an array. - */ - function (start, end, output) { - if (typeof output === "undefined") { output = []; } - for(var i = start; i <= end; i++) { - output.push(this._frames[i]); - } - return output; - }; - FrameData.prototype.getFrameIndexes = /** - * Get all indexes of frames by giving their name. - * @param [output] {number[]} result will be added into this array. - * @return {number[]} Indexes of specific frames in an array. - */ - function (output) { - if (typeof output === "undefined") { output = []; } - output.length = 0; - for(var i = 0; i < this._frames.length; i++) { - output.push(i); - } - return output; - }; - FrameData.prototype.getFrameIndexesByName = /** - * Get the frame indexes by giving the frame names. - * @param [output] {number[]} result will be added into this array. - * @return {number[]} Names of specific frames in an array. - */ - function (input) { - var output = []; - for(var i = 0; i < input.length; i++) { - if(this.getFrameByName(input[i])) { - output.push(this.getFrameByName(input[i]).index); - } - } - return output; - }; - FrameData.prototype.getAllFrames = /** - * Get all frames in this frame data. - * @return {Frame[]} All the frames in an array. - */ - function () { - return this._frames; - }; - FrameData.prototype.getFrames = /** - * Get All frames with specific ranges. - * @param range {number[]} Ranges in an array. - * @return {Frame[]} All frames in an array. - */ - function (range) { - var output = []; - for(var i = 0; i < range.length; i++) { - output.push(this._frames[i]); - } - return output; - }; - return FrameData; - })(); - Phaser.FrameData = FrameData; -})(Phaser || (Phaser = {})); -var Phaser; -(function (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. - */ - (function (Components) { - var AnimationManager = (function () { - /** - * AnimationManager constructor - * Create a new AnimationManager. - * - * @param parent {Sprite} Owner sprite of this manager. - */ - 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 = { - }; - } - 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(frames == null) { - frames = this._frameData.getFrameIndexes(); - } else { - if(this.validateFrames(frames, useNumericIndex) == false) { - throw Error('Invalid frames given to Animation ' + name); - 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; - } - } 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); - } - } - }; - 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._parent.frameBounds.width = this.currentFrame.sourceSizeW; - //this._parent.frameBounds.height = this.currentFrame.sourceSizeH; - 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 = {})); -/// -/// -/// -/** -* Phaser - RectangleUtils -* -* A collection of methods useful for manipulating and comparing Rectangle objects. -* -* TODO: Check docs + overlap + intersect + toPolygon? -*/ -var Phaser; -(function (Phaser) { - var RectangleUtils = (function () { - function RectangleUtils() { } - RectangleUtils.getTopLeftAsPoint = /** - * Get the location of the Rectangles top-left corner as a Point object. - * @method getTopLeftAsPoint - * @param {Rectangle} a - The Rectangle object. - * @param {Point} out - Optional Point to store the value in, if not supplied a new Point object will be created. - * @return {Point} The new Point object. - **/ - function getTopLeftAsPoint(a, out) { - if (typeof out === "undefined") { out = new Phaser.Point(); } - return out.setTo(a.x, a.y); - }; - RectangleUtils.getBottomRightAsPoint = /** - * Get the location of the Rectangles bottom-right corner as a Point object. - * @method getTopLeftAsPoint - * @param {Rectangle} a - The Rectangle object. - * @param {Point} out - Optional Point to store the value in, if not supplied a new Point object will be created. - * @return {Point} The new Point object. - **/ - function getBottomRightAsPoint(a, out) { - if (typeof out === "undefined") { out = new Phaser.Point(); } - return out.setTo(a.right, a.bottom); - }; - RectangleUtils.inflate = /** - * Increases the size of the Rectangle object by the specified amounts. The center point of the Rectangle object stays the same, and its size increases to the left and right by the dx value, and to the top and the bottom by the dy value. - * @method inflate - * @param {Rectangle} a - The Rectangle object. - * @param {Number} dx The amount to be added to the left side of the Rectangle. - * @param {Number} dy The amount to be added to the bottom side of the Rectangle. - * @return {Rectangle} This Rectangle object. - **/ - function inflate(a, dx, dy) { - a.x -= dx; - a.width += 2 * dx; - a.y -= dy; - a.height += 2 * dy; - return a; - }; - RectangleUtils.inflatePoint = /** - * Increases the size of the Rectangle object. This method is similar to the Rectangle.inflate() method except it takes a Point object as a parameter. - * @method inflatePoint - * @param {Rectangle} a - The Rectangle object. - * @param {Point} point The x property of this Point object is used to increase the horizontal dimension of the Rectangle object. The y property is used to increase the vertical dimension of the Rectangle object. - * @return {Rectangle} The Rectangle object. - **/ - function inflatePoint(a, point) { - return RectangleUtils.inflate(a, point.x, point.y); - }; - RectangleUtils.size = /** - * The size of the Rectangle object, expressed as a Point object with the values of the width and height properties. - * @method size - * @param {Rectangle} a - The Rectangle object. - * @param {Point} output Optional Point object. If given the values will be set into the object, otherwise a brand new Point object will be created and returned. - * @return {Point} The size of the Rectangle object - **/ - function size(a, output) { - if (typeof output === "undefined") { output = new Phaser.Point(); } - return output.setTo(a.width, a.height); - }; - RectangleUtils.clone = /** - * Returns a new Rectangle object with the same values for the x, y, width, and height properties as the original Rectangle object. - * @method clone - * @param {Rectangle} a - The Rectangle object. - * @param {Rectangle} output Optional Rectangle object. If given the values will be set into the object, otherwise a brand new Rectangle object will be created and returned. - * @return {Rectangle} - **/ - function clone(a, output) { - if (typeof output === "undefined") { output = new Phaser.Rectangle(); } - return output.setTo(a.x, a.y, a.width, a.height); - }; - RectangleUtils.contains = /** - * Determines whether the specified coordinates are contained within the region defined by this Rectangle object. - * @method contains - * @param {Rectangle} a - The Rectangle object. - * @param {Number} x The x coordinate of the point to test. - * @param {Number} y The y coordinate of the point to test. - * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. - **/ - function contains(a, x, y) { - return (x >= a.x && x <= a.right && y >= a.y && y <= a.bottom); - }; - RectangleUtils.containsPoint = /** - * Determines whether the specified point is contained within the rectangular region defined by this Rectangle object. This method is similar to the Rectangle.contains() method, except that it takes a Point object as a parameter. - * @method containsPoint - * @param {Rectangle} a - The Rectangle object. - * @param {Point} point The point object being checked. Can be Point or any object with .x and .y values. - * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. - **/ - function containsPoint(a, point) { - return RectangleUtils.contains(a, point.x, point.y); - }; - RectangleUtils.containsRect = /** - * Determines whether the first Rectangle object is fully contained within the second Rectangle object. - * A Rectangle object is said to contain another if the second Rectangle object falls entirely within the boundaries of the first. - * @method containsRect - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @return {Boolean} A value of true if the Rectangle object contains the specified point; otherwise false. - **/ - function containsRect(a, b) { - // If the given rect has a larger volume than this one then it can never contain it - if(a.volume > b.volume) { - return false; - } - return (a.x >= b.x && a.y >= b.y && a.right <= b.right && a.bottom <= b.bottom); - }; - RectangleUtils.equals = /** - * Determines whether the two Rectangles are equal. - * This method compares the x, y, width and height properties of each Rectangle. - * @method equals - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @return {Boolean} A value of true if the two Rectangles have exactly the same values for the x, y, width and height properties; otherwise false. - **/ - function equals(a, b) { - return (a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height); - }; - RectangleUtils.intersection = /** - * If the Rectangle object specified in the toIntersect parameter intersects with this Rectangle object, returns the area of intersection as a Rectangle object. If the rectangles do not intersect, this method returns an empty Rectangle object with its properties set to 0. - * @method intersection - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @param {Rectangle} output Optional Rectangle object. If given the intersection values will be set into this object, otherwise a brand new Rectangle object will be created and returned. - * @return {Rectangle} A Rectangle object that equals the area of intersection. If the rectangles do not intersect, this method returns an empty Rectangle object; that is, a rectangle with its x, y, width, and height properties set to 0. - **/ - function intersection(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Rectangle(); } - if(RectangleUtils.intersects(a, b)) { - out.x = Math.max(a.x, b.x); - out.y = Math.max(a.y, b.y); - out.width = Math.min(a.right, b.right) - out.x; - out.height = Math.min(a.bottom, b.bottom) - out.y; - } - return out; - }; - RectangleUtils.intersects = /** - * Determines whether the two Rectangles intersect with each other. - * This method checks the x, y, width, and height properties of the Rectangles. - * @method intersects - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @param {Number} tolerance A tolerance value to allow for an intersection test with padding, default to 0 - * @return {Boolean} A value of true if the specified object intersects with this Rectangle object; otherwise false. - **/ - function intersects(a, b, tolerance) { - if (typeof tolerance === "undefined") { tolerance = 0; } - return !(a.left > b.right + tolerance || a.right < b.left - tolerance || a.top > b.bottom + tolerance || a.bottom < b.top - tolerance); - }; - RectangleUtils.intersectsRaw = /** - * Determines whether the object specified intersects (overlaps) with the given values. - * @method intersectsRaw - * @param {Number} left - * @param {Number} right - * @param {Number} top - * @param {Number} bottomt - * @param {Number} tolerance A tolerance value to allow for an intersection test with padding, default to 0 - * @return {Boolean} A value of true if the specified object intersects with the Rectangle; otherwise false. - **/ - function intersectsRaw(a, left, right, top, bottom, tolerance) { - if (typeof tolerance === "undefined") { tolerance = 0; } - return !(left > a.right + tolerance || right < a.left - tolerance || top > a.bottom + tolerance || bottom < a.top - tolerance); - }; - RectangleUtils.union = /** - * Adds two rectangles together to create a new Rectangle object, by filling in the horizontal and vertical space between the two rectangles. - * @method union - * @param {Rectangle} a - The first Rectangle object. - * @param {Rectangle} b - The second Rectangle object. - * @param {Rectangle} output Optional Rectangle object. If given the new values will be set into this object, otherwise a brand new Rectangle object will be created and returned. - * @return {Rectangle} A Rectangle object that is the union of the two rectangles. - **/ - function union(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Rectangle(); } - return out.setTo(Math.min(a.x, b.x), Math.min(a.y, b.y), Math.max(a.right, b.right), Math.max(a.bottom, b.bottom)); - }; - return RectangleUtils; - })(); - Phaser.RectangleUtils = RectangleUtils; -})(Phaser || (Phaser = {})); -/// -/// -/// -/// -/** -* Phaser - ColorUtils -* -* A collection of methods useful for manipulating color values. -*/ -var Phaser; -(function (Phaser) { - var ColorUtils = (function () { - function ColorUtils() { } - ColorUtils.getColor32 = /** - * Given an alpha and 3 color values this will return an integer representation of it - * - * @param alpha {number} The Alpha value (between 0 and 255) - * @param red {number} The Red channel value (between 0 and 255) - * @param green {number} The Green channel value (between 0 and 255) - * @param blue {number} The Blue channel value (between 0 and 255) - * - * @return A native color value integer (format: 0xAARRGGBB) - */ - function getColor32(alpha, red, green, blue) { - return alpha << 24 | red << 16 | green << 8 | blue; - }; - ColorUtils.getColor = /** - * Given 3 color values this will return an integer representation of it - * - * @param red {number} The Red channel value (between 0 and 255) - * @param green {number} The Green channel value (between 0 and 255) - * @param blue {number} The Blue channel value (between 0 and 255) - * - * @return A native color value integer (format: 0xRRGGBB) - */ - function getColor(red, green, blue) { - return red << 16 | green << 8 | blue; - }; - ColorUtils.getHSVColorWheel = /** - * Get HSV color wheel values in an array which will be 360 elements in size - * - * @param alpha Alpha value for each color of the color wheel, between 0 (transparent) and 255 (opaque) - * - * @return Array - */ - function getHSVColorWheel(alpha) { - if (typeof alpha === "undefined") { alpha = 255; } - var colors = []; - for(var c = 0; c <= 359; c++) { - //colors[c] = HSVtoRGB(c, 1.0, 1.0, alpha); - colors[c] = ColorUtils.getWebRGB(ColorUtils.HSVtoRGB(c, 1.0, 1.0, alpha)); - } - return colors; - }; - ColorUtils.getComplementHarmony = /** - * Returns a Complementary Color Harmony for the given color. - *

A complementary hue is one directly opposite the color given on the color wheel

- *

Value returned in 0xAARRGGBB format with Alpha set to 255.

- * - * @param color The color to base the harmony on - * - * @return 0xAARRGGBB format color value - */ - function getComplementHarmony(color) { - var hsv = ColorUtils.RGBtoHSV(color); - var opposite = ColorUtils.game.math.wrapValue(hsv.hue, 180, 359); - return ColorUtils.HSVtoRGB(opposite, 1.0, 1.0); - }; - ColorUtils.getAnalogousHarmony = /** - * Returns an Analogous Color Harmony for the given color. - *

An Analogous harmony are hues adjacent to each other on the color wheel

- *

Values returned in 0xAARRGGBB format with Alpha set to 255.

- * - * @param color The color to base the harmony on - * @param threshold Control how adjacent the colors will be (default +- 30 degrees) - * - * @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color) - */ - function getAnalogousHarmony(color, threshold) { - if (typeof threshold === "undefined") { threshold = 30; } - var hsv = ColorUtils.RGBtoHSV(color); - if(threshold > 359 || threshold < 0) { - throw Error("Color Warning: Invalid threshold given to getAnalogousHarmony()"); - } - var warmer = ColorUtils.game.math.wrapValue(hsv.hue, 359 - threshold, 359); - var colder = ColorUtils.game.math.wrapValue(hsv.hue, threshold, 359); - return { - color1: color, - color2: ColorUtils.HSVtoRGB(warmer, 1.0, 1.0), - color3: ColorUtils.HSVtoRGB(colder, 1.0, 1.0), - hue1: hsv.hue, - hue2: warmer, - hue3: colder - }; - }; - ColorUtils.getSplitComplementHarmony = /** - * Returns an Split Complement Color Harmony for the given color. - *

A Split Complement harmony are the two hues on either side of the color's Complement

- *

Values returned in 0xAARRGGBB format with Alpha set to 255.

- * - * @param color The color to base the harmony on - * @param threshold Control how adjacent the colors will be to the Complement (default +- 30 degrees) - * - * @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color) - */ - function getSplitComplementHarmony(color, threshold) { - if (typeof threshold === "undefined") { threshold = 30; } - var hsv = ColorUtils.RGBtoHSV(color); - if(threshold >= 359 || threshold <= 0) { - throw Error("FlxColor Warning: Invalid threshold given to getSplitComplementHarmony()"); - } - var opposite = ColorUtils.game.math.wrapValue(hsv.hue, 180, 359); - var warmer = ColorUtils.game.math.wrapValue(hsv.hue, opposite - threshold, 359); - var colder = ColorUtils.game.math.wrapValue(hsv.hue, opposite + threshold, 359); - return { - color1: color, - color2: ColorUtils.HSVtoRGB(warmer, hsv.saturation, hsv.value), - color3: ColorUtils.HSVtoRGB(colder, hsv.saturation, hsv.value), - hue1: hsv.hue, - hue2: warmer, - hue3: colder - }; - }; - ColorUtils.getTriadicHarmony = /** - * Returns a Triadic Color Harmony for the given color. - *

A Triadic harmony are 3 hues equidistant from each other on the color wheel

- *

Values returned in 0xAARRGGBB format with Alpha set to 255.

- * - * @param color The color to base the harmony on - * - * @return Object containing 3 properties: color1 (the original color), color2 and color3 (the equidistant colors) - */ - function getTriadicHarmony(color) { - var hsv = ColorUtils.RGBtoHSV(color); - var triadic1 = ColorUtils.game.math.wrapValue(hsv.hue, 120, 359); - var triadic2 = ColorUtils.game.math.wrapValue(triadic1, 120, 359); - return { - color1: color, - color2: ColorUtils.HSVtoRGB(triadic1, 1.0, 1.0), - color3: ColorUtils.HSVtoRGB(triadic2, 1.0, 1.0) - }; - }; - ColorUtils.getColorInfo = /** - * Returns a string containing handy information about the given color including string hex value, - * RGB format information and HSL information. Each section starts on a newline, 3 lines in total. - * - * @param color A color value in the format 0xAARRGGBB - * - * @return string containing the 3 lines of information - */ - function getColorInfo(color) { - var argb = ColorUtils.getRGB(color); - var hsl = ColorUtils.RGBtoHSV(color); - // Hex format - var result = ColorUtils.RGBtoHexstring(color) + "\n"; - // RGB format - result = result.concat("Alpha: " + argb.alpha + " Red: " + argb.red + " Green: " + argb.green + " Blue: " + argb.blue) + "\n"; - // HSL info - result = result.concat("Hue: " + hsl.hue + " Saturation: " + hsl.saturation + " Lightnes: " + hsl.lightness); - return result; - }; - ColorUtils.RGBtoHexstring = /** - * Return a string representation of the color in the format 0xAARRGGBB - * - * @param color The color to get the string representation for - * - * @return A string of length 10 characters in the format 0xAARRGGBB - */ - function RGBtoHexstring(color) { - var argb = ColorUtils.getRGB(color); - return "0x" + ColorUtils.colorToHexstring(argb.alpha) + ColorUtils.colorToHexstring(argb.red) + ColorUtils.colorToHexstring(argb.green) + ColorUtils.colorToHexstring(argb.blue); - }; - ColorUtils.RGBtoWebstring = /** - * Return a string representation of the color in the format #RRGGBB - * - * @param color The color to get the string representation for - * - * @return A string of length 10 characters in the format 0xAARRGGBB - */ - function RGBtoWebstring(color) { - var argb = ColorUtils.getRGB(color); - return "#" + ColorUtils.colorToHexstring(argb.red) + ColorUtils.colorToHexstring(argb.green) + ColorUtils.colorToHexstring(argb.blue); - }; - ColorUtils.colorToHexstring = /** - * Return a string containing a hex representation of the given color - * - * @param color The color channel to get the hex value for, must be a value between 0 and 255) - * - * @return A string of length 2 characters, i.e. 255 = FF, 0 = 00 - */ - function colorToHexstring(color) { - var digits = "0123456789ABCDEF"; - var lsd = color % 16; - var msd = (color - lsd) / 16; - var hexified = digits.charAt(msd) + digits.charAt(lsd); - return hexified; - }; - ColorUtils.HSVtoRGB = /** - * Convert a HSV (hue, saturation, lightness) color space value to an RGB color - * - * @param h Hue degree, between 0 and 359 - * @param s Saturation, between 0.0 (grey) and 1.0 - * @param v Value, between 0.0 (black) and 1.0 - * @param alpha Alpha value to set per color (between 0 and 255) - * - * @return 32-bit ARGB color value (0xAARRGGBB) - */ - function HSVtoRGB(h, s, v, alpha) { - if (typeof alpha === "undefined") { alpha = 255; } - var result; - if(s == 0.0) { - result = ColorUtils.getColor32(alpha, v * 255, v * 255, v * 255); - } else { - h = h / 60.0; - var f = h - Math.floor(h); - var p = v * (1.0 - s); - var q = v * (1.0 - s * f); - var t = v * (1.0 - s * (1.0 - f)); - switch(Math.floor(h)) { - case 0: - result = ColorUtils.getColor32(alpha, v * 255, t * 255, p * 255); - break; - case 1: - result = ColorUtils.getColor32(alpha, q * 255, v * 255, p * 255); - break; - case 2: - result = ColorUtils.getColor32(alpha, p * 255, v * 255, t * 255); - break; - case 3: - result = ColorUtils.getColor32(alpha, p * 255, q * 255, v * 255); - break; - case 4: - result = ColorUtils.getColor32(alpha, t * 255, p * 255, v * 255); - break; - case 5: - result = ColorUtils.getColor32(alpha, v * 255, p * 255, q * 255); - break; - default: - throw new Error("ColorUtils.HSVtoRGB : Unknown color"); - } - } - return result; - }; - ColorUtils.RGBtoHSV = /** - * Convert an RGB color value to an object containing the HSV color space values: Hue, Saturation and Lightness - * - * @param color In format 0xRRGGBB - * - * @return Object with the properties hue (from 0 to 360), saturation (from 0 to 1.0) and lightness (from 0 to 1.0, also available under .value) - */ - function RGBtoHSV(color) { - var rgb = ColorUtils.getRGB(color); - var red = rgb.red / 255; - var green = rgb.green / 255; - var blue = rgb.blue / 255; - var min = Math.min(red, green, blue); - var max = Math.max(red, green, blue); - var delta = max - min; - var lightness = (max + min) / 2; - var hue; - var saturation; - // Grey color, no chroma - if(delta == 0) { - hue = 0; - saturation = 0; - } else { - if(lightness < 0.5) { - saturation = delta / (max + min); - } else { - saturation = delta / (2 - max - min); - } - var delta_r = (((max - red) / 6) + (delta / 2)) / delta; - var delta_g = (((max - green) / 6) + (delta / 2)) / delta; - var delta_b = (((max - blue) / 6) + (delta / 2)) / delta; - if(red == max) { - hue = delta_b - delta_g; - } else if(green == max) { - hue = (1 / 3) + delta_r - delta_b; - } else if(blue == max) { - hue = (2 / 3) + delta_g - delta_r; - } - if(hue < 0) { - hue += 1; - } - if(hue > 1) { - hue -= 1; - } - } - // Keep the value with 0 to 359 - hue *= 360; - hue = Math.round(hue); - return { - hue: hue, - saturation: saturation, - lightness: lightness, - value: lightness - }; - }; - ColorUtils.interpolateColor = /** - * - * @method interpolateColor - * @param {Number} color1 - * @param {Number} color2 - * @param {Number} steps - * @param {Number} currentStep - * @param {Number} alpha - * @return {Number} - * @static - */ - function interpolateColor(color1, color2, steps, currentStep, alpha) { - if (typeof alpha === "undefined") { alpha = 255; } - var src1 = ColorUtils.getRGB(color1); - var src2 = ColorUtils.getRGB(color2); - var r = (((src2.red - src1.red) * currentStep) / steps) + src1.red; - var g = (((src2.green - src1.green) * currentStep) / steps) + src1.green; - var b = (((src2.blue - src1.blue) * currentStep) / steps) + src1.blue; - return ColorUtils.getColor32(alpha, r, g, b); - }; - ColorUtils.interpolateColorWithRGB = /** - * - * @method interpolateColorWithRGB - * @param {Number} color - * @param {Number} r2 - * @param {Number} g2 - * @param {Number} b2 - * @param {Number} steps - * @param {Number} currentStep - * @return {Number} - * @static - */ - function interpolateColorWithRGB(color, r2, g2, b2, steps, currentStep) { - var src = ColorUtils.getRGB(color); - var r = (((r2 - src.red) * currentStep) / steps) + src.red; - var g = (((g2 - src.green) * currentStep) / steps) + src.green; - var b = (((b2 - src.blue) * currentStep) / steps) + src.blue; - return ColorUtils.getColor(r, g, b); - }; - ColorUtils.interpolateRGB = /** - * - * @method interpolateRGB - * @param {Number} r1 - * @param {Number} g1 - * @param {Number} b1 - * @param {Number} r2 - * @param {Number} g2 - * @param {Number} b2 - * @param {Number} steps - * @param {Number} currentStep - * @return {Number} - * @static - */ - function interpolateRGB(r1, g1, b1, r2, g2, b2, steps, currentStep) { - var r = (((r2 - r1) * currentStep) / steps) + r1; - var g = (((g2 - g1) * currentStep) / steps) + g1; - var b = (((b2 - b1) * currentStep) / steps) + b1; - return ColorUtils.getColor(r, g, b); - }; - ColorUtils.getRandomColor = /** - * Returns a random color value between black and white - *

Set the min value to start each channel from the given offset.

- *

Set the max value to restrict the maximum color used per channel

- * - * @param min The lowest value to use for the color - * @param max The highest value to use for the color - * @param alpha The alpha value of the returning color (default 255 = fully opaque) - * - * @return 32-bit color value with alpha - */ - function getRandomColor(min, max, alpha) { - if (typeof min === "undefined") { min = 0; } - if (typeof max === "undefined") { max = 255; } - if (typeof alpha === "undefined") { alpha = 255; } - // Sanity checks - if(max > 255) { - return ColorUtils.getColor(255, 255, 255); - } - if(min > max) { - return ColorUtils.getColor(255, 255, 255); - } - var red = min + Math.round(Math.random() * (max - min)); - var green = min + Math.round(Math.random() * (max - min)); - var blue = min + Math.round(Math.random() * (max - min)); - return ColorUtils.getColor32(alpha, red, green, blue); - }; - ColorUtils.getRGB = /** - * Return the component parts of a color as an Object with the properties alpha, red, green, blue - * - *

Alpha will only be set if it exist in the given color (0xAARRGGBB)

- * - * @param color in RGB (0xRRGGBB) or ARGB format (0xAARRGGBB) - * - * @return Object with properties: alpha, red, green, blue - */ - function getRGB(color) { - return { - alpha: color >>> 24, - red: color >> 16 & 0xFF, - green: color >> 8 & 0xFF, - blue: color & 0xFF - }; - }; - ColorUtils.getWebRGB = /** - * - * @method getWebRGB - * @param {Number} color - * @return {Any} - */ - function getWebRGB(color) { - var alpha = (color >>> 24) / 255; - var red = color >> 16 & 0xFF; - var green = color >> 8 & 0xFF; - var blue = color & 0xFF; - return 'rgba(' + red.toString() + ',' + green.toString() + ',' + blue.toString() + ',' + alpha.toString() + ')'; - }; - ColorUtils.getAlpha = /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component, as a value between 0 and 255 - * - * @param color In the format 0xAARRGGBB - * - * @return The Alpha component of the color, will be between 0 and 255 (0 being no Alpha, 255 full Alpha) - */ - function getAlpha(color) { - return color >>> 24; - }; - ColorUtils.getAlphaFloat = /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component as a value between 0 and 1 - * - * @param color In the format 0xAARRGGBB - * - * @return The Alpha component of the color, will be between 0 and 1 (0 being no Alpha (opaque), 1 full Alpha (transparent)) - */ - function getAlphaFloat(color) { - return (color >>> 24) / 255; - }; - ColorUtils.getRed = /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Red component, as a value between 0 and 255 - * - * @param color In the format 0xAARRGGBB - * - * @return The Red component of the color, will be between 0 and 255 (0 being no color, 255 full Red) - */ - function getRed(color) { - return color >> 16 & 0xFF; - }; - ColorUtils.getGreen = /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Green component, as a value between 0 and 255 - * - * @param color In the format 0xAARRGGBB - * - * @return The Green component of the color, will be between 0 and 255 (0 being no color, 255 full Green) - */ - function getGreen(color) { - return color >> 8 & 0xFF; - }; - ColorUtils.getBlue = /** - * Given a native color value (in the format 0xAARRGGBB) this will return the Blue component, as a value between 0 and 255 - * - * @param color In the format 0xAARRGGBB - * - * @return The Blue component of the color, will be between 0 and 255 (0 being no color, 255 full Blue) - */ - function getBlue(color) { - return color & 0xFF; - }; - return ColorUtils; - })(); - Phaser.ColorUtils = ColorUtils; -})(Phaser || (Phaser = {})); -/// -/// -/// -/// -/** -* Phaser - DynamicTexture -* -* A DynamicTexture can be thought of as a mini canvas into which you can draw anything. -* Game Objects can be assigned a DynamicTexture, so when they render in the world they do so -* based on the contents of the texture at the time. This allows you to create powerful effects -* once and have them replicated across as many game objects as you like. -*/ -var Phaser; -(function (Phaser) { - var DynamicTexture = (function () { - /** - * DynamicTexture constructor - * Create a new DynamicTexture. - * - * @param game {Phaser.Game} Current game instance. - * @param width {number} Init width of this texture. - * @param height {number} Init height of this texture. - */ - function DynamicTexture(game, width, height) { - this._sx = 0; - this._sy = 0; - this._sw = 0; - this._sh = 0; - this._dx = 0; - this._dy = 0; - this._dw = 0; - this._dh = 0; - this.game = game; - this.type = Phaser.Types.GEOMSPRITE; - this.canvas = document.createElement('canvas'); - this.canvas.width = width; - this.canvas.height = height; - this.context = this.canvas.getContext('2d'); - this.bounds = new Phaser.Rectangle(0, 0, width, height); - } - DynamicTexture.prototype.getPixel = /** - * Get a color of a specific pixel. - * @param x {number} X position of the pixel in this texture. - * @param y {number} Y position of the pixel in this texture. - * @return {number} A native color value integer (format: 0xRRGGBB) - */ - function (x, y) { - //r = imageData.data[0]; - //g = imageData.data[1]; - //b = imageData.data[2]; - //a = imageData.data[3]; - var imageData = this.context.getImageData(x, y, 1, 1); - return Phaser.ColorUtils.getColor(imageData.data[0], imageData.data[1], imageData.data[2]); - }; - DynamicTexture.prototype.getPixel32 = /** - * Get a color of a specific pixel (including alpha value). - * @param x {number} X position of the pixel in this texture. - * @param y {number} Y position of the pixel in this texture. - * @return A native color value integer (format: 0xAARRGGBB) - */ - function (x, y) { - var imageData = this.context.getImageData(x, y, 1, 1); - return Phaser.ColorUtils.getColor32(imageData.data[3], imageData.data[0], imageData.data[1], imageData.data[2]); - }; - DynamicTexture.prototype.getPixels = /** - * Get pixels in array in a specific rectangle. - * @param rect {Rectangle} The specific rectangle. - * @returns {array} CanvasPixelArray. - */ - function (rect) { - return this.context.getImageData(rect.x, rect.y, rect.width, rect.height); - }; - DynamicTexture.prototype.setPixel = /** - * Set color of a specific pixel. - * @param x {number} X position of the target pixel. - * @param y {number} Y position of the target pixel. - * @param color {number} Native integer with color value. (format: 0xRRGGBB) - */ - function (x, y, color) { - this.context.fillStyle = color; - this.context.fillRect(x, y, 1, 1); - }; - DynamicTexture.prototype.setPixel32 = /** - * Set color (with alpha) of a specific pixel. - * @param x {number} X position of the target pixel. - * @param y {number} Y position of the target pixel. - * @param color {number} Native integer with color value. (format: 0xAARRGGBB) - */ - function (x, y, color) { - this.context.fillStyle = color; - this.context.fillRect(x, y, 1, 1); - }; - DynamicTexture.prototype.setPixels = /** - * Set image data to a specific rectangle. - * @param rect {Rectangle} Target rectangle. - * @param input {object} Source image data. - */ - function (rect, input) { - this.context.putImageData(input, rect.x, rect.y); - }; - DynamicTexture.prototype.fillRect = /** - * Fill a given rectangle with specific color. - * @param rect {Rectangle} Target rectangle you want to fill. - * @param color {number} A native number with color value. (format: 0xRRGGBB) - */ - function (rect, color) { - this.context.fillStyle = color; - this.context.fillRect(rect.x, rect.y, rect.width, rect.height); - }; - DynamicTexture.prototype.pasteImage = /** - * - */ - function (key, frame, destX, destY, destWidth, destHeight) { - if (typeof frame === "undefined") { frame = -1; } - if (typeof destX === "undefined") { destX = 0; } - if (typeof destY === "undefined") { destY = 0; } - if (typeof destWidth === "undefined") { destWidth = null; } - if (typeof destHeight === "undefined") { destHeight = null; } - var texture = null; - var frameData; - this._sx = 0; - this._sy = 0; - this._dx = destX; - this._dy = destY; - // TODO - Load a frame from a sprite sheet, otherwise we'll draw the whole lot - if(frame > -1) { - //if (this.game.cache.isSpriteSheet(key)) - //{ - // texture = this.game.cache.getImage(key); - //this.animations.loadFrameData(this.game.cache.getFrameData(key)); - //} - } else { - texture = this.game.cache.getImage(key); - this._sw = texture.width; - this._sh = texture.height; - this._dw = texture.width; - this._dh = texture.height; - } - if(destWidth !== null) { - this._dw = destWidth; - } - if(destHeight !== null) { - this._dh = destHeight; - } - if(texture != null) { - this.context.drawImage(texture, // Source Image - this._sx, // Source X (location within the source image) - this._sy, // Source Y - this._sw, // Source Width - this._sh, // Source Height - this._dx, // Destination X (where on the canvas it'll be drawn) - this._dy, // Destination Y - this._dw, // Destination Width (always same as Source Width unless scaled) - this._dh); - // Destination Height (always same as Source Height unless scaled) - } - }; - DynamicTexture.prototype.copyPixels = // TODO - Add in support for: alphaBitmapData: BitmapData = null, alphaPoint: Point = null, mergeAlpha: bool = false - /** - * Copy pixel from another DynamicTexture to this texture. - * @param sourceTexture {DynamicTexture} Source texture object. - * @param sourceRect {Rectangle} The specific region rectangle to be copied to this in the source. - * @param destPoint {Point} Top-left point the target image data will be paste at. - */ - function (sourceTexture, sourceRect, destPoint) { - // Swap for drawImage if the sourceRect is the same size as the sourceTexture to avoid a costly getImageData call - if(Phaser.RectangleUtils.equals(sourceRect, this.bounds) == true) { - this.context.drawImage(sourceTexture.canvas, destPoint.x, destPoint.y); - } else { - this.context.putImageData(sourceTexture.getPixels(sourceRect), destPoint.x, destPoint.y); - } - }; - DynamicTexture.prototype.assignCanvasToGameObjects = /** - * Given an array of Sprites it will update each of them so that their canvas/contexts reference this DynamicTexture - * @param objects {Array} An array of GameObjects, or objects that inherit from it such as Sprites - */ - function (objects) { - for(var i = 0; i < objects.length; i++) { - objects[i].texture.canvas = this.canvas; - objects[i].texture.context = this.context; - } - }; - DynamicTexture.prototype.clear = /** - * Clear the whole canvas. - */ - function () { - this.context.clearRect(0, 0, this.bounds.width, this.bounds.height); - }; - DynamicTexture.prototype.render = /** - * Renders this DynamicTexture to the Stage at the given x/y coordinates - * - * @param x {number} The X coordinate to render on the stage to (given in screen coordinates, not world) - * @param y {number} The Y coordinate to render on the stage to (given in screen coordinates, not world) - */ - function (x, y) { - if (typeof x === "undefined") { x = 0; } - if (typeof y === "undefined") { y = 0; } - this.game.stage.context.drawImage(this.canvas, x, y); - }; - Object.defineProperty(DynamicTexture.prototype, "width", { - get: function () { - return this.bounds.width; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(DynamicTexture.prototype, "height", { - get: function () { - return this.bounds.height; - }, - enumerable: true, - configurable: true - }); - return DynamicTexture; - })(); - Phaser.DynamicTexture = DynamicTexture; -})(Phaser || (Phaser = {})); -/// -/// -/// -/// -/// -/// -/** -* Phaser - SpriteUtils -* -* A collection of methods useful for manipulating and checking Sprites. -*/ -var Phaser; -(function (Phaser) { - var SpriteUtils = (function () { - function SpriteUtils() { } - SpriteUtils.inCamera = /** - * Check whether this object is visible in a specific camera rectangle. - * @param camera {Rectangle} The rectangle you want to check. - * @return {boolean} Return true if bounds of this sprite intersects the given rectangle, otherwise return false. - */ - function inCamera(camera, sprite) { - // Object fixed in place regardless of the camera scrolling? Then it's always visible - if(sprite.scrollFactor.x == 0 && sprite.scrollFactor.y == 0) { - return true; - } - var dx = sprite.frameBounds.x - (camera.worldView.x * sprite.scrollFactor.x); - var dy = sprite.frameBounds.y - (camera.worldView.y * sprite.scrollFactor.y); - var dw = sprite.frameBounds.width * sprite.scale.x; - var dh = sprite.frameBounds.height * sprite.scale.y; - return (camera.scaledX + camera.worldView.width > this._dx) && (camera.scaledX < this._dx + this._dw) && (camera.scaledY + camera.worldView.height > this._dy) && (camera.scaledY < this._dy + this._dh); - }; - SpriteUtils.getAsPoints = function getAsPoints(sprite) { - var out = []; - // top left - out.push(new Phaser.Point(sprite.x, sprite.y)); - // top right - out.push(new Phaser.Point(sprite.x + sprite.width, sprite.y)); - // bottom right - out.push(new Phaser.Point(sprite.x + sprite.width, sprite.y + sprite.height)); - // bottom left - out.push(new Phaser.Point(sprite.x, sprite.y + sprite.height)); - return out; - }; - SpriteUtils.overlapsPoint = /** - * Checks to see if some GameObject overlaps this GameObject or Group. - * If the group has a LOT of things in it, it might be faster to use Collision.overlaps(). - * WARNING: Currently tilemaps do NOT support screen space overlap checks! - * - * @param objectOrGroup {object} The object or group being tested. - * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {boolean} Whether or not the objects overlap this. - */ - /* - static overlaps(objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { - - if (objectOrGroup.isGroup) - { - var results: bool = false; - var i: number = 0; - var members = objectOrGroup.members; - - while (i < length) - { - if (this.overlaps(members[i++], inScreenSpace, camera)) - { - results = true; - } - } - - return results; - - } - - if (!inScreenSpace) - { - return (objectOrGroup.x + objectOrGroup.width > this.x) && (objectOrGroup.x < this.x + this.width) && - (objectOrGroup.y + objectOrGroup.height > this.y) && (objectOrGroup.y < this.y + this.height); - } - - if (camera == null) - { - camera = this._game.camera; - } - - var objectScreenPos: Point = objectOrGroup.getScreenXY(null, camera); - - this.getScreenXY(this._point, camera); - - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && - (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); - } - */ - /** - * Checks to see if this GameObject were located at the given position, would it overlap the GameObject or Group? - * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size numbero account. - * WARNING: Currently tilemaps do NOT support screen space overlap checks! - * - * @param X {number} The X position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param Y {number} The Y position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param objectOrGroup {object} The object or group being tested. - * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {boolean} Whether or not the two objects overlap. - */ - /* - static overlapsAt(X: number, Y: number, objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { - - if (objectOrGroup.isGroup) - { - var results: bool = false; - var basic; - var i: number = 0; - var members = objectOrGroup.members; - - while (i < length) - { - if (this.overlapsAt(X, Y, members[i++], inScreenSpace, camera)) - { - results = true; - } - } - - return results; - } - - if (!inScreenSpace) - { - return (objectOrGroup.x + objectOrGroup.width > X) && (objectOrGroup.x < X + this.width) && - (objectOrGroup.y + objectOrGroup.height > Y) && (objectOrGroup.y < Y + this.height); - } - - if (camera == null) - { - camera = this._game.camera; - } - - var objectScreenPos: Point = objectOrGroup.getScreenXY(null, Camera); - - this._point.x = X - camera.scroll.x * this.scrollFactor.x; //copied from getScreenXY() - this._point.y = Y - camera.scroll.y * this.scrollFactor.y; - this._point.x += (this._point.x > 0) ? 0.0000001 : -0.0000001; - this._point.y += (this._point.y > 0) ? 0.0000001 : -0.0000001; - - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && - (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); - } - */ - /** - * Checks to see if a point in 2D world space overlaps this GameObject. - * - * @param point {Point} The point in world space you want to check. - * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return Whether or not the point overlaps this object. - */ - function overlapsPoint(sprite, point, inScreenSpace, camera) { - if (typeof inScreenSpace === "undefined") { inScreenSpace = false; } - if (typeof camera === "undefined") { camera = null; } - if(!inScreenSpace) { - return Phaser.RectangleUtils.containsPoint(sprite.body.bounds, point); - //return (point.x > sprite.x) && (point.x < sprite.x + sprite.width) && (point.y > sprite.y) && (point.y < sprite.y + sprite.height); - } - if(camera == null) { - camera = sprite.game.camera; - } - //var x: number = point.x - camera.scroll.x; - //var y: number = point.y - camera.scroll.y; - //this.getScreenXY(this._point, camera); - //return (x > this._point.x) && (X < this._point.x + this.width) && (Y > this._point.y) && (Y < this._point.y + this.height); - }; - SpriteUtils.onScreen = /** - * Check and see if this object is currently on screen. - * - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {boolean} Whether the object is on screen or not. - */ - function onScreen(sprite, camera) { - if (typeof camera === "undefined") { camera = null; } - if(camera == null) { - camera = sprite.game.camera; - } - SpriteUtils.getScreenXY(sprite, SpriteUtils._tempPoint, camera); - return (SpriteUtils._tempPoint.x + sprite.width > 0) && (SpriteUtils._tempPoint.x < camera.width) && (SpriteUtils._tempPoint.y + sprite.height > 0) && (SpriteUtils._tempPoint.y < camera.height); - }; - SpriteUtils.getScreenXY = /** - * Call this to figure out the on-screen position of the object. - * - * @param point {Point} Takes a Point object and assigns the post-scrolled X and Y values of this object to it. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {Point} The Point you passed in, or a new Point if you didn't pass one, containing the screen X and Y position of this object. - */ - function getScreenXY(sprite, point, camera) { - if (typeof point === "undefined") { point = null; } - if (typeof camera === "undefined") { camera = null; } - if(point == null) { - point = new Phaser.Point(); - } - if(camera == null) { - camera = this._game.camera; - } - point.x = sprite.x - camera.scroll.x * sprite.scrollFactor.x; - point.y = sprite.y - camera.scroll.y * sprite.scrollFactor.y; - point.x += (point.x > 0) ? 0.0000001 : -0.0000001; - point.y += (point.y > 0) ? 0.0000001 : -0.0000001; - return point; - }; - SpriteUtils.reset = /** - * Set the world bounds that this GameObject can exist within based on the size of the current game world. - * - * @param action {number} The action to take if the object hits the world bounds, either OUT_OF_BOUNDS_KILL or OUT_OF_BOUNDS_STOP - */ - /* - static setBoundsFromWorld(action?: number = GameObject.OUT_OF_BOUNDS_STOP) { - - this.setBounds(this._game.world.bounds.x, this._game.world.bounds.y, this._game.world.bounds.width, this._game.world.bounds.height); - this.outOfBoundsAction = action; - - } - */ - /** - * Handy for reviving game objects. - * Resets their existence flags and position. - * - * @param x {number} The new X position of this object. - * @param y {number} The new Y position of this object. - */ - function reset(sprite, x, y) { - sprite.revive(); - sprite.body.touching = Phaser.Types.NONE; - sprite.body.wasTouching = Phaser.Types.NONE; - sprite.x = x; - sprite.y = y; - sprite.body.velocity.x = 0; - sprite.body.velocity.y = 0; - sprite.body.position.x = x; - sprite.body.position.y = y; - }; - SpriteUtils.setOriginToCenter = function setOriginToCenter(sprite, fromFrameBounds, fromBody) { - if (typeof fromFrameBounds === "undefined") { fromFrameBounds = true; } - if (typeof fromBody === "undefined") { fromBody = false; } - if(fromFrameBounds) { - sprite.origin.setTo(sprite.frameBounds.halfWidth, sprite.frameBounds.halfHeight); - } else if(fromBody) { - sprite.origin.setTo(sprite.body.bounds.halfWidth, sprite.body.bounds.halfHeight); - } - }; - SpriteUtils.setBounds = /** - * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere - * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) - * it can be stopped from leaving the world, or a section of it. - * - * @param x {number} x position of the bound - * @param y {number} y position of the bound - * @param width {number} width of its bound - * @param height {number} height of its bound - */ - function setBounds(x, y, width, height) { - //this.worldBounds = new Quad(x, y, width, height); - }; - return SpriteUtils; - })(); - Phaser.SpriteUtils = SpriteUtils; - /** - * This function creates a flat colored square image dynamically. - * @param width {number} The width of the sprite you want to generate. - * @param height {number} The height of the sprite you want to generate. - * @param [color] {number} specifies the color of the generated block. (format is 0xAARRGGBB) - * @return {Sprite} Sprite instance itself. - */ - /* - static makeGraphic(width: number, height: number, color: string = 'rgb(255,255,255)'): Sprite { - - this._texture = null; - this.width = width; - this.height = height; - this.fillColor = color; - this._dynamicTexture = false; - - return this; - } - */ - })(Phaser || (Phaser = {})); -var Phaser; -(function (Phaser) { - /// - /// - /// - /** - * Phaser - Components - Texture - * - * The Texture being used to render the Sprite. Either Image based on a DynamicTexture. - */ - (function (Components) { - var Texture = (function () { - /** - * Creates a new Sprite Texture component - * @param parent The Sprite using this Texture to render - * @param key An optional Game.Cache key to load an image from - */ - function Texture(parent, key) { - if (typeof key === "undefined") { key = ''; } - /** - * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. - */ - this.imageTexture = null; - /** - * Reference to the DynamicTexture that is used as the texture for the Sprite. - * @type {DynamicTexture} - */ - this.dynamicTexture = null; - /** - * The load status of the texture image. - * @type {boolean} - */ - this.loaded = false; - /** - * Controls if the Sprite is rendered rotated or not. - * If renderRotation is false then the object can still rotate but it will never be rendered rotated. - * @type {boolean} - */ - this.renderRotation = true; - /** - * Flip the graphic horizontally (defaults to false) - * @type {boolean} - */ - this.flippedX = false; - /** - * Flip the graphic vertically (defaults to false) - * @type {boolean} - */ - this.flippedY = false; - /** - * Is the texture a DynamicTexture? - * @type {boolean} - */ - this.isDynamic = false; - this.game = parent.game; - this._sprite = parent; - this.canvas = parent.game.stage.canvas; - this.context = parent.game.stage.context; - this.alpha = 1; - this.flippedX = false; - this.flippedY = false; - if(key !== null) { - this.cacheKey = key; - this.loadImage(key); - } - } - Texture.prototype.setTo = /** - * Updates the texture being used to render the Sprite. - * Called automatically by SpriteUtils.loadTexture and SpriteUtils.loadDynamicTexture. - */ - function (image, dynamic) { - if (typeof image === "undefined") { image = null; } - if (typeof dynamic === "undefined") { dynamic = null; } - if(dynamic) { - this.isDynamic = true; - this.dynamicTexture = dynamic; - this.texture = this.dynamicTexture.canvas; - } else { - this.isDynamic = false; - this.imageTexture = image; - this.texture = this.imageTexture; - } - this.loaded = true; - return this._sprite; - }; - Texture.prototype.loadImage = /** - * Sets a new graphic from the game cache to use as the texture for this Sprite. - * The graphic can be SpriteSheet or Texture Atlas. If you need to use a DynamicTexture see loadDynamicTexture. - * @param key {string} Key of the graphic you want to load for this sprite. - * @param clearAnimations {boolean} If this Sprite has a set of animation data already loaded you can choose to keep or clear it with this boolean - */ - function (key, clearAnimations, updateBody) { - if (typeof clearAnimations === "undefined") { clearAnimations = true; } - if (typeof updateBody === "undefined") { updateBody = true; } - 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)) { - this._sprite.animations.loadFrameData(this._sprite.game.cache.getFrameData(key)); - } else { - this._sprite.frameBounds.width = this.width; - this._sprite.frameBounds.height = this.height; - } - if(updateBody) { - this._sprite.body.bounds.width = this.width; - this._sprite.body.bounds.height = this.height; - } - } - }; - Texture.prototype.loadDynamicTexture = /** - * Load a DynamicTexture as its texture. - * @param texture {DynamicTexture} The texture object to be used by this sprite. - */ - function (texture) { - 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; - }; - Object.defineProperty(Texture.prototype, "width", { - get: /** - * Getter only. The width of the texture. - * @type {number} - */ - function () { - if(this.isDynamic) { - return this.dynamicTexture.width; - } else { - return this.imageTexture.width; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Texture.prototype, "height", { - get: /** - * Getter only. The height of the texture. - * @type {number} - */ - function () { - if(this.isDynamic) { - return this.dynamicTexture.height; - } else { - return this.imageTexture.height; - } - }, - enumerable: true, - configurable: true - }); - return Texture; - })(); - Components.Texture = Texture; - })(Phaser.Components || (Phaser.Components = {})); - var Components = Phaser.Components; -})(Phaser || (Phaser = {})); -var Phaser; -(function (Phaser) { - /// - /// - /// - /// - /** - * Phaser - Components - Input - * - * Input detection component - */ - (function (Components) { - var Input = (function () { - /** - * Sprite Input component constructor - * @param parent The Sprite using this Input component - */ - function Input(parent) { - /** - * The PriorityID controls which Sprite receives an Input event first if they should overlap. - */ - this.priorityID = 0; - this.isDragged = false; - this.dragPixelPerfect = false; - this.allowHorizontalDrag = true; - this.allowVerticalDrag = true; - this.snapOnDrag = false; - this.snapOnRelease = false; - this.snapX = 0; - this.snapY = 0; - /** - * Is this sprite allowed to be dragged by the mouse? true = yes, false = no - * @default false - */ - this.draggable = false; - /** - * A region of the game world within which the sprite is restricted during drag - * @default null - */ - this.boundsRect = null; - /** - * An Sprite the bounds of which this sprite is restricted during drag - * @default null - */ - this.boundsSprite = null; - this.consumePointerEvent = false; - this.game = parent.game; - this._sprite = parent; - this.enabled = false; - } - Input.prototype.pointerX = /** - * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. - * This value is only set when the pointer is over this Sprite. - * @type {number} - */ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].x; - }; - Input.prototype.pointerY = /** - * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite - * This value is only set when the pointer is over this Sprite. - * @type {number} - */ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].y; - }; - Input.prototype.pointerDown = /** - * If the Pointer is touching the touchscreen, or the mouse button is held down, isDown is set to true - * @property isDown - * @type {Boolean} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].isDown; - }; - Input.prototype.pointerUp = /** - * If the Pointer is not touching the touchscreen, or the mouse button is up, isUp is set to true - * @property isUp - * @type {Boolean} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].isUp; - }; - Input.prototype.pointerTimeDown = /** - * A timestamp representing when the Pointer first touched the touchscreen. - * @property timeDown - * @type {Number} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].timeDown; - }; - Input.prototype.pointerTimeUp = /** - * A timestamp representing when the Pointer left the touchscreen. - * @property timeUp - * @type {Number} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].timeUp; - }; - Input.prototype.pointerOver = /** - * Is the Pointer over this Sprite - * @property isOver - * @type {Boolean} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].isOver; - }; - Input.prototype.pointerOut = /** - * Is the Pointer outside of this Sprite - * @property isOut - * @type {Boolean} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].isOut; - }; - Input.prototype.pointerTimeOver = /** - * A timestamp representing when the Pointer first touched the touchscreen. - * @property timeDown - * @type {Number} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].timeOver; - }; - Input.prototype.pointerTimeOut = /** - * A timestamp representing when the Pointer left the touchscreen. - * @property timeUp - * @type {Number} - **/ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].timeOut; - }; - Input.prototype.pointerDragged = /** - * Is this sprite being dragged by the mouse or not? - * @default false - */ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - return this._pointerData[pointer].isDragged; - }; - Input.prototype.start = function (priority, checkBody, useHandCursor) { - if (typeof priority === "undefined") { priority = 0; } - if (typeof checkBody === "undefined") { checkBody = false; } - if (typeof useHandCursor === "undefined") { useHandCursor = false; } - // Turning on - if(this.enabled == false) { - // Register, etc - this.checkBody = checkBody; - this.useHandCursor = useHandCursor; - this.priorityID = priority; - this._pointerData = []; - for(var i = 0; i < 10; i++) { - this._pointerData.push({ - id: i, - x: 0, - y: 0, - isDown: false, - isUp: false, - isOver: false, - isOut: false, - timeOver: 0, - timeOut: 0, - timeDown: 0, - timeUp: 0, - downDuration: 0, - isDragged: false - }); - } - this.snapOffset = new Phaser.Point(); - this.enabled = true; - this.game.input.addGameObject(this._sprite); - } - return this._sprite; - }; - Input.prototype.reset = function () { - this.enabled = false; - for(var i = 0; i < 10; i++) { - this._pointerData[i] = { - id: i, - x: 0, - y: 0, - isDown: false, - isUp: false, - isOver: false, - isOut: false, - timeOver: 0, - timeOut: 0, - timeDown: 0, - timeUp: 0, - downDuration: 0, - isDragged: false - }; - } - }; - Input.prototype.stop = function () { - // Turning off - if(this.enabled == false) { - return; - } else { - // De-register, etc - this.enabled = false; - this.game.input.removeGameObject(this._sprite); - } - }; - Input.prototype.checkPointerOver = function (pointer) { - if(this.enabled == false || this._sprite.visible == false) { - return false; - } else { - return Phaser.RectangleUtils.contains(this._sprite.frameBounds, pointer.scaledX, pointer.scaledY); - } - }; - Input.prototype.update = /** - * Update - */ - function (pointer) { - if(this.enabled == false || this._sprite.visible == false) { - return false; - } - if(this.draggable && this._draggedPointerID == pointer.id) { - return this.updateDrag(pointer); - } else if(this._pointerData[pointer.id].isOver == true) { - if(Phaser.RectangleUtils.contains(this._sprite.frameBounds, pointer.scaledX, pointer.scaledY)) { - this._pointerData[pointer.id].x = pointer.scaledX - this._sprite.x; - this._pointerData[pointer.id].y = pointer.scaledY - this._sprite.y; - return true; - } else { - this._pointerOutHandler(pointer); - return false; - } - } - }; - Input.prototype._pointerOverHandler = function (pointer) { - // { id: i, x: 0, y: 0, isDown: false, isUp: false, isOver: false, isOut: false, timeOver: 0, timeOut: 0, isDragged: false } - if(this._pointerData[pointer.id].isOver == false) { - this._pointerData[pointer.id].isOver = true; - this._pointerData[pointer.id].isOut = false; - this._pointerData[pointer.id].timeOver = this.game.time.now; - this._pointerData[pointer.id].x = pointer.x - this._sprite.x; - this._pointerData[pointer.id].y = pointer.y - this._sprite.y; - if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { - this.game.stage.canvas.style.cursor = "pointer"; - } - this._sprite.events.onInputOver.dispatch(this._sprite, pointer); - } - }; - Input.prototype._pointerOutHandler = function (pointer) { - this._pointerData[pointer.id].isOver = false; - this._pointerData[pointer.id].isOut = true; - this._pointerData[pointer.id].timeOut = this.game.time.now; - if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { - this.game.stage.canvas.style.cursor = "default"; - } - this._sprite.events.onInputOut.dispatch(this._sprite, pointer); - }; - Input.prototype._touchedHandler = function (pointer) { - if(this._pointerData[pointer.id].isDown == false && this._pointerData[pointer.id].isOver == true) { - this._pointerData[pointer.id].isDown = true; - this._pointerData[pointer.id].isUp = false; - this._pointerData[pointer.id].timeDown = this.game.time.now; - this._sprite.events.onInputDown.dispatch(this._sprite, pointer); - // Start drag - //if (this.draggable && this.isDragged == false && pointer.targetObject == null) - if(this.draggable && this.isDragged == false) { - this.startDrag(pointer); - } - } - // Consume the event? - return this.consumePointerEvent; - }; - Input.prototype._releasedHandler = function (pointer) { - // If was previously touched by this Pointer, check if still is - if(this._pointerData[pointer.id].isDown && pointer.isUp) { - this._pointerData[pointer.id].isDown = false; - this._pointerData[pointer.id].isUp = true; - this._pointerData[pointer.id].timeUp = this.game.time.now; - this._pointerData[pointer.id].downDuration = this._pointerData[pointer.id].timeUp - this._pointerData[pointer.id].timeDown; - this._sprite.events.onInputUp.dispatch(this._sprite, pointer); - // Stop drag - if(this.draggable && this.isDragged && this._draggedPointerID == pointer.id) { - this.stopDrag(pointer); - } - if(this.useHandCursor) { - this.game.stage.canvas.style.cursor = "default"; - } - } - }; - Input.prototype.updateDrag = /** - * Updates the Pointer drag on this Sprite. - */ - function (pointer) { - if(pointer.isUp) { - this.stopDrag(pointer); - return false; - } - if(this.allowHorizontalDrag) { - this._sprite.x = pointer.x + this._dragPoint.x + this.dragOffset.x; - } - if(this.allowVerticalDrag) { - this._sprite.y = pointer.y + this._dragPoint.y + this.dragOffset.y; - } - if(this.boundsRect) { - this.checkBoundsRect(); - } - if(this.boundsSprite) { - this.checkBoundsSprite(); - } - if(this.snapOnDrag) { - this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; - this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; - } - return true; - }; - Input.prototype.justOver = /** - * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) - * @param delay The time below which the pointer is considered as just over. - * @returns {boolean} - */ - function (pointer, delay) { - if (typeof pointer === "undefined") { pointer = 0; } - if (typeof delay === "undefined") { delay = 500; } - return (this._pointerData[pointer].isOver && this.overDuration(pointer) < delay); - }; - Input.prototype.justOut = /** - * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) - * @param delay The time below which the pointer is considered as just out. - * @returns {boolean} - */ - function (pointer, delay) { - if (typeof pointer === "undefined") { pointer = 0; } - if (typeof delay === "undefined") { delay = 500; } - return (this._pointerData[pointer].isOut && (this.game.time.now - this._pointerData[pointer].timeOut < delay)); - }; - Input.prototype.justPressed = /** - * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) - * @param delay The time below which the pointer is considered as just over. - * @returns {boolean} - */ - function (pointer, delay) { - if (typeof pointer === "undefined") { pointer = 0; } - if (typeof delay === "undefined") { delay = 500; } - return (this._pointerData[pointer].isDown && this.downDuration(pointer) < delay); - }; - Input.prototype.justReleased = /** - * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) - * @param delay The time below which the pointer is considered as just out. - * @returns {boolean} - */ - function (pointer, delay) { - if (typeof pointer === "undefined") { pointer = 0; } - if (typeof delay === "undefined") { delay = 500; } - return (this._pointerData[pointer].isUp && (this.game.time.now - this._pointerData[pointer].timeUp < delay)); - }; - Input.prototype.overDuration = /** - * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. - * @returns {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over. - */ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - if(this._pointerData[pointer].isOver) { - return this.game.time.now - this._pointerData[pointer].timeOver; - } - return -1; - }; - Input.prototype.downDuration = /** - * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. - * @returns {number} The number of milliseconds the pointer has been pressed down on the Sprite, or -1 if not over. - */ - function (pointer) { - if (typeof pointer === "undefined") { pointer = 0; } - if(this._pointerData[pointer].isDown) { - return this.game.time.now - this._pointerData[pointer].timeDown; - } - return -1; - }; - Input.prototype.enableDrag = /** - * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback - * - * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. - * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. - * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) - * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere - * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here - */ - function (lockCenter, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) { - if (typeof lockCenter === "undefined") { lockCenter = false; } - if (typeof pixelPerfect === "undefined") { pixelPerfect = false; } - if (typeof alphaThreshold === "undefined") { alphaThreshold = 255; } - if (typeof boundsRect === "undefined") { boundsRect = null; } - if (typeof boundsSprite === "undefined") { boundsSprite = null; } - this._dragPoint = new Phaser.Point(); - this.draggable = true; - this.dragOffset = new Phaser.Point(); - this.dragFromCenter = lockCenter; - this.dragPixelPerfect = pixelPerfect; - this.dragPixelPerfectAlpha = alphaThreshold; - if(boundsRect) { - this.boundsRect = boundsRect; - } - if(boundsSprite) { - this.boundsSprite = boundsSprite; - } - }; - Input.prototype.disableDrag = /** - * Stops this sprite from being able to be dragged. If it is currently the target of an active drag it will be stopped immediately. Also disables any set callbacks. - */ - function () { - if(this._pointerData) { - for(var i = 0; i < 10; i++) { - this._pointerData[i].isDragged = false; - } - } - this.draggable = false; - this.isDragged = false; - this._draggedPointerID = -1; - }; - Input.prototype.startDrag = /** - * Called by Pointer when drag starts on this Sprite. Should not usually be called directly. - */ - function (pointer) { - this.isDragged = true; - this._draggedPointerID = pointer.id; - this._pointerData[pointer.id].isDragged = true; - if(this.dragFromCenter) { - // Move the sprite to the middle of the pointer - this._dragPoint.setTo(-this._sprite.frameBounds.halfWidth, -this._sprite.frameBounds.halfHeight); - } else { - this._dragPoint.setTo(this._sprite.x - pointer.x, this._sprite.y - pointer.y); - } - this.updateDrag(pointer); - }; - Input.prototype.stopDrag = /** - * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. - */ - function (pointer) { - this.isDragged = false; - this._draggedPointerID = -1; - this._pointerData[pointer.id].isDragged = false; - if(this.snapOnRelease) { - this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; - this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; - } - //pointer.draggedObject = null; - }; - Input.prototype.setDragLock = /** - * Restricts this sprite to drag movement only on the given axis. Note: If both are set to false the sprite will never move! - * - * @param allowHorizontal To enable the sprite to be dragged horizontally set to true, otherwise false - * @param allowVertical To enable the sprite to be dragged vertically set to true, otherwise false - */ - function (allowHorizontal, allowVertical) { - if (typeof allowHorizontal === "undefined") { allowHorizontal = true; } - if (typeof allowVertical === "undefined") { allowVertical = true; } - this.allowHorizontalDrag = allowHorizontal; - this.allowVerticalDrag = allowVertical; - }; - Input.prototype.enableSnap = /** - * Make this Sprite snap to the given grid either during drag or when it's released. - * For example 16x16 as the snapX and snapY would make the sprite snap to every 16 pixels. - * - * @param snapX The width of the grid cell in pixels - * @param snapY The height of the grid cell in pixels - * @param onDrag If true the sprite will snap to the grid while being dragged - * @param onRelease If true the sprite will snap to the grid when released - */ - function (snapX, snapY, onDrag, onRelease) { - if (typeof onDrag === "undefined") { onDrag = true; } - if (typeof onRelease === "undefined") { onRelease = false; } - this.snapOnDrag = onDrag; - this.snapOnRelease = onRelease; - this.snapX = snapX; - this.snapY = snapY; - }; - Input.prototype.disableSnap = /** - * Stops the sprite from snapping to a grid during drag or release. - */ - function () { - this.snapOnDrag = false; - this.snapOnRelease = false; - }; - Input.prototype.checkBoundsRect = /** - * Bounds Rect check for the sprite drag - */ - function () { - if(this._sprite.x < this.boundsRect.left) { - this._sprite.x = this.boundsRect.x; - } else if((this._sprite.x + this._sprite.width) > this.boundsRect.right) { - this._sprite.x = this.boundsRect.right - this._sprite.width; - } - if(this._sprite.y < this.boundsRect.top) { - this._sprite.y = this.boundsRect.top; - } else if((this._sprite.y + this._sprite.height) > this.boundsRect.bottom) { - this._sprite.y = this.boundsRect.bottom - this._sprite.height; - } - }; - Input.prototype.checkBoundsSprite = /** - * Parent Sprite Bounds check for the sprite drag - */ - function () { - if(this._sprite.x < this.boundsSprite.x) { - this._sprite.x = this.boundsSprite.x; - } else if((this._sprite.x + this._sprite.width) > (this.boundsSprite.x + this.boundsSprite.width)) { - this._sprite.x = (this.boundsSprite.x + this.boundsSprite.width) - this._sprite.width; - } - if(this._sprite.y < this.boundsSprite.y) { - this._sprite.y = this.boundsSprite.y; - } else if((this._sprite.y + this._sprite.height) > (this.boundsSprite.y + this.boundsSprite.height)) { - this._sprite.y = (this.boundsSprite.y + this.boundsSprite.height) - this._sprite.height; - } - }; - Input.prototype.renderDebugInfo = /** - * Render debug infos. (including name, bounds info, position and some other properties) - * @param x {number} X position of the debug info to be rendered. - * @param y {number} Y position of the debug info to be rendered. - * @param [color] {number} color of the debug info to be rendered. (format is css color string) - */ - function (x, y, color) { - if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } - this._sprite.texture.context.font = '14px Courier'; - this._sprite.texture.context.fillStyle = color; - this._sprite.texture.context.fillText('Sprite Input: (' + this._sprite.frameBounds.width + ' x ' + this._sprite.frameBounds.height + ')', x, y); - this._sprite.texture.context.fillText('x: ' + this.pointerX().toFixed(1) + ' y: ' + this.pointerY().toFixed(1), x, y + 14); - this._sprite.texture.context.fillText('over: ' + this.pointerOver() + ' duration: ' + this.overDuration().toFixed(0), x, y + 28); - this._sprite.texture.context.fillText('down: ' + this.pointerDown() + ' duration: ' + this.downDuration().toFixed(0), x, y + 42); - this._sprite.texture.context.fillText('just over: ' + this.justOver() + ' just out: ' + this.justOut(), x, y + 56); - }; - return Input; - })(); - Components.Input = Input; - })(Phaser.Components || (Phaser.Components = {})); - var Components = Phaser.Components; -})(Phaser || (Phaser = {})); -var Phaser; -(function (Phaser) { - /// - /** - * Phaser - Components - Events - * - * Signals that are dispatched by the Sprite and its various components - */ - (function (Components) { - var Events = (function () { - /** - * The Events component is a collection of events fired by the parent Sprite and its other components. - * @param parent The Sprite using this Input component - */ - function Events(parent) { - this.game = parent.game; - this._sprite = parent; - this.onAddedToGroup = new Phaser.Signal(); - this.onRemovedFromGroup = new Phaser.Signal(); - this.onKilled = new Phaser.Signal(); - this.onRevived = new Phaser.Signal(); - this.onInputOver = new Phaser.Signal(); - this.onInputOut = new Phaser.Signal(); - this.onInputDown = new Phaser.Signal(); - this.onInputUp = new Phaser.Signal(); - } - return Events; - })(); - Components.Events = Events; - })(Phaser.Components || (Phaser.Components = {})); - var Components = Phaser.Components; -})(Phaser || (Phaser = {})); -/// -/// -/** -* Phaser - Vec2Utils -* -* A collection of methods useful for manipulating and performing operations on 2D vectors. -* -*/ -var Phaser; -(function (Phaser) { - var Vec2Utils = (function () { - function Vec2Utils() { } - Vec2Utils.add = /** - * Adds two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the sum of the two vectors. - */ - function add(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.x + b.x, a.y + b.y); - }; - Vec2Utils.subtract = /** - * Subtracts two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the difference of the two vectors. - */ - function subtract(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.x - b.x, a.y - b.y); - }; - Vec2Utils.multiply = /** - * Multiplies two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the sum of the two vectors multiplied. - */ - function multiply(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.x * b.x, a.y * b.y); - }; - Vec2Utils.divide = /** - * Divides two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the sum of the two vectors divided. - */ - function divide(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.x / b.x, a.y / b.y); - }; - Vec2Utils.scale = /** - * Scales a 2D vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {number} s Scaling value. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the scaled vector. - */ - function scale(a, s, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.x * s, a.y * s); - }; - Vec2Utils.perp = /** - * Rotate a 2D vector by 90 degrees. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is the scaled vector. - */ - function perp(a, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.y, -a.x); - }; - Vec2Utils.equals = /** - * Checks if two 2D vectors are equal. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Boolean} - */ - function equals(a, b) { - return a.x == b.x && a.y == b.y; - }; - Vec2Utils.epsilonEquals = /** - * - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} epsilon - * @return {Boolean} - */ - function epsilonEquals(a, b, epsilon) { - return Math.abs(a.x - b.x) <= epsilon && Math.abs(a.y - b.y) <= epsilon; - }; - Vec2Utils.distance = /** - * Get the distance between two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - function distance(a, b) { - return Math.sqrt(Vec2Utils.distanceSq(a, b)); - }; - Vec2Utils.distanceSq = /** - * Get the distance squared between two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - function distanceSq(a, b) { - return ((a.x - b.x) * (a.x - b.x)) + ((a.y - b.y) * (a.y - b.y)); - }; - Vec2Utils.project = /** - * Project two 2D vectors onto another vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - function project(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - var amt = a.dot(b) / b.lengthSq(); - if(amt != 0) { - out.setTo(amt * b.x, amt * b.y); - } - return out; - }; - Vec2Utils.projectUnit = /** - * Project this vector onto a vector of unit length. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - function projectUnit(a, b, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - var amt = a.dot(b); - if(amt != 0) { - out.setTo(amt * b.x, amt * b.y); - } - return out; - }; - Vec2Utils.normalRightHand = /** - * Right-hand normalize (make unit length) a 2D vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - function normalRightHand(a, out) { - if (typeof out === "undefined") { out = this; } - return out.setTo(a.y * -1, a.x); - }; - Vec2Utils.normalize = /** - * Normalize (make unit length) a 2D vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - function normalize(a, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - var m = a.length(); - if(m != 0) { - out.setTo(a.x / m, a.y / m); - } - return out; - }; - Vec2Utils.dot = /** - * The dot product of two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - function dot(a, b) { - return ((a.x * b.x) + (a.y * b.y)); - }; - Vec2Utils.cross = /** - * The cross product of two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - function cross(a, b) { - return ((a.x * b.y) - (a.y * b.x)); - }; - Vec2Utils.angle = /** - * The angle between two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - function angle(a, b) { - return Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y); - }; - Vec2Utils.angleSq = /** - * The angle squared between two 2D vectors. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @return {Number} - */ - function angleSq(a, b) { - return a.subtract(b).angle(b.subtract(a)); - }; - Vec2Utils.rotate = /** - * Rotate a 2D vector around the origin to the given angle (theta). - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} b Reference to a source Vec2 object. - * @param {Number} theta The angle of rotation in radians. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2. - */ - function rotate(a, b, theta, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - var x = a.x - b.x; - var y = a.y - b.y; - return out.setTo(x * Math.cos(theta) - y * Math.sin(theta) + b.x, x * Math.sin(theta) + y * Math.cos(theta) + b.y); - }; - Vec2Utils.clone = /** - * Clone a 2D vector. - * - * @param {Vec2} a Reference to a source Vec2 object. - * @param {Vec2} out The output Vec2 that is the result of the operation. - * @return {Vec2} A Vec2 that is a copy of the source Vec2. - */ - function clone(a, out) { - if (typeof out === "undefined") { out = new Phaser.Vec2(); } - return out.setTo(a.x, a.y); - }; - return Vec2Utils; - })(); - Phaser.Vec2Utils = Vec2Utils; - /** - * Reflect this vector on an arbitrary axis. - * - * @param {Vec2} axis The vector representing the axis. - * @return {Vec2} This for chaining. - */ - /* - static reflect(axis): Vec2 { - - var x = this.x; - var y = this.y; - this.project(axis).scale(2); - this.x -= x; - this.y -= y; - - return this; - - } - */ - /** - * Reflect this vector on an arbitrary axis (represented by a unit vector) - * - * @param {Vec2} axis The unit vector representing the axis. - * @return {Vec2} This for chaining. - */ - /* - static reflectN(axis): Vec2 { - - var x = this.x; - var y = this.y; - this.projectN(axis).scale(2); - this.x -= x; - this.y -= y; - - return this; - - } - - static getMagnitude(): number { - return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)); - } - */ - })(Phaser || (Phaser = {})); -var Phaser; -(function (Phaser) { - /// - /// - /// - /** - * Phaser - Physics - Body - */ - (function (Physics) { - var Body = (function () { - function Body(parent, type) { - this.angularVelocity = 0; - this.angularAcceleration = 0; - this.angularDrag = 0; - this.maxAngular = 10000; - this.mass = 1; - this.parent = parent; - this.game = parent.game; - this.type = type; - // Fixture properties - // Will extend into its own class at a later date - can move the fixture defs there and add shape support, but this will do for 1.0 release - this.bounds = new Phaser.Rectangle(parent.x + Math.round(parent.width / 2), parent.y + Math.round(parent.height / 2), parent.width, parent.height); - this.bounce = Phaser.Vec2Utils.clone(this.game.world.physics.bounce); - // Body properties - this.gravity = Phaser.Vec2Utils.clone(this.game.world.physics.gravity); - this.velocity = new Phaser.Vec2(); - this.acceleration = new Phaser.Vec2(); - this.drag = Phaser.Vec2Utils.clone(this.game.world.physics.drag); - this.maxVelocity = new Phaser.Vec2(10000, 10000); - this.angle = 0; - this.angularVelocity = 0; - this.angularAcceleration = 0; - this.angularDrag = 0; - this.touching = Phaser.Types.NONE; - this.wasTouching = Phaser.Types.NONE; - this.allowCollisions = Phaser.Types.ANY; - this.position = new Phaser.Vec2(parent.x + this.bounds.halfWidth, parent.y + this.bounds.halfHeight); - this.oldPosition = new Phaser.Vec2(parent.x + this.bounds.halfWidth, parent.y + this.bounds.halfHeight); - this.offset = new Phaser.Vec2(); - } - Body.prototype.preUpdate = function () { - this.oldPosition.copyFrom(this.position); - this.bounds.x = this.position.x - this.bounds.halfWidth; - this.bounds.y = this.position.y - this.bounds.halfHeight; - if(this.parent.scale.equals(1) == false) { - } - }; - Body.prototype.postUpdate = // Shall we do this? Or just update the values directly in the separate functions? But then the bounds will be out of sync - as long as - // the bounds are updated and used in calculations then we can do one final sprite movement here I guess? - function () { - // if this is all it does maybe move elsewhere? Sprite postUpdate? - if(this.type !== Phaser.Types.BODY_DISABLED) { - this.game.world.physics.updateMotion(this); - this.parent.x = (this.position.x - this.bounds.halfWidth) - this.offset.x; - this.parent.y = (this.position.y - this.bounds.halfHeight) - this.offset.y; - this.wasTouching = this.touching; - this.touching = Phaser.Types.NONE; - } - }; - Object.defineProperty(Body.prototype, "hullWidth", { - get: function () { - if(this.deltaX > 0) { - return this.bounds.width + this.deltaX; - } else { - return this.bounds.width - this.deltaX; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "hullHeight", { - get: function () { - if(this.deltaY > 0) { - return this.bounds.height + this.deltaY; - } else { - return this.bounds.height - this.deltaY; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "hullX", { - get: function () { - if(this.position.x < this.oldPosition.x) { - return this.position.x; - } else { - return this.oldPosition.x; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "hullY", { - get: function () { - if(this.position.y < this.oldPosition.y) { - return this.position.y; - } else { - return this.oldPosition.y; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "deltaXAbs", { - get: function () { - return (this.deltaX > 0 ? this.deltaX : -this.deltaX); - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "deltaYAbs", { - get: function () { - return (this.deltaY > 0 ? this.deltaY : -this.deltaY); - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "deltaX", { - get: function () { - return this.position.x - this.oldPosition.x; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Body.prototype, "deltaY", { - get: function () { - return this.position.y - this.oldPosition.y; - }, - enumerable: true, - configurable: true - }); - Body.prototype.render = // MOVE THESE TO A UTIL - function (context) { - context.beginPath(); - context.strokeStyle = 'rgb(0,255,0)'; - context.strokeRect(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight, this.bounds.width, this.bounds.height); - context.stroke(); - context.closePath(); - // center point - context.fillStyle = 'rgb(0,255,0)'; - context.fillRect(this.position.x, this.position.y, 2, 2); - if(this.touching & Phaser.Types.LEFT) { - context.beginPath(); - context.strokeStyle = 'rgb(255,0,0)'; - context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); - context.lineTo(this.position.x - this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); - context.stroke(); - context.closePath(); - } - if(this.touching & Phaser.Types.RIGHT) { - context.beginPath(); - context.strokeStyle = 'rgb(255,0,0)'; - context.moveTo(this.position.x + this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); - context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); - context.stroke(); - context.closePath(); - } - if(this.touching & Phaser.Types.UP) { - context.beginPath(); - context.strokeStyle = 'rgb(255,0,0)'; - context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); - context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y - this.bounds.halfHeight); - context.stroke(); - context.closePath(); - } - if(this.touching & Phaser.Types.DOWN) { - context.beginPath(); - context.strokeStyle = 'rgb(255,0,0)'; - context.moveTo(this.position.x - this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); - context.lineTo(this.position.x + this.bounds.halfWidth, this.position.y + this.bounds.halfHeight); - context.stroke(); - context.closePath(); - } - }; - Body.prototype.renderDebugInfo = /** - * Render debug infos. (including name, bounds info, position and some other properties) - * @param x {number} X position of the debug info to be rendered. - * @param y {number} Y position of the debug info to be rendered. - * @param [color] {number} color of the debug info to be rendered. (format is css color string) - */ - function (x, y, color) { - if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } - this.parent.texture.context.fillStyle = color; - this.parent.texture.context.fillText('Sprite: (' + this.parent.frameBounds.width + ' x ' + this.parent.frameBounds.height + ')', x, y); - //this.parent.texture.context.fillText('x: ' + this._parent.frameBounds.x.toFixed(1) + ' y: ' + this._parent.frameBounds.y.toFixed(1) + ' rotation: ' + this._parent.rotation.toFixed(1), x, y + 14); - this.parent.texture.context.fillText('x: ' + this.bounds.x.toFixed(1) + ' y: ' + this.bounds.y.toFixed(1) + ' angle: ' + this.angle.toFixed(0), x, y + 14); - this.parent.texture.context.fillText('vx: ' + this.velocity.x.toFixed(1) + ' vy: ' + this.velocity.y.toFixed(1), x, y + 28); - this.parent.texture.context.fillText('acx: ' + this.acceleration.x.toFixed(1) + ' acy: ' + this.acceleration.y.toFixed(1), x, y + 42); - this.parent.texture.context.fillText('angVx: ' + this.angularVelocity.toFixed(1) + ' angAc: ' + this.angularAcceleration.toFixed(1), x, y + 56); - }; - return Body; - })(); - Physics.Body = Body; - })(Phaser.Physics || (Phaser.Physics = {})); - var Physics = Phaser.Physics; -})(Phaser || (Phaser = {})); -/// -/// -/// -/// -/// -/// -/// -/// -/** -* Phaser - Sprite -* -*/ -var Phaser; -(function (Phaser) { - var Sprite = (function () { - /** - * Create a new Sprite. - * - * @param game {Phaser.Game} Current game instance. - * @param [x] {number} the initial x position of the sprite. - * @param [y] {number} the initial y position of the sprite. - * @param [key] {string} Key of the graphic you want to load for this sprite. - * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) - */ - function Sprite(game, x, y, key, bodyType) { - if (typeof x === "undefined") { x = 0; } - if (typeof y === "undefined") { y = 0; } - if (typeof key === "undefined") { key = null; } - if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } - /** - * 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; - /** - * y value of the object. - */ - this.y = 0; - /** - * z order value of the object. - */ - this.z = 0; - /** - * Render iteration - */ - this.renderOrderID = 0; - /** - * This value is added to the angle of the Sprite. - * For example if you had a sprite graphic drawn facing straight up then you could set - * angleOffset to 90 and it would correspond correctly with Phasers right-handed coordinate system. - * @type {number} - */ - this.angleOffset = 0; - this.game = game; - this.type = Phaser.Types.SPRITE; - this.exists = true; - this.active = true; - this.visible = true; - this.alive = true; - // We give it a default size of 16x16 but when the texture loads (if given) it will reset this - this.frameBounds = new Phaser.Rectangle(x, y, 16, 16); - this.scrollFactor = new Phaser.Vec2(1, 1); - this.x = x; - this.y = y; - this.z = -1; - this.group = null; - this.screen = new Phaser.Point(); - // If a texture has been given the body will be set to that size, otherwise 16x16 - this.body = new Phaser.Physics.Body(this, bodyType); - this.animations = new Phaser.Components.AnimationManager(this); - this.texture = new Phaser.Components.Texture(this, key); - this.input = new Phaser.Components.Input(this); - this.events = new Phaser.Components.Events(this); - this.cameraBlacklist = []; - // Transform related (if we add any more then move to a component) - this.origin = new Phaser.Vec2(0, 0); - this.scale = new Phaser.Vec2(1, 1); - this.skew = new Phaser.Vec2(0, 0); - } - Object.defineProperty(Sprite.prototype, "angle", { - get: /** - * The angle of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. - */ - function () { - return this.body.angle; - }, - set: /** - * Set the angle of the sprite in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. - * The value is automatically wrapped to be between 0 and 360. - */ - function (value) { - this.body.angle = this.game.math.wrap(value, 360, 0); - }, - 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 - }); - Object.defineProperty(Sprite.prototype, "width", { - get: function () { - return this.frameBounds.width; - }, - set: function (value) { - this.frameBounds.width = value; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Sprite.prototype, "height", { - get: function () { - return this.frameBounds.height; - }, - set: function (value) { - this.frameBounds.height = value; - }, - enumerable: true, - configurable: true - }); - Sprite.prototype.preUpdate = /** - * Pre-update is called right before update() on each object in the game loop. - */ - function () { - this.frameBounds.x = this.x; - this.frameBounds.y = this.y; - this.screen.x = this.x - (this.game.world.cameras.default.worldView.x * this.scrollFactor.x); - this.screen.y = this.y - (this.game.world.cameras.default.worldView.y * this.scrollFactor.y); - if(this.modified == false && (!this.scale.equals(1) || !this.skew.equals(0) || this.angle != 0 || this.angleOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { - this.modified = true; - } - }; - Sprite.prototype.update = /** - * Override this function to update your class's position and appearance. - */ - function () { - }; - Sprite.prototype.postUpdate = /** - * Automatically called after update() by the game loop. - */ - function () { - this.animations.update(); - this.body.postUpdate(); - /* - if (this.worldBounds != null) - { - if (this.outOfBoundsAction == GameObject.OUT_OF_BOUNDS_KILL) - { - if (this.x < this.worldBounds.x || this.x > this.worldBounds.right || this.y < this.worldBounds.y || this.y > this.worldBounds.bottom) - { - this.kill(); - } - } - else - { - if (this.x < this.worldBounds.x) - { - this.x = this.worldBounds.x; - } - else if (this.x > this.worldBounds.right) - { - this.x = this.worldBounds.right; - } - - if (this.y < this.worldBounds.y) - { - this.y = this.worldBounds.y; - } - else if (this.y > this.worldBounds.bottom) - { - this.y = this.worldBounds.bottom; - } - } - } - */ - if(this.modified == true && this.scale.equals(1) && this.skew.equals(0) && this.angle == 0 && this.angleOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { - this.modified = false; - } - }; - Sprite.prototype.destroy = /** - * Clean up memory. - */ - function () { - //this.input.destroy(); - }; - Sprite.prototype.kill = /** - * Handy for "killing" game objects. - * Default behavior is to flag them as nonexistent AND dead. - * However, if you want the "corpse" to remain in the game, - * like to animate an effect or whatever, you should override this, - * setting only alive to false, and leaving exists true. - */ - function (removeFromGroup) { - if (typeof removeFromGroup === "undefined") { removeFromGroup = false; } - this.alive = false; - this.exists = false; - if(removeFromGroup && this.group) { - this.group.remove(this); - } - this.events.onKilled.dispatch(this); - }; - Sprite.prototype.revive = /** - * Handy for bringing game objects "back to life". Just sets alive and exists back to true. - * In practice, this is most often called by Object.reset(). - */ - function () { - this.alive = true; - this.exists = true; - this.events.onRevived.dispatch(this); - }; - return Sprite; - })(); - Phaser.Sprite = Sprite; -})(Phaser || (Phaser = {})); /// /// /** @@ -7512,12 +7573,14 @@ var Phaser; })(); Phaser.CameraFX = CameraFX; })(Phaser || (Phaser = {})); +/// /// /// /// -/// -/// /// +/// +/// +/// /** * Phaser - Camera * @@ -7539,26 +7602,22 @@ var Phaser; * @param height {number} The height of the camera display in pixels. */ function Camera(game, id, x, y, width, height) { - this._clip = false; - this._rotation = 0; this._target = null; /** - * Scale factor of the camera. - * @type {Vec2} + * Controls if this camera is clipped or not when rendering. You shouldn't usually set this value directly. */ - this.scale = new Phaser.Vec2(1, 1); + this.clip = false; /** - * Scrolling factor. - * @type {MicroPoint} - */ - this.scroll = new Phaser.Vec2(0, 0); - /** - * Camera bounds. + * Camera worldBounds. * @type {Rectangle} */ - this.bounds = null; + this.worldBounds = null; /** - * Sprite moving inside this rectangle will not cause camera moving. + * A boolean representing if the Camera has been modified in any way via a scale, rotate, flip or skew. + */ + this.modified = false; + /** + * Sprite moving inside this Rectangle will not cause camera moving. * @type {Rectangle} */ this.deadzone = null; @@ -7568,48 +7627,26 @@ var Phaser; */ this.disableClipping = false; /** - * Whether the camera background is opaque or not. If set to true the Camera is filled with - * the value of Camera.backgroundColor every frame. Normally you wouldn't enable this if the - * Camera is the full Stage size, as the Stage.backgroundColor has the same effect. But for - * multiple or mini cameras it can be very useful. - * @type {boolean} - */ - this.opaque = false; - /** - * The Background Color of the camera in css color string format, i.e. 'rgb(0,0,0)' or '#ff0000'. - * Not used if the Camera.opaque property is false. - * @type {string} - */ - this.backgroundColor = 'rgb(0,0,0)'; - /** - * Whether this camera visible or not. (default is true) + * Whether this camera is visible or not. (default is true) * @type {boolean} */ this.visible = true; /** - * Alpha of the camera. (everything rendered to this camera will be affected) - * @type {number} + * The z value of this Camera. Cameras are rendered in z-index order by the Renderer. */ - this.alpha = 1; - /** - * The x position of the current input event in world coordinates. - * @type {number} - */ - this.inputX = 0; - /** - * The y position of the current input event in world coordinates. - * @type {number} - */ - this.inputY = 0; - this._game = game; + this.z = -1; + this.game = game; this.ID = id; - this._stageX = x; - this._stageY = y; - this.scaledX = x; - this.scaledY = y; - this.fx = new Phaser.CameraFX(this._game, this); - // The view into the world canvas we wish to render + this.z = id; + // The view into the world we wish to render (by default the full game world size) + // The size of this Rect is the same as screenView, but the values are all in world coordinates instead of screen coordinates this.worldView = new Phaser.Rectangle(0, 0, width, height); + // The rect of the area being rendered in stage/screen coordinates + this.screenView = new Phaser.Rectangle(x, y, width, height); + this.fx = new Phaser.CameraFX(this.game, this); + this.transform = new Phaser.Components.Transform(this); + this.texture = new Phaser.Components.Texture(this); + this.texture.opaque = false; this.checkClip(); } Camera.STYLE_LOCKON = 0; @@ -7624,7 +7661,7 @@ var Phaser; */ function (object) { if(this.isHidden(object) == false) { - object['cameraBlacklist'].push(this.ID); + object.texture['cameraBlacklist'].push(this.ID); } }; Camera.prototype.isHidden = /** @@ -7633,7 +7670,7 @@ var Phaser; * @param object {Sprite/Group} The object to check. */ function (object) { - return (object['cameraBlacklist'] && object['cameraBlacklist'].length > 0 && object['cameraBlacklist'].indexOf(this.ID) == -1); + return (object.texture['cameraBlacklist'] && object.texture['cameraBlacklist'].length > 0 && object.texture['cameraBlacklist'].indexOf(this.ID) == -1); }; Camera.prototype.show = /** * Un-hides an object previously hidden to this Camera. @@ -7643,7 +7680,7 @@ var Phaser; */ function (object) { if(this.isHidden(object) == true) { - object['cameraBlacklist'].slice(object['cameraBlacklist'].indexOf(this.ID), 1); + object.texture['cameraBlacklist'].slice(object.texture['cameraBlacklist'].indexOf(this.ID), 1); } }; Camera.prototype.follow = /** @@ -7683,8 +7720,8 @@ var Phaser; function (x, y) { x += (x > 0) ? 0.0000001 : -0.0000001; y += (y > 0) ? 0.0000001 : -0.0000001; - this.scroll.x = Math.round(x - this.worldView.halfWidth); - this.scroll.y = Math.round(y - this.worldView.halfHeight); + this.worldView.x = Math.round(x - this.worldView.halfWidth); + this.worldView.y = Math.round(y - this.worldView.halfHeight); }; Camera.prototype.focusOn = /** * Move the camera focus to this location instantly. @@ -7693,8 +7730,8 @@ var Phaser; function (point) { point.x += (point.x > 0) ? 0.0000001 : -0.0000001; point.y += (point.y > 0) ? 0.0000001 : -0.0000001; - this.scroll.x = Math.round(point.x - this.worldView.halfWidth); - this.scroll.y = Math.round(point.y - this.worldView.halfHeight); + this.worldView.x = Math.round(point.x - this.worldView.halfWidth); + this.worldView.y = Math.round(point.y - this.worldView.halfHeight); }; Camera.prototype.setBounds = /** * Specify the boundaries of the world or where the camera is allowed to move. @@ -7709,17 +7746,23 @@ var Phaser; if (typeof y === "undefined") { y = 0; } if (typeof width === "undefined") { width = 0; } if (typeof height === "undefined") { height = 0; } - if(this.bounds == null) { - this.bounds = new Phaser.Rectangle(); + if(this.worldBounds == null) { + this.worldBounds = new Phaser.Rectangle(); } - this.bounds.setTo(x, y, width, height); - this.scroll.setTo(0, 0); + this.worldBounds.setTo(x, y, width, height); + this.worldView.x = x; + this.worldView.y = y; this.update(); }; Camera.prototype.update = /** * Update focusing and scrolling. */ function () { + if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { + this.modified = true; + } else if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { + this.modified = false; + } this.fx.preUpdate(); if(this._target !== null) { if(this.deadzone == null) { @@ -7729,215 +7772,139 @@ var Phaser; var targetX = this._target.x + ((this._target.x > 0) ? 0.0000001 : -0.0000001); var targetY = this._target.y + ((this._target.y > 0) ? 0.0000001 : -0.0000001); edge = targetX - this.deadzone.x; - if(this.scroll.x > edge) { - this.scroll.x = edge; + if(this.worldView.x > edge) { + this.worldView.x = edge; } edge = targetX + this._target.width - this.deadzone.x - this.deadzone.width; - if(this.scroll.x < edge) { - this.scroll.x = edge; + if(this.worldView.x < edge) { + this.worldView.x = edge; } edge = targetY - this.deadzone.y; - if(this.scroll.y > edge) { - this.scroll.y = edge; + if(this.worldView.y > edge) { + this.worldView.y = edge; } edge = targetY + this._target.height - this.deadzone.y - this.deadzone.height; - if(this.scroll.y < edge) { - this.scroll.y = edge; + if(this.worldView.y < edge) { + this.worldView.y = edge; } } } - // Make sure we didn't go outside the cameras bounds - if(this.bounds !== null) { - if(this.scroll.x < this.bounds.left) { - this.scroll.x = this.bounds.left; + // Make sure we didn't go outside the cameras worldBounds + if(this.worldBounds !== null) { + if(this.worldView.x < this.worldBounds.left) { + this.worldView.x = this.worldBounds.left; } - if(this.scroll.x > this.bounds.right - this.width) { - this.scroll.x = (this.bounds.right - this.width) + 1; + if(this.worldView.x > this.worldBounds.right - this.width) { + this.worldView.x = (this.worldBounds.right - this.width) + 1; } - if(this.scroll.y < this.bounds.top) { - this.scroll.y = this.bounds.top; + if(this.worldView.y < this.worldBounds.top) { + this.worldView.y = this.worldBounds.top; } - if(this.scroll.y > this.bounds.bottom - this.height) { - this.scroll.y = (this.bounds.bottom - this.height) + 1; + if(this.worldView.y > this.worldBounds.bottom - this.height) { + this.worldView.y = (this.worldBounds.bottom - this.height) + 1; } } - this.worldView.x = this.scroll.x; - this.worldView.y = this.scroll.y; - // Input values - this.inputX = this.worldView.x + this._game.input.x; - this.inputY = this.worldView.y + this._game.input.y; this.fx.postUpdate(); }; - Camera.prototype.preRender = /** - * Camera preRender - */ - function () { - if(this.visible === false || this.alpha < 0.1) { - return; - } - if(this._rotation !== 0 || this._clip || this.scale.x !== 1 || this.scale.y !== 1) { - this._game.stage.context.save(); - } - this.fx.preRender(this, this._stageX, this._stageY, this.worldView.width, this.worldView.height); - if(this.alpha !== 1) { - this._game.stage.context.globalAlpha = this.alpha; - } - this.scaledX = this._stageX; - this.scaledY = this._stageY; - // Scale on - if(this.scale.x !== 1 || this.scale.y !== 1) { - this._game.stage.context.scale(this.scale.x, this.scale.y); - this.scaledX = this.scaledX / this.scale.x; - this.scaledY = this.scaledY / this.scale.y; - } - // Rotation - translate to the mid-point of the camera - if(this._rotation !== 0) { - this._game.stage.context.translate(this.scaledX + this.worldView.halfWidth, this.scaledY + this.worldView.halfHeight); - this._game.stage.context.rotate(this._rotation * (Math.PI / 180)); - // now shift back to where that should actually render - this._game.stage.context.translate(-(this.scaledX + this.worldView.halfWidth), -(this.scaledY + this.worldView.halfHeight)); - } - // Background - if(this.opaque) { - this._game.stage.context.fillStyle = this.backgroundColor; - this._game.stage.context.fillRect(this.scaledX, this.scaledY, this.worldView.width, this.worldView.height); - } - this.fx.render(this, this._stageX, this._stageY, this.worldView.width, this.worldView.height); - // Clip the camera so we don't get sprites appearing outside the edges - if(this._clip == true && this.disableClipping == false) { - this._game.stage.context.beginPath(); - this._game.stage.context.rect(this.scaledX, this.scaledY, this.worldView.width, this.worldView.height); - this._game.stage.context.closePath(); - this._game.stage.context.clip(); - } - }; - Camera.prototype.postRender = /** - * Camera postRender - */ - function () { - // Scale off - if(this.scale.x !== 1 || this.scale.y !== 1) { - this._game.stage.context.scale(1, 1); - } - this.fx.postRender(this, this.scaledX, this.scaledY, this.worldView.width, this.worldView.height); - if(this._rotation !== 0 || (this._clip && this.disableClipping == false)) { - this._game.stage.context.translate(0, 0); - } - if(this._rotation !== 0 || this._clip || this.scale.x !== 1 || this.scale.y !== 1) { - this._game.stage.context.restore(); - } - if(this.alpha !== 1) { - this._game.stage.context.globalAlpha = 1; - } - }; - Camera.prototype.setPosition = /** - * Set position of this camera. - * @param x {number} X position. - * @param y {number} Y position. - */ - function (x, y) { - this._stageX = x; - this._stageY = y; - this.checkClip(); - }; - Camera.prototype.setSize = /** - * Give this camera a new size. - * @param width {number} Width of new size. - * @param height {number} Height of new size. - */ - function (width, height) { - this.worldView.width = width; - this.worldView.height = height; - this.checkClip(); - }; Camera.prototype.renderDebugInfo = /** - * Render debug infos. (including id, position, rotation, scrolling factor, bounds and some other properties) + * Render debug infos. (including id, position, rotation, scrolling factor, worldBounds and some other properties) * @param x {number} X position of the debug info to be rendered. * @param y {number} Y position of the debug info to be rendered. * @param [color] {number} color of the debug info to be rendered. (format is css color string) */ function (x, y, color) { if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } - this._game.stage.context.fillStyle = color; - this._game.stage.context.fillText('Camera ID: ' + this.ID + ' (' + this.worldView.width + ' x ' + this.worldView.height + ')', x, y); - this._game.stage.context.fillText('X: ' + this._stageX + ' Y: ' + this._stageY + ' Rotation: ' + this._rotation, x, y + 14); - this._game.stage.context.fillText('World X: ' + this.scroll.x.toFixed(1) + ' World Y: ' + this.scroll.y.toFixed(1), x, y + 28); - if(this.bounds) { - this._game.stage.context.fillText('Bounds: ' + this.bounds.width + ' x ' + this.bounds.height, x, y + 42); + this.game.stage.context.fillStyle = color; + this.game.stage.context.fillText('Camera ID: ' + this.ID + ' (' + this.screenView.width + ' x ' + this.screenView.height + ')', x, y); + this.game.stage.context.fillText('X: ' + this.screenView.x + ' Y: ' + this.screenView.y + ' rotation: ' + this.transform.rotation, x, y + 14); + this.game.stage.context.fillText('World X: ' + this.worldView.x.toFixed(1) + ' World Y: ' + this.worldView.y.toFixed(1), x, y + 28); + if(this.worldBounds) { + this.game.stage.context.fillText('Bounds: ' + this.worldBounds.width + ' x ' + this.worldBounds.height, x, y + 42); } }; Camera.prototype.destroy = /** * Destroys this camera, associated FX and removes itself from the CameraManager. */ function () { - this._game.world.cameras.removeCamera(this.ID); + this.game.world.cameras.removeCamera(this.ID); this.fx.destroy(); }; Object.defineProperty(Camera.prototype, "x", { get: function () { - return this._stageX; + return this.worldView.x; }, set: function (value) { - this._stageX = value; - this.checkClip(); + this.worldView.x = value; }, enumerable: true, configurable: true }); Object.defineProperty(Camera.prototype, "y", { get: function () { - return this._stageY; + return this.worldView.y; }, set: function (value) { - this._stageY = value; - this.checkClip(); + this.worldView.y = value; }, enumerable: true, configurable: true }); Object.defineProperty(Camera.prototype, "width", { get: function () { - return this.worldView.width; + return this.screenView.width; }, set: function (value) { - if(value > this._game.stage.width) { - value = this._game.stage.width; - } + this.screenView.width = value; this.worldView.width = value; - this.checkClip(); }, enumerable: true, configurable: true }); Object.defineProperty(Camera.prototype, "height", { get: function () { - return this.worldView.height; + return this.screenView.height; }, set: function (value) { - if(value > this._game.stage.height) { - value = this._game.stage.height; - } + this.screenView.height = value; this.worldView.height = value; - this.checkClip(); }, enumerable: true, configurable: true }); + Camera.prototype.setPosition = function (x, y) { + this.screenView.x = x; + this.screenView.y = y; + this.checkClip(); + }; + Camera.prototype.setSize = function (width, height) { + this.screenView.width = width * this.transform.scale.x; + this.screenView.height = height * this.transform.scale.y; + this.worldView.width = width; + this.worldView.height = height; + this.checkClip(); + }; Object.defineProperty(Camera.prototype, "rotation", { - get: function () { - return this._rotation; + get: /** + * The angle of the Camera in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + */ + function () { + return this.transform.rotation; }, - set: function (value) { - this._rotation = this._game.math.wrap(value, 360, 0); + set: /** + * Set the angle of the Camera in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. + * The value is automatically wrapped to be between 0 and 360. + */ + function (value) { + this.transform.rotation = this.game.math.wrap(value, 360, 0); }, enumerable: true, configurable: true }); Camera.prototype.checkClip = function () { - if(this._stageX !== 0 || this._stageY !== 0 || this.worldView.width < this._game.stage.width || this.worldView.height < this._game.stage.height) { - this._clip = true; + if(this.screenView.x != 0 || this.screenView.y != 0 || this.screenView.width < this.game.stage.width || this.screenView.height < this.game.stage.height) { + this.clip = true; } else { - this._clip = false; + this.clip = false; } }; return Camera; @@ -7969,6 +7936,10 @@ var Phaser; * Local helper stores index of next created camera. */ this._cameraInstance = 0; + /** + * Helper for sort. + */ + this._sortIndex = ''; this._game = game; this._cameras = []; this.default = this.addCamera(x, y, width, height); @@ -8026,6 +7997,52 @@ var Phaser; } return false; }; + CameraManager.prototype.swap = function (camera1, camera2, sort) { + if (typeof sort === "undefined") { sort = true; } + if(camera1.ID == camera2.ID) { + return false; + } + var tempZ = camera1.z; + camera1.z = camera2.z; + camera2.z = tempZ; + if(sort) { + this.sort(); + } + return true; + }; + CameraManager.prototype.sort = /** + * Call this function to sort the Cameras according to a particular value and order (default is their Z value). + * The order in which they are sorted determines the render order. If sorted on z then Cameras with a lower z-index value render first. + * + * @param {string} index The string name of the Camera variable you want to sort on. Default value is "z". + * @param {number} order A Group constant that defines the sort order. Possible values are Group.ASCENDING and Group.DESCENDING. Default value is Group.ASCENDING. + */ + function (index, order) { + if (typeof index === "undefined") { index = 'z'; } + if (typeof order === "undefined") { order = Phaser.Group.ASCENDING; } + var _this = this; + this._sortIndex = index; + this._sortOrder = order; + this._cameras.sort(function (a, b) { + return _this.sortHandler(a, b); + }); + }; + CameraManager.prototype.sortHandler = /** + * Helper function for the sort process. + * + * @param {Basic} Obj1 The first object being sorted. + * @param {Basic} Obj2 The second object being sorted. + * + * @return {number} An integer value: -1 (Obj1 before Obj2), 0 (same), or 1 (Obj1 after Obj2). + */ + function (obj1, obj2) { + if(obj1[this._sortIndex] < obj2[this._sortIndex]) { + return this._sortOrder; + } else if(obj1[this._sortIndex] > obj2[this._sortIndex]) { + return -this._sortOrder; + } + return 0; + }; CameraManager.prototype.destroy = /** * Clean up memory. */ @@ -8893,7 +8910,7 @@ var Phaser; } particle.exists = false; // Center the origin for rotation assistance - particle.origin.setTo(particle.body.bounds.halfWidth, particle.body.bounds.halfHeight); + particle.transform.origin.setTo(particle.body.bounds.halfWidth, particle.body.bounds.halfHeight); this.add(particle); i++; } @@ -8999,7 +9016,7 @@ var Phaser; particle.body.angularVelocity = this.minRotation; } if(particle.body.angularVelocity != 0) { - particle.angle = this.game.math.random() * 360 - 180; + particle.rotation = this.game.math.random() * 360 - 180; } particle.body.drag.x = this.particleDrag.x; particle.body.drag.y = this.particleDrag.y; @@ -9436,10 +9453,10 @@ var Phaser; * Swap tiles with 2 kinds of indexes. * @param tileA {number} First tile index. * @param tileB {number} Second tile index. - * @param [x] {number} specify a rectangle of tiles to operate. The x position in tiles of rectangle's left-top corner. - * @param [y] {number} specify a rectangle of tiles to operate. The y position in tiles of rectangle's left-top corner. - * @param [width] {number} specify a rectangle of tiles to operate. The width in tiles. - * @param [height] {number} specify a rectangle of tiles to operate. The height in tiles. + * @param [x] {number} specify a Rectangle of tiles to operate. The x position in tiles of Rectangle's left-top corner. + * @param [y] {number} specify a Rectangle of tiles to operate. The y position in tiles of Rectangle's left-top corner. + * @param [width] {number} specify a Rectangle of tiles to operate. The width in tiles. + * @param [height] {number} specify a Rectangle of tiles to operate. The height in tiles. */ function (tileA, tileB, x, y, width, height) { if (typeof x === "undefined") { x = 0; } @@ -10271,13 +10288,15 @@ var Phaser; * @param x {number} X position of the new sprite. * @param y {number} Y position of the new sprite. * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this sprite + * @param [frame] {string|number} If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name. * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) * @returns {Sprite} The newly created sprite object. */ - function (x, y, key, bodyType) { + function (x, y, key, frame, bodyType) { if (typeof key === "undefined") { key = ''; } + if (typeof frame === "undefined") { frame = null; } if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } - return this._world.group.add(new Phaser.Sprite(this._game, x, y, key, bodyType)); + return this._world.group.add(new Phaser.Sprite(this._game, x, y, key, frame, bodyType)); }; GameObjectFactory.prototype.dynamicTexture = /** * Create a new DynamicTexture with specific size. @@ -10676,7 +10695,7 @@ var Phaser; /** * StageScaleMode constructor */ - function StageScaleMode(game) { + function StageScaleMode(game, width, height) { var _this = this; /** * Stage height when start the game. @@ -10699,6 +10718,20 @@ var Phaser; */ this.incorrectOrientation = false; /** + * If you wish to align your game in the middle of the page then you can set this value to true. + * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing. + * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin. + * @type {Boolean} + */ + this.pageAlignHorizontally = false; + /** + * If you wish to align your game in the middle of the page then you can set this value to true. + * It will place a re-calculated margin-left pixel value onto the canvas element which is updated on orientation/resizing. + * It doesn't care about any other DOM element that may be on the page, it literally just sets the margin. + * @type {Boolean} + */ + this.pageAlignVeritcally = false; + /** * Minimum width the canvas should be scaled to (in pixels) * @type {number} */ @@ -10744,6 +10777,10 @@ var Phaser; } this.scaleFactor = new Phaser.Vec2(1, 1); this.aspectRatio = 0; + this.minWidth = width; + this.minHeight = height; + this.maxWidth = width; + this.maxHeight = height; window.addEventListener('orientationchange', function (event) { return _this.checkOrientation(event); }, false); @@ -10888,7 +10925,8 @@ var Phaser; StageScaleMode.prototype.setScreenSize = /** * Set screen size automatically based on the scaleMode. */ - function () { + function (force) { + if (typeof force === "undefined") { force = false; } if(this._game.device.iPad == false && this._game.device.webApp == false && this._game.device.desktop == false) { if(this._game.device.android && this._game.device.chrome == false) { window.scrollTo(0, 1); @@ -10897,7 +10935,7 @@ var Phaser; } } this._iterations--; - if(window.innerHeight > this._startHeight || this._iterations < 0) { + if(force || window.innerHeight > this._startHeight || this._iterations < 0) { // Set minimum height of content to new window height document.documentElement.style.minHeight = window.innerHeight + 'px'; if(this.incorrectOrientation == true) { @@ -10913,29 +10951,43 @@ var Phaser; } }; StageScaleMode.prototype.setSize = function () { - if(this.maxWidth && this.width > this.maxWidth) { - this.width = this.maxWidth; - } - if(this.maxHeight && this.height > this.maxHeight) { - this.height = this.maxHeight; - } - if(this.minWidth && this.width < this.minWidth) { - this.width = this.minWidth; - } - if(this.minHeight && this.height < this.minHeight) { - this.height = this.minHeight; + if(this.incorrectOrientation == false) { + if(this.maxWidth && this.width > this.maxWidth) { + this.width = this.maxWidth; + } + if(this.maxHeight && this.height > this.maxHeight) { + this.height = this.maxHeight; + } + if(this.minWidth && this.width < this.minWidth) { + this.width = this.minWidth; + } + if(this.minHeight && this.height < this.minHeight) { + this.height = this.minHeight; + } } this._game.stage.canvas.style.width = this.width + 'px'; this._game.stage.canvas.style.height = this.height + 'px'; this._game.input.scaleX = this._game.stage.width / this.width; this._game.input.scaleY = this._game.stage.height / this.height; + if(this.pageAlignHorizontally) { + if(this.width < window.innerWidth && this.incorrectOrientation == false) { + this._game.stage.canvas.style.marginLeft = Math.round((window.innerWidth - this.width) / 2) + 'px'; + } else { + this._game.stage.canvas.style.marginLeft = '0px'; + } + } + if(this.pageAlignVeritcally) { + if(this.height < window.innerHeight && this.incorrectOrientation == false) { + this._game.stage.canvas.style.marginTop = Math.round((window.innerHeight - this.height) / 2) + 'px'; + } else { + this._game.stage.canvas.style.marginTop = '0px'; + } + } this._game.stage.getOffset(this._game.stage.canvas); this.aspectRatio = this.width / this.height; this.scaleFactor.x = this._game.stage.width / this.width; this.scaleFactor.y = this._game.stage.height / this.height; - //this.scaleFactor.x = this.width / this._game.stage.width; - //this.scaleFactor.y = this.height / this._game.stage.height; - }; + }; StageScaleMode.prototype.setMaximum = function () { this.width = window.innerWidth; this.height = window.innerHeight; @@ -11283,7 +11335,7 @@ var Phaser; }; this.context = this.canvas.getContext('2d'); this.scaleMode = Phaser.StageScaleMode.NO_SCALE; - this.scale = new Phaser.StageScaleMode(this._game); + this.scale = new Phaser.StageScaleMode(this._game, width, height); this.getOffset(this.canvas); this.bounds = new Phaser.Rectangle(this.offset.x, this.offset.y, width, height); this.aspectRatio = width / height; @@ -11307,6 +11359,7 @@ var Phaser; this.bootScreen = new Phaser.BootScreen(this._game); this.pauseScreen = new Phaser.PauseScreen(this._game, this.width, this.height); this.orientationScreen = new Phaser.OrientationScreen(this._game); + this.scale.setScreenSize(true); }; Stage.prototype.update = /** * Update stage for rendering. This will handle scaling, clearing @@ -11364,6 +11417,12 @@ var Phaser; } } }; + Stage.prototype.setImageRenderingCrisp = function () { + this.canvas.style['image-rendering'] = 'crisp-edges'; + this.canvas.style['image-rendering'] = '-moz-crisp-edges'; + this.canvas.style['image-rendering'] = '-webkit-optimize-contrast'; + this.canvas.style['-ms-interpolation-mode'] = 'nearest-neighbor'; + }; Stage.prototype.pauseGame = function () { if(this.disablePauseScreen == false && this.pauseScreen) { this.pauseScreen.onPaused(); @@ -11967,7 +12026,7 @@ var Phaser; } this._velocityDelta = (this.computeVelocity(body.angularVelocity, body.gravity.x, body.angularAcceleration, body.angularDrag, body.maxAngular) - body.angularVelocity) / 2; body.angularVelocity += this._velocityDelta; - body.angle += body.angularVelocity * this.game.time.elapsed; + body.sprite.transform.rotation += body.angularVelocity * this.game.time.elapsed; body.angularVelocity += this._velocityDelta; this._velocityDelta = (this.computeVelocity(body.velocity.x, body.gravity.x, body.acceleration.x, body.drag.x) - body.velocity.x) / 2; body.velocity.x += this._velocityDelta; @@ -12167,7 +12226,7 @@ var Phaser; body1.velocity.y = this._obj2Velocity - this._obj1Velocity * body1.bounce.y; // This is special case code that handles things like horizontal moving platforms you can ride //if (body2.parent.active && body2.moves && (body1.deltaY > body2.deltaY)) - if(body2.parent.active && (body1.deltaY > body2.deltaY)) { + if(body2.sprite.active && (body1.deltaY > body2.deltaY)) { body1.position.x += body2.position.x - body2.oldPosition.x; } } else if(body1.type != Phaser.Types.BODY_DYNAMIC) { @@ -12176,7 +12235,7 @@ var Phaser; body2.velocity.y = this._obj1Velocity - this._obj2Velocity * body2.bounce.y; // This is special case code that handles things like horizontal moving platforms you can ride //if (object1.active && body1.moves && (body1.deltaY < body2.deltaY)) - if(body1.parent.active && (body1.deltaY < body2.deltaY)) { + if(body1.sprite.active && (body1.deltaY < body2.deltaY)) { body2.position.x += body1.position.x - body1.oldPosition.x; } } @@ -13136,8 +13195,8 @@ var Phaser; * @return {number} Distance (in pixels) */ function (a, target) { - var dx = (a.x + a.origin.x) - (target.x); - var dy = (a.y + a.origin.y) - (target.y); + var dx = (a.x + a.transform.origin.x) - (target.x); + var dy = (a.y + a.transform.origin.y) - (target.y); return this.game.math.vectorLength(dx, dy); }; Motion.prototype.distanceToMouse = /** @@ -13147,8 +13206,8 @@ var Phaser; * @return {number} The distance between the given sprite and the mouse coordinates */ function (a) { - var dx = (a.x + a.origin.x) - this.game.input.x; - var dy = (a.y + a.origin.y) - this.game.input.y; + var dx = (a.x + a.transform.origin.x) - this.game.input.x; + var dy = (a.y + a.transform.origin.y) - this.game.input.y; return this.game.math.vectorLength(dx, dy); }; Motion.prototype.angleBetweenPoint = /** @@ -13163,8 +13222,8 @@ var Phaser; */ function (a, target, asDegrees) { if (typeof asDegrees === "undefined") { asDegrees = false; } - var dx = (target.x) - (a.x + a.origin.x); - var dy = (target.y) - (a.y + a.origin.y); + var dx = (target.x) - (a.x + a.transform.origin.x); + var dy = (target.y) - (a.y + a.transform.origin.y); if(asDegrees) { return this.game.math.radiansToDegrees(Math.atan2(dy, dx)); } else { @@ -13183,8 +13242,8 @@ var Phaser; */ function (a, b, asDegrees) { if (typeof asDegrees === "undefined") { asDegrees = false; } - var dx = (b.x + b.origin.x) - (a.x + a.origin.x); - var dy = (b.y + b.origin.y) - (a.y + a.origin.y); + var dx = (b.x + b.transform.origin.x) - (a.x + a.transform.origin.x); + var dy = (b.y + b.transform.origin.y) - (a.y + a.transform.origin.y); if(asDegrees) { return this.game.math.radiansToDegrees(Math.atan2(dy, dx)); } else { @@ -13941,7 +14000,7 @@ var Phaser; * @param x {number} The x coordinate of the anchor point * @param y {number} The y coordinate of the anchor point * @param {Number} angle The angle in radians (unless asDegrees is true) to rotate the Point to. - * @param {Boolean} asDegrees Is the given angle in radians (false) or degrees (true)? + * @param {Boolean} asDegrees Is the given rotation in radians (false) or degrees (true)? * @param {Number} distance An optional distance constraint between the Point and the anchor. * @return The modified point object */ @@ -13964,7 +14023,7 @@ var Phaser; * @param x {number} The x coordinate of the anchor point * @param y {number} The y coordinate of the anchor point * @param {Number} angle The angle in radians (unless asDegrees is true) to rotate the Point to. - * @param {Boolean} asDegrees Is the given angle in radians (false) or degrees (true)? + * @param {Boolean} asDegrees Is the given rotation in radians (false) or degrees (true)? * @param {Number} distance An optional distance constraint between the Point and the anchor. * @return The modified point object */ @@ -14162,7 +14221,7 @@ var Phaser; configurable: true }); Pointer.prototype.getWorldX = /** - * Gets the X value of this Pointer in world coordinate space + * Gets the X value of this Pointer in world coordinate space (is it properly scaled?) * @param {Camera} [camera] */ function (camera) { @@ -14222,6 +14281,7 @@ var Phaser; this.isUp = false; this.timeDown = this.game.time.now; this._holdSent = false; + // x and y are the old values here? this.positionDown.setTo(this.x, this.y); this.move(event); if(this.game.input.multiInputOverride == Phaser.Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Phaser.Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == Phaser.Input.TOUCH_OVERRIDES_MOUSE && this.game.input.currentPointers == 0)) { @@ -15762,6 +15822,14 @@ var Phaser; if (typeof lineWidth === "undefined") { lineWidth = 1; } return true; }; + HeadlessRenderer.prototype.preRenderCamera = function (camera) { + }; + HeadlessRenderer.prototype.postRenderCamera = function (camera) { + }; + HeadlessRenderer.prototype.preRenderGroup = function (camera, group) { + }; + HeadlessRenderer.prototype.postRenderGroup = function (camera, group) { + }; return HeadlessRenderer; })(); Phaser.HeadlessRenderer = HeadlessRenderer; @@ -15798,9 +15866,9 @@ var Phaser; // Then iterate through world.group on them all (where not blacklisted, etc) for(var c = 0; c < this._cameraList.length; c++) { this._camera = this._cameraList[c]; - this._camera.preRender(); + this.preRenderCamera(this._camera); this._game.world.group.render(this._camera); - this._camera.postRender(); + this.postRenderCamera(this._camera); } this.renderTotal = this._count; }; @@ -15811,21 +15879,236 @@ var Phaser; this.renderScrollZone(this._camera, object); } }; + CanvasRenderer.prototype.preRenderGroup = function (camera, group) { + if(camera.transform.scale.x == 0 || camera.transform.scale.y == 0 || camera.texture.alpha < 0.1 || this.inScreen(camera) == false) { + return false; + } + // Reset our temp vars + this._ga = -1; + this._sx = 0; + this._sy = 0; + this._sw = group.texture.width; + this._sh = group.texture.height; + this._fx = group.transform.scale.x; + this._fy = group.transform.scale.y; + this._sin = 0; + this._cos = 1; + //this._dx = (camera.screenView.x * camera.scrollFactor.x) + camera.frameBounds.x - (camera.worldView.x * camera.scrollFactor.x); + //this._dy = (camera.screenView.y * camera.scrollFactor.y) + camera.frameBounds.y - (camera.worldView.y * camera.scrollFactor.y); + this._dx = 0; + this._dy = 0; + this._dw = group.texture.width; + this._dh = group.texture.height; + // Global Composite Ops + if(group.texture.globalCompositeOperation) { + group.texture.context.save(); + group.texture.context.globalCompositeOperation = group.texture.globalCompositeOperation; + } + // Alpha + if(group.texture.alpha !== 1 && group.texture.context.globalAlpha !== group.texture.alpha) { + this._ga = group.texture.context.globalAlpha; + group.texture.context.globalAlpha = group.texture.alpha; + } + // Flip X + if(group.texture.flippedX) { + this._fx = -group.transform.scale.x; + } + // Flip Y + if(group.texture.flippedY) { + this._fy = -group.transform.scale.y; + } + // Rotation and Flipped + if(group.modified) { + if(group.transform.rotation !== 0 || group.transform.rotationOffset !== 0) { + this._sin = Math.sin(group.game.math.degreesToRadians(group.transform.rotationOffset + group.transform.rotation)); + this._cos = Math.cos(group.game.math.degreesToRadians(group.transform.rotationOffset + group.transform.rotation)); + } + // setTransform(a, b, c, d, e, f); + // a = scale x + // b = skew x + // c = skew y + // d = scale y + // e = translate x + // f = translate y + group.texture.context.save(); + group.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + group.transform.skew.x, -(this._sin * this._fy) + group.transform.skew.y, this._cos * this._fy, this._dx, this._dy); + this._dx = -group.transform.origin.x; + this._dy = -group.transform.origin.y; + } else { + if(!group.transform.origin.equals(0)) { + this._dx -= group.transform.origin.x; + this._dy -= group.transform.origin.y; + } + } + this._sx = Math.round(this._sx); + this._sy = Math.round(this._sy); + this._sw = Math.round(this._sw); + this._sh = Math.round(this._sh); + this._dx = Math.round(this._dx); + this._dy = Math.round(this._dy); + this._dw = Math.round(this._dw); + this._dh = Math.round(this._dh); + if(group.texture.opaque) { + group.texture.context.fillStyle = group.texture.backgroundColor; + group.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); + } + if(group.texture.loaded) { + group.texture.context.drawImage(group.texture.texture, // Source Image + this._sx, // Source X (location within the source image) + this._sy, // Source Y + this._sw, // Source Width + this._sh, // Source Height + this._dx, // Destination X (where on the canvas it'll be drawn) + this._dy, // Destination Y + this._dw, // Destination Width (always same as Source Width unless scaled) + this._dh); + // Destination Height (always same as Source Height unless scaled) + } + return true; + }; + CanvasRenderer.prototype.postRenderGroup = function (camera, group) { + if(group.modified || group.texture.globalCompositeOperation) { + group.texture.context.restore(); + } + // This could have been over-written by a sprite, need to store elsewhere + if(this._ga > -1) { + group.texture.context.globalAlpha = this._ga; + } + }; CanvasRenderer.prototype.inCamera = /** - * Check whether this object is visible in a specific camera rectangle. - * @param camera {Rectangle} The rectangle you want to check. - * @return {boolean} Return true if bounds of this sprite intersects the given rectangle, otherwise return false. + * Check whether this object is visible in a specific camera Rectangle. + * @param camera {Rectangle} The Rectangle you want to check. + * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. */ function (camera, sprite) { + return true; + /* + // Object fixed in place regardless of the camera scrolling? Then it's always visible - if(sprite.scrollFactor.x == 0 && sprite.scrollFactor.y == 0) { - return true; + if (sprite.scrollFactor.x == 0 && sprite.scrollFactor.y == 0) + { + return true; } + this._dx = sprite.frameBounds.x - (camera.worldView.x * sprite.scrollFactor.x); this._dy = sprite.frameBounds.y - (camera.worldView.y * sprite.scrollFactor.y); this._dw = sprite.frameBounds.width * sprite.scale.x; this._dh = sprite.frameBounds.height * sprite.scale.y; - return (camera.scaledX + camera.worldView.width > this._dx) && (camera.scaledX < this._dx + this._dw) && (camera.scaledY + camera.worldView.height > this._dy) && (camera.scaledY < this._dy + this._dh); + + //return (camera.screenView.x + camera.worldView.width > this._dx) && (camera.screenView.x < this._dx + this._dw) && (camera.screenView.y + camera.worldView.height > this._dy) && (camera.screenView.y < this._dy + this._dh); + + */ + }; + CanvasRenderer.prototype.inScreen = function (camera) { + return true; + }; + CanvasRenderer.prototype.preRenderCamera = /** + * Render this sprite to specific camera. Called by game loop after update(). + * @param camera {Camera} Camera this sprite will be rendered to. + * @return {boolean} Return false if not rendered, otherwise return true. + */ + function (camera) { + if(camera.transform.scale.x == 0 || camera.transform.scale.y == 0 || camera.texture.alpha < 0.1 || this.inScreen(camera) == false) { + return false; + } + // Reset our temp vars + this._ga = -1; + this._sx = 0; + this._sy = 0; + this._sw = camera.width; + this._sh = camera.height; + this._fx = camera.transform.scale.x; + this._fy = camera.transform.scale.y; + this._sin = 0; + this._cos = 1; + this._dx = camera.screenView.x; + this._dy = camera.screenView.y; + this._dw = camera.width; + this._dh = camera.height; + // Global Composite Ops + if(camera.texture.globalCompositeOperation) { + camera.texture.context.save(); + camera.texture.context.globalCompositeOperation = camera.texture.globalCompositeOperation; + } + // Alpha + if(camera.texture.alpha !== 1 && camera.texture.context.globalAlpha != camera.texture.alpha) { + this._ga = camera.texture.context.globalAlpha; + camera.texture.context.globalAlpha = camera.texture.alpha; + } + // Sprite Flip X + if(camera.texture.flippedX) { + this._fx = -camera.transform.scale.x; + } + // Sprite Flip Y + if(camera.texture.flippedY) { + this._fy = -camera.transform.scale.y; + } + // Rotation and Flipped + if(camera.modified) { + if(camera.transform.rotation !== 0 || camera.transform.rotationOffset !== 0) { + this._sin = Math.sin(camera.game.math.degreesToRadians(camera.transform.rotationOffset + camera.transform.rotation)); + this._cos = Math.cos(camera.game.math.degreesToRadians(camera.transform.rotationOffset + camera.transform.rotation)); + } + // setTransform(a, b, c, d, e, f); + // a = scale x + // b = skew x + // c = skew y + // d = scale y + // e = translate x + // f = translate y + camera.texture.context.save(); + camera.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + camera.transform.skew.x, -(this._sin * this._fy) + camera.transform.skew.y, this._cos * this._fy, this._dx, this._dy); + this._dx = -camera.transform.origin.x; + this._dy = -camera.transform.origin.y; + } else { + if(!camera.transform.origin.equals(0)) { + this._dx -= camera.transform.origin.x; + this._dy -= camera.transform.origin.y; + } + } + this._sx = Math.round(this._sx); + this._sy = Math.round(this._sy); + this._sw = Math.round(this._sw); + this._sh = Math.round(this._sh); + this._dx = Math.round(this._dx); + this._dy = Math.round(this._dy); + this._dw = Math.round(this._dw); + this._dh = Math.round(this._dh); + // Clip the camera so we don't get sprites appearing outside the edges + if(camera.clip == true && camera.disableClipping == false) { + camera.texture.context.beginPath(); + camera.texture.context.rect(camera.screenView.x, camera.screenView.x, camera.screenView.width, camera.screenView.height); + camera.texture.context.closePath(); + camera.texture.context.clip(); + } + if(camera.texture.opaque) { + camera.texture.context.fillStyle = camera.texture.backgroundColor; + camera.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); + } + //camera.fx.render(camera); + if(camera.texture.loaded) { + camera.texture.context.drawImage(camera.texture.texture, // Source Image + this._sx, // Source X (location within the source image) + this._sy, // Source Y + this._sw, // Source Width + this._sh, // Source Height + this._dx, // Destination X (where on the canvas it'll be drawn) + this._dy, // Destination Y + this._dw, // Destination Width (always same as Source Width unless scaled) + this._dh); + // Destination Height (always same as Source Height unless scaled) + } + return true; + }; + CanvasRenderer.prototype.postRenderCamera = function (camera) { + //camera.fx.postRender(camera); + if(camera.modified || camera.texture.globalCompositeOperation) { + camera.texture.context.restore(); + } + // This could have been over-written by a sprite, need to store elsewhere + if(this._ga > -1) { + camera.texture.context.globalAlpha = this._ga; + } }; CanvasRenderer.prototype.renderCircle = function (camera, circle, context, outline, fill, lineColor, fillColor, lineWidth) { if (typeof outline === "undefined") { outline = false; } @@ -15843,8 +16126,8 @@ var Phaser; this._fy = 1; this._sin = 0; this._cos = 1; - this._dx = camera.scaledX + circle.x - camera.worldView.x; - this._dy = camera.scaledY + circle.y - camera.worldView.y; + this._dx = camera.screenView.x + circle.x - camera.worldView.x; + this._dy = camera.screenView.y + circle.y - camera.worldView.y; this._dw = circle.diameter; this._dh = circle.diameter; this._sx = Math.round(this._sx); @@ -15879,7 +16162,7 @@ var Phaser; * @return {boolean} Return false if not rendered, otherwise return true. */ function (camera, sprite) { - if(sprite.scale.x == 0 || sprite.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { + if(sprite.transform.scale.x == 0 || sprite.transform.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { return false; } sprite.renderOrderID = this._count; @@ -15888,28 +16171,33 @@ var Phaser; this._ga = -1; this._sx = 0; this._sy = 0; - this._sw = sprite.frameBounds.width; - this._sh = sprite.frameBounds.height; - this._fx = sprite.scale.x; - this._fy = sprite.scale.y; + this._sw = sprite.texture.width; + this._sh = sprite.texture.height; + this._fx = sprite.transform.scale.x; + this._fy = sprite.transform.scale.y; this._sin = 0; this._cos = 1; - this._dx = (camera.scaledX * sprite.scrollFactor.x) + sprite.frameBounds.x - (camera.worldView.x * sprite.scrollFactor.x); - 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; + this._dx = (camera.screenView.x * sprite.transform.scrollFactor.x) + sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + this._dy = (camera.screenView.y * sprite.transform.scrollFactor.y) + sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + this._dw = sprite.texture.width; + this._dh = sprite.texture.height; + // Global Composite Ops + if(sprite.texture.globalCompositeOperation) { + sprite.texture.context.save(); + sprite.texture.context.globalCompositeOperation = sprite.texture.globalCompositeOperation; + } // Alpha - if(sprite.texture.alpha !== 1) { + if(sprite.texture.alpha !== 1 && sprite.texture.context.globalAlpha != sprite.texture.alpha) { this._ga = sprite.texture.context.globalAlpha; sprite.texture.context.globalAlpha = sprite.texture.alpha; } // Sprite Flip X if(sprite.texture.flippedX) { - this._fx = -sprite.scale.x; + this._fx = -sprite.transform.scale.x; } // Sprite Flip Y if(sprite.texture.flippedY) { - this._fy = -sprite.scale.y; + this._fy = -sprite.transform.scale.y; } if(sprite.animations.currentFrame !== null) { this._sx = sprite.animations.currentFrame.x; @@ -15917,13 +16205,17 @@ var Phaser; if(sprite.animations.currentFrame.trimmed) { this._dx += sprite.animations.currentFrame.spriteSourceSizeX; this._dy += sprite.animations.currentFrame.spriteSourceSizeY; + this._sw = sprite.animations.currentFrame.spriteSourceSizeW; + this._sh = sprite.animations.currentFrame.spriteSourceSizeH; + this._dw = sprite.animations.currentFrame.spriteSourceSizeW; + this._dh = sprite.animations.currentFrame.spriteSourceSizeH; } } // Rotation and Flipped if(sprite.modified) { - if(sprite.texture.renderRotation == true && (sprite.angle !== 0 || sprite.angleOffset !== 0)) { - this._sin = Math.sin(sprite.game.math.degreesToRadians(sprite.angleOffset + sprite.angle)); - this._cos = Math.cos(sprite.game.math.degreesToRadians(sprite.angleOffset + sprite.angle)); + if(sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.transform.rotationOffset !== 0)) { + this._sin = Math.sin(sprite.game.math.degreesToRadians(sprite.transform.rotationOffset + sprite.rotation)); + this._cos = Math.cos(sprite.game.math.degreesToRadians(sprite.transform.rotationOffset + sprite.rotation)); } // setTransform(a, b, c, d, e, f); // a = scale x @@ -15933,13 +16225,13 @@ var Phaser; // e = translate x // f = translate y sprite.texture.context.save(); - 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; + sprite.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + sprite.transform.skew.x, -(this._sin * this._fy) + sprite.transform.skew.y, this._cos * this._fy, this._dx, this._dy); + this._dx = -sprite.transform.origin.x; + this._dy = -sprite.transform.origin.y; } else { - if(!sprite.origin.equals(0)) { - this._dx -= sprite.origin.x; - this._dy -= sprite.origin.y; + if(!sprite.transform.origin.equals(0)) { + this._dx -= sprite.transform.origin.x; + this._dy -= sprite.transform.origin.y; } } this._sx = Math.round(this._sx); @@ -15950,6 +16242,10 @@ var Phaser; this._dy = Math.round(this._dy); this._dw = Math.round(this._dw); this._dh = Math.round(this._dh); + if(sprite.texture.opaque) { + sprite.texture.context.fillStyle = sprite.texture.backgroundColor; + sprite.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); + } if(sprite.texture.loaded) { sprite.texture.context.drawImage(sprite.texture.texture, // Source Image this._sx, // Source X (location within the source image) @@ -15961,12 +16257,8 @@ var Phaser; this._dw, // Destination Width (always same as Source Width unless scaled) this._dh); // Destination Height (always same as Source Height unless scaled) - } else { - //sprite.texture.context.fillStyle = this.fillColor; - sprite.texture.context.fillStyle = 'rgb(255,255,255)'; - sprite.texture.context.fillRect(this._dx, this._dy, this._dw, this._dh); - } - if(sprite.modified) { + } + if(sprite.modified || sprite.texture.globalCompositeOperation) { sprite.texture.context.restore(); } if(this._ga > -1) { @@ -15975,7 +16267,7 @@ var Phaser; return true; }; CanvasRenderer.prototype.renderScrollZone = function (camera, scrollZone) { - if(scrollZone.scale.x == 0 || scrollZone.scale.y == 0 || scrollZone.texture.alpha < 0.1 || this.inCamera(camera, scrollZone) == false) { + if(scrollZone.transform.scale.x == 0 || scrollZone.transform.scale.y == 0 || scrollZone.texture.alpha < 0.1 || this.inCamera(camera, scrollZone) == false) { return false; } this._count++; @@ -15983,16 +16275,16 @@ var Phaser; this._ga = -1; this._sx = 0; this._sy = 0; - this._sw = scrollZone.frameBounds.width; - this._sh = scrollZone.frameBounds.height; - this._fx = scrollZone.scale.x; - this._fy = scrollZone.scale.y; + this._sw = scrollZone.width; + this._sh = scrollZone.height; + this._fx = scrollZone.transform.scale.x; + this._fy = scrollZone.transform.scale.y; this._sin = 0; this._cos = 1; - this._dx = (camera.scaledX * scrollZone.scrollFactor.x) + scrollZone.frameBounds.x - (camera.worldView.x * scrollZone.scrollFactor.x); - this._dy = (camera.scaledY * scrollZone.scrollFactor.y) + scrollZone.frameBounds.y - (camera.worldView.y * scrollZone.scrollFactor.y); - this._dw = scrollZone.frameBounds.width; - this._dh = scrollZone.frameBounds.height; + this._dx = (camera.screenView.x * scrollZone.transform.scrollFactor.x) + scrollZone.x - (camera.worldView.x * scrollZone.transform.scrollFactor.x); + this._dy = (camera.screenView.y * scrollZone.transform.scrollFactor.y) + scrollZone.y - (camera.worldView.y * scrollZone.transform.scrollFactor.y); + this._dw = scrollZone.width; + this._dh = scrollZone.height; // Alpha if(scrollZone.texture.alpha !== 1) { this._ga = scrollZone.texture.context.globalAlpha; @@ -16000,17 +16292,17 @@ var Phaser; } // Sprite Flip X if(scrollZone.texture.flippedX) { - this._fx = -scrollZone.scale.x; + this._fx = -scrollZone.transform.scale.x; } // Sprite Flip Y if(scrollZone.texture.flippedY) { - this._fy = -scrollZone.scale.y; + this._fy = -scrollZone.transform.scale.y; } // Rotation and Flipped if(scrollZone.modified) { - if(scrollZone.texture.renderRotation == true && (scrollZone.angle !== 0 || scrollZone.angleOffset !== 0)) { - this._sin = Math.sin(scrollZone.game.math.degreesToRadians(scrollZone.angleOffset + scrollZone.angle)); - this._cos = Math.cos(scrollZone.game.math.degreesToRadians(scrollZone.angleOffset + scrollZone.angle)); + if(scrollZone.texture.renderRotation == true && (scrollZone.rotation !== 0 || scrollZone.transform.rotationOffset !== 0)) { + this._sin = Math.sin(scrollZone.game.math.degreesToRadians(scrollZone.transform.rotationOffset + scrollZone.rotation)); + this._cos = Math.cos(scrollZone.game.math.degreesToRadians(scrollZone.transform.rotationOffset + scrollZone.rotation)); } // setTransform(a, b, c, d, e, f); // a = scale x @@ -16020,13 +16312,13 @@ var Phaser; // e = translate x // f = translate y scrollZone.texture.context.save(); - scrollZone.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + scrollZone.skew.x, -(this._sin * this._fy) + scrollZone.skew.y, this._cos * this._fy, this._dx, this._dy); - this._dx = -scrollZone.origin.x; - this._dy = -scrollZone.origin.y; + scrollZone.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + scrollZone.transform.skew.x, -(this._sin * this._fy) + scrollZone.transform.skew.y, this._cos * this._fy, this._dx, this._dy); + this._dx = -scrollZone.transform.origin.x; + this._dy = -scrollZone.transform.origin.y; } else { - if(!scrollZone.origin.equals(0)) { - this._dx -= scrollZone.origin.x; - this._dy -= scrollZone.origin.y; + if(!scrollZone.transform.origin.equals(0)) { + this._dx -= scrollZone.transform.origin.x; + this._dy -= scrollZone.transform.origin.y; } } this._sx = Math.round(this._sx); @@ -16080,8 +16372,8 @@ var Phaser; function renderSpriteInfo(sprite, x, y, color) { if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } DebugUtils.game.stage.context.fillStyle = color; - DebugUtils.game.stage.context.fillText('Sprite: ' + ' (' + sprite.frameBounds.width + ' x ' + sprite.frameBounds.height + ')', x, y); - DebugUtils.game.stage.context.fillText('x: ' + sprite.frameBounds.x.toFixed(1) + ' y: ' + sprite.frameBounds.y.toFixed(1) + ' angle: ' + sprite.angle.toFixed(1), x, y + 14); + DebugUtils.game.stage.context.fillText('Sprite: ' + ' (' + sprite.width + ' x ' + sprite.height + ')', x, y); + DebugUtils.game.stage.context.fillText('x: ' + sprite.x.toFixed(1) + ' y: ' + sprite.y.toFixed(1) + ' rotation: ' + sprite.rotation.toFixed(1), x, y + 14); //DebugUtils.game.stage.context.fillText('dx: ' + this._dx.toFixed(1) + ' dy: ' + this._dy.toFixed(1) + ' dw: ' + this._dw.toFixed(1) + ' dh: ' + this._dh.toFixed(1), x, y + 28); //DebugUtils.game.stage.context.fillText('sx: ' + this._sx.toFixed(1) + ' sy: ' + this._sy.toFixed(1) + ' sw: ' + this._sw.toFixed(1) + ' sh: ' + this._sh.toFixed(1), x, y + 42); }; From a30762ed8ca95039c864629259bd5aca24c900bd Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 7 Jun 2013 07:35:28 +0100 Subject: [PATCH 2/8] Fixed world drag support and other input modifications. --- Phaser/Game.ts | 2 + Phaser/World.ts | 11 + Phaser/cameras/Camera.ts | 45 +++- Phaser/cameras/CameraManager.ts | 19 +- Phaser/components/sprite/Input.ts | 8 +- Phaser/core/Group.ts | 29 ++- Phaser/gameobjects/GameObjectFactory.ts | 2 +- Phaser/gameobjects/Sprite.ts | 12 +- Phaser/input/Input.ts | 86 +++--- Phaser/input/Pointer.ts | 52 ++-- Phaser/physics/Body.ts | 51 +++- Phaser/physics/PhysicsManager.ts | 11 +- Phaser/renderers/CanvasRenderer.ts | 15 +- Phaser/renderers/HeadlessRenderer.ts | 28 +- Phaser/renderers/IRenderer.ts | 3 +- Phaser/system/StageScaleMode.ts | 3 +- Phaser/utils/DebugUtils.ts | 40 ++- README.md | 10 +- Tests/Tests.csproj | 12 + Tests/cameras/world sprite.js | 62 +++++ Tests/cameras/world sprite.ts | 91 +++++++ Tests/index.php | 1 - Tests/input/game scale 1.js | 35 +++ Tests/input/game scale 1.ts | 62 +++++ Tests/input/multitouch.js | 10 + Tests/input/multitouch.ts | 16 ++ Tests/input/over sprite 2.js | 4 +- Tests/input/over sprite 2.ts | 4 +- Tests/input/world drag.js | 1 + Tests/input/world drag.ts | 2 + Tests/phaser.js | 331 +++++++++++++++--------- Tests/physics/aabb 1.js | 1 + Tests/physics/aabb 1.ts | 1 + Tests/physics/aabb vs aabb 1.js | 5 +- Tests/physics/aabb vs aabb 1.ts | 4 + build/phaser.d.ts | 113 ++++---- build/phaser.js | 331 +++++++++++++++--------- 37 files changed, 1078 insertions(+), 435 deletions(-) create mode 100644 Tests/cameras/world sprite.js create mode 100644 Tests/cameras/world sprite.ts create mode 100644 Tests/input/game scale 1.js create mode 100644 Tests/input/game scale 1.ts create mode 100644 Tests/input/multitouch.js create mode 100644 Tests/input/multitouch.ts diff --git a/Phaser/Game.ts b/Phaser/Game.ts index 52db70dc..7df89909 100644 --- a/Phaser/Game.ts +++ b/Phaser/Game.ts @@ -416,6 +416,8 @@ module Phaser { this.onUpdateCallback.call(this.callbackContext); } + this.world.postUpdate(); + this.renderer.render(); if (this._loadComplete && this.onRenderCallback) diff --git a/Phaser/World.ts b/Phaser/World.ts index 2eb6dd88..0b1aabbf 100644 --- a/Phaser/World.ts +++ b/Phaser/World.ts @@ -96,6 +96,17 @@ module Phaser { } + /** + * This is called automatically every frame, and is where main logic happens. + */ + public postUpdate() { + + //this.physics.postUpdate(); + this.group.postUpdate(); + this.cameras.postUpdate(); + + } + /** * Clean up memory. */ diff --git a/Phaser/cameras/Camera.ts b/Phaser/cameras/Camera.ts index 66a40c9b..b8badc77 100644 --- a/Phaser/cameras/Camera.ts +++ b/Phaser/cameras/Camera.ts @@ -291,10 +291,6 @@ module Phaser { { this.modified = true; } - else if (this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) - { - this.modified = false; - } this.fx.preUpdate(); @@ -365,6 +361,42 @@ module Phaser { } } + } + + /** + * Update focusing and scrolling. + */ + public postUpdate() { + + if (this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) + { + this.modified = false; + } + + // Make sure we didn't go outside the cameras worldBounds + if (this.worldBounds !== null) + { + if (this.worldView.x < this.worldBounds.left) + { + this.worldView.x = this.worldBounds.left; + } + + if (this.worldView.x > this.worldBounds.right - this.width) + { + this.worldView.x = (this.worldBounds.right - this.width) + 1; + } + + if (this.worldView.y < this.worldBounds.top) + { + this.worldView.y = this.worldBounds.top; + } + + if (this.worldView.y > this.worldBounds.bottom - this.height) + { + this.worldView.y = (this.worldBounds.bottom - this.height) + 1; + } + } + this.fx.postUpdate(); } @@ -380,11 +412,12 @@ module Phaser { this.game.stage.context.fillStyle = color; this.game.stage.context.fillText('Camera ID: ' + this.ID + ' (' + this.screenView.width + ' x ' + this.screenView.height + ')', x, y); this.game.stage.context.fillText('X: ' + this.screenView.x + ' Y: ' + this.screenView.y + ' rotation: ' + this.transform.rotation, x, y + 14); - this.game.stage.context.fillText('World X: ' + this.worldView.x.toFixed(1) + ' World Y: ' + this.worldView.y.toFixed(1), x, y + 28); + this.game.stage.context.fillText('World X: ' + this.worldView.x + ' World Y: ' + this.worldView.y + ' W: ' + this.worldView.width + ' H: ' + this.worldView.height + ' R: ' + this.worldView.right + ' B: ' + this.worldView.bottom, x, y + 28); + this.game.stage.context.fillText('ScreenView X: ' + this.screenView.x + ' Y: ' + this.screenView.y + ' W: ' + this.screenView.width + ' H: ' + this.screenView.height, x, y + 42); if (this.worldBounds) { - this.game.stage.context.fillText('Bounds: ' + this.worldBounds.width + ' x ' + this.worldBounds.height, x, y + 42); + this.game.stage.context.fillText('Bounds: ' + this.worldBounds.width + ' x ' + this.worldBounds.height, x, y + 56); } } diff --git a/Phaser/cameras/CameraManager.ts b/Phaser/cameras/CameraManager.ts index c3bbc476..2b85559a 100644 --- a/Phaser/cameras/CameraManager.ts +++ b/Phaser/cameras/CameraManager.ts @@ -83,7 +83,24 @@ module Phaser { * Update cameras. */ public update() { - this._cameras.forEach((camera) => camera.update()); + + for (var i = 0; i < this._cameras.length; i++) + { + this._cameras[i].update(); + } + + } + + /** + * postUpdate cameras. + */ + public postUpdate() { + + for (var i = 0; i < this._cameras.length; i++) + { + this._cameras[i].postUpdate(); + } + } /** diff --git a/Phaser/components/sprite/Input.ts b/Phaser/components/sprite/Input.ts index 91641e98..6adac87f 100644 --- a/Phaser/components/sprite/Input.ts +++ b/Phaser/components/sprite/Input.ts @@ -258,7 +258,7 @@ module Phaser.Components.Sprite { } else { - return RectangleUtils.contains(this.sprite.worldView, pointer.scaledX, pointer.scaledY); + return RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY()); } } @@ -279,10 +279,10 @@ module Phaser.Components.Sprite { } else if (this._pointerData[pointer.id].isOver == true) { - if (RectangleUtils.contains(this.sprite.worldView, pointer.scaledX, pointer.scaledY)) + if (RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY())) { - this._pointerData[pointer.id].x = pointer.scaledX - this.sprite.x; - this._pointerData[pointer.id].y = pointer.scaledY - this.sprite.y; + this._pointerData[pointer.id].x = pointer.x - this.sprite.x; + this._pointerData[pointer.id].y = pointer.y - this.sprite.y; return true; } else diff --git a/Phaser/core/Group.ts b/Phaser/core/Group.ts index 3fe8f725..ad9397d7 100644 --- a/Phaser/core/Group.ts +++ b/Phaser/core/Group.ts @@ -186,7 +186,28 @@ module Phaser { { this.modified = true; } - else if (this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) + + this._i = 0; + + while (this._i < this.length) + { + this._member = this.members[this._i++]; + + if (this._member != null && this._member.exists && this._member.active) + { + this._member.preUpdate(); + this._member.update(); + } + } + } + + /** + * Calls update on all members of this Group who have a status of active=true and exists=true + * You can also call Object.postUpdate directly, which will bypass the active/exists check. + */ + public postUpdate() { + + if (this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { this.modified = false; } @@ -199,8 +220,6 @@ module Phaser { if (this._member != null && this._member.exists && this._member.active) { - this._member.preUpdate(); - this._member.update(); this._member.postUpdate(); } } @@ -398,10 +417,10 @@ module Phaser { * @param y {number} Y position of the new sprite. * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this sprite * @param [frame] {string|number} If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name. - * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) + * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DYNAMIC) * @returns {Sprite} The newly created sprite object. */ - public addNewSprite(x: number, y: number, key?: string = '', frame? = null, bodyType?: number = Phaser.Types.BODY_DISABLED): Sprite { + public addNewSprite(x: number, y: number, key?: string = '', frame? = null, bodyType?: number = Phaser.Types.BODY_DYNAMIC): Sprite { return this.add(new Sprite(this.game, x, y, key, frame, bodyType)); } diff --git a/Phaser/gameobjects/GameObjectFactory.ts b/Phaser/gameobjects/GameObjectFactory.ts index 22a6de4b..d74ac54c 100644 --- a/Phaser/gameobjects/GameObjectFactory.ts +++ b/Phaser/gameobjects/GameObjectFactory.ts @@ -72,7 +72,7 @@ module Phaser { * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) * @returns {Sprite} The newly created sprite object. */ - public sprite(x: number, y: number, key?: string = '', frame? = null, bodyType?: number = Phaser.Types.BODY_DISABLED): Sprite { + public sprite(x: number, y: number, key?: string = '', frame? = null, bodyType?: number = Phaser.Types.BODY_DYNAMIC): Sprite { return this._world.group.add(new Sprite(this._game, x, y, key, frame, bodyType)); } diff --git a/Phaser/gameobjects/Sprite.ts b/Phaser/gameobjects/Sprite.ts index c58cda21..001d59b1 100644 --- a/Phaser/gameobjects/Sprite.ts +++ b/Phaser/gameobjects/Sprite.ts @@ -23,9 +23,9 @@ module Phaser { * @param [x] {number} the initial x position of the sprite. * @param [y] {number} the initial y position of the sprite. * @param [key] {string} Key of the graphic you want to load for this sprite. - * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) + * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DYNAMIC) */ - constructor(game: Game, x?: number = 0, y?: number = 0, key?: string = null, frame? = null, bodyType?: number = Phaser.Types.BODY_DISABLED) { + constructor(game: Game, x?: number = 0, y?: number = 0, key?: string = null, frame? = null, bodyType?: number = Phaser.Types.BODY_DYNAMIC) { this.game = game; this.type = Phaser.Types.SPRITE; @@ -43,7 +43,6 @@ module Phaser { this.transform = new Phaser.Components.Transform(this); this.animations = new Phaser.Components.AnimationManager(this); this.texture = new Phaser.Components.Texture(this); - this.body = new Phaser.Physics.Body(this, bodyType); this.input = new Phaser.Components.Sprite.Input(this); this.events = new Phaser.Components.Sprite.Events(this); @@ -68,6 +67,7 @@ module Phaser { } } + this.body = new Phaser.Physics.Body(this, bodyType); this.worldView = new Rectangle(x, y, this.width, this.height); } @@ -233,8 +233,10 @@ module Phaser { */ public preUpdate() { - this.worldView.x = this.x - (this.game.world.cameras.default.worldView.x * this.transform.scrollFactor.x); - this.worldView.y = this.y - (this.game.world.cameras.default.worldView.y * this.transform.scrollFactor.y); + //this.worldView.x = this.x * this.transform.scrollFactor.x; + //this.worldView.y = this.y * this.transform.scrollFactor.y; + this.worldView.x = this.x - this.transform.origin.x; + this.worldView.y = this.y - this.transform.origin.y; this.worldView.width = this.width; this.worldView.height = this.height; diff --git a/Phaser/input/Input.ts b/Phaser/input/Input.ts index 5153f9f3..6c76469d 100644 --- a/Phaser/input/Input.ts +++ b/Phaser/input/Input.ts @@ -42,11 +42,15 @@ module Phaser { this.onTap = new Phaser.Signal(); this.onHold = new Phaser.Signal(); + this.scale = new Vec2(1, 1); this.speed = new Vec2; this.position = new Vec2; this._oldPosition = new Vec2; this.circle = new Circle(0, 0, 44); + this.camera = this._game.camera; + + this.activePointer = this.mousePointer; this.currentPointers = 0; } @@ -63,6 +67,20 @@ module Phaser { **/ private _oldPosition: Vec2 = null; + /** + * X coordinate of the most recent Pointer event + * @type {Number} + * @private + */ + private _x: number = 0; + + /** + * X coordinate of the most recent Pointer event + * @type {Number} + * @private + */ + private _y: number = 0; + /** * You can disable all Input by setting Input.disabled = true. While set all new input related events will be ignored. * If you need to disable just one type of input, for example mouse, use Input.mouse.disabled = true instead @@ -93,6 +111,13 @@ module Phaser { */ public static MOUSE_TOUCH_COMBINE: number = 2; + /** + * The camera being used for mouse and touch based pointers to calculate their world coordinates. + * @property camera + * @type {Camera} + **/ + public camera: Camera; + /** * Phaser.Mouse handler * @type {Mouse} @@ -147,30 +172,11 @@ module Phaser { public circle: Circle = null; /** - * X coordinate of the most recent Pointer event - * @type {Number} - * @private - */ - private _x: number = 0; - - /** - * X coordinate of the most recent Pointer event - * @type {Number} - * @private - */ - private _y: number = 0; - - /** - * - * @type {Number} + * The scale by which all input coordinates are multiplied, calculated by the StageScaleMode. + * In an un-scaled game the values will be x: 1 and y: 1. + * @type {Vec2} */ - public scaleX: number = 1; - - /** - * - * @type {Number} - */ - public scaleY: number = 1; + public scale: Vec2 = null; /** * The maximum number of Pointers allowed to be active at any one time. @@ -347,37 +353,39 @@ module Phaser { public pointer10: Pointer = null; /** - * The screen X coordinate + * The most recently active Pointer object. + * When you've limited max pointers to 1 this will accurately be either the first finger touched or mouse. + * @property activePointer + * @type {Pointer} + **/ + public activePointer: Pointer = null; + + /** + * The X coordinate of the most recently active pointer. + * This value takes game scaling into account automatically. See Pointer.screenX/clientX for source values. * @property x * @type {Number} **/ public get x(): number { - return this._x; - } public set x(value: number) { - this._x = Math.round(value); - } /** - * The screen Y coordinate + * The Y coordinate of the most recently active pointer. + * This value takes game scaling into account automatically. See Pointer.screenY/clientY for source values. * @property y * @type {Number} **/ public get y(): number { - return this._y; - } public set y(value: number) { - this._y = Math.round(value); - } /** @@ -469,7 +477,6 @@ module Phaser { **/ public update() { - // Swap for velocity vector - and add it to Pointer? this.speed.x = this.position.x - this._oldPosition.x; this.speed.y = this.position.y - this._oldPosition.y; @@ -488,6 +495,7 @@ module Phaser { if (this.pointer9) { this.pointer9.update(); } if (this.pointer10) { this.pointer10.update(); } + } /** @@ -883,18 +891,14 @@ module Phaser { * @param {Camera} [camera] */ public getWorldX(camera?: Camera = this._game.camera) { - return camera.worldView.x + this.x; - } /** * @param {Camera} [camera] */ public getWorldY(camera?: Camera = this._game.camera) { - return camera.worldView.y + this.y; - } /** @@ -904,12 +908,12 @@ module Phaser { */ public renderDebugInfo(x: number, y: number, color?: string = 'rgb(255,255,255)') { - this._game.stage.context.font = '14px Courier'; this._game.stage.context.fillStyle = color; this._game.stage.context.fillText('Input', x, y); - this._game.stage.context.fillText('Screen X: ' + this.x + ' Screen Y: ' + this.y, x, y + 14); + this._game.stage.context.fillText('X: ' + this.x + ' Y: ' + this.y, x, y + 14); this._game.stage.context.fillText('World X: ' + this.getWorldX() + ' World Y: ' + this.getWorldY(), x, y + 28); - this._game.stage.context.fillText('Scale X: ' + this.scaleX.toFixed(1) + ' Scale Y: ' + this.scaleY.toFixed(1), x, y + 42); + this._game.stage.context.fillText('Scale X: ' + this.scale.x.toFixed(1) + ' Scale Y: ' + this.scale.x.toFixed(1), x, y + 42); + this._game.stage.context.fillText('Screen X: ' + this.activePointer.screenX + ' Screen Y: ' + this.activePointer.screenY, x, y + 56); } diff --git a/Phaser/input/Pointer.ts b/Phaser/input/Pointer.ts index a5edaf65..e9afa9b3 100644 --- a/Phaser/input/Pointer.ts +++ b/Phaser/input/Pointer.ts @@ -170,14 +170,14 @@ module Phaser { public screenY: number = -1; /** - * The horizontal coordinate of point relative to the game element + * The horizontal coordinate of point relative to the game element. This value is automatically scaled based on game size. * @property x * @type {Number} */ public x: number = -1; /** - * The vertical coordinate of point relative to the game element + * The vertical coordinate of point relative to the game element. This value is automatically scaled based on game size. * @property y * @type {Number} */ @@ -263,39 +263,19 @@ module Phaser { public targetObject = null; /** - * Gets the X value of this Pointer in world coordinate space (is it properly scaled?) + * Gets the X value of this Pointer in world coordinates based on the given camera. * @param {Camera} [camera] */ - public getWorldX(camera?: Camera = this.game.camera) { - + public worldX(camera?: Camera = this.game.input.camera) { return camera.worldView.x + this.x; - } /** - * Gets the Y value of this Pointer in world coordinate space + * Gets the Y value of this Pointer in world coordinates based on the given camera. * @param {Camera} [camera] */ - public getWorldY(camera?: Camera = this.game.camera) { - + public worldY(camera?: Camera = this.game.input.camera) { return camera.worldView.y + this.y; - - } - - /** - * Gets the X value of this Pointer in world coordinate space - * @param {Camera} [camera] - */ - public get scaledX():number { - return Math.floor(this.x * this.game.input.scaleX); - } - - /** - * Gets the Y value of this Pointer in world coordinate space - * @param {Camera} [camera] - */ - public get scaledY():number { - return Math.floor(this.y * this.game.input.scaleY); } /** @@ -329,15 +309,18 @@ module Phaser { this.timeDown = this.game.time.now; this._holdSent = false; + // This sets the x/y and other local values + this.move(event); + // x and y are the old values here? this.positionDown.setTo(this.x, this.y); - this.move(event); - if (this.game.input.multiInputOverride == Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == Input.TOUCH_OVERRIDES_MOUSE && this.game.input.currentPointers == 0)) { - this.game.input.x = this.x * this.game.input.scaleX; - this.game.input.y = this.y * this.game.input.scaleY; + //this.game.input.x = this.x * this.game.input.scale.x; + //this.game.input.y = this.y * this.game.input.scale.y; + this.game.input.x = this.x; + this.game.input.y = this.y; this.game.input.onDown.dispatch(this); } @@ -407,8 +390,8 @@ module Phaser { this.screenX = event.screenX; this.screenY = event.screenY; - this.x = this.pageX - this.game.stage.offset.x; - this.y = this.pageY - this.game.stage.offset.y; + this.x = (this.pageX - this.game.stage.offset.x) * this.game.input.scale.x; + this.y = (this.pageY - this.game.stage.offset.y) * this.game.input.scale.y; this.position.setTo(this.x, this.y); this.circle.x = this.x; @@ -416,8 +399,9 @@ module Phaser { if (this.game.input.multiInputOverride == Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == Input.TOUCH_OVERRIDES_MOUSE && this.game.input.currentPointers == 0)) { - this.game.input.x = this.x * this.game.input.scaleX; - this.game.input.y = this.y * this.game.input.scaleY; + this.game.input.activePointer = this; + this.game.input.x = this.x; + this.game.input.y = this.y; this.game.input.position.setTo(this.game.input.x, this.game.input.y); this.game.input.circle.x = this.game.input.x; this.game.input.circle.y = this.game.input.y; diff --git a/Phaser/physics/Body.ts b/Phaser/physics/Body.ts index cd2d17fa..aaa547b1 100644 --- a/Phaser/physics/Body.ts +++ b/Phaser/physics/Body.ts @@ -18,11 +18,15 @@ module Phaser.Physics { // Fixture properties // Will extend into its own class at a later date - can move the fixture defs there and add shape support, but this will do for 1.0 release - this.bounds = new Rectangle(sprite.x + Math.round(sprite.width / 2), sprite.y + Math.round(sprite.height / 2), sprite.width, sprite.height); - this.bounce = Vec2Utils.clone(this.game.world.physics.bounce); + this.bounds = new Rectangle; + + this._width = sprite.width; + this._height = sprite.height; + // Body properties this.gravity = Vec2Utils.clone(this.game.world.physics.gravity); + this.bounce = Vec2Utils.clone(this.game.world.physics.bounce); this.velocity = new Vec2; this.acceleration = new Vec2; @@ -49,7 +53,7 @@ module Phaser.Physics { public game: Game; /** - * Reference to the sprite Sprite + * Reference to the parent Sprite */ public sprite: Phaser.Sprite; @@ -94,17 +98,41 @@ module Phaser.Physics { + private _width: number = 0; + private _height: number = 0; + + public get x(): number { + return this.sprite.x + this.offset.x; + } + + public get y(): number { + return this.sprite.y + this.offset.y; + } + + public set width(value: number) { + this._width = value; + } + + public set height(value: number) { + this._height = value; + } + + public get width(): number { + return this._width * this.sprite.transform.scale.x; + } + + public get height(): number { + return this._height * this.sprite.transform.scale.y; + } public preUpdate() { this.oldPosition.copyFrom(this.position); - this.bounds.x = this.position.x - this.bounds.halfWidth; - this.bounds.y = this.position.y - this.bounds.halfHeight; - - if (this.sprite.transform.scale.equals(1) == false) - { - } + this.bounds.x = this.x; + this.bounds.y = this.y; + this.bounds.width = this.width; + this.bounds.height = this.height; } @@ -117,14 +145,13 @@ module Phaser.Physics { { this.game.world.physics.updateMotion(this); - this.sprite.x = (this.position.x - this.bounds.halfWidth) - this.offset.x; - this.sprite.y = (this.position.y - this.bounds.halfHeight) - this.offset.y; - this.wasTouching = this.touching; this.touching = Phaser.Types.NONE; } + this.position.setTo(this.x, this.y); + } public get hullWidth(): number { diff --git a/Phaser/physics/PhysicsManager.ts b/Phaser/physics/PhysicsManager.ts index d11399da..ab24ed07 100644 --- a/Phaser/physics/PhysicsManager.ts +++ b/Phaser/physics/PhysicsManager.ts @@ -62,9 +62,6 @@ module Phaser.Physics { private _quadTree: QuadTree; private _quadTreeResult: bool; - - - public bounds: Rectangle; public gravity: Vec2; @@ -148,13 +145,15 @@ module Phaser.Physics { body.velocity.x += this._velocityDelta; this._delta = body.velocity.x * this.game.time.elapsed; body.velocity.x += this._velocityDelta; - body.position.x += this._delta; + //body.position.x += this._delta; + body.sprite.x += this._delta; this._velocityDelta = (this.computeVelocity(body.velocity.y, body.gravity.y, body.acceleration.y, body.drag.y) - body.velocity.y) / 2; body.velocity.y += this._velocityDelta; this._delta = body.velocity.y * this.game.time.elapsed; body.velocity.y += this._velocityDelta; - body.position.y += this._delta; + //body.position.y += this._delta; + body.sprite.y += this._delta; } @@ -748,6 +747,8 @@ module Phaser.Physics { this._quadTreeResult = this._quadTree.execute(); + console.log('over', this._quadTreeResult); + this._quadTree.destroy(); this._quadTree = null; diff --git a/Phaser/renderers/CanvasRenderer.ts b/Phaser/renderers/CanvasRenderer.ts index 72aedd85..cd5777d1 100644 --- a/Phaser/renderers/CanvasRenderer.ts +++ b/Phaser/renderers/CanvasRenderer.ts @@ -215,24 +215,13 @@ module Phaser { */ public inCamera(camera: Camera, sprite: Sprite): bool { - return true; - - /* - // Object fixed in place regardless of the camera scrolling? Then it's always visible - if (sprite.scrollFactor.x == 0 && sprite.scrollFactor.y == 0) + if (sprite.transform.scrollFactor.equals(0)) { return true; } - this._dx = sprite.frameBounds.x - (camera.worldView.x * sprite.scrollFactor.x); - this._dy = sprite.frameBounds.y - (camera.worldView.y * sprite.scrollFactor.y); - this._dw = sprite.frameBounds.width * sprite.scale.x; - this._dh = sprite.frameBounds.height * sprite.scale.y; - - //return (camera.screenView.x + camera.worldView.width > this._dx) && (camera.screenView.x < this._dx + this._dw) && (camera.screenView.y + camera.worldView.height > this._dy) && (camera.screenView.y < this._dy + this._dh); - - */ + return RectangleUtils.intersects(sprite.worldView, camera.worldView); } diff --git a/Phaser/renderers/HeadlessRenderer.ts b/Phaser/renderers/HeadlessRenderer.ts index 7225c950..f130147e 100644 --- a/Phaser/renderers/HeadlessRenderer.ts +++ b/Phaser/renderers/HeadlessRenderer.ts @@ -10,39 +10,29 @@ module Phaser { this._game = game; } - /** - * The essential reference to the main game object - */ private _game: Phaser.Game; public render() {} - public renderGameObject(object) { - } + public inCamera(camera: Camera, sprite: Sprite): bool { return true; } - public renderSprite(camera: Camera, sprite: Sprite): bool { - return true; - } + public renderGameObject(object) {} - public renderScrollZone(camera: Camera, scrollZone: ScrollZone): bool { - return true; - } + public renderSprite(camera: Camera, sprite: Sprite): bool { return true; } + + public renderScrollZone(camera: Camera, scrollZone: ScrollZone): bool { return true; } public renderCircle(camera: Camera, circle: Circle, context, outline?: bool = true, fill?: bool = true, lineColor?: string = 'rgb(0,255,0)', fillColor?: string = 'rgba(0,100,0.0.3)', lineWidth?: number = 1): bool { return true; } - public preRenderCamera(camera: Camera) { - } + public preRenderCamera(camera: Camera) { } - public postRenderCamera(camera: Camera) { - } + public postRenderCamera(camera: Camera) { } - public preRenderGroup(camera: Camera, group: Group) { - } + public preRenderGroup(camera: Camera, group: Group) { } - public postRenderGroup(camera: Camera, group: Group) { - } + public postRenderGroup(camera: Camera, group: Group) { } } diff --git a/Phaser/renderers/IRenderer.ts b/Phaser/renderers/IRenderer.ts index 07acbc94..07fd14d9 100644 --- a/Phaser/renderers/IRenderer.ts +++ b/Phaser/renderers/IRenderer.ts @@ -13,7 +13,8 @@ module Phaser { postRenderGroup(camera: Camera, group: Group); preRenderCamera(camera: Camera); postRenderCamera(camera: Camera); - + + inCamera(camera: Camera, sprite: Sprite): bool; } diff --git a/Phaser/system/StageScaleMode.ts b/Phaser/system/StageScaleMode.ts index fd3e5fe1..317c6911 100644 --- a/Phaser/system/StageScaleMode.ts +++ b/Phaser/system/StageScaleMode.ts @@ -446,8 +446,7 @@ module Phaser { this._game.stage.canvas.style.width = this.width + 'px'; this._game.stage.canvas.style.height = this.height + 'px'; - this._game.input.scaleX = this._game.stage.width / this.width; - this._game.input.scaleY = this._game.stage.height / this.height; + this._game.input.scale.setTo(this._game.stage.width / this.width, this._game.stage.height / this.height); if (this.pageAlignHorizontally) { diff --git a/Phaser/utils/DebugUtils.ts b/Phaser/utils/DebugUtils.ts index 8a775fbe..d27b0cb6 100644 --- a/Phaser/utils/DebugUtils.ts +++ b/Phaser/utils/DebugUtils.ts @@ -26,10 +26,44 @@ module Phaser { static renderSpriteInfo(sprite: Sprite, x: number, y: number, color?: string = 'rgb(255,255,255)') { DebugUtils.game.stage.context.fillStyle = color; - DebugUtils.game.stage.context.fillText('Sprite: ' + ' (' + sprite.width + ' x ' + sprite.height + ')', x, y); + DebugUtils.game.stage.context.fillText('Sprite: ' + ' (' + sprite.width + ' x ' + sprite.height + ') origin: ' + sprite.transform.origin.x + ' x ' + sprite.transform.origin.y, x, y); DebugUtils.game.stage.context.fillText('x: ' + sprite.x.toFixed(1) + ' y: ' + sprite.y.toFixed(1) + ' rotation: ' + sprite.rotation.toFixed(1), x, y + 14); - //DebugUtils.game.stage.context.fillText('dx: ' + this._dx.toFixed(1) + ' dy: ' + this._dy.toFixed(1) + ' dw: ' + this._dw.toFixed(1) + ' dh: ' + this._dh.toFixed(1), x, y + 28); - //DebugUtils.game.stage.context.fillText('sx: ' + this._sx.toFixed(1) + ' sy: ' + this._sy.toFixed(1) + ' sw: ' + this._sw.toFixed(1) + ' sh: ' + this._sh.toFixed(1), x, y + 42); + DebugUtils.game.stage.context.fillText('wx: ' + sprite.worldView.x + ' wy: ' + sprite.worldView.y + ' ww: ' + sprite.worldView.width.toFixed(1) + ' wh: ' + sprite.worldView.height.toFixed(1) + ' wb: ' + sprite.worldView.bottom + ' wr: ' + sprite.worldView.right, x, y + 28); + DebugUtils.game.stage.context.fillText('sx: ' + sprite.transform.scale.x.toFixed(1) + ' sy: ' + sprite.transform.scale.y.toFixed(1), x, y + 42); + DebugUtils.game.stage.context.fillText('tx: ' + sprite.texture.width.toFixed(1) + ' ty: ' + sprite.texture.height.toFixed(1), x, y + 56); + DebugUtils.game.stage.context.fillText('inCamera: ' + DebugUtils.game.renderer.inCamera(DebugUtils.game.camera, sprite), x, y + 70); + + } + + static renderSpriteBounds(sprite: Sprite, camera?: Camera = null, color?: string = 'rgba(0,255,0,0.2)') { + + if (camera == null) + { + camera = DebugUtils.game.camera; + } + + //var dx = (camera.screenView.x * sprite.transform.scrollFactor.x) + sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + //var dy = (camera.screenView.y * sprite.transform.scrollFactor.y) + sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + var dx = sprite.worldView.x; + var dy = sprite.worldView.y; + + DebugUtils.game.stage.context.fillStyle = color; + DebugUtils.game.stage.context.fillRect(dx, dy, sprite.width, sprite.height); + + } + + static renderSpritePhysicsBody(sprite: Sprite, camera?: Camera = null, color?: string = 'rgba(255,0,0,0.2)') { + + if (camera == null) + { + camera = DebugUtils.game.camera; + } + + var dx = (camera.screenView.x * sprite.transform.scrollFactor.x) + sprite.body.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + var dy = (camera.screenView.y * sprite.transform.scrollFactor.y) + sprite.body.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + + DebugUtils.game.stage.context.fillStyle = color; + DebugUtils.game.stage.context.fillRect(dx, dy, sprite.body.width, sprite.body.height); } diff --git a/README.md b/README.md index d6b9efea..8c7c8478 100644 --- a/README.md +++ b/README.md @@ -41,10 +41,13 @@ TODO: * Added JSON Texture Atlas object support. * RenderOrderID won't work across cameras - but then neither do Pointers yet anyway * Swap to using time based motion (like the tweens) rather than delta timer - it just doesn't work well on slow phones -* Bug in World drag +* Pointer.getWorldX(camera) needs to take camera scale into consideration +* Add a 'click to bring to top' demo (+ Group feature?) * Add clip support + shape options to Texture Component. +Make sure I'm using Point and not Vec2 when it's not a directional vector I need + V1.0.0 @@ -103,6 +106,11 @@ V1.0.0 * Created a Transform component containing scale, skew, rotation, scrollFactor, origin and rotationOffset. Added to Sprite, Camera, Group. * Created a Texture component containing image data, alpha, flippedX, flippedY, etc. Added to Sprite, Camera, Group. * Added CameraManager.swap and CameraManager.sort methods and added a z-index property to Camera to control render order. +* Added World.postUpdate loop + Group and Camera postUpdate methods. +* Fixed issue stopping Pointer from working in world coordinates and fixed the world drag example. +* For consistency renamed input.scaledX/Y = input.scale. +* Added input.activePointer which contains a reference to the most recently active pointer. + diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index f5e72a6e..0c682e29 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -69,6 +69,10 @@ + + + world sprite.ts + create group 1.ts @@ -90,12 +94,20 @@
+ + + game scale 1.ts + motion lock 2.ts motion lock.ts + + + multitouch.ts + over sprite 1.ts diff --git a/Tests/cameras/world sprite.js b/Tests/cameras/world sprite.js new file mode 100644 index 00000000..588a638a --- /dev/null +++ b/Tests/cameras/world sprite.js @@ -0,0 +1,62 @@ +/// +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); + function init() { + game.world.setSize(1920, 1200, true); + game.load.image('backdrop', 'assets/pics/remember-me.jpg'); + game.load.image('ball', 'assets/sprites/mana_card.png'); + game.load.start(); + } + var ball; + function create() { + game.add.sprite(0, 0, 'backdrop'); + ball = game.add.sprite(200, 200, 'ball'); + ball.body.offset.setTo(-16, -16); + ball.body.width = 100; + ball.body.height = 100; + ball.body.velocity.x = 50; + ball.transform.scale.setTo(2, 2); + } + function update() { + /* + if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) + { + game.camera.x -= 4; + //ball.x -= 4; + } + else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) + { + game.camera.x += 4; + //ball.x += 4; + } + + if (game.input.keyboard.isDown(Phaser.Keyboard.UP)) + { + game.camera.y -= 4; + //ball.y -= 4; + } + else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) + { + game.camera.y += 4; + //ball.y += 4; + } + */ + if(game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { + ball.x -= 4; + } else if(game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { + ball.x += 4; + } + if(game.input.keyboard.isDown(Phaser.Keyboard.UP)) { + ball.y -= 4; + } else if(game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { + ball.y += 4; + } + } + function render() { + game.camera.renderDebugInfo(32, 32); + Phaser.DebugUtils.renderSpriteInfo(ball, 32, 200); + //Phaser.DebugUtils.renderSpriteBounds(ball); + Phaser.DebugUtils.renderSpritePhysicsBody(ball); + } +})(); diff --git a/Tests/cameras/world sprite.ts b/Tests/cameras/world sprite.ts new file mode 100644 index 00000000..597b4c67 --- /dev/null +++ b/Tests/cameras/world sprite.ts @@ -0,0 +1,91 @@ +/// +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); + + function init() { + + game.world.setSize(1920, 1200, true); + + game.load.image('backdrop', 'assets/pics/remember-me.jpg'); + game.load.image('ball', 'assets/sprites/mana_card.png'); + + game.load.start(); + + } + + var ball: Phaser.Sprite; + + function create() { + + game.add.sprite(0, 0, 'backdrop'); + + ball = game.add.sprite(200, 200, 'ball'); + + ball.body.offset.setTo(-16, -16); + ball.body.width = 100; + ball.body.height = 100; + + ball.body.velocity.x = 50; + ball.transform.scale.setTo(2, 2); + + } + + function update() { + + /* + if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) + { + game.camera.x -= 4; + //ball.x -= 4; + } + else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) + { + game.camera.x += 4; + //ball.x += 4; + } + + if (game.input.keyboard.isDown(Phaser.Keyboard.UP)) + { + game.camera.y -= 4; + //ball.y -= 4; + } + else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) + { + game.camera.y += 4; + //ball.y += 4; + } + */ + + if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) + { + ball.x -= 4; + } + else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) + { + ball.x += 4; + } + + if (game.input.keyboard.isDown(Phaser.Keyboard.UP)) + { + ball.y -= 4; + } + else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) + { + ball.y += 4; + } + + } + + function render() { + + game.camera.renderDebugInfo(32, 32); + Phaser.DebugUtils.renderSpriteInfo(ball, 32, 200); + //Phaser.DebugUtils.renderSpriteBounds(ball); + Phaser.DebugUtils.renderSpritePhysicsBody(ball); + + } + +})(); diff --git a/Tests/index.php b/Tests/index.php index 55369666..ff75d675 100644 --- a/Tests/index.php +++ b/Tests/index.php @@ -93,7 +93,6 @@ if (isset($_GET['m'])) View JavaScript View TypeScript -

You'll learn best from these Tests by viewing the source code.
diff --git a/Tests/input/game scale 1.js b/Tests/input/game scale 1.js new file mode 100644 index 00000000..1c00f49a --- /dev/null +++ b/Tests/input/game scale 1.js @@ -0,0 +1,35 @@ +/// +(function () { + // Here we create a tiny game (320x240 in size) + var game = new Phaser.Game(this, 'game', 320, 240, init, create, update, render); + function init() { + // This sets a limit on the up-scale + game.stage.scale.maxWidth = 800; + game.stage.scale.maxHeight = 600; + // Then we tell Phaser that we want it to scale up to whatever the browser can handle, but to do it proportionally + game.stage.scaleMode = Phaser.StageScaleMode.SHOW_ALL; + game.load.image('melon', 'assets/sprites/melon.png'); + game.load.start(); + } + function create() { + game.world.setSize(2000, 2000); + for(var i = 0; i < 1000; i++) { + game.add.sprite(game.world.randomX, game.world.randomY, 'melon'); + } + } + function update() { + if(game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { + game.camera.x -= 4; + } else if(game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { + game.camera.x += 4; + } + if(game.input.keyboard.isDown(Phaser.Keyboard.UP)) { + game.camera.y -= 4; + } else if(game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { + game.camera.y += 4; + } + } + function render() { + game.input.renderDebugInfo(16, 16); + } +})(); diff --git a/Tests/input/game scale 1.ts b/Tests/input/game scale 1.ts new file mode 100644 index 00000000..01448f7d --- /dev/null +++ b/Tests/input/game scale 1.ts @@ -0,0 +1,62 @@ +/// + +(function () { + + // Here we create a tiny game (320x240 in size) + var game = new Phaser.Game(this, 'game', 320, 240, init, create, update, render); + + function init() { + + // This sets a limit on the up-scale + game.stage.scale.maxWidth = 800; + game.stage.scale.maxHeight = 600; + + // Then we tell Phaser that we want it to scale up to whatever the browser can handle, but to do it proportionally + game.stage.scaleMode = Phaser.StageScaleMode.SHOW_ALL; + + game.load.image('melon', 'assets/sprites/melon.png'); + + game.load.start(); + + } + + function create() { + + game.world.setSize(2000, 2000); + + for (var i = 0; i < 1000; i++) + { + game.add.sprite(game.world.randomX, game.world.randomY, 'melon'); + } + + } + + function update() { + + if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) + { + game.camera.x -= 4; + } + else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) + { + game.camera.x += 4; + } + + if (game.input.keyboard.isDown(Phaser.Keyboard.UP)) + { + game.camera.y -= 4; + } + else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) + { + game.camera.y += 4; + } + + } + + function render() { + + game.input.renderDebugInfo(16, 16); + + } + +})(); diff --git a/Tests/input/multitouch.js b/Tests/input/multitouch.js new file mode 100644 index 00000000..e0f2c4d4 --- /dev/null +++ b/Tests/input/multitouch.js @@ -0,0 +1,10 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, null, null, null, render); + function render() { + game.input.pointer1.renderDebug(); + game.input.pointer2.renderDebug(); + game.input.pointer3.renderDebug(); + game.input.pointer4.renderDebug(); + } +})(); diff --git a/Tests/input/multitouch.ts b/Tests/input/multitouch.ts new file mode 100644 index 00000000..f38ffa72 --- /dev/null +++ b/Tests/input/multitouch.ts @@ -0,0 +1,16 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, null, null, null, render); + + function render() { + + game.input.pointer1.renderDebug(); + game.input.pointer2.renderDebug(); + game.input.pointer3.renderDebug(); + game.input.pointer4.renderDebug(); + + } + +})(); diff --git a/Tests/input/over sprite 2.js b/Tests/input/over sprite 2.js index 52eb22b8..f73e906b 100644 --- a/Tests/input/over sprite 2.js +++ b/Tests/input/over sprite 2.js @@ -10,8 +10,8 @@ function create() { // Create a load of sprites for(var i = 0; i < 26; i++) { - var tempSprite = game.add.sprite(i * 32, 100, 'sprite', Phaser.Types.BODY_DYNAMIC); - tempSprite.input.enabled = true; + var tempSprite = game.add.sprite(i * 32, 100, 'sprite'); + tempSprite.input.start(0, false, true); tempSprite.events.onInputOver.add(dropSprite, this); } } diff --git a/Tests/input/over sprite 2.ts b/Tests/input/over sprite 2.ts index 475166ae..fbaf704a 100644 --- a/Tests/input/over sprite 2.ts +++ b/Tests/input/over sprite 2.ts @@ -19,8 +19,8 @@ // Create a load of sprites for (var i = 0; i < 26; i++) { - var tempSprite: Phaser.Sprite = game.add.sprite(i * 32, 100, 'sprite', Phaser.Types.BODY_DYNAMIC); - tempSprite.input.enabled = true; + var tempSprite: Phaser.Sprite = game.add.sprite(i * 32, 100, 'sprite'); + tempSprite.input.start(0, false, true); tempSprite.events.onInputOver.add(dropSprite, this); } diff --git a/Tests/input/world drag.js b/Tests/input/world drag.js index 685e7198..f6a3d3ab 100644 --- a/Tests/input/world drag.js +++ b/Tests/input/world drag.js @@ -35,5 +35,6 @@ game.camera.renderDebugInfo(32, 32); test.body.renderDebugInfo(300, 32); Phaser.DebugUtils.renderSpriteInfo(test, 32, 200); + game.input.renderDebugInfo(300, 200); } })(); diff --git a/Tests/input/world drag.ts b/Tests/input/world drag.ts index 8cb78a8c..afbb9f87 100644 --- a/Tests/input/world drag.ts +++ b/Tests/input/world drag.ts @@ -66,6 +66,8 @@ Phaser.DebugUtils.renderSpriteInfo(test, 32, 200); + game.input.renderDebugInfo(300, 200); + } })(); diff --git a/Tests/phaser.js b/Tests/phaser.js index 4839d5cb..a07d9581 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -3051,7 +3051,7 @@ var Phaser; if(this.enabled == false || this.sprite.visible == false) { return false; } else { - return Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.scaledX, pointer.scaledY); + return Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY()); } }; Input.prototype.update = /** @@ -3064,9 +3064,9 @@ var Phaser; if(this.draggable && this._draggedPointerID == pointer.id) { return this.updateDrag(pointer); } else if(this._pointerData[pointer.id].isOver == true) { - if(Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.scaledX, pointer.scaledY)) { - this._pointerData[pointer.id].x = pointer.scaledX - this.sprite.x; - this._pointerData[pointer.id].y = pointer.scaledY - this.sprite.y; + if(Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY())) { + this._pointerData[pointer.id].x = pointer.x - this.sprite.x; + this._pointerData[pointer.id].y = pointer.y - this.sprite.y; return true; } else { this._pointerOutHandler(pointer); @@ -3721,15 +3721,19 @@ var Phaser; this.angularDrag = 0; this.maxAngular = 10000; this.mass = 1; + this._width = 0; + this._height = 0; this.sprite = sprite; this.game = sprite.game; this.type = type; // Fixture properties // Will extend into its own class at a later date - can move the fixture defs there and add shape support, but this will do for 1.0 release - this.bounds = new Phaser.Rectangle(sprite.x + Math.round(sprite.width / 2), sprite.y + Math.round(sprite.height / 2), sprite.width, sprite.height); - this.bounce = Phaser.Vec2Utils.clone(this.game.world.physics.bounce); + this.bounds = new Phaser.Rectangle(); + this._width = sprite.width; + this._height = sprite.height; // Body properties this.gravity = Phaser.Vec2Utils.clone(this.game.world.physics.gravity); + this.bounce = Phaser.Vec2Utils.clone(this.game.world.physics.bounce); this.velocity = new Phaser.Vec2(); this.acceleration = new Phaser.Vec2(); this.drag = Phaser.Vec2Utils.clone(this.game.world.physics.drag); @@ -3744,12 +3748,46 @@ var Phaser; this.oldPosition = new Phaser.Vec2(sprite.x + this.bounds.halfWidth, sprite.y + this.bounds.halfHeight); this.offset = new Phaser.Vec2(); } + Object.defineProperty(Body.prototype, "x", { + get: function () { + return this.sprite.x + this.offset.x; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "y", { + get: function () { + return this.sprite.y + this.offset.y; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "width", { + get: function () { + return this._width * this.sprite.transform.scale.x; + }, + set: function (value) { + this._width = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "height", { + get: function () { + return this._height * this.sprite.transform.scale.y; + }, + set: function (value) { + this._height = value; + }, + enumerable: true, + configurable: true + }); Body.prototype.preUpdate = function () { this.oldPosition.copyFrom(this.position); - this.bounds.x = this.position.x - this.bounds.halfWidth; - this.bounds.y = this.position.y - this.bounds.halfHeight; - if(this.sprite.transform.scale.equals(1) == false) { - } + this.bounds.x = this.x; + this.bounds.y = this.y; + this.bounds.width = this.width; + this.bounds.height = this.height; }; Body.prototype.postUpdate = // Shall we do this? Or just update the values directly in the separate functions? But then the bounds will be out of sync - as long as // the bounds are updated and used in calculations then we can do one final sprite movement here I guess? @@ -3757,11 +3795,10 @@ var Phaser; // if this is all it does maybe move elsewhere? Sprite postUpdate? if(this.type !== Phaser.Types.BODY_DISABLED) { this.game.world.physics.updateMotion(this); - this.sprite.x = (this.position.x - this.bounds.halfWidth) - this.offset.x; - this.sprite.y = (this.position.y - this.bounds.halfHeight) - this.offset.y; this.wasTouching = this.touching; this.touching = Phaser.Types.NONE; } + this.position.setTo(this.x, this.y); }; Object.defineProperty(Body.prototype, "hullWidth", { get: function () { @@ -3922,14 +3959,14 @@ var Phaser; * @param [x] {number} the initial x position of the sprite. * @param [y] {number} the initial y position of the sprite. * @param [key] {string} Key of the graphic you want to load for this sprite. - * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) + * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DYNAMIC) */ function Sprite(game, x, y, key, frame, bodyType) { if (typeof x === "undefined") { x = 0; } if (typeof y === "undefined") { y = 0; } if (typeof key === "undefined") { key = null; } if (typeof frame === "undefined") { frame = null; } - if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } + if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DYNAMIC; } /** * A boolean representing if the Sprite has been modified in any way via a scale, rotate, flip or skew. */ @@ -3963,7 +4000,6 @@ var Phaser; this.transform = new Phaser.Components.Transform(this); this.animations = new Phaser.Components.AnimationManager(this); this.texture = new Phaser.Components.Texture(this); - this.body = new Phaser.Physics.Body(this, bodyType); this.input = new Phaser.Components.Sprite.Input(this); this.events = new Phaser.Components.Sprite.Events(this); if(key !== null) { @@ -3978,6 +4014,7 @@ var Phaser; this.frame = frame; } } + this.body = new Phaser.Physics.Body(this, bodyType); this.worldView = new Phaser.Rectangle(x, y, this.width, this.height); } Object.defineProperty(Sprite.prototype, "rotation", { @@ -4053,8 +4090,10 @@ var Phaser; * Pre-update is called right before update() on each object in the game loop. */ function () { - this.worldView.x = this.x - (this.game.world.cameras.default.worldView.x * this.transform.scrollFactor.x); - this.worldView.y = this.y - (this.game.world.cameras.default.worldView.y * this.transform.scrollFactor.y); + //this.worldView.x = this.x * this.transform.scrollFactor.x; + //this.worldView.y = this.y * this.transform.scrollFactor.y; + this.worldView.x = this.x - this.transform.origin.x; + this.worldView.y = this.y - this.transform.origin.y; this.worldView.width = this.width; this.worldView.height = this.height; if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { @@ -4702,8 +4741,6 @@ var Phaser; function () { if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { this.modified = true; - } else if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { - this.modified = false; } this._i = 0; while(this._i < this.length) { @@ -4711,6 +4748,21 @@ var Phaser; if(this._member != null && this._member.exists && this._member.active) { this._member.preUpdate(); this._member.update(); + } + } + }; + Group.prototype.postUpdate = /** + * Calls update on all members of this Group who have a status of active=true and exists=true + * You can also call Object.postUpdate directly, which will bypass the active/exists check. + */ + function () { + if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { + this.modified = false; + } + this._i = 0; + while(this._i < this.length) { + this._member = this.members[this._i++]; + if(this._member != null && this._member.exists && this._member.active) { this._member.postUpdate(); } } @@ -4846,13 +4898,13 @@ var Phaser; * @param y {number} Y position of the new sprite. * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this sprite * @param [frame] {string|number} If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name. - * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) + * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DYNAMIC) * @returns {Sprite} The newly created sprite object. */ function (x, y, key, frame, bodyType) { if (typeof key === "undefined") { key = ''; } if (typeof frame === "undefined") { frame = null; } - if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } + if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DYNAMIC; } return this.add(new Phaser.Sprite(this.game, x, y, key, frame, bodyType)); }; Group.prototype.setObjectIDs = /** @@ -7760,8 +7812,6 @@ var Phaser; function () { if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { this.modified = true; - } else if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { - this.modified = false; } this.fx.preUpdate(); if(this._target !== null) { @@ -7804,6 +7854,29 @@ var Phaser; this.worldView.y = (this.worldBounds.bottom - this.height) + 1; } } + }; + Camera.prototype.postUpdate = /** + * Update focusing and scrolling. + */ + function () { + if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { + this.modified = false; + } + // Make sure we didn't go outside the cameras worldBounds + if(this.worldBounds !== null) { + if(this.worldView.x < this.worldBounds.left) { + this.worldView.x = this.worldBounds.left; + } + if(this.worldView.x > this.worldBounds.right - this.width) { + this.worldView.x = (this.worldBounds.right - this.width) + 1; + } + if(this.worldView.y < this.worldBounds.top) { + this.worldView.y = this.worldBounds.top; + } + if(this.worldView.y > this.worldBounds.bottom - this.height) { + this.worldView.y = (this.worldBounds.bottom - this.height) + 1; + } + } this.fx.postUpdate(); }; Camera.prototype.renderDebugInfo = /** @@ -7817,9 +7890,10 @@ var Phaser; this.game.stage.context.fillStyle = color; this.game.stage.context.fillText('Camera ID: ' + this.ID + ' (' + this.screenView.width + ' x ' + this.screenView.height + ')', x, y); this.game.stage.context.fillText('X: ' + this.screenView.x + ' Y: ' + this.screenView.y + ' rotation: ' + this.transform.rotation, x, y + 14); - this.game.stage.context.fillText('World X: ' + this.worldView.x.toFixed(1) + ' World Y: ' + this.worldView.y.toFixed(1), x, y + 28); + this.game.stage.context.fillText('World X: ' + this.worldView.x + ' World Y: ' + this.worldView.y + ' W: ' + this.worldView.width + ' H: ' + this.worldView.height + ' R: ' + this.worldView.right + ' B: ' + this.worldView.bottom, x, y + 28); + this.game.stage.context.fillText('ScreenView X: ' + this.screenView.x + ' Y: ' + this.screenView.y + ' W: ' + this.screenView.width + ' H: ' + this.screenView.height, x, y + 42); if(this.worldBounds) { - this.game.stage.context.fillText('Bounds: ' + this.worldBounds.width + ' x ' + this.worldBounds.height, x, y + 42); + this.game.stage.context.fillText('Bounds: ' + this.worldBounds.width + ' x ' + this.worldBounds.height, x, y + 56); } }; Camera.prototype.destroy = /** @@ -7959,9 +8033,17 @@ var Phaser; * Update cameras. */ function () { - this._cameras.forEach(function (camera) { - return camera.update(); - }); + for(var i = 0; i < this._cameras.length; i++) { + this._cameras[i].update(); + } + }; + CameraManager.prototype.postUpdate = /** + * postUpdate cameras. + */ + function () { + for(var i = 0; i < this._cameras.length; i++) { + this._cameras[i].postUpdate(); + } }; CameraManager.prototype.addCamera = /** * Create a new camera with specific position and size. @@ -10295,7 +10377,7 @@ var Phaser; function (x, y, key, frame, bodyType) { if (typeof key === "undefined") { key = ''; } if (typeof frame === "undefined") { frame = null; } - if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } + if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DYNAMIC; } return this._world.group.add(new Phaser.Sprite(this._game, x, y, key, frame, bodyType)); }; GameObjectFactory.prototype.dynamicTexture = /** @@ -10967,8 +11049,7 @@ var Phaser; } this._game.stage.canvas.style.width = this.width + 'px'; this._game.stage.canvas.style.height = this.height + 'px'; - this._game.input.scaleX = this._game.stage.width / this.width; - this._game.input.scaleY = this._game.stage.height / this.height; + this._game.input.scale.setTo(this._game.stage.width / this.width, this._game.stage.height / this.height); if(this.pageAlignHorizontally) { if(this.width < window.innerWidth && this.incorrectOrientation == false) { this._game.stage.canvas.style.marginLeft = Math.round((window.innerWidth - this.width) / 2) + 'px'; @@ -12032,12 +12113,14 @@ var Phaser; body.velocity.x += this._velocityDelta; this._delta = body.velocity.x * this.game.time.elapsed; body.velocity.x += this._velocityDelta; - body.position.x += this._delta; + //body.position.x += this._delta; + body.sprite.x += this._delta; this._velocityDelta = (this.computeVelocity(body.velocity.y, body.gravity.y, body.acceleration.y, body.drag.y) - body.velocity.y) / 2; body.velocity.y += this._velocityDelta; this._delta = body.velocity.y * this.game.time.elapsed; body.velocity.y += this._velocityDelta; - body.position.y += this._delta; + //body.position.y += this._delta; + body.sprite.y += this._delta; }; PhysicsManager.prototype.computeVelocity = /** * A tween-like function that takes a starting velocity and some other factors and returns an altered velocity. @@ -12531,6 +12614,7 @@ var Phaser; this._quadTree = new Phaser.QuadTree(this, this.bounds.x, this.bounds.y, this.bounds.width, this.bounds.height); this._quadTree.load(object1, object2, notifyCallback, processCallback, context); this._quadTreeResult = this._quadTree.execute(); + console.log('over', this._quadTreeResult); this._quadTree.destroy(); this._quadTree = null; return this._quadTreeResult; @@ -12932,6 +13016,14 @@ var Phaser; this.group.update(); this.cameras.update(); }; + World.prototype.postUpdate = /** + * This is called automatically every frame, and is where main logic happens. + */ + function () { + //this.physics.postUpdate(); + this.group.postUpdate(); + this.cameras.postUpdate(); + }; World.prototype.destroy = /** * Clean up memory. */ @@ -14136,13 +14228,13 @@ var Phaser; */ this.screenY = -1; /** - * The horizontal coordinate of point relative to the game element + * The horizontal coordinate of point relative to the game element. This value is automatically scaled based on game size. * @property x * @type {Number} */ this.x = -1; /** - * The vertical coordinate of point relative to the game element + * The vertical coordinate of point relative to the game element. This value is automatically scaled based on game size. * @property y * @type {Number} */ @@ -14220,44 +14312,22 @@ var Phaser; enumerable: true, configurable: true }); - Pointer.prototype.getWorldX = /** - * Gets the X value of this Pointer in world coordinate space (is it properly scaled?) + Pointer.prototype.worldX = /** + * Gets the X value of this Pointer in world coordinates based on the given camera. * @param {Camera} [camera] */ function (camera) { - if (typeof camera === "undefined") { camera = this.game.camera; } + if (typeof camera === "undefined") { camera = this.game.input.camera; } return camera.worldView.x + this.x; }; - Pointer.prototype.getWorldY = /** - * Gets the Y value of this Pointer in world coordinate space + Pointer.prototype.worldY = /** + * Gets the Y value of this Pointer in world coordinates based on the given camera. * @param {Camera} [camera] */ function (camera) { - if (typeof camera === "undefined") { camera = this.game.camera; } + if (typeof camera === "undefined") { camera = this.game.input.camera; } return camera.worldView.y + this.y; }; - Object.defineProperty(Pointer.prototype, "scaledX", { - get: /** - * Gets the X value of this Pointer in world coordinate space - * @param {Camera} [camera] - */ - function () { - return Math.floor(this.x * this.game.input.scaleX); - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Pointer.prototype, "scaledY", { - get: /** - * Gets the Y value of this Pointer in world coordinate space - * @param {Camera} [camera] - */ - function () { - return Math.floor(this.y * this.game.input.scaleY); - }, - enumerable: true, - configurable: true - }); Pointer.prototype.start = /** * Called when the Pointer is pressed onto the touchscreen * @method start @@ -14281,12 +14351,15 @@ var Phaser; this.isUp = false; this.timeDown = this.game.time.now; this._holdSent = false; + // This sets the x/y and other local values + this.move(event); // x and y are the old values here? this.positionDown.setTo(this.x, this.y); - this.move(event); if(this.game.input.multiInputOverride == Phaser.Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Phaser.Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == Phaser.Input.TOUCH_OVERRIDES_MOUSE && this.game.input.currentPointers == 0)) { - this.game.input.x = this.x * this.game.input.scaleX; - this.game.input.y = this.y * this.game.input.scaleY; + //this.game.input.x = this.x * this.game.input.scale.x; + //this.game.input.y = this.y * this.game.input.scale.y; + this.game.input.x = this.x; + this.game.input.y = this.y; this.game.input.onDown.dispatch(this); } this._stateReset = false; @@ -14335,14 +14408,15 @@ var Phaser; this.pageY = event.pageY; this.screenX = event.screenX; this.screenY = event.screenY; - this.x = this.pageX - this.game.stage.offset.x; - this.y = this.pageY - this.game.stage.offset.y; + this.x = (this.pageX - this.game.stage.offset.x) * this.game.input.scale.x; + this.y = (this.pageY - this.game.stage.offset.y) * this.game.input.scale.y; this.position.setTo(this.x, this.y); this.circle.x = this.x; this.circle.y = this.y; if(this.game.input.multiInputOverride == Phaser.Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Phaser.Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == Phaser.Input.TOUCH_OVERRIDES_MOUSE && this.game.input.currentPointers == 0)) { - this.game.input.x = this.x * this.game.input.scaleX; - this.game.input.y = this.y * this.game.input.scaleY; + this.game.input.activePointer = this; + this.game.input.x = this.x; + this.game.input.y = this.y; this.game.input.position.setTo(this.game.input.x, this.game.input.y); this.game.input.circle.x = this.game.input.x; this.game.input.circle.y = this.game.input.y; @@ -15209,6 +15283,18 @@ var Phaser; **/ this._oldPosition = null; /** + * X coordinate of the most recent Pointer event + * @type {Number} + * @private + */ + this._x = 0; + /** + * X coordinate of the most recent Pointer event + * @type {Number} + * @private + */ + this._y = 0; + /** * You can disable all Input by setting Input.disabled = true. While set all new input related events will be ignored. * If you need to disable just one type of input, for example mouse, use Input.mouse.disabled = true instead * @type {Boolean} @@ -15239,27 +15325,11 @@ var Phaser; **/ this.circle = null; /** - * X coordinate of the most recent Pointer event - * @type {Number} - * @private + * The scale by which all input coordinates are multiplied, calculated by the StageScaleMode. + * In an un-scaled game the values will be x: 1 and y: 1. + * @type {Vec2} */ - this._x = 0; - /** - * X coordinate of the most recent Pointer event - * @type {Number} - * @private - */ - this._y = 0; - /** - * - * @type {Number} - */ - this.scaleX = 1; - /** - * - * @type {Number} - */ - this.scaleY = 1; + this.scale = null; /** * The maximum number of Pointers allowed to be active at any one time. * For lots of games it's useful to set this to 1 @@ -15352,6 +15422,13 @@ var Phaser; * @type {Pointer} **/ this.pointer10 = null; + /** + * The most recently active Pointer object. + * When you've limited max pointers to 1 this will accurately be either the first finger touched or mouse. + * @property activePointer + * @type {Pointer} + **/ + this.activePointer = null; this.inputObjects = []; this.totalTrackedObjects = 0; this._game = game; @@ -15370,10 +15447,13 @@ var Phaser; this.onUp = new Phaser.Signal(); this.onTap = new Phaser.Signal(); this.onHold = new Phaser.Signal(); + this.scale = new Phaser.Vec2(1, 1); this.speed = new Phaser.Vec2(); this.position = new Phaser.Vec2(); this._oldPosition = new Phaser.Vec2(); this.circle = new Phaser.Circle(0, 0, 44); + this.camera = this._game.camera; + this.activePointer = this.mousePointer; this.currentPointers = 0; } Input.MOUSE_OVERRIDES_TOUCH = 0; @@ -15381,7 +15461,8 @@ var Phaser; Input.MOUSE_TOUCH_COMBINE = 2; Object.defineProperty(Input.prototype, "x", { get: /** - * The screen X coordinate + * The X coordinate of the most recently active pointer. + * This value takes game scaling into account automatically. See Pointer.screenX/clientX for source values. * @property x * @type {Number} **/ @@ -15396,7 +15477,8 @@ var Phaser; }); Object.defineProperty(Input.prototype, "y", { get: /** - * The screen Y coordinate + * The Y coordinate of the most recently active pointer. + * This value takes game scaling into account automatically. See Pointer.screenY/clientY for source values. * @property y * @type {Number} **/ @@ -15467,7 +15549,6 @@ var Phaser; * @method update **/ function () { - // Swap for velocity vector - and add it to Pointer? this.speed.x = this.position.x - this._oldPosition.x; this.speed.y = this.position.y - this._oldPosition.y; this._oldPosition.copyFrom(this.position); @@ -15766,12 +15847,12 @@ var Phaser; */ function (x, y, color) { if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } - this._game.stage.context.font = '14px Courier'; this._game.stage.context.fillStyle = color; this._game.stage.context.fillText('Input', x, y); - this._game.stage.context.fillText('Screen X: ' + this.x + ' Screen Y: ' + this.y, x, y + 14); + this._game.stage.context.fillText('X: ' + this.x + ' Y: ' + this.y, x, y + 14); this._game.stage.context.fillText('World X: ' + this.getWorldX() + ' World Y: ' + this.getWorldY(), x, y + 28); - this._game.stage.context.fillText('Scale X: ' + this.scaleX.toFixed(1) + ' Scale Y: ' + this.scaleY.toFixed(1), x, y + 42); + this._game.stage.context.fillText('Scale X: ' + this.scale.x.toFixed(1) + ' Scale Y: ' + this.scale.x.toFixed(1), x, y + 42); + this._game.stage.context.fillText('Screen X: ' + this.activePointer.screenX + ' Screen Y: ' + this.activePointer.screenY, x, y + 56); }; Input.prototype.getDistance = /** * Get the distance between two Pointer objects @@ -15806,6 +15887,9 @@ var Phaser; } HeadlessRenderer.prototype.render = function () { }; + HeadlessRenderer.prototype.inCamera = function (camera, sprite) { + return true; + }; HeadlessRenderer.prototype.renderGameObject = function (object) { }; HeadlessRenderer.prototype.renderSprite = function (camera, sprite) { @@ -15981,24 +16065,12 @@ var Phaser; * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. */ function (camera, sprite) { - return true; - /* - // Object fixed in place regardless of the camera scrolling? Then it's always visible - if (sprite.scrollFactor.x == 0 && sprite.scrollFactor.y == 0) - { - return true; + if(sprite.transform.scrollFactor.equals(0)) { + return true; } - - this._dx = sprite.frameBounds.x - (camera.worldView.x * sprite.scrollFactor.x); - this._dy = sprite.frameBounds.y - (camera.worldView.y * sprite.scrollFactor.y); - this._dw = sprite.frameBounds.width * sprite.scale.x; - this._dh = sprite.frameBounds.height * sprite.scale.y; - - //return (camera.screenView.x + camera.worldView.width > this._dx) && (camera.screenView.x < this._dx + this._dw) && (camera.screenView.y + camera.worldView.height > this._dy) && (camera.screenView.y < this._dy + this._dh); - - */ - }; + return Phaser.RectangleUtils.intersects(sprite.worldView, camera.worldView); + }; CanvasRenderer.prototype.inScreen = function (camera) { return true; }; @@ -16372,11 +16444,37 @@ var Phaser; function renderSpriteInfo(sprite, x, y, color) { if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } DebugUtils.game.stage.context.fillStyle = color; - DebugUtils.game.stage.context.fillText('Sprite: ' + ' (' + sprite.width + ' x ' + sprite.height + ')', x, y); + DebugUtils.game.stage.context.fillText('Sprite: ' + ' (' + sprite.width + ' x ' + sprite.height + ') origin: ' + sprite.transform.origin.x + ' x ' + sprite.transform.origin.y, x, y); DebugUtils.game.stage.context.fillText('x: ' + sprite.x.toFixed(1) + ' y: ' + sprite.y.toFixed(1) + ' rotation: ' + sprite.rotation.toFixed(1), x, y + 14); - //DebugUtils.game.stage.context.fillText('dx: ' + this._dx.toFixed(1) + ' dy: ' + this._dy.toFixed(1) + ' dw: ' + this._dw.toFixed(1) + ' dh: ' + this._dh.toFixed(1), x, y + 28); - //DebugUtils.game.stage.context.fillText('sx: ' + this._sx.toFixed(1) + ' sy: ' + this._sy.toFixed(1) + ' sw: ' + this._sw.toFixed(1) + ' sh: ' + this._sh.toFixed(1), x, y + 42); - }; + DebugUtils.game.stage.context.fillText('wx: ' + sprite.worldView.x + ' wy: ' + sprite.worldView.y + ' ww: ' + sprite.worldView.width.toFixed(1) + ' wh: ' + sprite.worldView.height.toFixed(1) + ' wb: ' + sprite.worldView.bottom + ' wr: ' + sprite.worldView.right, x, y + 28); + DebugUtils.game.stage.context.fillText('sx: ' + sprite.transform.scale.x.toFixed(1) + ' sy: ' + sprite.transform.scale.y.toFixed(1), x, y + 42); + DebugUtils.game.stage.context.fillText('tx: ' + sprite.texture.width.toFixed(1) + ' ty: ' + sprite.texture.height.toFixed(1), x, y + 56); + DebugUtils.game.stage.context.fillText('inCamera: ' + DebugUtils.game.renderer.inCamera(DebugUtils.game.camera, sprite), x, y + 70); + }; + DebugUtils.renderSpriteBounds = function renderSpriteBounds(sprite, camera, color) { + if (typeof camera === "undefined") { camera = null; } + if (typeof color === "undefined") { color = 'rgba(0,255,0,0.2)'; } + if(camera == null) { + camera = DebugUtils.game.camera; + } + //var dx = (camera.screenView.x * sprite.transform.scrollFactor.x) + sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + //var dy = (camera.screenView.y * sprite.transform.scrollFactor.y) + sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + var dx = sprite.worldView.x; + var dy = sprite.worldView.y; + DebugUtils.game.stage.context.fillStyle = color; + DebugUtils.game.stage.context.fillRect(dx, dy, sprite.width, sprite.height); + }; + DebugUtils.renderSpritePhysicsBody = function renderSpritePhysicsBody(sprite, camera, color) { + if (typeof camera === "undefined") { camera = null; } + if (typeof color === "undefined") { color = 'rgba(255,0,0,0.2)'; } + if(camera == null) { + camera = DebugUtils.game.camera; + } + var dx = (camera.screenView.x * sprite.transform.scrollFactor.x) + sprite.body.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + var dy = (camera.screenView.y * sprite.transform.scrollFactor.y) + sprite.body.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + DebugUtils.game.stage.context.fillStyle = color; + DebugUtils.game.stage.context.fillRect(dx, dy, sprite.body.width, sprite.body.height); + }; return DebugUtils; })(); Phaser.DebugUtils = DebugUtils; @@ -16651,6 +16749,7 @@ var Phaser; if(this._loadComplete && this.onUpdateCallback) { this.onUpdateCallback.call(this.callbackContext); } + this.world.postUpdate(); this.renderer.render(); if(this._loadComplete && this.onRenderCallback) { this.onRenderCallback.call(this.callbackContext); diff --git a/Tests/physics/aabb 1.js b/Tests/physics/aabb 1.js index d8fd9fbd..a1d610f0 100644 --- a/Tests/physics/aabb 1.js +++ b/Tests/physics/aabb 1.js @@ -33,5 +33,6 @@ } function render() { atari.body.renderDebugInfo(16, 16); + Phaser.DebugUtils.renderSpritePhysicsBody(atari); } })(); diff --git a/Tests/physics/aabb 1.ts b/Tests/physics/aabb 1.ts index 0295c21f..df5ac64b 100644 --- a/Tests/physics/aabb 1.ts +++ b/Tests/physics/aabb 1.ts @@ -57,6 +57,7 @@ function render() { atari.body.renderDebugInfo(16, 16); + Phaser.DebugUtils.renderSpritePhysicsBody(atari); } diff --git a/Tests/physics/aabb vs aabb 1.js b/Tests/physics/aabb vs aabb 1.js index 01407402..71a16648 100644 --- a/Tests/physics/aabb vs aabb 1.js +++ b/Tests/physics/aabb vs aabb 1.js @@ -39,9 +39,12 @@ atari.body.acceleration.y = 150; } // collide? - } + game.collide(atari, card); + } function render() { atari.body.renderDebugInfo(16, 16); card.body.renderDebugInfo(200, 16); + Phaser.DebugUtils.renderSpritePhysicsBody(atari); + Phaser.DebugUtils.renderSpritePhysicsBody(card); } })(); diff --git a/Tests/physics/aabb vs aabb 1.ts b/Tests/physics/aabb vs aabb 1.ts index 25e16c23..bbaf3f5e 100644 --- a/Tests/physics/aabb vs aabb 1.ts +++ b/Tests/physics/aabb vs aabb 1.ts @@ -64,6 +64,7 @@ } // collide? + game.collide(atari, card); } @@ -72,6 +73,9 @@ atari.body.renderDebugInfo(16, 16); card.body.renderDebugInfo(200, 16); + Phaser.DebugUtils.renderSpritePhysicsBody(atari); + Phaser.DebugUtils.renderSpritePhysicsBody(card); + } })(); diff --git a/build/phaser.d.ts b/build/phaser.d.ts index 797452bf..379a1323 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -2344,7 +2344,7 @@ module Phaser.Physics { */ public game: Game; /** - * Reference to the sprite Sprite + * Reference to the parent Sprite */ public sprite: Sprite; /** @@ -2379,6 +2379,12 @@ module Phaser.Physics { public oldPosition: Vec2; public offset: Vec2; public bounds: Rectangle; + private _width; + private _height; + public x : number; + public y : number; + public width : number; + public height : number; public preUpdate(): void; public postUpdate(): void; public hullWidth : number; @@ -2411,7 +2417,7 @@ module Phaser { * @param [x] {number} the initial x position of the sprite. * @param [y] {number} the initial y position of the sprite. * @param [key] {string} Key of the graphic you want to load for this sprite. - * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) + * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DYNAMIC) */ constructor(game: Game, x?: number, y?: number, key?: string, frame?, bodyType?: number); /** @@ -2865,6 +2871,11 @@ module Phaser { */ public update(): void; /** + * Calls update on all members of this Group who have a status of active=true and exists=true + * You can also call Object.postUpdate directly, which will bypass the active/exists check. + */ + public postUpdate(): void; + /** * Calls render on all members of this Group who have a status of visible=true and exists=true * You can also call Object.render directly, which will bypass the visible/exists check. */ @@ -2901,7 +2912,7 @@ module Phaser { * @param y {number} Y position of the new sprite. * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this sprite * @param [frame] {string|number} If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name. - * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) + * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DYNAMIC) * @returns {Sprite} The newly created sprite object. */ public addNewSprite(x: number, y: number, key?: string, frame?, bodyType?: number): Sprite; @@ -4490,6 +4501,10 @@ module Phaser { */ public update(): void; /** + * Update focusing and scrolling. + */ + public postUpdate(): void; + /** * Render debug infos. (including id, position, rotation, scrolling factor, worldBounds and some other properties) * @param x {number} X position of the debug info to be rendered. * @param y {number} Y position of the debug info to be rendered. @@ -4576,6 +4591,10 @@ module Phaser { */ public update(): void; /** + * postUpdate cameras. + */ + public postUpdate(): void; + /** * Create a new camera with specific position and size. * * @param x {number} X position of the new camera. @@ -6989,6 +7008,10 @@ module Phaser { */ public update(): void; /** + * This is called automatically every frame, and is where main logic happens. + */ + public postUpdate(): void; + /** * Clean up memory. */ public destroy(): void; @@ -7618,13 +7641,13 @@ module Phaser { */ public screenY: number; /** - * The horizontal coordinate of point relative to the game element + * The horizontal coordinate of point relative to the game element. This value is automatically scaled based on game size. * @property x * @type {Number} */ public x: number; /** - * The vertical coordinate of point relative to the game element + * The vertical coordinate of point relative to the game element. This value is automatically scaled based on game size. * @property y * @type {Number} */ @@ -7690,25 +7713,15 @@ module Phaser { **/ public targetObject; /** - * Gets the X value of this Pointer in world coordinate space (is it properly scaled?) + * Gets the X value of this Pointer in world coordinates based on the given camera. * @param {Camera} [camera] */ - public getWorldX(camera?: Camera): number; + public worldX(camera?: Camera): number; /** - * Gets the Y value of this Pointer in world coordinate space + * Gets the Y value of this Pointer in world coordinates based on the given camera. * @param {Camera} [camera] */ - public getWorldY(camera?: Camera): number; - /** - * Gets the X value of this Pointer in world coordinate space - * @param {Camera} [camera] - */ - public scaledX : number; - /** - * Gets the Y value of this Pointer in world coordinate space - * @param {Camera} [camera] - */ - public scaledY : number; + public worldY(camera?: Camera): number; /** * Called when the Pointer is pressed onto the touchscreen * @method start @@ -8187,6 +8200,18 @@ module Phaser { **/ private _oldPosition; /** + * X coordinate of the most recent Pointer event + * @type {Number} + * @private + */ + private _x; + /** + * X coordinate of the most recent Pointer event + * @type {Number} + * @private + */ + private _y; + /** * You can disable all Input by setting Input.disabled = true. While set all new input related events will be ignored. * If you need to disable just one type of input, for example mouse, use Input.mouse.disabled = true instead * @type {Boolean} @@ -8212,6 +8237,12 @@ module Phaser { */ static MOUSE_TOUCH_COMBINE: number; /** + * The camera being used for mouse and touch based pointers to calculate their world coordinates. + * @property camera + * @type {Camera} + **/ + public camera: Camera; + /** * Phaser.Mouse handler * @type {Mouse} */ @@ -8257,27 +8288,11 @@ module Phaser { **/ public circle: Circle; /** - * X coordinate of the most recent Pointer event - * @type {Number} - * @private + * The scale by which all input coordinates are multiplied, calculated by the StageScaleMode. + * In an un-scaled game the values will be x: 1 and y: 1. + * @type {Vec2} */ - private _x; - /** - * X coordinate of the most recent Pointer event - * @type {Number} - * @private - */ - private _y; - /** - * - * @type {Number} - */ - public scaleX: number; - /** - * - * @type {Number} - */ - public scaleY: number; + public scale: Vec2; /** * The maximum number of Pointers allowed to be active at any one time. * For lots of games it's useful to set this to 1 @@ -8428,13 +8443,22 @@ module Phaser { **/ public pointer10: Pointer; /** - * The screen X coordinate + * The most recently active Pointer object. + * When you've limited max pointers to 1 this will accurately be either the first finger touched or mouse. + * @property activePointer + * @type {Pointer} + **/ + public activePointer: Pointer; + /** + * The X coordinate of the most recently active pointer. + * This value takes game scaling into account automatically. See Pointer.screenX/clientX for source values. * @property x * @type {Number} **/ public x : number; /** - * The screen Y coordinate + * The Y coordinate of the most recently active pointer. + * This value takes game scaling into account automatically. See Pointer.screenY/clientY for source values. * @property y * @type {Number} **/ @@ -8554,16 +8578,15 @@ module Phaser { postRenderGroup(camera: Camera, group: Group); preRenderCamera(camera: Camera); postRenderCamera(camera: Camera); + inCamera(camera: Camera, sprite: Sprite): bool; } } module Phaser { class HeadlessRenderer implements IRenderer { constructor(game: Game); - /** - * The essential reference to the main game object - */ private _game; public render(): void; + public inCamera(camera: Camera, sprite: Sprite): bool; public renderGameObject(object): void; public renderSprite(camera: Camera, sprite: Sprite): bool; public renderScrollZone(camera: Camera, scrollZone: ScrollZone): bool; @@ -8642,6 +8665,8 @@ module Phaser { * @param [color] {number} color of the debug info to be rendered. (format is css color string) */ static renderSpriteInfo(sprite: Sprite, x: number, y: number, color?: string): void; + static renderSpriteBounds(sprite: Sprite, camera?: Camera, color?: string): void; + static renderSpritePhysicsBody(sprite: Sprite, camera?: Camera, color?: string): void; } } /** diff --git a/build/phaser.js b/build/phaser.js index 4839d5cb..a07d9581 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -3051,7 +3051,7 @@ var Phaser; if(this.enabled == false || this.sprite.visible == false) { return false; } else { - return Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.scaledX, pointer.scaledY); + return Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY()); } }; Input.prototype.update = /** @@ -3064,9 +3064,9 @@ var Phaser; if(this.draggable && this._draggedPointerID == pointer.id) { return this.updateDrag(pointer); } else if(this._pointerData[pointer.id].isOver == true) { - if(Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.scaledX, pointer.scaledY)) { - this._pointerData[pointer.id].x = pointer.scaledX - this.sprite.x; - this._pointerData[pointer.id].y = pointer.scaledY - this.sprite.y; + if(Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY())) { + this._pointerData[pointer.id].x = pointer.x - this.sprite.x; + this._pointerData[pointer.id].y = pointer.y - this.sprite.y; return true; } else { this._pointerOutHandler(pointer); @@ -3721,15 +3721,19 @@ var Phaser; this.angularDrag = 0; this.maxAngular = 10000; this.mass = 1; + this._width = 0; + this._height = 0; this.sprite = sprite; this.game = sprite.game; this.type = type; // Fixture properties // Will extend into its own class at a later date - can move the fixture defs there and add shape support, but this will do for 1.0 release - this.bounds = new Phaser.Rectangle(sprite.x + Math.round(sprite.width / 2), sprite.y + Math.round(sprite.height / 2), sprite.width, sprite.height); - this.bounce = Phaser.Vec2Utils.clone(this.game.world.physics.bounce); + this.bounds = new Phaser.Rectangle(); + this._width = sprite.width; + this._height = sprite.height; // Body properties this.gravity = Phaser.Vec2Utils.clone(this.game.world.physics.gravity); + this.bounce = Phaser.Vec2Utils.clone(this.game.world.physics.bounce); this.velocity = new Phaser.Vec2(); this.acceleration = new Phaser.Vec2(); this.drag = Phaser.Vec2Utils.clone(this.game.world.physics.drag); @@ -3744,12 +3748,46 @@ var Phaser; this.oldPosition = new Phaser.Vec2(sprite.x + this.bounds.halfWidth, sprite.y + this.bounds.halfHeight); this.offset = new Phaser.Vec2(); } + Object.defineProperty(Body.prototype, "x", { + get: function () { + return this.sprite.x + this.offset.x; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "y", { + get: function () { + return this.sprite.y + this.offset.y; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "width", { + get: function () { + return this._width * this.sprite.transform.scale.x; + }, + set: function (value) { + this._width = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Body.prototype, "height", { + get: function () { + return this._height * this.sprite.transform.scale.y; + }, + set: function (value) { + this._height = value; + }, + enumerable: true, + configurable: true + }); Body.prototype.preUpdate = function () { this.oldPosition.copyFrom(this.position); - this.bounds.x = this.position.x - this.bounds.halfWidth; - this.bounds.y = this.position.y - this.bounds.halfHeight; - if(this.sprite.transform.scale.equals(1) == false) { - } + this.bounds.x = this.x; + this.bounds.y = this.y; + this.bounds.width = this.width; + this.bounds.height = this.height; }; Body.prototype.postUpdate = // Shall we do this? Or just update the values directly in the separate functions? But then the bounds will be out of sync - as long as // the bounds are updated and used in calculations then we can do one final sprite movement here I guess? @@ -3757,11 +3795,10 @@ var Phaser; // if this is all it does maybe move elsewhere? Sprite postUpdate? if(this.type !== Phaser.Types.BODY_DISABLED) { this.game.world.physics.updateMotion(this); - this.sprite.x = (this.position.x - this.bounds.halfWidth) - this.offset.x; - this.sprite.y = (this.position.y - this.bounds.halfHeight) - this.offset.y; this.wasTouching = this.touching; this.touching = Phaser.Types.NONE; } + this.position.setTo(this.x, this.y); }; Object.defineProperty(Body.prototype, "hullWidth", { get: function () { @@ -3922,14 +3959,14 @@ var Phaser; * @param [x] {number} the initial x position of the sprite. * @param [y] {number} the initial y position of the sprite. * @param [key] {string} Key of the graphic you want to load for this sprite. - * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) + * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DYNAMIC) */ function Sprite(game, x, y, key, frame, bodyType) { if (typeof x === "undefined") { x = 0; } if (typeof y === "undefined") { y = 0; } if (typeof key === "undefined") { key = null; } if (typeof frame === "undefined") { frame = null; } - if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } + if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DYNAMIC; } /** * A boolean representing if the Sprite has been modified in any way via a scale, rotate, flip or skew. */ @@ -3963,7 +4000,6 @@ var Phaser; this.transform = new Phaser.Components.Transform(this); this.animations = new Phaser.Components.AnimationManager(this); this.texture = new Phaser.Components.Texture(this); - this.body = new Phaser.Physics.Body(this, bodyType); this.input = new Phaser.Components.Sprite.Input(this); this.events = new Phaser.Components.Sprite.Events(this); if(key !== null) { @@ -3978,6 +4014,7 @@ var Phaser; this.frame = frame; } } + this.body = new Phaser.Physics.Body(this, bodyType); this.worldView = new Phaser.Rectangle(x, y, this.width, this.height); } Object.defineProperty(Sprite.prototype, "rotation", { @@ -4053,8 +4090,10 @@ var Phaser; * Pre-update is called right before update() on each object in the game loop. */ function () { - this.worldView.x = this.x - (this.game.world.cameras.default.worldView.x * this.transform.scrollFactor.x); - this.worldView.y = this.y - (this.game.world.cameras.default.worldView.y * this.transform.scrollFactor.y); + //this.worldView.x = this.x * this.transform.scrollFactor.x; + //this.worldView.y = this.y * this.transform.scrollFactor.y; + this.worldView.x = this.x - this.transform.origin.x; + this.worldView.y = this.y - this.transform.origin.y; this.worldView.width = this.width; this.worldView.height = this.height; if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { @@ -4702,8 +4741,6 @@ var Phaser; function () { if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { this.modified = true; - } else if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { - this.modified = false; } this._i = 0; while(this._i < this.length) { @@ -4711,6 +4748,21 @@ var Phaser; if(this._member != null && this._member.exists && this._member.active) { this._member.preUpdate(); this._member.update(); + } + } + }; + Group.prototype.postUpdate = /** + * Calls update on all members of this Group who have a status of active=true and exists=true + * You can also call Object.postUpdate directly, which will bypass the active/exists check. + */ + function () { + if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { + this.modified = false; + } + this._i = 0; + while(this._i < this.length) { + this._member = this.members[this._i++]; + if(this._member != null && this._member.exists && this._member.active) { this._member.postUpdate(); } } @@ -4846,13 +4898,13 @@ var Phaser; * @param y {number} Y position of the new sprite. * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this sprite * @param [frame] {string|number} If the sprite uses an image from a texture atlas or sprite sheet you can pass the frame here. Either a number for a frame ID or a string for a frame name. - * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DISABLED) + * @param [bodyType] {number} The physics body type of the object (defaults to BODY_DYNAMIC) * @returns {Sprite} The newly created sprite object. */ function (x, y, key, frame, bodyType) { if (typeof key === "undefined") { key = ''; } if (typeof frame === "undefined") { frame = null; } - if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } + if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DYNAMIC; } return this.add(new Phaser.Sprite(this.game, x, y, key, frame, bodyType)); }; Group.prototype.setObjectIDs = /** @@ -7760,8 +7812,6 @@ var Phaser; function () { if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { this.modified = true; - } else if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { - this.modified = false; } this.fx.preUpdate(); if(this._target !== null) { @@ -7804,6 +7854,29 @@ var Phaser; this.worldView.y = (this.worldBounds.bottom - this.height) + 1; } } + }; + Camera.prototype.postUpdate = /** + * Update focusing and scrolling. + */ + function () { + if(this.modified == true && this.transform.scale.equals(1) && this.transform.skew.equals(0) && this.transform.rotation == 0 && this.transform.rotationOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { + this.modified = false; + } + // Make sure we didn't go outside the cameras worldBounds + if(this.worldBounds !== null) { + if(this.worldView.x < this.worldBounds.left) { + this.worldView.x = this.worldBounds.left; + } + if(this.worldView.x > this.worldBounds.right - this.width) { + this.worldView.x = (this.worldBounds.right - this.width) + 1; + } + if(this.worldView.y < this.worldBounds.top) { + this.worldView.y = this.worldBounds.top; + } + if(this.worldView.y > this.worldBounds.bottom - this.height) { + this.worldView.y = (this.worldBounds.bottom - this.height) + 1; + } + } this.fx.postUpdate(); }; Camera.prototype.renderDebugInfo = /** @@ -7817,9 +7890,10 @@ var Phaser; this.game.stage.context.fillStyle = color; this.game.stage.context.fillText('Camera ID: ' + this.ID + ' (' + this.screenView.width + ' x ' + this.screenView.height + ')', x, y); this.game.stage.context.fillText('X: ' + this.screenView.x + ' Y: ' + this.screenView.y + ' rotation: ' + this.transform.rotation, x, y + 14); - this.game.stage.context.fillText('World X: ' + this.worldView.x.toFixed(1) + ' World Y: ' + this.worldView.y.toFixed(1), x, y + 28); + this.game.stage.context.fillText('World X: ' + this.worldView.x + ' World Y: ' + this.worldView.y + ' W: ' + this.worldView.width + ' H: ' + this.worldView.height + ' R: ' + this.worldView.right + ' B: ' + this.worldView.bottom, x, y + 28); + this.game.stage.context.fillText('ScreenView X: ' + this.screenView.x + ' Y: ' + this.screenView.y + ' W: ' + this.screenView.width + ' H: ' + this.screenView.height, x, y + 42); if(this.worldBounds) { - this.game.stage.context.fillText('Bounds: ' + this.worldBounds.width + ' x ' + this.worldBounds.height, x, y + 42); + this.game.stage.context.fillText('Bounds: ' + this.worldBounds.width + ' x ' + this.worldBounds.height, x, y + 56); } }; Camera.prototype.destroy = /** @@ -7959,9 +8033,17 @@ var Phaser; * Update cameras. */ function () { - this._cameras.forEach(function (camera) { - return camera.update(); - }); + for(var i = 0; i < this._cameras.length; i++) { + this._cameras[i].update(); + } + }; + CameraManager.prototype.postUpdate = /** + * postUpdate cameras. + */ + function () { + for(var i = 0; i < this._cameras.length; i++) { + this._cameras[i].postUpdate(); + } }; CameraManager.prototype.addCamera = /** * Create a new camera with specific position and size. @@ -10295,7 +10377,7 @@ var Phaser; function (x, y, key, frame, bodyType) { if (typeof key === "undefined") { key = ''; } if (typeof frame === "undefined") { frame = null; } - if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DISABLED; } + if (typeof bodyType === "undefined") { bodyType = Phaser.Types.BODY_DYNAMIC; } return this._world.group.add(new Phaser.Sprite(this._game, x, y, key, frame, bodyType)); }; GameObjectFactory.prototype.dynamicTexture = /** @@ -10967,8 +11049,7 @@ var Phaser; } this._game.stage.canvas.style.width = this.width + 'px'; this._game.stage.canvas.style.height = this.height + 'px'; - this._game.input.scaleX = this._game.stage.width / this.width; - this._game.input.scaleY = this._game.stage.height / this.height; + this._game.input.scale.setTo(this._game.stage.width / this.width, this._game.stage.height / this.height); if(this.pageAlignHorizontally) { if(this.width < window.innerWidth && this.incorrectOrientation == false) { this._game.stage.canvas.style.marginLeft = Math.round((window.innerWidth - this.width) / 2) + 'px'; @@ -12032,12 +12113,14 @@ var Phaser; body.velocity.x += this._velocityDelta; this._delta = body.velocity.x * this.game.time.elapsed; body.velocity.x += this._velocityDelta; - body.position.x += this._delta; + //body.position.x += this._delta; + body.sprite.x += this._delta; this._velocityDelta = (this.computeVelocity(body.velocity.y, body.gravity.y, body.acceleration.y, body.drag.y) - body.velocity.y) / 2; body.velocity.y += this._velocityDelta; this._delta = body.velocity.y * this.game.time.elapsed; body.velocity.y += this._velocityDelta; - body.position.y += this._delta; + //body.position.y += this._delta; + body.sprite.y += this._delta; }; PhysicsManager.prototype.computeVelocity = /** * A tween-like function that takes a starting velocity and some other factors and returns an altered velocity. @@ -12531,6 +12614,7 @@ var Phaser; this._quadTree = new Phaser.QuadTree(this, this.bounds.x, this.bounds.y, this.bounds.width, this.bounds.height); this._quadTree.load(object1, object2, notifyCallback, processCallback, context); this._quadTreeResult = this._quadTree.execute(); + console.log('over', this._quadTreeResult); this._quadTree.destroy(); this._quadTree = null; return this._quadTreeResult; @@ -12932,6 +13016,14 @@ var Phaser; this.group.update(); this.cameras.update(); }; + World.prototype.postUpdate = /** + * This is called automatically every frame, and is where main logic happens. + */ + function () { + //this.physics.postUpdate(); + this.group.postUpdate(); + this.cameras.postUpdate(); + }; World.prototype.destroy = /** * Clean up memory. */ @@ -14136,13 +14228,13 @@ var Phaser; */ this.screenY = -1; /** - * The horizontal coordinate of point relative to the game element + * The horizontal coordinate of point relative to the game element. This value is automatically scaled based on game size. * @property x * @type {Number} */ this.x = -1; /** - * The vertical coordinate of point relative to the game element + * The vertical coordinate of point relative to the game element. This value is automatically scaled based on game size. * @property y * @type {Number} */ @@ -14220,44 +14312,22 @@ var Phaser; enumerable: true, configurable: true }); - Pointer.prototype.getWorldX = /** - * Gets the X value of this Pointer in world coordinate space (is it properly scaled?) + Pointer.prototype.worldX = /** + * Gets the X value of this Pointer in world coordinates based on the given camera. * @param {Camera} [camera] */ function (camera) { - if (typeof camera === "undefined") { camera = this.game.camera; } + if (typeof camera === "undefined") { camera = this.game.input.camera; } return camera.worldView.x + this.x; }; - Pointer.prototype.getWorldY = /** - * Gets the Y value of this Pointer in world coordinate space + Pointer.prototype.worldY = /** + * Gets the Y value of this Pointer in world coordinates based on the given camera. * @param {Camera} [camera] */ function (camera) { - if (typeof camera === "undefined") { camera = this.game.camera; } + if (typeof camera === "undefined") { camera = this.game.input.camera; } return camera.worldView.y + this.y; }; - Object.defineProperty(Pointer.prototype, "scaledX", { - get: /** - * Gets the X value of this Pointer in world coordinate space - * @param {Camera} [camera] - */ - function () { - return Math.floor(this.x * this.game.input.scaleX); - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Pointer.prototype, "scaledY", { - get: /** - * Gets the Y value of this Pointer in world coordinate space - * @param {Camera} [camera] - */ - function () { - return Math.floor(this.y * this.game.input.scaleY); - }, - enumerable: true, - configurable: true - }); Pointer.prototype.start = /** * Called when the Pointer is pressed onto the touchscreen * @method start @@ -14281,12 +14351,15 @@ var Phaser; this.isUp = false; this.timeDown = this.game.time.now; this._holdSent = false; + // This sets the x/y and other local values + this.move(event); // x and y are the old values here? this.positionDown.setTo(this.x, this.y); - this.move(event); if(this.game.input.multiInputOverride == Phaser.Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Phaser.Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == Phaser.Input.TOUCH_OVERRIDES_MOUSE && this.game.input.currentPointers == 0)) { - this.game.input.x = this.x * this.game.input.scaleX; - this.game.input.y = this.y * this.game.input.scaleY; + //this.game.input.x = this.x * this.game.input.scale.x; + //this.game.input.y = this.y * this.game.input.scale.y; + this.game.input.x = this.x; + this.game.input.y = this.y; this.game.input.onDown.dispatch(this); } this._stateReset = false; @@ -14335,14 +14408,15 @@ var Phaser; this.pageY = event.pageY; this.screenX = event.screenX; this.screenY = event.screenY; - this.x = this.pageX - this.game.stage.offset.x; - this.y = this.pageY - this.game.stage.offset.y; + this.x = (this.pageX - this.game.stage.offset.x) * this.game.input.scale.x; + this.y = (this.pageY - this.game.stage.offset.y) * this.game.input.scale.y; this.position.setTo(this.x, this.y); this.circle.x = this.x; this.circle.y = this.y; if(this.game.input.multiInputOverride == Phaser.Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Phaser.Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == Phaser.Input.TOUCH_OVERRIDES_MOUSE && this.game.input.currentPointers == 0)) { - this.game.input.x = this.x * this.game.input.scaleX; - this.game.input.y = this.y * this.game.input.scaleY; + this.game.input.activePointer = this; + this.game.input.x = this.x; + this.game.input.y = this.y; this.game.input.position.setTo(this.game.input.x, this.game.input.y); this.game.input.circle.x = this.game.input.x; this.game.input.circle.y = this.game.input.y; @@ -15209,6 +15283,18 @@ var Phaser; **/ this._oldPosition = null; /** + * X coordinate of the most recent Pointer event + * @type {Number} + * @private + */ + this._x = 0; + /** + * X coordinate of the most recent Pointer event + * @type {Number} + * @private + */ + this._y = 0; + /** * You can disable all Input by setting Input.disabled = true. While set all new input related events will be ignored. * If you need to disable just one type of input, for example mouse, use Input.mouse.disabled = true instead * @type {Boolean} @@ -15239,27 +15325,11 @@ var Phaser; **/ this.circle = null; /** - * X coordinate of the most recent Pointer event - * @type {Number} - * @private + * The scale by which all input coordinates are multiplied, calculated by the StageScaleMode. + * In an un-scaled game the values will be x: 1 and y: 1. + * @type {Vec2} */ - this._x = 0; - /** - * X coordinate of the most recent Pointer event - * @type {Number} - * @private - */ - this._y = 0; - /** - * - * @type {Number} - */ - this.scaleX = 1; - /** - * - * @type {Number} - */ - this.scaleY = 1; + this.scale = null; /** * The maximum number of Pointers allowed to be active at any one time. * For lots of games it's useful to set this to 1 @@ -15352,6 +15422,13 @@ var Phaser; * @type {Pointer} **/ this.pointer10 = null; + /** + * The most recently active Pointer object. + * When you've limited max pointers to 1 this will accurately be either the first finger touched or mouse. + * @property activePointer + * @type {Pointer} + **/ + this.activePointer = null; this.inputObjects = []; this.totalTrackedObjects = 0; this._game = game; @@ -15370,10 +15447,13 @@ var Phaser; this.onUp = new Phaser.Signal(); this.onTap = new Phaser.Signal(); this.onHold = new Phaser.Signal(); + this.scale = new Phaser.Vec2(1, 1); this.speed = new Phaser.Vec2(); this.position = new Phaser.Vec2(); this._oldPosition = new Phaser.Vec2(); this.circle = new Phaser.Circle(0, 0, 44); + this.camera = this._game.camera; + this.activePointer = this.mousePointer; this.currentPointers = 0; } Input.MOUSE_OVERRIDES_TOUCH = 0; @@ -15381,7 +15461,8 @@ var Phaser; Input.MOUSE_TOUCH_COMBINE = 2; Object.defineProperty(Input.prototype, "x", { get: /** - * The screen X coordinate + * The X coordinate of the most recently active pointer. + * This value takes game scaling into account automatically. See Pointer.screenX/clientX for source values. * @property x * @type {Number} **/ @@ -15396,7 +15477,8 @@ var Phaser; }); Object.defineProperty(Input.prototype, "y", { get: /** - * The screen Y coordinate + * The Y coordinate of the most recently active pointer. + * This value takes game scaling into account automatically. See Pointer.screenY/clientY for source values. * @property y * @type {Number} **/ @@ -15467,7 +15549,6 @@ var Phaser; * @method update **/ function () { - // Swap for velocity vector - and add it to Pointer? this.speed.x = this.position.x - this._oldPosition.x; this.speed.y = this.position.y - this._oldPosition.y; this._oldPosition.copyFrom(this.position); @@ -15766,12 +15847,12 @@ var Phaser; */ function (x, y, color) { if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } - this._game.stage.context.font = '14px Courier'; this._game.stage.context.fillStyle = color; this._game.stage.context.fillText('Input', x, y); - this._game.stage.context.fillText('Screen X: ' + this.x + ' Screen Y: ' + this.y, x, y + 14); + this._game.stage.context.fillText('X: ' + this.x + ' Y: ' + this.y, x, y + 14); this._game.stage.context.fillText('World X: ' + this.getWorldX() + ' World Y: ' + this.getWorldY(), x, y + 28); - this._game.stage.context.fillText('Scale X: ' + this.scaleX.toFixed(1) + ' Scale Y: ' + this.scaleY.toFixed(1), x, y + 42); + this._game.stage.context.fillText('Scale X: ' + this.scale.x.toFixed(1) + ' Scale Y: ' + this.scale.x.toFixed(1), x, y + 42); + this._game.stage.context.fillText('Screen X: ' + this.activePointer.screenX + ' Screen Y: ' + this.activePointer.screenY, x, y + 56); }; Input.prototype.getDistance = /** * Get the distance between two Pointer objects @@ -15806,6 +15887,9 @@ var Phaser; } HeadlessRenderer.prototype.render = function () { }; + HeadlessRenderer.prototype.inCamera = function (camera, sprite) { + return true; + }; HeadlessRenderer.prototype.renderGameObject = function (object) { }; HeadlessRenderer.prototype.renderSprite = function (camera, sprite) { @@ -15981,24 +16065,12 @@ var Phaser; * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. */ function (camera, sprite) { - return true; - /* - // Object fixed in place regardless of the camera scrolling? Then it's always visible - if (sprite.scrollFactor.x == 0 && sprite.scrollFactor.y == 0) - { - return true; + if(sprite.transform.scrollFactor.equals(0)) { + return true; } - - this._dx = sprite.frameBounds.x - (camera.worldView.x * sprite.scrollFactor.x); - this._dy = sprite.frameBounds.y - (camera.worldView.y * sprite.scrollFactor.y); - this._dw = sprite.frameBounds.width * sprite.scale.x; - this._dh = sprite.frameBounds.height * sprite.scale.y; - - //return (camera.screenView.x + camera.worldView.width > this._dx) && (camera.screenView.x < this._dx + this._dw) && (camera.screenView.y + camera.worldView.height > this._dy) && (camera.screenView.y < this._dy + this._dh); - - */ - }; + return Phaser.RectangleUtils.intersects(sprite.worldView, camera.worldView); + }; CanvasRenderer.prototype.inScreen = function (camera) { return true; }; @@ -16372,11 +16444,37 @@ var Phaser; function renderSpriteInfo(sprite, x, y, color) { if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } DebugUtils.game.stage.context.fillStyle = color; - DebugUtils.game.stage.context.fillText('Sprite: ' + ' (' + sprite.width + ' x ' + sprite.height + ')', x, y); + DebugUtils.game.stage.context.fillText('Sprite: ' + ' (' + sprite.width + ' x ' + sprite.height + ') origin: ' + sprite.transform.origin.x + ' x ' + sprite.transform.origin.y, x, y); DebugUtils.game.stage.context.fillText('x: ' + sprite.x.toFixed(1) + ' y: ' + sprite.y.toFixed(1) + ' rotation: ' + sprite.rotation.toFixed(1), x, y + 14); - //DebugUtils.game.stage.context.fillText('dx: ' + this._dx.toFixed(1) + ' dy: ' + this._dy.toFixed(1) + ' dw: ' + this._dw.toFixed(1) + ' dh: ' + this._dh.toFixed(1), x, y + 28); - //DebugUtils.game.stage.context.fillText('sx: ' + this._sx.toFixed(1) + ' sy: ' + this._sy.toFixed(1) + ' sw: ' + this._sw.toFixed(1) + ' sh: ' + this._sh.toFixed(1), x, y + 42); - }; + DebugUtils.game.stage.context.fillText('wx: ' + sprite.worldView.x + ' wy: ' + sprite.worldView.y + ' ww: ' + sprite.worldView.width.toFixed(1) + ' wh: ' + sprite.worldView.height.toFixed(1) + ' wb: ' + sprite.worldView.bottom + ' wr: ' + sprite.worldView.right, x, y + 28); + DebugUtils.game.stage.context.fillText('sx: ' + sprite.transform.scale.x.toFixed(1) + ' sy: ' + sprite.transform.scale.y.toFixed(1), x, y + 42); + DebugUtils.game.stage.context.fillText('tx: ' + sprite.texture.width.toFixed(1) + ' ty: ' + sprite.texture.height.toFixed(1), x, y + 56); + DebugUtils.game.stage.context.fillText('inCamera: ' + DebugUtils.game.renderer.inCamera(DebugUtils.game.camera, sprite), x, y + 70); + }; + DebugUtils.renderSpriteBounds = function renderSpriteBounds(sprite, camera, color) { + if (typeof camera === "undefined") { camera = null; } + if (typeof color === "undefined") { color = 'rgba(0,255,0,0.2)'; } + if(camera == null) { + camera = DebugUtils.game.camera; + } + //var dx = (camera.screenView.x * sprite.transform.scrollFactor.x) + sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + //var dy = (camera.screenView.y * sprite.transform.scrollFactor.y) + sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + var dx = sprite.worldView.x; + var dy = sprite.worldView.y; + DebugUtils.game.stage.context.fillStyle = color; + DebugUtils.game.stage.context.fillRect(dx, dy, sprite.width, sprite.height); + }; + DebugUtils.renderSpritePhysicsBody = function renderSpritePhysicsBody(sprite, camera, color) { + if (typeof camera === "undefined") { camera = null; } + if (typeof color === "undefined") { color = 'rgba(255,0,0,0.2)'; } + if(camera == null) { + camera = DebugUtils.game.camera; + } + var dx = (camera.screenView.x * sprite.transform.scrollFactor.x) + sprite.body.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + var dy = (camera.screenView.y * sprite.transform.scrollFactor.y) + sprite.body.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + DebugUtils.game.stage.context.fillStyle = color; + DebugUtils.game.stage.context.fillRect(dx, dy, sprite.body.width, sprite.body.height); + }; return DebugUtils; })(); Phaser.DebugUtils = DebugUtils; @@ -16651,6 +16749,7 @@ var Phaser; if(this._loadComplete && this.onUpdateCallback) { this.onUpdateCallback.call(this.callbackContext); } + this.world.postUpdate(); this.renderer.render(); if(this._loadComplete && this.onRenderCallback) { this.onRenderCallback.call(this.callbackContext); From 3b9386727e641c648b09632672ea2719f05bed7d Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 7 Jun 2013 16:27:33 +0100 Subject: [PATCH 3/8] Small refactoring and massively optimised the canvas renderer, also added new Mat3 class. --- Phaser/Game.ts | 8 +- Phaser/Phaser.csproj | 52 ++- Phaser/World.ts | 2 +- Phaser/cameras/Camera.ts | 6 +- Phaser/components/ScrollRegion.ts | 4 +- Phaser/components/Transform.ts | 90 +++- Phaser/core/Polygon.ts | 54 --- Phaser/gameobjects/ScrollZone.ts | 2 +- Phaser/gameobjects/Sprite.ts | 17 +- Phaser/{core => geom}/Circle.ts | 0 Phaser/{core => geom}/Line.ts | 0 Phaser/{core => geom}/Point.ts | 0 Phaser/{core => geom}/Rectangle.ts | 0 Phaser/input/Pointer.ts | 2 +- Phaser/math/GameMath.ts | 15 + Phaser/math/Mat3.ts | 275 +++++++++++ Phaser/math/Mat3Utils.ts | 189 ++++++++ Phaser/math/QuadTree.ts | 2 +- Phaser/{core => math}/Vec2.ts | 2 +- Phaser/math/Vec2Utils.ts | 2 +- Phaser/physics/Body.ts | 4 +- Phaser/renderers/CanvasRenderer.ts | 61 +-- Phaser/utils/CircleUtils.ts | 6 +- Phaser/utils/ColorUtils.ts | 6 +- Phaser/utils/DebugUtils.ts | 6 +- Phaser/utils/PixelUtils.ts | 6 +- Phaser/utils/PointUtils.ts | 2 +- Phaser/utils/RectangleUtils.ts | 4 +- Phaser/utils/SpriteUtils.ts | 6 +- Tests/Tests.csproj | 4 + Tests/phaser.js | 712 +++++++++++++++++++++++------ Tests/sprites/origin 5.js | 67 +++ Tests/sprites/origin 5.ts | 106 +++++ build/phaser.d.ts | 193 ++++++-- build/phaser.js | 712 +++++++++++++++++++++++------ 35 files changed, 2141 insertions(+), 476 deletions(-) delete mode 100644 Phaser/core/Polygon.ts rename Phaser/{core => geom}/Circle.ts (100%) rename Phaser/{core => geom}/Line.ts (100%) rename Phaser/{core => geom}/Point.ts (100%) rename Phaser/{core => geom}/Rectangle.ts (100%) create mode 100644 Phaser/math/Mat3.ts create mode 100644 Phaser/math/Mat3Utils.ts rename Phaser/{core => math}/Vec2.ts (98%) create mode 100644 Tests/sprites/origin 5.js create mode 100644 Tests/sprites/origin 5.ts diff --git a/Phaser/Game.ts b/Phaser/Game.ts index 7df89909..49e96bc9 100644 --- a/Phaser/Game.ts +++ b/Phaser/Game.ts @@ -1,9 +1,9 @@ -/// +/// /// /// -/// -/// -/// +/// +/// +/// /// /// /// diff --git a/Phaser/Phaser.csproj b/Phaser/Phaser.csproj index 8028b489..f699e104 100644 --- a/Phaser/Phaser.csproj +++ b/Phaser/Phaser.csproj @@ -87,27 +87,11 @@ Game.ts - - CameraFX.ts - - Point.ts - - - - Polygon.ts - - - Rectangle.ts - - - - Vec2.ts - DynamicTexture.ts @@ -126,6 +110,22 @@ Tilemap.ts + + + Circle.ts + + + + Line.ts + + + + Point.ts + + + + Rectangle.ts + GameMath.ts @@ -144,6 +144,14 @@ + + + Mat3.ts + + + + Mat3Utils.ts + QuadTree.ts @@ -152,6 +160,10 @@ LinkedList.ts + + + Vec2.ts + Motion.ts @@ -200,15 +212,9 @@ RectangleUtils.ts - - Circle.ts - IntersectResult.ts - - Line.ts - Vec2Utils.ts @@ -341,9 +347,7 @@ - - Group.ts diff --git a/Phaser/World.ts b/Phaser/World.ts index 0b1aabbf..6309e499 100644 --- a/Phaser/World.ts +++ b/Phaser/World.ts @@ -1,7 +1,7 @@ /// /// /// -/// +/// /// /** diff --git a/Phaser/cameras/Camera.ts b/Phaser/cameras/Camera.ts index b8badc77..0d873f81 100644 --- a/Phaser/cameras/Camera.ts +++ b/Phaser/cameras/Camera.ts @@ -1,7 +1,7 @@ /// -/// -/// -/// +/// +/// +/// /// /// /// diff --git a/Phaser/components/ScrollRegion.ts b/Phaser/components/ScrollRegion.ts index aa75d28d..e8369dd7 100644 --- a/Phaser/components/ScrollRegion.ts +++ b/Phaser/components/ScrollRegion.ts @@ -1,6 +1,6 @@ /// -/// -/// +/// +/// /** * Phaser - ScrollRegion diff --git a/Phaser/components/Transform.ts b/Phaser/components/Transform.ts index 70dd8f84..e56d1f0d 100644 --- a/Phaser/components/Transform.ts +++ b/Phaser/components/Transform.ts @@ -1,4 +1,5 @@ /// +/// /** * Phaser - Components - Transform @@ -17,6 +18,8 @@ module Phaser.Components { this.game = parent.game; this.parent = parent; + this.local = new Mat3; + this.scrollFactor = new Phaser.Vec2(1, 1); this.origin = new Phaser.Vec2; this.scale = new Phaser.Vec2(1, 1); @@ -24,6 +27,77 @@ module Phaser.Components { } + public local: Mat3; + + private _sin: number; + private _cos: number; + + public update() { + + // 0 a = scale x + // 3 b = skew x + // 1 c = skew y + // 4 d = scale y + // 2 e = translate x + // 5 f = translate y + + // Scale & Skew + + // if (sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.transform.rotationOffset !== 0)) + + this._sin = 0; + this._cos = 1; + + if (this.parent.texture.renderRotation) + { + this._sin = GameMath.sinA[this.rotation + this.rotationOffset]; + this._cos = GameMath.cosA[this.rotation + this.rotationOffset]; + } + + if (this.parent.texture.flippedX) + { + //this.local.data[0] = GameMath.cosA[this.rotation + this.rotationOffset] * -this.scale.x; + //this.local.data[3] = (GameMath.sinA[this.rotation + this.rotationOffset] * -this.scale.x) + this.skew.x; + this.local.data[0] = this._cos * -this.scale.x; + this.local.data[3] = (this._sin * -this.scale.x) + this.skew.x; + } + else + { + //this.local.data[0] = GameMath.cosA[this.rotation + this.rotationOffset] * this.scale.x; + //this.local.data[3] = (GameMath.sinA[this.rotation + this.rotationOffset] * this.scale.x) + this.skew.x; + this.local.data[0] = this._cos * this.scale.x; + this.local.data[3] = (this._sin * this.scale.x) + this.skew.x; + } + + if (this.parent.texture.flippedY) + { + //this.local.data[4] = GameMath.cosA[this.rotation + this.rotationOffset] * -this.scale.y; + //this.local.data[1] = -(GameMath.sinA[this.rotation + this.rotationOffset] * -this.scale.y) + this.skew.y; + this.local.data[4] = this._cos * -this.scale.y; + this.local.data[1] = -(this._sin * -this.scale.y) + this.skew.y; + } + else + { + //this.local.data[4] = GameMath.cosA[this.rotation + this.rotationOffset] * this.scale.y; + //this.local.data[1] = -(GameMath.sinA[this.rotation + this.rotationOffset] * this.scale.y) + this.skew.y; + this.local.data[4] = this._cos * this.scale.y; + this.local.data[1] = -(this._sin * this.scale.y) + this.skew.y; + } + + // Translate + this.local.data[2] = this.parent.x; + this.local.data[5] = this.parent.y; + + } + + public get calculatedX(): number { + return this.origin.x * this.scale.x; + } + + public get calculatedY(): number { + return this.origin.y * this.scale.y; + } + /** * Reference to Phaser.Game */ @@ -50,7 +124,7 @@ module Phaser.Components { public scrollFactor: Phaser.Vec2; /** - * The origin is the point around which scale and rotation takes place. + * The origin is the point around which scale and rotation takes place and defaults to the center of the sprite. */ public origin: Phaser.Vec2; @@ -67,6 +141,20 @@ module Phaser.Components { */ public rotation: number = 0; + /** + * The center of the Sprite after taking scaling into consideration + */ + public get centerX(): number { + return this.parent.width / 2; + } + + /** + * The center of the Sprite after taking scaling into consideration + */ + public get centerY(): number { + return this.parent.height / 2; + } + } } \ No newline at end of file diff --git a/Phaser/core/Polygon.ts b/Phaser/core/Polygon.ts deleted file mode 100644 index d1e851c4..00000000 --- a/Phaser/core/Polygon.ts +++ /dev/null @@ -1,54 +0,0 @@ -/// - -/** -* Phaser - Polygon -* -* -*/ - -module Phaser { - - export class Polygon { - - /** - * - **/ - constructor(game: Game, points: Point[]) { - - this.game = game; - this.context = game.stage.context; - - this.points = []; - - for (var i = 0; i < points.length; i++) - { - this.points.push(new Point().copyFrom(points[i])); - } - - } - - public points: Point[]; - public game: Game; - public context: CanvasRenderingContext2D; - - public render() { - - this.context.beginPath(); - this.context.strokeStyle = 'rgb(255,255,0)'; - this.context.moveTo(this.points[0].x, this.points[0].y); - - for (var i = 1; i < this.points.length; i++) - { - this.context.lineTo(this.points[i].x, this.points[i].y); - } - - this.context.lineTo(this.points[0].x, this.points[0].y); - - this.context.stroke(); - this.context.closePath(); - - } - - } - -} \ No newline at end of file diff --git a/Phaser/gameobjects/ScrollZone.ts b/Phaser/gameobjects/ScrollZone.ts index 2044a00d..aac49c72 100644 --- a/Phaser/gameobjects/ScrollZone.ts +++ b/Phaser/gameobjects/ScrollZone.ts @@ -1,5 +1,5 @@ /// -/// +/// /// /** diff --git a/Phaser/gameobjects/Sprite.ts b/Phaser/gameobjects/Sprite.ts index 001d59b1..3bf3d28e 100644 --- a/Phaser/gameobjects/Sprite.ts +++ b/Phaser/gameobjects/Sprite.ts @@ -1,6 +1,6 @@ /// -/// -/// +/// +/// /// /// /// @@ -40,11 +40,12 @@ module Phaser { this.z = -1; this.group = null; - this.transform = new Phaser.Components.Transform(this); + // No dependencies this.animations = new Phaser.Components.AnimationManager(this); - this.texture = new Phaser.Components.Texture(this); this.input = new Phaser.Components.Sprite.Input(this); this.events = new Phaser.Components.Sprite.Events(this); + this.texture = new Phaser.Components.Texture(this); + this.transform = new Phaser.Components.Transform(this); if (key !== null) { @@ -233,10 +234,14 @@ module Phaser { */ public preUpdate() { + this.transform.update(); + //this.worldView.x = this.x * this.transform.scrollFactor.x; //this.worldView.y = this.y * this.transform.scrollFactor.y; - this.worldView.x = this.x - this.transform.origin.x; - this.worldView.y = this.y - this.transform.origin.y; + this.worldView.x = this.x; + this.worldView.y = this.y; + //this.worldView.x = this.x - this.transform.origin.x; + //this.worldView.y = this.y - this.transform.origin.y; this.worldView.width = this.width; this.worldView.height = this.height; diff --git a/Phaser/core/Circle.ts b/Phaser/geom/Circle.ts similarity index 100% rename from Phaser/core/Circle.ts rename to Phaser/geom/Circle.ts diff --git a/Phaser/core/Line.ts b/Phaser/geom/Line.ts similarity index 100% rename from Phaser/core/Line.ts rename to Phaser/geom/Line.ts diff --git a/Phaser/core/Point.ts b/Phaser/geom/Point.ts similarity index 100% rename from Phaser/core/Point.ts rename to Phaser/geom/Point.ts diff --git a/Phaser/core/Rectangle.ts b/Phaser/geom/Rectangle.ts similarity index 100% rename from Phaser/core/Rectangle.ts rename to Phaser/geom/Rectangle.ts diff --git a/Phaser/input/Pointer.ts b/Phaser/input/Pointer.ts index e9afa9b3..7b89d213 100644 --- a/Phaser/input/Pointer.ts +++ b/Phaser/input/Pointer.ts @@ -1,5 +1,5 @@ /// -/// +/// /** * Phaser - Pointer diff --git a/Phaser/math/GameMath.ts b/Phaser/math/GameMath.ts index 0c071772..c9afa8f4 100644 --- a/Phaser/math/GameMath.ts +++ b/Phaser/math/GameMath.ts @@ -12,11 +12,26 @@ module Phaser { export class GameMath { constructor(game: Game) { + this.game = game; + + GameMath.sinA = []; + GameMath.cosA = []; + + for (var i = 0; i < 360; i++) + { + GameMath.sinA.push(Math.sin(this.degreesToRadians(i))); + GameMath.cosA.push(Math.cos(this.degreesToRadians(i))); + } } public game: Game; + // Pre-calculated tables containing Math.sin(angle) and Math.cos(angle) from -180 to 180 + // So sinA[sprite.rotation] would be the same as Math.sin(sprite.rotation) without a call to Math.sin + static sinA: number[]; + static cosA: number[]; + static PI: number = 3.141592653589793; //number pi static PI_2: number = 1.5707963267948965; //PI / 2 OR 90 deg static PI_4: number = 0.7853981633974483; //PI / 4 OR 45 deg diff --git a/Phaser/math/Mat3.ts b/Phaser/math/Mat3.ts new file mode 100644 index 00000000..9b37f7f2 --- /dev/null +++ b/Phaser/math/Mat3.ts @@ -0,0 +1,275 @@ +/// + +/** +* Phaser - Mat3 +* +* A 3x3 Matrix +*/ + +module Phaser { + + export class Mat3 { + + /** + * Creates a new Mat3 object. + * @class Mat3 + * @constructor + * @return {Mat3} This object + **/ + constructor() { + this.data = [1, 0, 0, 0, 1, 0, 0, 0, 1]; + } + + // Temporary vars used for internal calculations + private _a00: number; + private _a01: number; + private _a02: number; + private _a10: number; + private _a11: number; + private _a12: number; + private _a20: number; + private _a21: number; + private _a22: number; + + public data: number[]; + + public get a00(): number { + return this.data[0]; + } + + public set a00(value: number) { + this.data[0] = value; + } + + public get a01(): number { + return this.data[1]; + } + + public set a01(value: number) { + this.data[1] = value; + } + + public get a02(): number { + return this.data[2]; + } + + public set a02(value: number) { + this.data[2] = value; + } + + public get a10(): number { + return this.data[3]; + } + + public set a10(value: number) { + this.data[3] = value; + } + + public get a11(): number { + return this.data[4]; + } + + public set a11(value: number) { + this.data[4] = value; + } + + public get a12(): number { + return this.data[5]; + } + + public set a12(value: number) { + this.data[5] = value; + } + + public get a20(): number { + return this.data[6]; + } + + public set a20(value: number) { + this.data[6] = value; + } + + public get a21(): number { + return this.data[7]; + } + + public set a21(value: number) { + this.data[7] = value; + } + + public get a22(): number { + return this.data[8]; + } + + public set a22(value: number) { + this.data[8] = value; + } + + /** + * Copies the values from one Mat3 into this Mat3. + * @method copyFromMat3 + * @param {any} source - The object to copy from. + * @return {Mat3} This Mat3 object. + **/ + public copyFromMat3(source: Mat3): Mat3 { + + this.data[0] = source.data[0]; + this.data[1] = source.data[1]; + this.data[2] = source.data[2]; + this.data[3] = source.data[3]; + this.data[4] = source.data[4]; + this.data[5] = source.data[5]; + this.data[6] = source.data[6]; + this.data[7] = source.data[7]; + this.data[8] = source.data[8]; + + return this; + } + + /** + * Copies the upper-left 3x3 values into this Mat3. + * @method copyFromMat4 + * @param {any} source - The object to copy from. + * @return {Mat3} This Mat3 object. + **/ + public copyFromMat4(source: any): Mat3 { + + this.data[0] = source[0]; + this.data[1] = source[1]; + this.data[2] = source[2]; + this.data[3] = source[4]; + this.data[4] = source[5]; + this.data[5] = source[6]; + this.data[6] = source[8]; + this.data[7] = source[9]; + this.data[8] = source[10]; + + return this; + } + + /** + * Clones this Mat3 into a new Mat3 + * @param {Mat3} out The output Mat3, if none is given a new Mat3 object will be created. + * @return {Mat3} The new Mat3 + **/ + public clone(out?:Mat3 = new Phaser.Mat3): Mat3 { + + out[0] = this.data[0]; + out[1] = this.data[1]; + out[2] = this.data[2]; + out[3] = this.data[3]; + out[4] = this.data[4]; + out[5] = this.data[5]; + out[6] = this.data[6]; + out[7] = this.data[7]; + out[8] = this.data[8]; + + return out; + + } + + /** + * Sets this Mat3 to the identity matrix. + * @method identity + * @param {any} source - The object to copy from. + * @return {Mat3} This Mat3 object. + **/ + public identity(): Mat3 { + return this.setTo(1, 0, 0, 0, 1, 0, 0, 0, 1); + } + + /** + * Translates this Mat3 by the given vector + **/ + public translate(v:Phaser.Vec2): Mat3 { + + this.a20 = v.x * this.a00 + v.y * this.a10 + this.a20; + this.a21 = v.x * this.a01 + v.y * this.a11 + this.a21; + this.a22 = v.x * this.a02 + v.y * this.a12 + this.a22; + + return this; + + } + + private setTemps() { + + this._a00 = this.data[0]; + this._a01 = this.data[1]; + this._a02 = this.data[2]; + this._a10 = this.data[3]; + this._a11 = this.data[4]; + this._a12 = this.data[5]; + this._a20 = this.data[6]; + this._a21 = this.data[7]; + this._a22 = this.data[8]; + + } + + /** + * Rotates this Mat3 by the given angle (given in radians) + **/ + public rotate(rad:number): Mat3 { + + this.setTemps(); + + var s = GameMath.sinA[rad]; + var c = GameMath.cosA[rad]; + + this.data[0] = c * this._a00 + s * this._a10; + this.data[1] = c * this._a01 + s * this._a10; + this.data[2] = c * this._a02 + s * this._a12; + + this.data[3] = c * this._a10 - s * this._a00; + this.data[4] = c * this._a11 - s * this._a01; + this.data[5] = c * this._a12 - s * this._a02; + + return this; + + } + + /** + * Scales this Mat3 by the given vector + **/ + public scale(v: Vec2): Mat3 { + + this.data[0] = v.x * this.data[0]; + this.data[1] = v.x * this.data[1]; + this.data[2] = v.x * this.data[2]; + + this.data[3] = v.y * this.data[3]; + this.data[4] = v.y * this.data[4]; + this.data[5] = v.y * this.data[5]; + + return this; + + } + + public setTo(a00: number, a01: number, a02: number, a10: number, a11: number, a12: number, a20: number, a21: number, a22: number): Mat3 { + + this.data[0] = a00; + this.data[1] = a01; + this.data[2] = a02; + this.data[3] = a10; + this.data[4] = a11; + this.data[5] = a12; + this.data[6] = a20; + this.data[7] = a21; + this.data[8] = a22; + + return this; + + } + + /** + * Returns a string representation of this object. + * @method toString + * @return {string} a string representation of the object. + **/ + public toString(): string { + return ''; + //return "[{Vec2 (x=" + this.x + " y=" + this.y + ")}]"; + } + + } + +} \ No newline at end of file diff --git a/Phaser/math/Mat3Utils.ts b/Phaser/math/Mat3Utils.ts new file mode 100644 index 00000000..3808a5d2 --- /dev/null +++ b/Phaser/math/Mat3Utils.ts @@ -0,0 +1,189 @@ +/// +/// +/// + +/** +* Phaser - Mat3Utils +* +* A collection of methods useful for manipulating and performing operations on Mat3 objects. +* +*/ + +module Phaser { + + export class Mat3Utils { + + /** + * Transpose the values of a Mat3 + **/ + static transpose(source:Phaser.Mat3, dest?:Phaser.Mat3 = null): Mat3 { + + if (dest === null) + { + // Transpose ourselves + var a01 = source.data[1]; + var a02 = source.data[2]; + var a12 = source.data[5]; + + source.data[1] = source.data[3]; + source.data[2] = source.data[6]; + source.data[3] = a01; + source.data[5] = source.data[7]; + source.data[6] = a02; + source.data[7] = a12; + } + else + { + source.data[0] = dest.data[0]; + source.data[1] = dest.data[3]; + source.data[2] = dest.data[6]; + source.data[3] = dest.data[1]; + source.data[4] = dest.data[4]; + source.data[5] = dest.data[7]; + source.data[6] = dest.data[2]; + source.data[7] = dest.data[5]; + source.data[8] = dest.data[8]; + } + + return source; + + } + + /** + * Inverts a Mat3 + **/ + static invert(source:Phaser.Mat3): Mat3 { + + var a00 = source.data[0]; + var a01 = source.data[1]; + var a02 = source.data[2]; + var a10 = source.data[3]; + var a11 = source.data[4]; + var a12 = source.data[5]; + var a20 = source.data[6]; + var a21 = source.data[7]; + var a22 = source.data[8]; + + var b01 = a22 * a11 - a12 * a21; + var b11 = -a22 * a10 + a12 * a20; + var b21 = a21 * a10 - a11 * a20; + + // Determinant + var det = a00 * b01 + a01 * b11 + a02 * b21; + + if (!det) { + return null; + } + + det = 1.0 / det; + + source.data[0] = b01 * det; + source.data[1] = (-a22 * a01 + a02 * a21) * det; + source.data[2] = (a12 * a01 - a02 * a11) * det; + source.data[3] = b11 * det; + source.data[4] = (a22 * a00 - a02 * a20) * det; + source.data[5] = (-a12 * a00 + a02 * a10) * det; + source.data[6] = b21 * det; + source.data[7] = (-a21 * a00 + a01 * a20) * det; + source.data[8] = (a11 * a00 - a01 * a10) * det; + + return source; + + } + + /** + * Calculates the adjugate of a Mat3 + **/ + static adjoint(source:Phaser.Mat3): Mat3 { + + var a00 = source.data[0]; + var a01 = source.data[1]; + var a02 = source.data[2]; + var a10 = source.data[3]; + var a11 = source.data[4]; + var a12 = source.data[5]; + var a20 = source.data[6]; + var a21 = source.data[7]; + var a22 = source.data[8]; + + source.data[0] = (a11 * a22 - a12 * a21); + source.data[1] = (a02 * a21 - a01 * a22); + source.data[2] = (a01 * a12 - a02 * a11); + source.data[3] = (a12 * a20 - a10 * a22); + source.data[4] = (a00 * a22 - a02 * a20); + source.data[5] = (a02 * a10 - a00 * a12); + source.data[6] = (a10 * a21 - a11 * a20); + source.data[7] = (a01 * a20 - a00 * a21); + source.data[8] = (a00 * a11 - a01 * a10); + + return source; + + } + + /** + * Calculates the adjugate of a Mat3 + **/ + static determinant(source:Phaser.Mat3): number { + + var a00 = source.data[0]; + var a01 = source.data[1]; + var a02 = source.data[2]; + var a10 = source.data[3]; + var a11 = source.data[4]; + var a12 = source.data[5]; + var a20 = source.data[6]; + var a21 = source.data[7]; + var a22 = source.data[8]; + + return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); + + } + + /** + * Multiplies two Mat3s + **/ + static multiply(source:Phaser.Mat3, b:Phaser.Mat3): Mat3 { + + var a00 = source.data[0]; + var a01 = source.data[1]; + var a02 = source.data[2]; + var a10 = source.data[3]; + var a11 = source.data[4]; + var a12 = source.data[5]; + var a20 = source.data[6]; + var a21 = source.data[7]; + var a22 = source.data[8]; + + var b00 = b.data[0]; + var b01 = b.data[1]; + var b02 = b.data[2]; + var b10 = b.data[3]; + var b11 = b.data[4]; + var b12 = b.data[5]; + var b20 = b.data[6]; + var b21 = b.data[7]; + var b22 = b.data[8]; + + source.data[0] = b00 * a00 + b01 * a10 + b02 * a20; + source.data[1] = b00 * a01 + b01 * a11 + b02 * a21; + source.data[2] = b00 * a02 + b01 * a12 + b02 * a22; + + source.data[3] = b10 * a00 + b11 * a10 + b12 * a20; + source.data[4] = b10 * a01 + b11 * a11 + b12 * a21; + source.data[5] = b10 * a02 + b11 * a12 + b12 * a22; + + source.data[6] = b20 * a00 + b21 * a10 + b22 * a20; + source.data[7] = b20 * a01 + b21 * a11 + b22 * a21; + source.data[8] = b20 * a02 + b21 * a12 + b22 * a22; + + return source; + + } + + static fromQuaternion() { } + static normalFromMat4() { } + + + } + +} \ No newline at end of file diff --git a/Phaser/math/QuadTree.ts b/Phaser/math/QuadTree.ts index 1675a98c..738ab331 100644 --- a/Phaser/math/QuadTree.ts +++ b/Phaser/math/QuadTree.ts @@ -1,5 +1,5 @@ /// -/// +/// /// /** diff --git a/Phaser/core/Vec2.ts b/Phaser/math/Vec2.ts similarity index 98% rename from Phaser/core/Vec2.ts rename to Phaser/math/Vec2.ts index e3118c35..637c78b6 100644 --- a/Phaser/core/Vec2.ts +++ b/Phaser/math/Vec2.ts @@ -3,7 +3,7 @@ /** * Phaser - Vec2 * -* A Circle object is an area defined by its position, as indicated by its center point (x,y) and diameter. +* A Vector 2 */ module Phaser { diff --git a/Phaser/math/Vec2Utils.ts b/Phaser/math/Vec2Utils.ts index b0f4f14a..3c093fca 100644 --- a/Phaser/math/Vec2Utils.ts +++ b/Phaser/math/Vec2Utils.ts @@ -1,5 +1,5 @@ /// -/// +/// /** * Phaser - Vec2Utils diff --git a/Phaser/physics/Body.ts b/Phaser/physics/Body.ts index aaa547b1..a4b7a9f8 100644 --- a/Phaser/physics/Body.ts +++ b/Phaser/physics/Body.ts @@ -1,5 +1,5 @@ -/// -/// +/// +/// /// /** diff --git a/Phaser/renderers/CanvasRenderer.ts b/Phaser/renderers/CanvasRenderer.ts index cd5777d1..13d635bc 100644 --- a/Phaser/renderers/CanvasRenderer.ts +++ b/Phaser/renderers/CanvasRenderer.ts @@ -443,11 +443,10 @@ module Phaser { if (sprite.transform.scale.x == 0 || sprite.transform.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { - return false; + //return false; } sprite.renderOrderID = this._count; - this._count++; // Reset our temp vars @@ -456,12 +455,8 @@ module Phaser { this._sy = 0; this._sw = sprite.texture.width; this._sh = sprite.texture.height; - this._fx = sprite.transform.scale.x; - this._fy = sprite.transform.scale.y; - this._sin = 0; - this._cos = 1; - this._dx = (camera.screenView.x * sprite.transform.scrollFactor.x) + sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); - this._dy = (camera.screenView.y * sprite.transform.scrollFactor.y) + sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + this._dx = camera.screenView.x + sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + this._dy = camera.screenView.y + sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); this._dw = sprite.texture.width; this._dh = sprite.texture.height; @@ -479,18 +474,6 @@ module Phaser { sprite.texture.context.globalAlpha = sprite.texture.alpha; } - // Sprite Flip X - if (sprite.texture.flippedX) - { - this._fx = -sprite.transform.scale.x; - } - - // Sprite Flip Y - if (sprite.texture.flippedY) - { - this._fy = -sprite.transform.scale.y; - } - if (sprite.animations.currentFrame !== null) { this._sx = sprite.animations.currentFrame.x; @@ -507,36 +490,26 @@ module Phaser { } } - // Rotation and Flipped if (sprite.modified) { - if (sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.transform.rotationOffset !== 0)) - { - this._sin = Math.sin(sprite.game.math.degreesToRadians(sprite.transform.rotationOffset + sprite.rotation)); - this._cos = Math.cos(sprite.game.math.degreesToRadians(sprite.transform.rotationOffset + sprite.rotation)); - } - - // setTransform(a, b, c, d, e, f); - // a = scale x - // b = skew x - // c = skew y - // d = scale y - // e = translate x - // f = translate y - sprite.texture.context.save(); - sprite.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + sprite.transform.skew.x, -(this._sin * this._fy) + sprite.transform.skew.y, this._cos * this._fy, this._dx, this._dy); - this._dx = -sprite.transform.origin.x; - this._dy = -sprite.transform.origin.y; + sprite.texture.context.setTransform( + sprite.transform.local.data[0], // scale x + sprite.transform.local.data[3], // skew x + sprite.transform.local.data[1], // skew y + sprite.transform.local.data[4], // scale y + this._dx, // translate x + this._dy // translate y + ); + + this._dx = sprite.transform.origin.x * -this._dw; + this._dy = sprite.transform.origin.y * -this._dh; } else { - if (!sprite.transform.origin.equals(0)) - { - this._dx -= sprite.transform.origin.x; - this._dy -= sprite.transform.origin.y; - } + this._dx -= (this._dw * sprite.transform.origin.x); + this._dy -= (this._dh * sprite.transform.origin.y); } this._sx = Math.round(this._sx); @@ -568,7 +541,7 @@ module Phaser { this._dh // Destination Height (always same as Source Height unless scaled) ); } - + if (sprite.modified || sprite.texture.globalCompositeOperation) { sprite.texture.context.restore(); diff --git a/Phaser/utils/CircleUtils.ts b/Phaser/utils/CircleUtils.ts index 51fa2005..35c26673 100644 --- a/Phaser/utils/CircleUtils.ts +++ b/Phaser/utils/CircleUtils.ts @@ -1,7 +1,7 @@ /// -/// -/// -/// +/// +/// +/// /** * Phaser - CircleUtils diff --git a/Phaser/utils/ColorUtils.ts b/Phaser/utils/ColorUtils.ts index 426bff91..9f26ca8e 100644 --- a/Phaser/utils/ColorUtils.ts +++ b/Phaser/utils/ColorUtils.ts @@ -1,7 +1,7 @@ /// -/// -/// -/// +/// +/// +/// /** * Phaser - ColorUtils diff --git a/Phaser/utils/DebugUtils.ts b/Phaser/utils/DebugUtils.ts index d27b0cb6..e1bf9039 100644 --- a/Phaser/utils/DebugUtils.ts +++ b/Phaser/utils/DebugUtils.ts @@ -1,7 +1,7 @@ /// -/// -/// -/// +/// +/// +/// /// /// diff --git a/Phaser/utils/PixelUtils.ts b/Phaser/utils/PixelUtils.ts index 21ec835f..dfd1f8d3 100644 --- a/Phaser/utils/PixelUtils.ts +++ b/Phaser/utils/PixelUtils.ts @@ -1,7 +1,7 @@ /// -/// -/// -/// +/// +/// +/// /** * Phaser - PixelUtils diff --git a/Phaser/utils/PointUtils.ts b/Phaser/utils/PointUtils.ts index f15cea4d..1431f215 100644 --- a/Phaser/utils/PointUtils.ts +++ b/Phaser/utils/PointUtils.ts @@ -1,5 +1,5 @@ /// -/// +/// /** * Phaser - PointUtils diff --git a/Phaser/utils/RectangleUtils.ts b/Phaser/utils/RectangleUtils.ts index 7882f27b..180af7a3 100644 --- a/Phaser/utils/RectangleUtils.ts +++ b/Phaser/utils/RectangleUtils.ts @@ -1,6 +1,6 @@ /// -/// -/// +/// +/// /** * Phaser - RectangleUtils diff --git a/Phaser/utils/SpriteUtils.ts b/Phaser/utils/SpriteUtils.ts index f3bd461d..7d8519bc 100644 --- a/Phaser/utils/SpriteUtils.ts +++ b/Phaser/utils/SpriteUtils.ts @@ -1,7 +1,7 @@ /// -/// -/// -/// +/// +/// +/// /// /// diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 0c682e29..e26a5666 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -193,6 +193,10 @@ atlas 2.ts + + + origin 5.ts + tween loop 1.ts diff --git a/Tests/phaser.js b/Tests/phaser.js index a07d9581..79107e15 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -384,7 +384,7 @@ var __extends = this.__extends || function (d, b) { d.prototype = new __(); }; /// -/// +/// /// /** * Phaser - QuadTree @@ -734,7 +734,7 @@ var Phaser; /** * Phaser - Vec2 * -* A Circle object is an area defined by its position, as indicated by its center point (x,y) and diameter. +* A Vector 2 */ var Phaser; (function (Phaser) { @@ -1264,8 +1264,8 @@ var Phaser; Phaser.Types = Types; })(Phaser || (Phaser = {})); /// -/// -/// +/// +/// /** * Phaser - RectangleUtils * @@ -1455,9 +1455,9 @@ var Phaser; Phaser.RectangleUtils = RectangleUtils; })(Phaser || (Phaser = {})); /// -/// -/// -/// +/// +/// +/// /** * Phaser - ColorUtils * @@ -2797,9 +2797,263 @@ var Phaser; })(Phaser.Components || (Phaser.Components = {})); var Components = Phaser.Components; })(Phaser || (Phaser = {})); +/// +/** +* Phaser - Mat3 +* +* A 3x3 Matrix +*/ +var Phaser; +(function (Phaser) { + var Mat3 = (function () { + /** + * Creates a new Mat3 object. + * @class Mat3 + * @constructor + * @return {Mat3} This object + **/ + function Mat3() { + this.data = [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1 + ]; + } + Object.defineProperty(Mat3.prototype, "a00", { + get: function () { + return this.data[0]; + }, + set: function (value) { + this.data[0] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a01", { + get: function () { + return this.data[1]; + }, + set: function (value) { + this.data[1] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a02", { + get: function () { + return this.data[2]; + }, + set: function (value) { + this.data[2] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a10", { + get: function () { + return this.data[3]; + }, + set: function (value) { + this.data[3] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a11", { + get: function () { + return this.data[4]; + }, + set: function (value) { + this.data[4] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a12", { + get: function () { + return this.data[5]; + }, + set: function (value) { + this.data[5] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a20", { + get: function () { + return this.data[6]; + }, + set: function (value) { + this.data[6] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a21", { + get: function () { + return this.data[7]; + }, + set: function (value) { + this.data[7] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a22", { + get: function () { + return this.data[8]; + }, + set: function (value) { + this.data[8] = value; + }, + enumerable: true, + configurable: true + }); + Mat3.prototype.copyFromMat3 = /** + * Copies the values from one Mat3 into this Mat3. + * @method copyFromMat3 + * @param {any} source - The object to copy from. + * @return {Mat3} This Mat3 object. + **/ + function (source) { + this.data[0] = source.data[0]; + this.data[1] = source.data[1]; + this.data[2] = source.data[2]; + this.data[3] = source.data[3]; + this.data[4] = source.data[4]; + this.data[5] = source.data[5]; + this.data[6] = source.data[6]; + this.data[7] = source.data[7]; + this.data[8] = source.data[8]; + return this; + }; + Mat3.prototype.copyFromMat4 = /** + * Copies the upper-left 3x3 values into this Mat3. + * @method copyFromMat4 + * @param {any} source - The object to copy from. + * @return {Mat3} This Mat3 object. + **/ + function (source) { + this.data[0] = source[0]; + this.data[1] = source[1]; + this.data[2] = source[2]; + this.data[3] = source[4]; + this.data[4] = source[5]; + this.data[5] = source[6]; + this.data[6] = source[8]; + this.data[7] = source[9]; + this.data[8] = source[10]; + return this; + }; + Mat3.prototype.clone = /** + * Clones this Mat3 into a new Mat3 + * @param {Mat3} out The output Mat3, if none is given a new Mat3 object will be created. + * @return {Mat3} The new Mat3 + **/ + function (out) { + if (typeof out === "undefined") { out = new Phaser.Mat3(); } + out[0] = this.data[0]; + out[1] = this.data[1]; + out[2] = this.data[2]; + out[3] = this.data[3]; + out[4] = this.data[4]; + out[5] = this.data[5]; + out[6] = this.data[6]; + out[7] = this.data[7]; + out[8] = this.data[8]; + return out; + }; + Mat3.prototype.identity = /** + * Sets this Mat3 to the identity matrix. + * @method identity + * @param {any} source - The object to copy from. + * @return {Mat3} This Mat3 object. + **/ + function () { + return this.setTo(1, 0, 0, 0, 1, 0, 0, 0, 1); + }; + Mat3.prototype.translate = /** + * Translates this Mat3 by the given vector + **/ + function (v) { + this.a20 = v.x * this.a00 + v.y * this.a10 + this.a20; + this.a21 = v.x * this.a01 + v.y * this.a11 + this.a21; + this.a22 = v.x * this.a02 + v.y * this.a12 + this.a22; + return this; + }; + Mat3.prototype.setTemps = function () { + this._a00 = this.data[0]; + this._a01 = this.data[1]; + this._a02 = this.data[2]; + this._a10 = this.data[3]; + this._a11 = this.data[4]; + this._a12 = this.data[5]; + this._a20 = this.data[6]; + this._a21 = this.data[7]; + this._a22 = this.data[8]; + }; + Mat3.prototype.rotate = /** + * Rotates this Mat3 by the given angle (given in radians) + **/ + function (rad) { + this.setTemps(); + var s = Phaser.GameMath.sinA[rad]; + var c = Phaser.GameMath.cosA[rad]; + this.data[0] = c * this._a00 + s * this._a10; + this.data[1] = c * this._a01 + s * this._a10; + this.data[2] = c * this._a02 + s * this._a12; + this.data[3] = c * this._a10 - s * this._a00; + this.data[4] = c * this._a11 - s * this._a01; + this.data[5] = c * this._a12 - s * this._a02; + return this; + }; + Mat3.prototype.scale = /** + * Scales this Mat3 by the given vector + **/ + function (v) { + this.data[0] = v.x * this.data[0]; + this.data[1] = v.x * this.data[1]; + this.data[2] = v.x * this.data[2]; + this.data[3] = v.y * this.data[3]; + this.data[4] = v.y * this.data[4]; + this.data[5] = v.y * this.data[5]; + return this; + }; + Mat3.prototype.setTo = function (a00, a01, a02, a10, a11, a12, a20, a21, a22) { + this.data[0] = a00; + this.data[1] = a01; + this.data[2] = a02; + this.data[3] = a10; + this.data[4] = a11; + this.data[5] = a12; + this.data[6] = a20; + this.data[7] = a21; + this.data[8] = a22; + return this; + }; + Mat3.prototype.toString = /** + * Returns a string representation of this object. + * @method toString + * @return {string} a string representation of the object. + **/ + function () { + return ''; + //return "[{Vec2 (x=" + this.x + " y=" + this.y + ")}]"; + }; + return Mat3; + })(); + Phaser.Mat3 = Mat3; +})(Phaser || (Phaser = {})); var Phaser; (function (Phaser) { /// + /// /** * Phaser - Components - Transform */ @@ -2823,11 +3077,87 @@ var Phaser; this.rotation = 0; this.game = parent.game; this.parent = parent; + this.local = new Phaser.Mat3(); this.scrollFactor = new Phaser.Vec2(1, 1); this.origin = new Phaser.Vec2(); this.scale = new Phaser.Vec2(1, 1); this.skew = new Phaser.Vec2(); } + Transform.prototype.update = function () { + // 0 a = scale x + // 3 b = skew x + // 1 c = skew y + // 4 d = scale y + // 2 e = translate x + // 5 f = translate y + // Scale & Skew + // if (sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.transform.rotationOffset !== 0)) + this._sin = 0; + this._cos = 1; + if(this.parent.texture.renderRotation) { + this._sin = Phaser.GameMath.sinA[this.rotation + this.rotationOffset]; + this._cos = Phaser.GameMath.cosA[this.rotation + this.rotationOffset]; + } + if(this.parent.texture.flippedX) { + //this.local.data[0] = GameMath.cosA[this.rotation + this.rotationOffset] * -this.scale.x; + //this.local.data[3] = (GameMath.sinA[this.rotation + this.rotationOffset] * -this.scale.x) + this.skew.x; + this.local.data[0] = this._cos * -this.scale.x; + this.local.data[3] = (this._sin * -this.scale.x) + this.skew.x; + } else { + //this.local.data[0] = GameMath.cosA[this.rotation + this.rotationOffset] * this.scale.x; + //this.local.data[3] = (GameMath.sinA[this.rotation + this.rotationOffset] * this.scale.x) + this.skew.x; + this.local.data[0] = this._cos * this.scale.x; + this.local.data[3] = (this._sin * this.scale.x) + this.skew.x; + } + if(this.parent.texture.flippedY) { + //this.local.data[4] = GameMath.cosA[this.rotation + this.rotationOffset] * -this.scale.y; + //this.local.data[1] = -(GameMath.sinA[this.rotation + this.rotationOffset] * -this.scale.y) + this.skew.y; + this.local.data[4] = this._cos * -this.scale.y; + this.local.data[1] = -(this._sin * -this.scale.y) + this.skew.y; + } else { + //this.local.data[4] = GameMath.cosA[this.rotation + this.rotationOffset] * this.scale.y; + //this.local.data[1] = -(GameMath.sinA[this.rotation + this.rotationOffset] * this.scale.y) + this.skew.y; + this.local.data[4] = this._cos * this.scale.y; + this.local.data[1] = -(this._sin * this.scale.y) + this.skew.y; + } + // Translate + this.local.data[2] = this.parent.x; + this.local.data[5] = this.parent.y; + }; + Object.defineProperty(Transform.prototype, "calculatedX", { + get: function () { + return this.origin.x * this.scale.x; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "calculatedY", { + get: function () { + return this.origin.y * this.scale.y; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "centerX", { + get: /** + * The center of the Sprite after taking scaling into consideration + */ + function () { + return this.parent.width / 2; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "centerY", { + get: /** + * The center of the Sprite after taking scaling into consideration + */ + function () { + return this.parent.height / 2; + }, + enumerable: true, + configurable: true + }); return Transform; })(); Components.Transform = Transform; @@ -3412,7 +3742,7 @@ var Phaser; var Components = Phaser.Components; })(Phaser || (Phaser = {})); /// -/// +/// /** * Phaser - Vec2Utils * @@ -3707,8 +4037,8 @@ var Phaser; })(Phaser || (Phaser = {})); var Phaser; (function (Phaser) { - /// - /// + /// + /// /// /** * Phaser - Physics - Body @@ -3938,8 +4268,8 @@ var Phaser; var Physics = Phaser.Physics; })(Phaser || (Phaser = {})); /// -/// -/// +/// +/// /// /// /// @@ -3997,11 +4327,12 @@ var Phaser; this.y = y; this.z = -1; this.group = null; - this.transform = new Phaser.Components.Transform(this); + // No dependencies this.animations = new Phaser.Components.AnimationManager(this); - this.texture = new Phaser.Components.Texture(this); this.input = new Phaser.Components.Sprite.Input(this); this.events = new Phaser.Components.Sprite.Events(this); + this.texture = new Phaser.Components.Texture(this); + this.transform = new Phaser.Components.Transform(this); if(key !== null) { this.texture.loadImage(key, false); } else { @@ -4090,10 +4421,13 @@ var Phaser; * Pre-update is called right before update() on each object in the game loop. */ function () { + this.transform.update(); //this.worldView.x = this.x * this.transform.scrollFactor.x; //this.worldView.y = this.y * this.transform.scrollFactor.y; - this.worldView.x = this.x - this.transform.origin.x; - this.worldView.y = this.y - this.transform.origin.y; + this.worldView.x = this.x; + this.worldView.y = this.y; + //this.worldView.x = this.x - this.transform.origin.x; + //this.worldView.y = this.y - this.transform.origin.y; this.worldView.width = this.width; this.worldView.height = this.height; if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { @@ -4183,9 +4517,9 @@ var Phaser; Phaser.Sprite = Sprite; })(Phaser || (Phaser = {})); /// -/// -/// -/// +/// +/// +/// /// /// /** @@ -6357,6 +6691,12 @@ var Phaser; */ this.globalSeed = Math.random(); this.game = game; + GameMath.sinA = []; + GameMath.cosA = []; + for(var i = 0; i < 360; i++) { + GameMath.sinA.push(Math.sin(this.degreesToRadians(i))); + GameMath.cosA.push(Math.cos(this.degreesToRadians(i))); + } } GameMath.PI = 3.141592653589793; GameMath.PI_2 = 1.5707963267948965; @@ -7626,9 +7966,9 @@ var Phaser; Phaser.CameraFX = CameraFX; })(Phaser || (Phaser = {})); /// -/// -/// -/// +/// +/// +/// /// /// /// @@ -9164,8 +9504,8 @@ var Phaser; Phaser.Emitter = Emitter; })(Phaser || (Phaser = {})); /// -/// -/// +/// +/// /** * Phaser - ScrollRegion * @@ -9314,7 +9654,7 @@ var Phaser; Phaser.ScrollRegion = ScrollRegion; })(Phaser || (Phaser = {})); /// -/// +/// /// /** * Phaser - ScrollZone @@ -11865,9 +12205,9 @@ var Phaser; Phaser.TweenManager = TweenManager; })(Phaser || (Phaser = {})); /// -/// -/// -/// +/// +/// +/// /** * Phaser - CircleUtils * @@ -12967,7 +13307,7 @@ var Phaser; /// /// /// -/// +/// /// /** * Phaser - World @@ -13931,7 +14271,7 @@ var Phaser; Phaser.RequestAnimationFrame = RequestAnimationFrame; })(Phaser || (Phaser = {})); /// -/// +/// /** * Phaser - PointUtils * @@ -14128,7 +14468,7 @@ var Phaser; })(); })(Phaser || (Phaser = {})); /// -/// +/// /** * Phaser - Pointer * @@ -16235,8 +16575,8 @@ var Phaser; */ function (camera, sprite) { if(sprite.transform.scale.x == 0 || sprite.transform.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { - return false; - } + //return false; + } sprite.renderOrderID = this._count; this._count++; // Reset our temp vars @@ -16245,12 +16585,8 @@ var Phaser; this._sy = 0; this._sw = sprite.texture.width; this._sh = sprite.texture.height; - this._fx = sprite.transform.scale.x; - this._fy = sprite.transform.scale.y; - this._sin = 0; - this._cos = 1; - this._dx = (camera.screenView.x * sprite.transform.scrollFactor.x) + sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); - this._dy = (camera.screenView.y * sprite.transform.scrollFactor.y) + sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + this._dx = camera.screenView.x + sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + this._dy = camera.screenView.y + sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); this._dw = sprite.texture.width; this._dh = sprite.texture.height; // Global Composite Ops @@ -16263,14 +16599,6 @@ var Phaser; this._ga = sprite.texture.context.globalAlpha; sprite.texture.context.globalAlpha = sprite.texture.alpha; } - // Sprite Flip X - if(sprite.texture.flippedX) { - this._fx = -sprite.transform.scale.x; - } - // Sprite Flip Y - if(sprite.texture.flippedY) { - this._fy = -sprite.transform.scale.y; - } if(sprite.animations.currentFrame !== null) { this._sx = sprite.animations.currentFrame.x; this._sy = sprite.animations.currentFrame.y; @@ -16283,28 +16611,20 @@ var Phaser; this._dh = sprite.animations.currentFrame.spriteSourceSizeH; } } - // Rotation and Flipped if(sprite.modified) { - if(sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.transform.rotationOffset !== 0)) { - this._sin = Math.sin(sprite.game.math.degreesToRadians(sprite.transform.rotationOffset + sprite.rotation)); - this._cos = Math.cos(sprite.game.math.degreesToRadians(sprite.transform.rotationOffset + sprite.rotation)); - } - // setTransform(a, b, c, d, e, f); - // a = scale x - // b = skew x - // c = skew y - // d = scale y - // e = translate x - // f = translate y sprite.texture.context.save(); - sprite.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + sprite.transform.skew.x, -(this._sin * this._fy) + sprite.transform.skew.y, this._cos * this._fy, this._dx, this._dy); - this._dx = -sprite.transform.origin.x; - this._dy = -sprite.transform.origin.y; + sprite.texture.context.setTransform(sprite.transform.local.data[0], // scale x + sprite.transform.local.data[3], // skew x + sprite.transform.local.data[1], // skew y + sprite.transform.local.data[4], // scale y + this._dx, // translate x + this._dy); + // translate y + this._dx = sprite.transform.origin.x * -this._dw; + this._dy = sprite.transform.origin.y * -this._dh; } else { - if(!sprite.transform.origin.equals(0)) { - this._dx -= sprite.transform.origin.x; - this._dy -= sprite.transform.origin.y; - } + this._dx -= (this._dw * sprite.transform.origin.x); + this._dy -= (this._dh * sprite.transform.origin.y); } this._sx = Math.round(this._sx); this._sy = Math.round(this._sy); @@ -16421,9 +16741,9 @@ var Phaser; Phaser.CanvasRenderer = CanvasRenderer; })(Phaser || (Phaser = {})); /// -/// -/// -/// +/// +/// +/// /// /// /** @@ -16479,12 +16799,12 @@ var Phaser; })(); Phaser.DebugUtils = DebugUtils; })(Phaser || (Phaser = {})); -/// +/// /// /// -/// -/// -/// +/// +/// +/// /// /// /// @@ -17015,69 +17335,6 @@ var Phaser; })(Phaser || (Phaser = {})); /// /** -* Phaser - Polygon -* -* -*/ -var Phaser; -(function (Phaser) { - var Polygon = (function () { - /** - * - **/ - function Polygon(game, points) { - this.game = game; - this.context = game.stage.context; - this.points = []; - for(var i = 0; i < points.length; i++) { - this.points.push(new Phaser.Point().copyFrom(points[i])); - } - } - Polygon.prototype.render = function () { - this.context.beginPath(); - this.context.strokeStyle = 'rgb(255,255,0)'; - this.context.moveTo(this.points[0].x, this.points[0].y); - for(var i = 1; i < this.points.length; i++) { - this.context.lineTo(this.points[i].x, this.points[i].y); - } - this.context.lineTo(this.points[0].x, this.points[0].y); - this.context.stroke(); - this.context.closePath(); - }; - return Polygon; - })(); - Phaser.Polygon = Polygon; -})(Phaser || (Phaser = {})); -/// -/// -/// -/// -/** -* Phaser - PixelUtils -* -* A collection of methods useful for manipulating pixels. -*/ -var Phaser; -(function (Phaser) { - var PixelUtils = (function () { - function PixelUtils() { } - PixelUtils.boot = function boot() { - PixelUtils.pixelCanvas = document.createElement('canvas'); - PixelUtils.pixelCanvas.width = 1; - PixelUtils.pixelCanvas.height = 1; - PixelUtils.pixelContext = PixelUtils.pixelCanvas.getContext('2d'); - }; - PixelUtils.getPixel = function getPixel(key, x, y) { - // write out a single pixel (won't help with rotated sprites though.. hmm) - var imageData = PixelUtils.pixelContext.getImageData(0, 0, 1, 1); - return Phaser.ColorUtils.getColor32(imageData.data[3], imageData.data[0], imageData.data[1], imageData.data[2]); - }; - return PixelUtils; - })(); - Phaser.PixelUtils = PixelUtils; -})(Phaser || (Phaser = {})); -/// -/** * Phaser - Line * * A Line object is an infinte line through space. The two sets of x/y coordinates define the Line Segment. @@ -17347,6 +17604,189 @@ var Phaser; Phaser.Line = Line; })(Phaser || (Phaser = {})); /// +/// +/// +/** +* Phaser - Mat3Utils +* +* A collection of methods useful for manipulating and performing operations on Mat3 objects. +* +*/ +var Phaser; +(function (Phaser) { + var Mat3Utils = (function () { + function Mat3Utils() { } + Mat3Utils.transpose = /** + * Transpose the values of a Mat3 + **/ + function transpose(source, dest) { + if (typeof dest === "undefined") { dest = null; } + if(dest === null) { + // Transpose ourselves + var a01 = source.data[1]; + var a02 = source.data[2]; + var a12 = source.data[5]; + source.data[1] = source.data[3]; + source.data[2] = source.data[6]; + source.data[3] = a01; + source.data[5] = source.data[7]; + source.data[6] = a02; + source.data[7] = a12; + } else { + source.data[0] = dest.data[0]; + source.data[1] = dest.data[3]; + source.data[2] = dest.data[6]; + source.data[3] = dest.data[1]; + source.data[4] = dest.data[4]; + source.data[5] = dest.data[7]; + source.data[6] = dest.data[2]; + source.data[7] = dest.data[5]; + source.data[8] = dest.data[8]; + } + return source; + }; + Mat3Utils.invert = /** + * Inverts a Mat3 + **/ + function invert(source) { + var a00 = source.data[0]; + var a01 = source.data[1]; + var a02 = source.data[2]; + var a10 = source.data[3]; + var a11 = source.data[4]; + var a12 = source.data[5]; + var a20 = source.data[6]; + var a21 = source.data[7]; + var a22 = source.data[8]; + var b01 = a22 * a11 - a12 * a21; + var b11 = -a22 * a10 + a12 * a20; + var b21 = a21 * a10 - a11 * a20; + // Determinant + var det = a00 * b01 + a01 * b11 + a02 * b21; + if(!det) { + return null; + } + det = 1.0 / det; + source.data[0] = b01 * det; + source.data[1] = (-a22 * a01 + a02 * a21) * det; + source.data[2] = (a12 * a01 - a02 * a11) * det; + source.data[3] = b11 * det; + source.data[4] = (a22 * a00 - a02 * a20) * det; + source.data[5] = (-a12 * a00 + a02 * a10) * det; + source.data[6] = b21 * det; + source.data[7] = (-a21 * a00 + a01 * a20) * det; + source.data[8] = (a11 * a00 - a01 * a10) * det; + return source; + }; + Mat3Utils.adjoint = /** + * Calculates the adjugate of a Mat3 + **/ + function adjoint(source) { + var a00 = source.data[0]; + var a01 = source.data[1]; + var a02 = source.data[2]; + var a10 = source.data[3]; + var a11 = source.data[4]; + var a12 = source.data[5]; + var a20 = source.data[6]; + var a21 = source.data[7]; + var a22 = source.data[8]; + source.data[0] = (a11 * a22 - a12 * a21); + source.data[1] = (a02 * a21 - a01 * a22); + source.data[2] = (a01 * a12 - a02 * a11); + source.data[3] = (a12 * a20 - a10 * a22); + source.data[4] = (a00 * a22 - a02 * a20); + source.data[5] = (a02 * a10 - a00 * a12); + source.data[6] = (a10 * a21 - a11 * a20); + source.data[7] = (a01 * a20 - a00 * a21); + source.data[8] = (a00 * a11 - a01 * a10); + return source; + }; + Mat3Utils.determinant = /** + * Calculates the adjugate of a Mat3 + **/ + function determinant(source) { + var a00 = source.data[0]; + var a01 = source.data[1]; + var a02 = source.data[2]; + var a10 = source.data[3]; + var a11 = source.data[4]; + var a12 = source.data[5]; + var a20 = source.data[6]; + var a21 = source.data[7]; + var a22 = source.data[8]; + return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); + }; + Mat3Utils.multiply = /** + * Multiplies two Mat3s + **/ + function multiply(source, b) { + var a00 = source.data[0]; + var a01 = source.data[1]; + var a02 = source.data[2]; + var a10 = source.data[3]; + var a11 = source.data[4]; + var a12 = source.data[5]; + var a20 = source.data[6]; + var a21 = source.data[7]; + var a22 = source.data[8]; + var b00 = b.data[0]; + var b01 = b.data[1]; + var b02 = b.data[2]; + var b10 = b.data[3]; + var b11 = b.data[4]; + var b12 = b.data[5]; + var b20 = b.data[6]; + var b21 = b.data[7]; + var b22 = b.data[8]; + source.data[0] = b00 * a00 + b01 * a10 + b02 * a20; + source.data[1] = b00 * a01 + b01 * a11 + b02 * a21; + source.data[2] = b00 * a02 + b01 * a12 + b02 * a22; + source.data[3] = b10 * a00 + b11 * a10 + b12 * a20; + source.data[4] = b10 * a01 + b11 * a11 + b12 * a21; + source.data[5] = b10 * a02 + b11 * a12 + b12 * a22; + source.data[6] = b20 * a00 + b21 * a10 + b22 * a20; + source.data[7] = b20 * a01 + b21 * a11 + b22 * a21; + source.data[8] = b20 * a02 + b21 * a12 + b22 * a22; + return source; + }; + Mat3Utils.fromQuaternion = function fromQuaternion() { + }; + Mat3Utils.normalFromMat4 = function normalFromMat4() { + }; + return Mat3Utils; + })(); + Phaser.Mat3Utils = Mat3Utils; +})(Phaser || (Phaser = {})); +/// +/// +/// +/// +/** +* Phaser - PixelUtils +* +* A collection of methods useful for manipulating pixels. +*/ +var Phaser; +(function (Phaser) { + var PixelUtils = (function () { + function PixelUtils() { } + PixelUtils.boot = function boot() { + PixelUtils.pixelCanvas = document.createElement('canvas'); + PixelUtils.pixelCanvas.width = 1; + PixelUtils.pixelCanvas.height = 1; + PixelUtils.pixelContext = PixelUtils.pixelCanvas.getContext('2d'); + }; + PixelUtils.getPixel = function getPixel(key, x, y) { + // write out a single pixel (won't help with rotated sprites though.. hmm) + var imageData = PixelUtils.pixelContext.getImageData(0, 0, 1, 1); + return Phaser.ColorUtils.getColor32(imageData.data[3], imageData.data[0], imageData.data[1], imageData.data[2]); + }; + return PixelUtils; + })(); + Phaser.PixelUtils = PixelUtils; +})(Phaser || (Phaser = {})); +/// /** * Phaser - IntersectResult * diff --git a/Tests/sprites/origin 5.js b/Tests/sprites/origin 5.js new file mode 100644 index 00000000..e860d17b --- /dev/null +++ b/Tests/sprites/origin 5.js @@ -0,0 +1,67 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); + function init() { + // Using Phasers asset loader we load up a PNG from the assets folder + game.load.image('fuji', 'assets/pics/atari_fujilogo.png'); + game.load.start(); + } + var fuji; + var wn; + var hn; + function create() { + game.stage.backgroundColor = 'rgb(0,0,100)'; + game.world.setSize(2000, 1200, true); + // The sprite is 320 x 200 pixels in size positioned in the middle of the stage + fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji'); + //fuji.transform.scale.setTo(1.5, 1.5); + //fuji.transform.scale.setTo(1.5, 1.5); + //fuji.transform.skew.setTo(0.1, 0.1); + //fuji.texture.alpha = 0.5; + fuji.texture.renderRotation = false; + //fuji.texture.flippedX = true; + //fuji.texture.flippedY = true; + //fuji.transform.scale.setTo(2, 2); + //fuji.transform.scale.setTo(2, 2); + // This sets the origin to the center + //fuji.transform.origin.setTo(0.5, 0.5); + game.input.onTap.add(rotateIt, this); + } + function rotateIt() { + fuji.rotation += 20; + console.log(fuji.rotation); + } + function update() { + var s = Math.sin(fuji.rotation); + var c = Math.cos(fuji.rotation); + if(s < 0) { + s = -s; + } + if(c < 0) { + c = -c; + } + wn = fuji.width * s + fuji.width * c; + hn = fuji.height * c + fuji.height * s; + if(game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { + game.camera.x -= 4; + } else if(game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { + game.camera.x += 4; + } + if(game.input.keyboard.isDown(Phaser.Keyboard.UP)) { + game.camera.y -= 4; + } else if(game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { + game.camera.y += 4; + } + } + function render() { + game.stage.context.fillStyle = 'rgb(255,255,255)'; + game.stage.context.fillRect(fuji.x, fuji.y, 2, 2); + game.stage.context.fillStyle = 'rgb(255,255,0)'; + game.stage.context.fillRect(fuji.x + fuji.transform.centerX, fuji.y + fuji.transform.centerY, 2, 2); + game.stage.context.strokeStyle = 'rgb(255,0,0)'; + game.stage.context.strokeRect(fuji.worldView.x, fuji.worldView.y, fuji.worldView.width, fuji.worldView.height); + game.stage.context.strokeStyle = 'rgb(0,255,0)'; + game.stage.context.strokeRect(fuji.x, fuji.y, wn, hn); + game.camera.renderDebugInfo(32, 32); + } +})(); diff --git a/Tests/sprites/origin 5.ts b/Tests/sprites/origin 5.ts new file mode 100644 index 00000000..60b2fdc5 --- /dev/null +++ b/Tests/sprites/origin 5.ts @@ -0,0 +1,106 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); + + function init() { + + // Using Phasers asset loader we load up a PNG from the assets folder + game.load.image('fuji', 'assets/pics/atari_fujilogo.png'); + game.load.start(); + + } + + var fuji: Phaser.Sprite; + var wn: number; + var hn: number; + + + function create() { + + game.stage.backgroundColor = 'rgb(0,0,100)'; + game.world.setSize(2000, 1200, true); + + // The sprite is 320 x 200 pixels in size positioned in the middle of the stage + fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji'); + + //fuji.transform.scale.setTo(1.5, 1.5); + //fuji.transform.scale.setTo(1.5, 1.5); + //fuji.transform.skew.setTo(0.1, 0.1); + //fuji.texture.alpha = 0.5; + + //fuji.texture.flippedX = true; + //fuji.texture.flippedY = true; + + //fuji.transform.scale.setTo(2, 2); + //fuji.transform.scale.setTo(2, 2); + + // This sets the origin to the center + //fuji.transform.origin.setTo(0.5, 0.5); + + game.input.onTap.add(rotateIt, this); + + } + + function rotateIt() { + fuji.rotation += 20; + } + + function update() { + + var s = Math.sin(fuji.rotation); + var c = Math.cos(fuji.rotation); + + if (s < 0) + { + s = -s; + } + + if (c < 0) + { + c = -c; + } + + wn = fuji.width * s + fuji.width * c; + hn = fuji.height * c + fuji.height * s; + + if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) + { + game.camera.x -= 4; + } + else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) + { + game.camera.x += 4; + } + + if (game.input.keyboard.isDown(Phaser.Keyboard.UP)) + { + game.camera.y -= 4; + } + else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) + { + game.camera.y += 4; + } + + } + + function render() { + + game.stage.context.fillStyle = 'rgb(255,255,255)'; + game.stage.context.fillRect(fuji.x, fuji.y, 2, 2); + + game.stage.context.fillStyle = 'rgb(255,255,0)'; + game.stage.context.fillRect(fuji.x + fuji.transform.centerX, fuji.y + fuji.transform.centerY, 2, 2); + + game.stage.context.strokeStyle = 'rgb(255,0,0)'; + game.stage.context.strokeRect(fuji.worldView.x, fuji.worldView.y, fuji.worldView.width, fuji.worldView.height); + + game.stage.context.strokeStyle = 'rgb(0,255,0)'; + game.stage.context.strokeRect(fuji.x, fuji.y, wn, hn); + + game.camera.renderDebugInfo(32, 32); + + } + +})(); diff --git a/build/phaser.d.ts b/build/phaser.d.ts index 379a1323..ab3fad57 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -492,7 +492,7 @@ module Phaser { /** * Phaser - Vec2 * -* A Circle object is an area defined by its position, as indicated by its center point (x,y) and diameter. +* A Vector 2 */ module Phaser { class Vec2 { @@ -1805,6 +1805,88 @@ module Phaser.Components { } } /** +* Phaser - Mat3 +* +* A 3x3 Matrix +*/ +module Phaser { + class Mat3 { + /** + * Creates a new Mat3 object. + * @class Mat3 + * @constructor + * @return {Mat3} This object + **/ + constructor(); + private _a00; + private _a01; + private _a02; + private _a10; + private _a11; + private _a12; + private _a20; + private _a21; + private _a22; + public data: number[]; + public a00 : number; + public a01 : number; + public a02 : number; + public a10 : number; + public a11 : number; + public a12 : number; + public a20 : number; + public a21 : number; + public a22 : number; + /** + * Copies the values from one Mat3 into this Mat3. + * @method copyFromMat3 + * @param {any} source - The object to copy from. + * @return {Mat3} This Mat3 object. + **/ + public copyFromMat3(source: Mat3): Mat3; + /** + * Copies the upper-left 3x3 values into this Mat3. + * @method copyFromMat4 + * @param {any} source - The object to copy from. + * @return {Mat3} This Mat3 object. + **/ + public copyFromMat4(source: any): Mat3; + /** + * Clones this Mat3 into a new Mat3 + * @param {Mat3} out The output Mat3, if none is given a new Mat3 object will be created. + * @return {Mat3} The new Mat3 + **/ + public clone(out?: Mat3): Mat3; + /** + * Sets this Mat3 to the identity matrix. + * @method identity + * @param {any} source - The object to copy from. + * @return {Mat3} This Mat3 object. + **/ + public identity(): Mat3; + /** + * Translates this Mat3 by the given vector + **/ + public translate(v: Vec2): Mat3; + private setTemps(); + /** + * Rotates this Mat3 by the given angle (given in radians) + **/ + public rotate(rad: number): Mat3; + /** + * Scales this Mat3 by the given vector + **/ + public scale(v: Vec2): Mat3; + public setTo(a00: number, a01: number, a02: number, a10: number, a11: number, a12: number, a20: number, a21: number, a22: number): Mat3; + /** + * Returns a string representation of this object. + * @method toString + * @return {string} a string representation of the object. + **/ + public toString(): string; + } +} +/** * Phaser - Components - Transform */ module Phaser.Components { @@ -1814,6 +1896,12 @@ module Phaser.Components { * @param parent The Sprite using this transform */ constructor(parent); + public local: Mat3; + private _sin; + private _cos; + public update(): void; + public calculatedX : number; + public calculatedY : number; /** * Reference to Phaser.Game */ @@ -1835,7 +1923,7 @@ module Phaser.Components { */ public scrollFactor: Vec2; /** - * The origin is the point around which scale and rotation takes place. + * The origin is the point around which scale and rotation takes place and defaults to the center of the sprite. */ public origin: Vec2; /** @@ -1849,6 +1937,14 @@ module Phaser.Components { * The rotation of the object in degrees. Phaser uses a right-handed coordinate system, where 0 points to the right. */ public rotation: number; + /** + * The center of the Sprite after taking scaling into consideration + */ + public centerX : number; + /** + * The center of the Sprite after taking scaling into consideration + */ + public centerY : number; } } /** @@ -3636,6 +3732,8 @@ module Phaser { class GameMath { constructor(game: Game); public game: Game; + static sinA: number[]; + static cosA: number[]; static PI: number; static PI_2: number; static PI_4: number; @@ -8943,44 +9041,6 @@ module Phaser.Components { } } /** -* Phaser - Polygon -* -* -*/ -module Phaser { - class Polygon { - /** - * - **/ - constructor(game: Game, points: Point[]); - public points: Point[]; - public game: Game; - public context: CanvasRenderingContext2D; - public render(): void; - } -} -/** -* Phaser - PixelUtils -* -* A collection of methods useful for manipulating pixels. -*/ -module Phaser { - class PixelUtils { - static boot(): void; - /** - * Canvas element used in 1x1 pixel checks. - * @type {HTMLCanvasElement} - */ - static pixelCanvas: HTMLCanvasElement; - /** - * Render context of pixelCanvas - * @type {CanvasRenderingContext2D} - */ - static pixelContext: CanvasRenderingContext2D; - static getPixel(key: string, x: number, y: number): number; - } -} -/** * Phaser - Line * * A Line object is an infinte line through space. The two sets of x/y coordinates define the Line Segment. @@ -9132,6 +9192,59 @@ module Phaser { } } /** +* Phaser - Mat3Utils +* +* A collection of methods useful for manipulating and performing operations on Mat3 objects. +* +*/ +module Phaser { + class Mat3Utils { + /** + * Transpose the values of a Mat3 + **/ + static transpose(source: Mat3, dest?: Mat3): Mat3; + /** + * Inverts a Mat3 + **/ + static invert(source: Mat3): Mat3; + /** + * Calculates the adjugate of a Mat3 + **/ + static adjoint(source: Mat3): Mat3; + /** + * Calculates the adjugate of a Mat3 + **/ + static determinant(source: Mat3): number; + /** + * Multiplies two Mat3s + **/ + static multiply(source: Mat3, b: Mat3): Mat3; + static fromQuaternion(): void; + static normalFromMat4(): void; + } +} +/** +* Phaser - PixelUtils +* +* A collection of methods useful for manipulating pixels. +*/ +module Phaser { + class PixelUtils { + static boot(): void; + /** + * Canvas element used in 1x1 pixel checks. + * @type {HTMLCanvasElement} + */ + static pixelCanvas: HTMLCanvasElement; + /** + * Render context of pixelCanvas + * @type {CanvasRenderingContext2D} + */ + static pixelContext: CanvasRenderingContext2D; + static getPixel(key: string, x: number, y: number): number; + } +} +/** * Phaser - IntersectResult * * A light-weight result object to hold the results of an intersection. For when you need more than just true/false. diff --git a/build/phaser.js b/build/phaser.js index a07d9581..79107e15 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -384,7 +384,7 @@ var __extends = this.__extends || function (d, b) { d.prototype = new __(); }; /// -/// +/// /// /** * Phaser - QuadTree @@ -734,7 +734,7 @@ var Phaser; /** * Phaser - Vec2 * -* A Circle object is an area defined by its position, as indicated by its center point (x,y) and diameter. +* A Vector 2 */ var Phaser; (function (Phaser) { @@ -1264,8 +1264,8 @@ var Phaser; Phaser.Types = Types; })(Phaser || (Phaser = {})); /// -/// -/// +/// +/// /** * Phaser - RectangleUtils * @@ -1455,9 +1455,9 @@ var Phaser; Phaser.RectangleUtils = RectangleUtils; })(Phaser || (Phaser = {})); /// -/// -/// -/// +/// +/// +/// /** * Phaser - ColorUtils * @@ -2797,9 +2797,263 @@ var Phaser; })(Phaser.Components || (Phaser.Components = {})); var Components = Phaser.Components; })(Phaser || (Phaser = {})); +/// +/** +* Phaser - Mat3 +* +* A 3x3 Matrix +*/ +var Phaser; +(function (Phaser) { + var Mat3 = (function () { + /** + * Creates a new Mat3 object. + * @class Mat3 + * @constructor + * @return {Mat3} This object + **/ + function Mat3() { + this.data = [ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1 + ]; + } + Object.defineProperty(Mat3.prototype, "a00", { + get: function () { + return this.data[0]; + }, + set: function (value) { + this.data[0] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a01", { + get: function () { + return this.data[1]; + }, + set: function (value) { + this.data[1] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a02", { + get: function () { + return this.data[2]; + }, + set: function (value) { + this.data[2] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a10", { + get: function () { + return this.data[3]; + }, + set: function (value) { + this.data[3] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a11", { + get: function () { + return this.data[4]; + }, + set: function (value) { + this.data[4] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a12", { + get: function () { + return this.data[5]; + }, + set: function (value) { + this.data[5] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a20", { + get: function () { + return this.data[6]; + }, + set: function (value) { + this.data[6] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a21", { + get: function () { + return this.data[7]; + }, + set: function (value) { + this.data[7] = value; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Mat3.prototype, "a22", { + get: function () { + return this.data[8]; + }, + set: function (value) { + this.data[8] = value; + }, + enumerable: true, + configurable: true + }); + Mat3.prototype.copyFromMat3 = /** + * Copies the values from one Mat3 into this Mat3. + * @method copyFromMat3 + * @param {any} source - The object to copy from. + * @return {Mat3} This Mat3 object. + **/ + function (source) { + this.data[0] = source.data[0]; + this.data[1] = source.data[1]; + this.data[2] = source.data[2]; + this.data[3] = source.data[3]; + this.data[4] = source.data[4]; + this.data[5] = source.data[5]; + this.data[6] = source.data[6]; + this.data[7] = source.data[7]; + this.data[8] = source.data[8]; + return this; + }; + Mat3.prototype.copyFromMat4 = /** + * Copies the upper-left 3x3 values into this Mat3. + * @method copyFromMat4 + * @param {any} source - The object to copy from. + * @return {Mat3} This Mat3 object. + **/ + function (source) { + this.data[0] = source[0]; + this.data[1] = source[1]; + this.data[2] = source[2]; + this.data[3] = source[4]; + this.data[4] = source[5]; + this.data[5] = source[6]; + this.data[6] = source[8]; + this.data[7] = source[9]; + this.data[8] = source[10]; + return this; + }; + Mat3.prototype.clone = /** + * Clones this Mat3 into a new Mat3 + * @param {Mat3} out The output Mat3, if none is given a new Mat3 object will be created. + * @return {Mat3} The new Mat3 + **/ + function (out) { + if (typeof out === "undefined") { out = new Phaser.Mat3(); } + out[0] = this.data[0]; + out[1] = this.data[1]; + out[2] = this.data[2]; + out[3] = this.data[3]; + out[4] = this.data[4]; + out[5] = this.data[5]; + out[6] = this.data[6]; + out[7] = this.data[7]; + out[8] = this.data[8]; + return out; + }; + Mat3.prototype.identity = /** + * Sets this Mat3 to the identity matrix. + * @method identity + * @param {any} source - The object to copy from. + * @return {Mat3} This Mat3 object. + **/ + function () { + return this.setTo(1, 0, 0, 0, 1, 0, 0, 0, 1); + }; + Mat3.prototype.translate = /** + * Translates this Mat3 by the given vector + **/ + function (v) { + this.a20 = v.x * this.a00 + v.y * this.a10 + this.a20; + this.a21 = v.x * this.a01 + v.y * this.a11 + this.a21; + this.a22 = v.x * this.a02 + v.y * this.a12 + this.a22; + return this; + }; + Mat3.prototype.setTemps = function () { + this._a00 = this.data[0]; + this._a01 = this.data[1]; + this._a02 = this.data[2]; + this._a10 = this.data[3]; + this._a11 = this.data[4]; + this._a12 = this.data[5]; + this._a20 = this.data[6]; + this._a21 = this.data[7]; + this._a22 = this.data[8]; + }; + Mat3.prototype.rotate = /** + * Rotates this Mat3 by the given angle (given in radians) + **/ + function (rad) { + this.setTemps(); + var s = Phaser.GameMath.sinA[rad]; + var c = Phaser.GameMath.cosA[rad]; + this.data[0] = c * this._a00 + s * this._a10; + this.data[1] = c * this._a01 + s * this._a10; + this.data[2] = c * this._a02 + s * this._a12; + this.data[3] = c * this._a10 - s * this._a00; + this.data[4] = c * this._a11 - s * this._a01; + this.data[5] = c * this._a12 - s * this._a02; + return this; + }; + Mat3.prototype.scale = /** + * Scales this Mat3 by the given vector + **/ + function (v) { + this.data[0] = v.x * this.data[0]; + this.data[1] = v.x * this.data[1]; + this.data[2] = v.x * this.data[2]; + this.data[3] = v.y * this.data[3]; + this.data[4] = v.y * this.data[4]; + this.data[5] = v.y * this.data[5]; + return this; + }; + Mat3.prototype.setTo = function (a00, a01, a02, a10, a11, a12, a20, a21, a22) { + this.data[0] = a00; + this.data[1] = a01; + this.data[2] = a02; + this.data[3] = a10; + this.data[4] = a11; + this.data[5] = a12; + this.data[6] = a20; + this.data[7] = a21; + this.data[8] = a22; + return this; + }; + Mat3.prototype.toString = /** + * Returns a string representation of this object. + * @method toString + * @return {string} a string representation of the object. + **/ + function () { + return ''; + //return "[{Vec2 (x=" + this.x + " y=" + this.y + ")}]"; + }; + return Mat3; + })(); + Phaser.Mat3 = Mat3; +})(Phaser || (Phaser = {})); var Phaser; (function (Phaser) { /// + /// /** * Phaser - Components - Transform */ @@ -2823,11 +3077,87 @@ var Phaser; this.rotation = 0; this.game = parent.game; this.parent = parent; + this.local = new Phaser.Mat3(); this.scrollFactor = new Phaser.Vec2(1, 1); this.origin = new Phaser.Vec2(); this.scale = new Phaser.Vec2(1, 1); this.skew = new Phaser.Vec2(); } + Transform.prototype.update = function () { + // 0 a = scale x + // 3 b = skew x + // 1 c = skew y + // 4 d = scale y + // 2 e = translate x + // 5 f = translate y + // Scale & Skew + // if (sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.transform.rotationOffset !== 0)) + this._sin = 0; + this._cos = 1; + if(this.parent.texture.renderRotation) { + this._sin = Phaser.GameMath.sinA[this.rotation + this.rotationOffset]; + this._cos = Phaser.GameMath.cosA[this.rotation + this.rotationOffset]; + } + if(this.parent.texture.flippedX) { + //this.local.data[0] = GameMath.cosA[this.rotation + this.rotationOffset] * -this.scale.x; + //this.local.data[3] = (GameMath.sinA[this.rotation + this.rotationOffset] * -this.scale.x) + this.skew.x; + this.local.data[0] = this._cos * -this.scale.x; + this.local.data[3] = (this._sin * -this.scale.x) + this.skew.x; + } else { + //this.local.data[0] = GameMath.cosA[this.rotation + this.rotationOffset] * this.scale.x; + //this.local.data[3] = (GameMath.sinA[this.rotation + this.rotationOffset] * this.scale.x) + this.skew.x; + this.local.data[0] = this._cos * this.scale.x; + this.local.data[3] = (this._sin * this.scale.x) + this.skew.x; + } + if(this.parent.texture.flippedY) { + //this.local.data[4] = GameMath.cosA[this.rotation + this.rotationOffset] * -this.scale.y; + //this.local.data[1] = -(GameMath.sinA[this.rotation + this.rotationOffset] * -this.scale.y) + this.skew.y; + this.local.data[4] = this._cos * -this.scale.y; + this.local.data[1] = -(this._sin * -this.scale.y) + this.skew.y; + } else { + //this.local.data[4] = GameMath.cosA[this.rotation + this.rotationOffset] * this.scale.y; + //this.local.data[1] = -(GameMath.sinA[this.rotation + this.rotationOffset] * this.scale.y) + this.skew.y; + this.local.data[4] = this._cos * this.scale.y; + this.local.data[1] = -(this._sin * this.scale.y) + this.skew.y; + } + // Translate + this.local.data[2] = this.parent.x; + this.local.data[5] = this.parent.y; + }; + Object.defineProperty(Transform.prototype, "calculatedX", { + get: function () { + return this.origin.x * this.scale.x; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "calculatedY", { + get: function () { + return this.origin.y * this.scale.y; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "centerX", { + get: /** + * The center of the Sprite after taking scaling into consideration + */ + function () { + return this.parent.width / 2; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "centerY", { + get: /** + * The center of the Sprite after taking scaling into consideration + */ + function () { + return this.parent.height / 2; + }, + enumerable: true, + configurable: true + }); return Transform; })(); Components.Transform = Transform; @@ -3412,7 +3742,7 @@ var Phaser; var Components = Phaser.Components; })(Phaser || (Phaser = {})); /// -/// +/// /** * Phaser - Vec2Utils * @@ -3707,8 +4037,8 @@ var Phaser; })(Phaser || (Phaser = {})); var Phaser; (function (Phaser) { - /// - /// + /// + /// /// /** * Phaser - Physics - Body @@ -3938,8 +4268,8 @@ var Phaser; var Physics = Phaser.Physics; })(Phaser || (Phaser = {})); /// -/// -/// +/// +/// /// /// /// @@ -3997,11 +4327,12 @@ var Phaser; this.y = y; this.z = -1; this.group = null; - this.transform = new Phaser.Components.Transform(this); + // No dependencies this.animations = new Phaser.Components.AnimationManager(this); - this.texture = new Phaser.Components.Texture(this); this.input = new Phaser.Components.Sprite.Input(this); this.events = new Phaser.Components.Sprite.Events(this); + this.texture = new Phaser.Components.Texture(this); + this.transform = new Phaser.Components.Transform(this); if(key !== null) { this.texture.loadImage(key, false); } else { @@ -4090,10 +4421,13 @@ var Phaser; * Pre-update is called right before update() on each object in the game loop. */ function () { + this.transform.update(); //this.worldView.x = this.x * this.transform.scrollFactor.x; //this.worldView.y = this.y * this.transform.scrollFactor.y; - this.worldView.x = this.x - this.transform.origin.x; - this.worldView.y = this.y - this.transform.origin.y; + this.worldView.x = this.x; + this.worldView.y = this.y; + //this.worldView.x = this.x - this.transform.origin.x; + //this.worldView.y = this.y - this.transform.origin.y; this.worldView.width = this.width; this.worldView.height = this.height; if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { @@ -4183,9 +4517,9 @@ var Phaser; Phaser.Sprite = Sprite; })(Phaser || (Phaser = {})); /// -/// -/// -/// +/// +/// +/// /// /// /** @@ -6357,6 +6691,12 @@ var Phaser; */ this.globalSeed = Math.random(); this.game = game; + GameMath.sinA = []; + GameMath.cosA = []; + for(var i = 0; i < 360; i++) { + GameMath.sinA.push(Math.sin(this.degreesToRadians(i))); + GameMath.cosA.push(Math.cos(this.degreesToRadians(i))); + } } GameMath.PI = 3.141592653589793; GameMath.PI_2 = 1.5707963267948965; @@ -7626,9 +7966,9 @@ var Phaser; Phaser.CameraFX = CameraFX; })(Phaser || (Phaser = {})); /// -/// -/// -/// +/// +/// +/// /// /// /// @@ -9164,8 +9504,8 @@ var Phaser; Phaser.Emitter = Emitter; })(Phaser || (Phaser = {})); /// -/// -/// +/// +/// /** * Phaser - ScrollRegion * @@ -9314,7 +9654,7 @@ var Phaser; Phaser.ScrollRegion = ScrollRegion; })(Phaser || (Phaser = {})); /// -/// +/// /// /** * Phaser - ScrollZone @@ -11865,9 +12205,9 @@ var Phaser; Phaser.TweenManager = TweenManager; })(Phaser || (Phaser = {})); /// -/// -/// -/// +/// +/// +/// /** * Phaser - CircleUtils * @@ -12967,7 +13307,7 @@ var Phaser; /// /// /// -/// +/// /// /** * Phaser - World @@ -13931,7 +14271,7 @@ var Phaser; Phaser.RequestAnimationFrame = RequestAnimationFrame; })(Phaser || (Phaser = {})); /// -/// +/// /** * Phaser - PointUtils * @@ -14128,7 +14468,7 @@ var Phaser; })(); })(Phaser || (Phaser = {})); /// -/// +/// /** * Phaser - Pointer * @@ -16235,8 +16575,8 @@ var Phaser; */ function (camera, sprite) { if(sprite.transform.scale.x == 0 || sprite.transform.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { - return false; - } + //return false; + } sprite.renderOrderID = this._count; this._count++; // Reset our temp vars @@ -16245,12 +16585,8 @@ var Phaser; this._sy = 0; this._sw = sprite.texture.width; this._sh = sprite.texture.height; - this._fx = sprite.transform.scale.x; - this._fy = sprite.transform.scale.y; - this._sin = 0; - this._cos = 1; - this._dx = (camera.screenView.x * sprite.transform.scrollFactor.x) + sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); - this._dy = (camera.screenView.y * sprite.transform.scrollFactor.y) + sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); + this._dx = camera.screenView.x + sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); + this._dy = camera.screenView.y + sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); this._dw = sprite.texture.width; this._dh = sprite.texture.height; // Global Composite Ops @@ -16263,14 +16599,6 @@ var Phaser; this._ga = sprite.texture.context.globalAlpha; sprite.texture.context.globalAlpha = sprite.texture.alpha; } - // Sprite Flip X - if(sprite.texture.flippedX) { - this._fx = -sprite.transform.scale.x; - } - // Sprite Flip Y - if(sprite.texture.flippedY) { - this._fy = -sprite.transform.scale.y; - } if(sprite.animations.currentFrame !== null) { this._sx = sprite.animations.currentFrame.x; this._sy = sprite.animations.currentFrame.y; @@ -16283,28 +16611,20 @@ var Phaser; this._dh = sprite.animations.currentFrame.spriteSourceSizeH; } } - // Rotation and Flipped if(sprite.modified) { - if(sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.transform.rotationOffset !== 0)) { - this._sin = Math.sin(sprite.game.math.degreesToRadians(sprite.transform.rotationOffset + sprite.rotation)); - this._cos = Math.cos(sprite.game.math.degreesToRadians(sprite.transform.rotationOffset + sprite.rotation)); - } - // setTransform(a, b, c, d, e, f); - // a = scale x - // b = skew x - // c = skew y - // d = scale y - // e = translate x - // f = translate y sprite.texture.context.save(); - sprite.texture.context.setTransform(this._cos * this._fx, (this._sin * this._fx) + sprite.transform.skew.x, -(this._sin * this._fy) + sprite.transform.skew.y, this._cos * this._fy, this._dx, this._dy); - this._dx = -sprite.transform.origin.x; - this._dy = -sprite.transform.origin.y; + sprite.texture.context.setTransform(sprite.transform.local.data[0], // scale x + sprite.transform.local.data[3], // skew x + sprite.transform.local.data[1], // skew y + sprite.transform.local.data[4], // scale y + this._dx, // translate x + this._dy); + // translate y + this._dx = sprite.transform.origin.x * -this._dw; + this._dy = sprite.transform.origin.y * -this._dh; } else { - if(!sprite.transform.origin.equals(0)) { - this._dx -= sprite.transform.origin.x; - this._dy -= sprite.transform.origin.y; - } + this._dx -= (this._dw * sprite.transform.origin.x); + this._dy -= (this._dh * sprite.transform.origin.y); } this._sx = Math.round(this._sx); this._sy = Math.round(this._sy); @@ -16421,9 +16741,9 @@ var Phaser; Phaser.CanvasRenderer = CanvasRenderer; })(Phaser || (Phaser = {})); /// -/// -/// -/// +/// +/// +/// /// /// /** @@ -16479,12 +16799,12 @@ var Phaser; })(); Phaser.DebugUtils = DebugUtils; })(Phaser || (Phaser = {})); -/// +/// /// /// -/// -/// -/// +/// +/// +/// /// /// /// @@ -17015,69 +17335,6 @@ var Phaser; })(Phaser || (Phaser = {})); /// /** -* Phaser - Polygon -* -* -*/ -var Phaser; -(function (Phaser) { - var Polygon = (function () { - /** - * - **/ - function Polygon(game, points) { - this.game = game; - this.context = game.stage.context; - this.points = []; - for(var i = 0; i < points.length; i++) { - this.points.push(new Phaser.Point().copyFrom(points[i])); - } - } - Polygon.prototype.render = function () { - this.context.beginPath(); - this.context.strokeStyle = 'rgb(255,255,0)'; - this.context.moveTo(this.points[0].x, this.points[0].y); - for(var i = 1; i < this.points.length; i++) { - this.context.lineTo(this.points[i].x, this.points[i].y); - } - this.context.lineTo(this.points[0].x, this.points[0].y); - this.context.stroke(); - this.context.closePath(); - }; - return Polygon; - })(); - Phaser.Polygon = Polygon; -})(Phaser || (Phaser = {})); -/// -/// -/// -/// -/** -* Phaser - PixelUtils -* -* A collection of methods useful for manipulating pixels. -*/ -var Phaser; -(function (Phaser) { - var PixelUtils = (function () { - function PixelUtils() { } - PixelUtils.boot = function boot() { - PixelUtils.pixelCanvas = document.createElement('canvas'); - PixelUtils.pixelCanvas.width = 1; - PixelUtils.pixelCanvas.height = 1; - PixelUtils.pixelContext = PixelUtils.pixelCanvas.getContext('2d'); - }; - PixelUtils.getPixel = function getPixel(key, x, y) { - // write out a single pixel (won't help with rotated sprites though.. hmm) - var imageData = PixelUtils.pixelContext.getImageData(0, 0, 1, 1); - return Phaser.ColorUtils.getColor32(imageData.data[3], imageData.data[0], imageData.data[1], imageData.data[2]); - }; - return PixelUtils; - })(); - Phaser.PixelUtils = PixelUtils; -})(Phaser || (Phaser = {})); -/// -/** * Phaser - Line * * A Line object is an infinte line through space. The two sets of x/y coordinates define the Line Segment. @@ -17347,6 +17604,189 @@ var Phaser; Phaser.Line = Line; })(Phaser || (Phaser = {})); /// +/// +/// +/** +* Phaser - Mat3Utils +* +* A collection of methods useful for manipulating and performing operations on Mat3 objects. +* +*/ +var Phaser; +(function (Phaser) { + var Mat3Utils = (function () { + function Mat3Utils() { } + Mat3Utils.transpose = /** + * Transpose the values of a Mat3 + **/ + function transpose(source, dest) { + if (typeof dest === "undefined") { dest = null; } + if(dest === null) { + // Transpose ourselves + var a01 = source.data[1]; + var a02 = source.data[2]; + var a12 = source.data[5]; + source.data[1] = source.data[3]; + source.data[2] = source.data[6]; + source.data[3] = a01; + source.data[5] = source.data[7]; + source.data[6] = a02; + source.data[7] = a12; + } else { + source.data[0] = dest.data[0]; + source.data[1] = dest.data[3]; + source.data[2] = dest.data[6]; + source.data[3] = dest.data[1]; + source.data[4] = dest.data[4]; + source.data[5] = dest.data[7]; + source.data[6] = dest.data[2]; + source.data[7] = dest.data[5]; + source.data[8] = dest.data[8]; + } + return source; + }; + Mat3Utils.invert = /** + * Inverts a Mat3 + **/ + function invert(source) { + var a00 = source.data[0]; + var a01 = source.data[1]; + var a02 = source.data[2]; + var a10 = source.data[3]; + var a11 = source.data[4]; + var a12 = source.data[5]; + var a20 = source.data[6]; + var a21 = source.data[7]; + var a22 = source.data[8]; + var b01 = a22 * a11 - a12 * a21; + var b11 = -a22 * a10 + a12 * a20; + var b21 = a21 * a10 - a11 * a20; + // Determinant + var det = a00 * b01 + a01 * b11 + a02 * b21; + if(!det) { + return null; + } + det = 1.0 / det; + source.data[0] = b01 * det; + source.data[1] = (-a22 * a01 + a02 * a21) * det; + source.data[2] = (a12 * a01 - a02 * a11) * det; + source.data[3] = b11 * det; + source.data[4] = (a22 * a00 - a02 * a20) * det; + source.data[5] = (-a12 * a00 + a02 * a10) * det; + source.data[6] = b21 * det; + source.data[7] = (-a21 * a00 + a01 * a20) * det; + source.data[8] = (a11 * a00 - a01 * a10) * det; + return source; + }; + Mat3Utils.adjoint = /** + * Calculates the adjugate of a Mat3 + **/ + function adjoint(source) { + var a00 = source.data[0]; + var a01 = source.data[1]; + var a02 = source.data[2]; + var a10 = source.data[3]; + var a11 = source.data[4]; + var a12 = source.data[5]; + var a20 = source.data[6]; + var a21 = source.data[7]; + var a22 = source.data[8]; + source.data[0] = (a11 * a22 - a12 * a21); + source.data[1] = (a02 * a21 - a01 * a22); + source.data[2] = (a01 * a12 - a02 * a11); + source.data[3] = (a12 * a20 - a10 * a22); + source.data[4] = (a00 * a22 - a02 * a20); + source.data[5] = (a02 * a10 - a00 * a12); + source.data[6] = (a10 * a21 - a11 * a20); + source.data[7] = (a01 * a20 - a00 * a21); + source.data[8] = (a00 * a11 - a01 * a10); + return source; + }; + Mat3Utils.determinant = /** + * Calculates the adjugate of a Mat3 + **/ + function determinant(source) { + var a00 = source.data[0]; + var a01 = source.data[1]; + var a02 = source.data[2]; + var a10 = source.data[3]; + var a11 = source.data[4]; + var a12 = source.data[5]; + var a20 = source.data[6]; + var a21 = source.data[7]; + var a22 = source.data[8]; + return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); + }; + Mat3Utils.multiply = /** + * Multiplies two Mat3s + **/ + function multiply(source, b) { + var a00 = source.data[0]; + var a01 = source.data[1]; + var a02 = source.data[2]; + var a10 = source.data[3]; + var a11 = source.data[4]; + var a12 = source.data[5]; + var a20 = source.data[6]; + var a21 = source.data[7]; + var a22 = source.data[8]; + var b00 = b.data[0]; + var b01 = b.data[1]; + var b02 = b.data[2]; + var b10 = b.data[3]; + var b11 = b.data[4]; + var b12 = b.data[5]; + var b20 = b.data[6]; + var b21 = b.data[7]; + var b22 = b.data[8]; + source.data[0] = b00 * a00 + b01 * a10 + b02 * a20; + source.data[1] = b00 * a01 + b01 * a11 + b02 * a21; + source.data[2] = b00 * a02 + b01 * a12 + b02 * a22; + source.data[3] = b10 * a00 + b11 * a10 + b12 * a20; + source.data[4] = b10 * a01 + b11 * a11 + b12 * a21; + source.data[5] = b10 * a02 + b11 * a12 + b12 * a22; + source.data[6] = b20 * a00 + b21 * a10 + b22 * a20; + source.data[7] = b20 * a01 + b21 * a11 + b22 * a21; + source.data[8] = b20 * a02 + b21 * a12 + b22 * a22; + return source; + }; + Mat3Utils.fromQuaternion = function fromQuaternion() { + }; + Mat3Utils.normalFromMat4 = function normalFromMat4() { + }; + return Mat3Utils; + })(); + Phaser.Mat3Utils = Mat3Utils; +})(Phaser || (Phaser = {})); +/// +/// +/// +/// +/** +* Phaser - PixelUtils +* +* A collection of methods useful for manipulating pixels. +*/ +var Phaser; +(function (Phaser) { + var PixelUtils = (function () { + function PixelUtils() { } + PixelUtils.boot = function boot() { + PixelUtils.pixelCanvas = document.createElement('canvas'); + PixelUtils.pixelCanvas.width = 1; + PixelUtils.pixelCanvas.height = 1; + PixelUtils.pixelContext = PixelUtils.pixelCanvas.getContext('2d'); + }; + PixelUtils.getPixel = function getPixel(key, x, y) { + // write out a single pixel (won't help with rotated sprites though.. hmm) + var imageData = PixelUtils.pixelContext.getImageData(0, 0, 1, 1); + return Phaser.ColorUtils.getColor32(imageData.data[3], imageData.data[0], imageData.data[1], imageData.data[2]); + }; + return PixelUtils; + })(); + Phaser.PixelUtils = PixelUtils; +})(Phaser || (Phaser = {})); +/// /** * Phaser - IntersectResult * From 1f8c809f53232f5a13117a8856b6316e0080e2bb Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 7 Jun 2013 19:18:39 +0100 Subject: [PATCH 4/8] cameraView working for center rotated sprites, just need to handle any point of rotation. --- Phaser/components/Transform.ts | 29 +------- Phaser/gameobjects/Sprite.ts | 15 +++-- Phaser/renderers/CanvasRenderer.ts | 6 +- Phaser/utils/DebugUtils.ts | 3 +- Phaser/utils/SpriteUtils.ts | 76 +++++++++++++++++---- Tests/phaser.js | 105 +++++++++++++++-------------- Tests/sprites/origin 5.js | 33 ++++----- Tests/sprites/origin 5.ts | 38 +++++------ build/phaser.d.ts | 20 ++++-- build/phaser.js | 105 +++++++++++++++-------------- 10 files changed, 234 insertions(+), 196 deletions(-) diff --git a/Phaser/components/Transform.ts b/Phaser/components/Transform.ts index e56d1f0d..206a3fbe 100644 --- a/Phaser/components/Transform.ts +++ b/Phaser/components/Transform.ts @@ -27,24 +27,15 @@ module Phaser.Components { } - public local: Mat3; - private _sin: number; private _cos: number; + public local: Mat3; + public update() { - // 0 a = scale x - // 3 b = skew x - // 1 c = skew y - // 4 d = scale y - // 2 e = translate x - // 5 f = translate y - // Scale & Skew - // if (sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.transform.rotationOffset !== 0)) - this._sin = 0; this._cos = 1; @@ -56,30 +47,22 @@ module Phaser.Components { if (this.parent.texture.flippedX) { - //this.local.data[0] = GameMath.cosA[this.rotation + this.rotationOffset] * -this.scale.x; - //this.local.data[3] = (GameMath.sinA[this.rotation + this.rotationOffset] * -this.scale.x) + this.skew.x; this.local.data[0] = this._cos * -this.scale.x; this.local.data[3] = (this._sin * -this.scale.x) + this.skew.x; } else { - //this.local.data[0] = GameMath.cosA[this.rotation + this.rotationOffset] * this.scale.x; - //this.local.data[3] = (GameMath.sinA[this.rotation + this.rotationOffset] * this.scale.x) + this.skew.x; this.local.data[0] = this._cos * this.scale.x; this.local.data[3] = (this._sin * this.scale.x) + this.skew.x; } if (this.parent.texture.flippedY) { - //this.local.data[4] = GameMath.cosA[this.rotation + this.rotationOffset] * -this.scale.y; - //this.local.data[1] = -(GameMath.sinA[this.rotation + this.rotationOffset] * -this.scale.y) + this.skew.y; this.local.data[4] = this._cos * -this.scale.y; this.local.data[1] = -(this._sin * -this.scale.y) + this.skew.y; } else { - //this.local.data[4] = GameMath.cosA[this.rotation + this.rotationOffset] * this.scale.y; - //this.local.data[1] = -(GameMath.sinA[this.rotation + this.rotationOffset] * this.scale.y) + this.skew.y; this.local.data[4] = this._cos * this.scale.y; this.local.data[1] = -(this._sin * this.scale.y) + this.skew.y; } @@ -90,14 +73,6 @@ module Phaser.Components { } - public get calculatedX(): number { - return this.origin.x * this.scale.x; - } - - public get calculatedY(): number { - return this.origin.y * this.scale.y; - } - /** * Reference to Phaser.Game */ diff --git a/Phaser/gameobjects/Sprite.ts b/Phaser/gameobjects/Sprite.ts index 3bf3d28e..7cd30f57 100644 --- a/Phaser/gameobjects/Sprite.ts +++ b/Phaser/gameobjects/Sprite.ts @@ -70,6 +70,7 @@ module Phaser { this.body = new Phaser.Physics.Body(this, bodyType); this.worldView = new Rectangle(x, y, this.width, this.height); + this.cameraView = new Rectangle(x, y, this.width, this.height); } @@ -145,6 +146,12 @@ module Phaser { */ public worldView: Phaser.Rectangle; + /** + * A Rectangle that maps to the placement of this sprite with respect to a specific Camera. + * This value is constantly updated and modified during the internal render pass, it is not meant to be accessed directly. + */ + public cameraView: Phaser.Rectangle; + /** * A boolean representing if the Sprite has been modified in any way via a scale, rotate, flip or skew. */ @@ -236,12 +243,8 @@ module Phaser { this.transform.update(); - //this.worldView.x = this.x * this.transform.scrollFactor.x; - //this.worldView.y = this.y * this.transform.scrollFactor.y; - this.worldView.x = this.x; - this.worldView.y = this.y; - //this.worldView.x = this.x - this.transform.origin.x; - //this.worldView.y = this.y - this.transform.origin.y; + this.worldView.x = this.x * this.transform.scrollFactor.x; + this.worldView.y = this.y * this.transform.scrollFactor.y; this.worldView.width = this.width; this.worldView.height = this.height; diff --git a/Phaser/renderers/CanvasRenderer.ts b/Phaser/renderers/CanvasRenderer.ts index 13d635bc..8535068c 100644 --- a/Phaser/renderers/CanvasRenderer.ts +++ b/Phaser/renderers/CanvasRenderer.ts @@ -221,7 +221,9 @@ module Phaser { return true; } - return RectangleUtils.intersects(sprite.worldView, camera.worldView); + Phaser.SpriteUtils.updateCameraView(camera, sprite); + + return RectangleUtils.intersects(sprite.cameraView, camera.screenView); } @@ -441,6 +443,8 @@ module Phaser { */ public renderSprite(camera: Camera, sprite: Sprite): bool { + Phaser.SpriteUtils.updateCameraView(camera, sprite); + if (sprite.transform.scale.x == 0 || sprite.transform.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { //return false; diff --git a/Phaser/utils/DebugUtils.ts b/Phaser/utils/DebugUtils.ts index e1bf9039..ec2220b7 100644 --- a/Phaser/utils/DebugUtils.ts +++ b/Phaser/utils/DebugUtils.ts @@ -31,7 +31,8 @@ module Phaser { DebugUtils.game.stage.context.fillText('wx: ' + sprite.worldView.x + ' wy: ' + sprite.worldView.y + ' ww: ' + sprite.worldView.width.toFixed(1) + ' wh: ' + sprite.worldView.height.toFixed(1) + ' wb: ' + sprite.worldView.bottom + ' wr: ' + sprite.worldView.right, x, y + 28); DebugUtils.game.stage.context.fillText('sx: ' + sprite.transform.scale.x.toFixed(1) + ' sy: ' + sprite.transform.scale.y.toFixed(1), x, y + 42); DebugUtils.game.stage.context.fillText('tx: ' + sprite.texture.width.toFixed(1) + ' ty: ' + sprite.texture.height.toFixed(1), x, y + 56); - DebugUtils.game.stage.context.fillText('inCamera: ' + DebugUtils.game.renderer.inCamera(DebugUtils.game.camera, sprite), x, y + 70); + DebugUtils.game.stage.context.fillText('cx: ' + sprite.cameraView.x + ' cy: ' + sprite.cameraView.y + ' cw: ' + sprite.cameraView.width + ' ch: ' + sprite.cameraView.height + ' cb: ' + sprite.cameraView.bottom + ' cr: ' + sprite.cameraView.right, x, y + 70); + DebugUtils.game.stage.context.fillText('inCamera: ' + DebugUtils.game.renderer.inCamera(DebugUtils.game.camera, sprite), x, y + 84); } diff --git a/Phaser/utils/SpriteUtils.ts b/Phaser/utils/SpriteUtils.ts index 7d8519bc..29b844d4 100644 --- a/Phaser/utils/SpriteUtils.ts +++ b/Phaser/utils/SpriteUtils.ts @@ -16,26 +16,78 @@ module Phaser { export class SpriteUtils { static _tempPoint: Point; + static _sin: number; + static _cos: number; /** - * Check whether this object is visible in a specific camera Rectangle. - * @param camera {Rectangle} The Rectangle you want to check. - * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. + * Updates a Sprites cameraView Rectangle based on the given camera, sprite world position and rotation + * @param camera {Camera} The Camera to use in the view + * @param sprite {Sprite} The Sprite that will have its cameraView property modified + * @return {Rectangle} A reference to the Sprite.cameraView property */ - static inCamera(camera: Camera, sprite: Sprite): bool { + static updateCameraView(camera: Camera, sprite: Sprite): Rectangle { - // Object fixed in place regardless of the camera scrolling? Then it's always visible - if (sprite.transform.scrollFactor.x == 0 && sprite.transform.scrollFactor.y == 0) + if (sprite.rotation == 0 || sprite.texture.renderRotation == false) { - return true; + // Easy out + sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.width * sprite.transform.origin.x)); + sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.height * sprite.transform.origin.y)); + sprite.cameraView.width = sprite.width; + sprite.cameraView.height = sprite.height; + } + else + { + // If the sprite is rotated around its center we can use this quicker method: + + // Work out bounding box + SpriteUtils._sin = Phaser.GameMath.sinA[sprite.rotation]; + SpriteUtils._cos = Phaser.GameMath.cosA[sprite.rotation]; + + if (SpriteUtils._sin < 0) + { + SpriteUtils._sin = -SpriteUtils._sin; + } + + if (SpriteUtils._cos < 0) + { + SpriteUtils._cos = -SpriteUtils._cos; + } + + sprite.cameraView.width = Math.round(sprite.height * SpriteUtils._sin + sprite.width * SpriteUtils._cos); + sprite.cameraView.height = Math.round(sprite.height * SpriteUtils._cos + sprite.width * SpriteUtils._sin); + + // if origin isn't 0.5 we need to work out the difference to apply to the x/y + if (sprite.transform.origin.equals(0.5)) + { + // Easy out + sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); + sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); + } + else + { + //var ax = sprite.cameraView.width * sprite.transform.origin.x; + //var ay = sprite.cameraView.height * sprite.transform.origin.y; + //var bx = sprite.cameraView.width * 0.5; + //var by = sprite.cameraView.height * 0.5; + //var c = sprite.game.math.distanceBetween(ax, ay, bx, by) / 2; + + //console.log('actual x', ax, 'actual y', ay, 'cx', bx, 'cy', by); + + sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); + sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); + } + } - var dx = sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); - var dy = sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); - var dw = sprite.width * sprite.transform.scale.x; - var dh = sprite.height * sprite.transform.scale.y; + if (sprite.animations.currentFrame !== null && sprite.animations.currentFrame.trimmed) + { + //sprite.cameraView.x += sprite.animations.currentFrame.spriteSourceSizeX; + //sprite.cameraView.y += sprite.animations.currentFrame.spriteSourceSizeY; + //this._dw = sprite.animations.currentFrame.spriteSourceSizeW; + //this._dh = sprite.animations.currentFrame.spriteSourceSizeH; + } - return (camera.screenView.x + camera.worldView.width > this._dx) && (camera.screenView.x < this._dx + this._dw) && (camera.screenView.y + camera.worldView.height > this._dy) && (camera.screenView.y < this._dy + this._dh); + return sprite.cameraView; } diff --git a/Tests/phaser.js b/Tests/phaser.js index 79107e15..3cd97fca 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -3084,14 +3084,7 @@ var Phaser; this.skew = new Phaser.Vec2(); } Transform.prototype.update = function () { - // 0 a = scale x - // 3 b = skew x - // 1 c = skew y - // 4 d = scale y - // 2 e = translate x - // 5 f = translate y // Scale & Skew - // if (sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.transform.rotationOffset !== 0)) this._sin = 0; this._cos = 1; if(this.parent.texture.renderRotation) { @@ -3099,24 +3092,16 @@ var Phaser; this._cos = Phaser.GameMath.cosA[this.rotation + this.rotationOffset]; } if(this.parent.texture.flippedX) { - //this.local.data[0] = GameMath.cosA[this.rotation + this.rotationOffset] * -this.scale.x; - //this.local.data[3] = (GameMath.sinA[this.rotation + this.rotationOffset] * -this.scale.x) + this.skew.x; this.local.data[0] = this._cos * -this.scale.x; this.local.data[3] = (this._sin * -this.scale.x) + this.skew.x; } else { - //this.local.data[0] = GameMath.cosA[this.rotation + this.rotationOffset] * this.scale.x; - //this.local.data[3] = (GameMath.sinA[this.rotation + this.rotationOffset] * this.scale.x) + this.skew.x; this.local.data[0] = this._cos * this.scale.x; this.local.data[3] = (this._sin * this.scale.x) + this.skew.x; } if(this.parent.texture.flippedY) { - //this.local.data[4] = GameMath.cosA[this.rotation + this.rotationOffset] * -this.scale.y; - //this.local.data[1] = -(GameMath.sinA[this.rotation + this.rotationOffset] * -this.scale.y) + this.skew.y; this.local.data[4] = this._cos * -this.scale.y; this.local.data[1] = -(this._sin * -this.scale.y) + this.skew.y; } else { - //this.local.data[4] = GameMath.cosA[this.rotation + this.rotationOffset] * this.scale.y; - //this.local.data[1] = -(GameMath.sinA[this.rotation + this.rotationOffset] * this.scale.y) + this.skew.y; this.local.data[4] = this._cos * this.scale.y; this.local.data[1] = -(this._sin * this.scale.y) + this.skew.y; } @@ -3124,20 +3109,6 @@ var Phaser; this.local.data[2] = this.parent.x; this.local.data[5] = this.parent.y; }; - Object.defineProperty(Transform.prototype, "calculatedX", { - get: function () { - return this.origin.x * this.scale.x; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Transform.prototype, "calculatedY", { - get: function () { - return this.origin.y * this.scale.y; - }, - enumerable: true, - configurable: true - }); Object.defineProperty(Transform.prototype, "centerX", { get: /** * The center of the Sprite after taking scaling into consideration @@ -4347,6 +4318,7 @@ var Phaser; } this.body = new Phaser.Physics.Body(this, bodyType); this.worldView = new Phaser.Rectangle(x, y, this.width, this.height); + this.cameraView = new Phaser.Rectangle(x, y, this.width, this.height); } Object.defineProperty(Sprite.prototype, "rotation", { get: /** @@ -4422,12 +4394,8 @@ var Phaser; */ function () { this.transform.update(); - //this.worldView.x = this.x * this.transform.scrollFactor.x; - //this.worldView.y = this.y * this.transform.scrollFactor.y; - this.worldView.x = this.x; - this.worldView.y = this.y; - //this.worldView.x = this.x - this.transform.origin.x; - //this.worldView.y = this.y - this.transform.origin.y; + this.worldView.x = this.x * this.transform.scrollFactor.x; + this.worldView.y = this.y * this.transform.scrollFactor.y; this.worldView.width = this.width; this.worldView.height = this.height; if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { @@ -4531,21 +4499,55 @@ var Phaser; (function (Phaser) { var SpriteUtils = (function () { function SpriteUtils() { } - SpriteUtils.inCamera = /** - * Check whether this object is visible in a specific camera Rectangle. - * @param camera {Rectangle} The Rectangle you want to check. - * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. + SpriteUtils.updateCameraView = /** + * Updates a Sprites cameraView Rectangle based on the given camera, sprite world position and rotation + * @param camera {Camera} The Camera to use in the view + * @param sprite {Sprite} The Sprite that will have its cameraView property modified + * @return {Rectangle} A reference to the Sprite.cameraView property */ - function inCamera(camera, sprite) { - // Object fixed in place regardless of the camera scrolling? Then it's always visible - if(sprite.transform.scrollFactor.x == 0 && sprite.transform.scrollFactor.y == 0) { - return true; + function updateCameraView(camera, sprite) { + if(sprite.rotation == 0 || sprite.texture.renderRotation == false) { + // Easy out + sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.width * sprite.transform.origin.x)); + sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.height * sprite.transform.origin.y)); + sprite.cameraView.width = sprite.width; + sprite.cameraView.height = sprite.height; + } else { + // If the sprite is rotated around its center we can use this quicker method: + // Work out bounding box + SpriteUtils._sin = Phaser.GameMath.sinA[sprite.rotation]; + SpriteUtils._cos = Phaser.GameMath.cosA[sprite.rotation]; + if(SpriteUtils._sin < 0) { + SpriteUtils._sin = -SpriteUtils._sin; + } + if(SpriteUtils._cos < 0) { + SpriteUtils._cos = -SpriteUtils._cos; + } + sprite.cameraView.width = Math.round(sprite.height * SpriteUtils._sin + sprite.width * SpriteUtils._cos); + sprite.cameraView.height = Math.round(sprite.height * SpriteUtils._cos + sprite.width * SpriteUtils._sin); + // if origin isn't 0.5 we need to work out the difference to apply to the x/y + if(sprite.transform.origin.equals(0.5)) { + // Easy out + sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); + sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); + } else { + //var ax = sprite.cameraView.width * sprite.transform.origin.x; + //var ay = sprite.cameraView.height * sprite.transform.origin.y; + //var bx = sprite.cameraView.width * 0.5; + //var by = sprite.cameraView.height * 0.5; + //var c = sprite.game.math.distanceBetween(ax, ay, bx, by) / 2; + //console.log('actual x', ax, 'actual y', ay, 'cx', bx, 'cy', by); + sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); + sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); + } } - var dx = sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); - var dy = sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); - var dw = sprite.width * sprite.transform.scale.x; - var dh = sprite.height * sprite.transform.scale.y; - return (camera.screenView.x + camera.worldView.width > this._dx) && (camera.screenView.x < this._dx + this._dw) && (camera.screenView.y + camera.worldView.height > this._dy) && (camera.screenView.y < this._dy + this._dh); + if(sprite.animations.currentFrame !== null && sprite.animations.currentFrame.trimmed) { + //sprite.cameraView.x += sprite.animations.currentFrame.spriteSourceSizeX; + //sprite.cameraView.y += sprite.animations.currentFrame.spriteSourceSizeY; + //this._dw = sprite.animations.currentFrame.spriteSourceSizeW; + //this._dh = sprite.animations.currentFrame.spriteSourceSizeH; + } + return sprite.cameraView; }; SpriteUtils.getAsPoints = function getAsPoints(sprite) { var out = []; @@ -16409,7 +16411,8 @@ var Phaser; if(sprite.transform.scrollFactor.equals(0)) { return true; } - return Phaser.RectangleUtils.intersects(sprite.worldView, camera.worldView); + Phaser.SpriteUtils.updateCameraView(camera, sprite); + return Phaser.RectangleUtils.intersects(sprite.cameraView, camera.screenView); }; CanvasRenderer.prototype.inScreen = function (camera) { return true; @@ -16574,6 +16577,7 @@ var Phaser; * @return {boolean} Return false if not rendered, otherwise return true. */ function (camera, sprite) { + Phaser.SpriteUtils.updateCameraView(camera, sprite); if(sprite.transform.scale.x == 0 || sprite.transform.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { //return false; } @@ -16769,7 +16773,8 @@ var Phaser; DebugUtils.game.stage.context.fillText('wx: ' + sprite.worldView.x + ' wy: ' + sprite.worldView.y + ' ww: ' + sprite.worldView.width.toFixed(1) + ' wh: ' + sprite.worldView.height.toFixed(1) + ' wb: ' + sprite.worldView.bottom + ' wr: ' + sprite.worldView.right, x, y + 28); DebugUtils.game.stage.context.fillText('sx: ' + sprite.transform.scale.x.toFixed(1) + ' sy: ' + sprite.transform.scale.y.toFixed(1), x, y + 42); DebugUtils.game.stage.context.fillText('tx: ' + sprite.texture.width.toFixed(1) + ' ty: ' + sprite.texture.height.toFixed(1), x, y + 56); - DebugUtils.game.stage.context.fillText('inCamera: ' + DebugUtils.game.renderer.inCamera(DebugUtils.game.camera, sprite), x, y + 70); + DebugUtils.game.stage.context.fillText('cx: ' + sprite.cameraView.x + ' cy: ' + sprite.cameraView.y + ' cw: ' + sprite.cameraView.width + ' ch: ' + sprite.cameraView.height + ' cb: ' + sprite.cameraView.bottom + ' cr: ' + sprite.cameraView.right, x, y + 70); + DebugUtils.game.stage.context.fillText('inCamera: ' + DebugUtils.game.renderer.inCamera(DebugUtils.game.camera, sprite), x, y + 84); }; DebugUtils.renderSpriteBounds = function renderSpriteBounds(sprite, camera, color) { if (typeof camera === "undefined") { camera = null; } diff --git a/Tests/sprites/origin 5.js b/Tests/sprites/origin 5.js index e860d17b..cc88a6b4 100644 --- a/Tests/sprites/origin 5.js +++ b/Tests/sprites/origin 5.js @@ -18,7 +18,6 @@ //fuji.transform.scale.setTo(1.5, 1.5); //fuji.transform.skew.setTo(0.1, 0.1); //fuji.texture.alpha = 0.5; - fuji.texture.renderRotation = false; //fuji.texture.flippedX = true; //fuji.texture.flippedY = true; //fuji.transform.scale.setTo(2, 2); @@ -29,19 +28,9 @@ } function rotateIt() { fuji.rotation += 20; - console.log(fuji.rotation); } function update() { - var s = Math.sin(fuji.rotation); - var c = Math.cos(fuji.rotation); - if(s < 0) { - s = -s; - } - if(c < 0) { - c = -c; - } - wn = fuji.width * s + fuji.width * c; - hn = fuji.height * c + fuji.height * s; + fuji.rotation += 1; if(game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { game.camera.x -= 4; } else if(game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { @@ -52,16 +41,20 @@ } else if(game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { game.camera.y += 4; } - } + //Phaser.SpriteUtils.updateCameraDisplay(game.camera, fuji); + } function render() { - game.stage.context.fillStyle = 'rgb(255,255,255)'; + //game.stage.context.fillStyle = 'rgb(255,255,255)'; + //game.stage.context.fillRect(fuji.x, fuji.y, 2, 2); + game.stage.context.fillStyle = 'rgb(255,0,0)'; game.stage.context.fillRect(fuji.x, fuji.y, 2, 2); game.stage.context.fillStyle = 'rgb(255,255,0)'; - game.stage.context.fillRect(fuji.x + fuji.transform.centerX, fuji.y + fuji.transform.centerY, 2, 2); - game.stage.context.strokeStyle = 'rgb(255,0,0)'; - game.stage.context.strokeRect(fuji.worldView.x, fuji.worldView.y, fuji.worldView.width, fuji.worldView.height); - game.stage.context.strokeStyle = 'rgb(0,255,0)'; - game.stage.context.strokeRect(fuji.x, fuji.y, wn, hn); - game.camera.renderDebugInfo(32, 32); + game.stage.context.fillRect(fuji.cameraView.x + fuji.cameraView.halfWidth, fuji.cameraView.y + fuji.cameraView.halfHeight, 2, 2); + game.stage.context.strokeStyle = 'rgb(255,255,0)'; + game.stage.context.strokeRect(fuji.cameraView.x, fuji.cameraView.y, fuji.cameraView.width, fuji.cameraView.height); + //game.stage.context.strokeStyle = 'rgb(0,255,0)'; + //game.stage.context.strokeRect(fuji.x, fuji.y, wn, hn); + //game.camera.renderDebugInfo(32, 32); + Phaser.DebugUtils.renderSpriteInfo(fuji, 32, 32); } })(); diff --git a/Tests/sprites/origin 5.ts b/Tests/sprites/origin 5.ts index 60b2fdc5..750f6ea0 100644 --- a/Tests/sprites/origin 5.ts +++ b/Tests/sprites/origin 5.ts @@ -49,21 +49,7 @@ function update() { - var s = Math.sin(fuji.rotation); - var c = Math.cos(fuji.rotation); - - if (s < 0) - { - s = -s; - } - - if (c < 0) - { - c = -c; - } - - wn = fuji.width * s + fuji.width * c; - hn = fuji.height * c + fuji.height * s; + fuji.rotation += 1; if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { @@ -83,23 +69,31 @@ game.camera.y += 4; } + //Phaser.SpriteUtils.updateCameraDisplay(game.camera, fuji); + } function render() { - game.stage.context.fillStyle = 'rgb(255,255,255)'; + //game.stage.context.fillStyle = 'rgb(255,255,255)'; + //game.stage.context.fillRect(fuji.x, fuji.y, 2, 2); + + game.stage.context.fillStyle = 'rgb(255,0,0)'; game.stage.context.fillRect(fuji.x, fuji.y, 2, 2); game.stage.context.fillStyle = 'rgb(255,255,0)'; - game.stage.context.fillRect(fuji.x + fuji.transform.centerX, fuji.y + fuji.transform.centerY, 2, 2); + game.stage.context.fillRect(fuji.cameraView.x + fuji.cameraView.halfWidth, fuji.cameraView.y + fuji.cameraView.halfHeight, 2, 2); - game.stage.context.strokeStyle = 'rgb(255,0,0)'; - game.stage.context.strokeRect(fuji.worldView.x, fuji.worldView.y, fuji.worldView.width, fuji.worldView.height); + game.stage.context.strokeStyle = 'rgb(255,255,0)'; + game.stage.context.strokeRect(fuji.cameraView.x, fuji.cameraView.y, fuji.cameraView.width, fuji.cameraView.height); - game.stage.context.strokeStyle = 'rgb(0,255,0)'; - game.stage.context.strokeRect(fuji.x, fuji.y, wn, hn); + //game.stage.context.strokeStyle = 'rgb(0,255,0)'; + //game.stage.context.strokeRect(fuji.x, fuji.y, wn, hn); + + //game.camera.renderDebugInfo(32, 32); + + Phaser.DebugUtils.renderSpriteInfo(fuji, 32, 32); - game.camera.renderDebugInfo(32, 32); } diff --git a/build/phaser.d.ts b/build/phaser.d.ts index ab3fad57..9244f4d4 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -1896,12 +1896,10 @@ module Phaser.Components { * @param parent The Sprite using this transform */ constructor(parent); - public local: Mat3; private _sin; private _cos; + public local: Mat3; public update(): void; - public calculatedX : number; - public calculatedY : number; /** * Reference to Phaser.Game */ @@ -2575,6 +2573,11 @@ module Phaser { */ public worldView: Rectangle; /** + * A Rectangle that maps to the placement of this sprite with respect to a specific Camera. + * This value is constantly updated and modified during the internal render pass, it is not meant to be accessed directly. + */ + public cameraView: Rectangle; + /** * A boolean representing if the Sprite has been modified in any way via a scale, rotate, flip or skew. */ public modified: bool; @@ -2657,12 +2660,15 @@ module Phaser { module Phaser { class SpriteUtils { static _tempPoint: Point; + static _sin: number; + static _cos: number; /** - * Check whether this object is visible in a specific camera Rectangle. - * @param camera {Rectangle} The Rectangle you want to check. - * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. + * Updates a Sprites cameraView Rectangle based on the given camera, sprite world position and rotation + * @param camera {Camera} The Camera to use in the view + * @param sprite {Sprite} The Sprite that will have its cameraView property modified + * @return {Rectangle} A reference to the Sprite.cameraView property */ - static inCamera(camera: Camera, sprite: Sprite): bool; + static updateCameraView(camera: Camera, sprite: Sprite): Rectangle; static getAsPoints(sprite: Sprite): Point[]; /** * Checks to see if a point in 2D world space overlaps this GameObject. diff --git a/build/phaser.js b/build/phaser.js index 79107e15..3cd97fca 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -3084,14 +3084,7 @@ var Phaser; this.skew = new Phaser.Vec2(); } Transform.prototype.update = function () { - // 0 a = scale x - // 3 b = skew x - // 1 c = skew y - // 4 d = scale y - // 2 e = translate x - // 5 f = translate y // Scale & Skew - // if (sprite.texture.renderRotation == true && (sprite.rotation !== 0 || sprite.transform.rotationOffset !== 0)) this._sin = 0; this._cos = 1; if(this.parent.texture.renderRotation) { @@ -3099,24 +3092,16 @@ var Phaser; this._cos = Phaser.GameMath.cosA[this.rotation + this.rotationOffset]; } if(this.parent.texture.flippedX) { - //this.local.data[0] = GameMath.cosA[this.rotation + this.rotationOffset] * -this.scale.x; - //this.local.data[3] = (GameMath.sinA[this.rotation + this.rotationOffset] * -this.scale.x) + this.skew.x; this.local.data[0] = this._cos * -this.scale.x; this.local.data[3] = (this._sin * -this.scale.x) + this.skew.x; } else { - //this.local.data[0] = GameMath.cosA[this.rotation + this.rotationOffset] * this.scale.x; - //this.local.data[3] = (GameMath.sinA[this.rotation + this.rotationOffset] * this.scale.x) + this.skew.x; this.local.data[0] = this._cos * this.scale.x; this.local.data[3] = (this._sin * this.scale.x) + this.skew.x; } if(this.parent.texture.flippedY) { - //this.local.data[4] = GameMath.cosA[this.rotation + this.rotationOffset] * -this.scale.y; - //this.local.data[1] = -(GameMath.sinA[this.rotation + this.rotationOffset] * -this.scale.y) + this.skew.y; this.local.data[4] = this._cos * -this.scale.y; this.local.data[1] = -(this._sin * -this.scale.y) + this.skew.y; } else { - //this.local.data[4] = GameMath.cosA[this.rotation + this.rotationOffset] * this.scale.y; - //this.local.data[1] = -(GameMath.sinA[this.rotation + this.rotationOffset] * this.scale.y) + this.skew.y; this.local.data[4] = this._cos * this.scale.y; this.local.data[1] = -(this._sin * this.scale.y) + this.skew.y; } @@ -3124,20 +3109,6 @@ var Phaser; this.local.data[2] = this.parent.x; this.local.data[5] = this.parent.y; }; - Object.defineProperty(Transform.prototype, "calculatedX", { - get: function () { - return this.origin.x * this.scale.x; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Transform.prototype, "calculatedY", { - get: function () { - return this.origin.y * this.scale.y; - }, - enumerable: true, - configurable: true - }); Object.defineProperty(Transform.prototype, "centerX", { get: /** * The center of the Sprite after taking scaling into consideration @@ -4347,6 +4318,7 @@ var Phaser; } this.body = new Phaser.Physics.Body(this, bodyType); this.worldView = new Phaser.Rectangle(x, y, this.width, this.height); + this.cameraView = new Phaser.Rectangle(x, y, this.width, this.height); } Object.defineProperty(Sprite.prototype, "rotation", { get: /** @@ -4422,12 +4394,8 @@ var Phaser; */ function () { this.transform.update(); - //this.worldView.x = this.x * this.transform.scrollFactor.x; - //this.worldView.y = this.y * this.transform.scrollFactor.y; - this.worldView.x = this.x; - this.worldView.y = this.y; - //this.worldView.x = this.x - this.transform.origin.x; - //this.worldView.y = this.y - this.transform.origin.y; + this.worldView.x = this.x * this.transform.scrollFactor.x; + this.worldView.y = this.y * this.transform.scrollFactor.y; this.worldView.width = this.width; this.worldView.height = this.height; if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { @@ -4531,21 +4499,55 @@ var Phaser; (function (Phaser) { var SpriteUtils = (function () { function SpriteUtils() { } - SpriteUtils.inCamera = /** - * Check whether this object is visible in a specific camera Rectangle. - * @param camera {Rectangle} The Rectangle you want to check. - * @return {boolean} Return true if bounds of this sprite intersects the given Rectangle, otherwise return false. + SpriteUtils.updateCameraView = /** + * Updates a Sprites cameraView Rectangle based on the given camera, sprite world position and rotation + * @param camera {Camera} The Camera to use in the view + * @param sprite {Sprite} The Sprite that will have its cameraView property modified + * @return {Rectangle} A reference to the Sprite.cameraView property */ - function inCamera(camera, sprite) { - // Object fixed in place regardless of the camera scrolling? Then it's always visible - if(sprite.transform.scrollFactor.x == 0 && sprite.transform.scrollFactor.y == 0) { - return true; + function updateCameraView(camera, sprite) { + if(sprite.rotation == 0 || sprite.texture.renderRotation == false) { + // Easy out + sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.width * sprite.transform.origin.x)); + sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.height * sprite.transform.origin.y)); + sprite.cameraView.width = sprite.width; + sprite.cameraView.height = sprite.height; + } else { + // If the sprite is rotated around its center we can use this quicker method: + // Work out bounding box + SpriteUtils._sin = Phaser.GameMath.sinA[sprite.rotation]; + SpriteUtils._cos = Phaser.GameMath.cosA[sprite.rotation]; + if(SpriteUtils._sin < 0) { + SpriteUtils._sin = -SpriteUtils._sin; + } + if(SpriteUtils._cos < 0) { + SpriteUtils._cos = -SpriteUtils._cos; + } + sprite.cameraView.width = Math.round(sprite.height * SpriteUtils._sin + sprite.width * SpriteUtils._cos); + sprite.cameraView.height = Math.round(sprite.height * SpriteUtils._cos + sprite.width * SpriteUtils._sin); + // if origin isn't 0.5 we need to work out the difference to apply to the x/y + if(sprite.transform.origin.equals(0.5)) { + // Easy out + sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); + sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); + } else { + //var ax = sprite.cameraView.width * sprite.transform.origin.x; + //var ay = sprite.cameraView.height * sprite.transform.origin.y; + //var bx = sprite.cameraView.width * 0.5; + //var by = sprite.cameraView.height * 0.5; + //var c = sprite.game.math.distanceBetween(ax, ay, bx, by) / 2; + //console.log('actual x', ax, 'actual y', ay, 'cx', bx, 'cy', by); + sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); + sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); + } } - var dx = sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x); - var dy = sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y); - var dw = sprite.width * sprite.transform.scale.x; - var dh = sprite.height * sprite.transform.scale.y; - return (camera.screenView.x + camera.worldView.width > this._dx) && (camera.screenView.x < this._dx + this._dw) && (camera.screenView.y + camera.worldView.height > this._dy) && (camera.screenView.y < this._dy + this._dh); + if(sprite.animations.currentFrame !== null && sprite.animations.currentFrame.trimmed) { + //sprite.cameraView.x += sprite.animations.currentFrame.spriteSourceSizeX; + //sprite.cameraView.y += sprite.animations.currentFrame.spriteSourceSizeY; + //this._dw = sprite.animations.currentFrame.spriteSourceSizeW; + //this._dh = sprite.animations.currentFrame.spriteSourceSizeH; + } + return sprite.cameraView; }; SpriteUtils.getAsPoints = function getAsPoints(sprite) { var out = []; @@ -16409,7 +16411,8 @@ var Phaser; if(sprite.transform.scrollFactor.equals(0)) { return true; } - return Phaser.RectangleUtils.intersects(sprite.worldView, camera.worldView); + Phaser.SpriteUtils.updateCameraView(camera, sprite); + return Phaser.RectangleUtils.intersects(sprite.cameraView, camera.screenView); }; CanvasRenderer.prototype.inScreen = function (camera) { return true; @@ -16574,6 +16577,7 @@ var Phaser; * @return {boolean} Return false if not rendered, otherwise return true. */ function (camera, sprite) { + Phaser.SpriteUtils.updateCameraView(camera, sprite); if(sprite.transform.scale.x == 0 || sprite.transform.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { //return false; } @@ -16769,7 +16773,8 @@ var Phaser; DebugUtils.game.stage.context.fillText('wx: ' + sprite.worldView.x + ' wy: ' + sprite.worldView.y + ' ww: ' + sprite.worldView.width.toFixed(1) + ' wh: ' + sprite.worldView.height.toFixed(1) + ' wb: ' + sprite.worldView.bottom + ' wr: ' + sprite.worldView.right, x, y + 28); DebugUtils.game.stage.context.fillText('sx: ' + sprite.transform.scale.x.toFixed(1) + ' sy: ' + sprite.transform.scale.y.toFixed(1), x, y + 42); DebugUtils.game.stage.context.fillText('tx: ' + sprite.texture.width.toFixed(1) + ' ty: ' + sprite.texture.height.toFixed(1), x, y + 56); - DebugUtils.game.stage.context.fillText('inCamera: ' + DebugUtils.game.renderer.inCamera(DebugUtils.game.camera, sprite), x, y + 70); + DebugUtils.game.stage.context.fillText('cx: ' + sprite.cameraView.x + ' cy: ' + sprite.cameraView.y + ' cw: ' + sprite.cameraView.width + ' ch: ' + sprite.cameraView.height + ' cb: ' + sprite.cameraView.bottom + ' cr: ' + sprite.cameraView.right, x, y + 70); + DebugUtils.game.stage.context.fillText('inCamera: ' + DebugUtils.game.renderer.inCamera(DebugUtils.game.camera, sprite), x, y + 84); }; DebugUtils.renderSpriteBounds = function renderSpriteBounds(sprite, camera, color) { if (typeof camera === "undefined") { camera = null; } From c5f6817c4ca07bcc7e1d65bfcdb1b397b1c09833 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 11 Jun 2013 21:30:15 +0100 Subject: [PATCH 5/8] Working sprite bounds / vertices regardless of scale or rotation --- Phaser/components/Transform.ts | 207 +++++++++++++++--- Phaser/gameobjects/Sprite.ts | 8 +- Phaser/renderers/CanvasRenderer.ts | 4 +- Phaser/utils/SpriteUtils.ts | 132 ++++++++--- README.md | 1 + Tests/Tests.csproj | 12 + Tests/assets/tests/200x100corners.png | Bin 0 -> 357 bytes Tests/assets/tests/200x100corners2.png | Bin 0 -> 500 bytes Tests/assets/tests/320x200.png | Bin 0 -> 708 bytes Tests/assets/tests/320x200g.png | Bin 0 -> 713 bytes Tests/misc/point1.js | 97 +++++++++ Tests/misc/point1.ts | 123 +++++++++++ Tests/misc/point2.js | 56 +++++ Tests/misc/point2.ts | 76 +++++++ Tests/misc/point3.js | 57 +++++ Tests/misc/point3.ts | 77 +++++++ Tests/phaser.js | 290 ++++++++++++++++++++----- Tests/sprites/origin 5.js | 207 ++++++++++++++++-- Tests/sprites/origin 5.ts | 225 +++++++++++++++++-- build/phaser.d.ts | 59 ++++- build/phaser.js | 290 ++++++++++++++++++++----- 21 files changed, 1718 insertions(+), 203 deletions(-) create mode 100644 Tests/assets/tests/200x100corners.png create mode 100644 Tests/assets/tests/200x100corners2.png create mode 100644 Tests/assets/tests/320x200.png create mode 100644 Tests/assets/tests/320x200g.png create mode 100644 Tests/misc/point1.js create mode 100644 Tests/misc/point1.ts create mode 100644 Tests/misc/point2.js create mode 100644 Tests/misc/point2.ts create mode 100644 Tests/misc/point3.js create mode 100644 Tests/misc/point3.ts diff --git a/Phaser/components/Transform.ts b/Phaser/components/Transform.ts index 206a3fbe..bc9830da 100644 --- a/Phaser/components/Transform.ts +++ b/Phaser/components/Transform.ts @@ -27,44 +27,135 @@ module Phaser.Components { } - private _sin: number; - private _cos: number; + private _rotation: number; + + private _cachedSin: number; + private _cachedCos: number; + private _cachedRotation: number; + private _cachedScaleX: number; + private _cachedScaleY: number; + private _cachedAngle: number; + private _cachedAngleToCenter: number; + private _cachedDistance: number; + private _cachedWidth: number; + private _cachedHeight: number; + private _cachedHalfWidth: number; + private _cachedHalfHeight: number; + private _cachedCosAngle: number; + private _cachedSinAngle: number; + private _cachedOffsetX: number; + private _cachedOffsetY: number; + private _cachedOriginX: number; + private _cachedOriginY: number; + private _cachedCenterX: number; + private _cachedCenterY: number; public local: Mat3; - public update() { + public setCache() { - // Scale & Skew + this._cachedHalfWidth = this.parent.width / 2; + this._cachedHalfHeight = this.parent.height / 2; + this._cachedOffsetX = this.origin.x * this.parent.width; + this._cachedOffsetY = this.origin.y * this.parent.height; + this._cachedAngleToCenter = Math.atan2(this.halfHeight - this._cachedOffsetY, this.halfWidth - this._cachedOffsetX); + this._cachedDistance = Math.sqrt(((this._cachedOffsetX - this._cachedHalfWidth) * (this._cachedOffsetX - this._cachedHalfWidth)) + ((this._cachedOffsetY - this._cachedHalfHeight) * (this._cachedOffsetY - this._cachedHalfHeight))); + this._cachedWidth = this.parent.width; + this._cachedHeight = this.parent.height; + this._cachedOriginX = this.origin.x; + this._cachedOriginY = this.origin.y; + this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._cachedCosAngle = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + this._cachedSinAngle = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + this._cachedRotation = this.rotation; - this._sin = 0; - this._cos = 1; - - if (this.parent.texture.renderRotation) + if (this.parent.texture && this.parent.texture.renderRotation) { - this._sin = GameMath.sinA[this.rotation + this.rotationOffset]; - this._cos = GameMath.cosA[this.rotation + this.rotationOffset]; - } - - if (this.parent.texture.flippedX) - { - this.local.data[0] = this._cos * -this.scale.x; - this.local.data[3] = (this._sin * -this.scale.x) + this.skew.x; + this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); } else { - this.local.data[0] = this._cos * this.scale.x; - this.local.data[3] = (this._sin * this.scale.x) + this.skew.x; + this._cachedSin = 0; + this._cachedCos = 1; + } + + } + + public update() { + + // Check cache + var dirty: bool = false; + + // 1) Height or Width change (also triggered by a change in scale) or an Origin change + if (this.parent.width !== this._cachedWidth || this.parent.height !== this._cachedHeight || this.origin.x !== this._cachedOriginX|| this.origin.y !== this._cachedOriginY) + { + this._cachedHalfWidth = this.parent.width / 2; + this._cachedHalfHeight = this.parent.height / 2; + this._cachedOffsetX = this.origin.x * this.parent.width; + this._cachedOffsetY = this.origin.y * this.parent.height; + this._cachedAngleToCenter = Math.atan2(this.halfHeight - this._cachedOffsetY, this.halfWidth - this._cachedOffsetX); + this._cachedDistance = Math.sqrt(((this._cachedOffsetX - this._cachedHalfWidth) * (this._cachedOffsetX - this._cachedHalfWidth)) + ((this._cachedOffsetY - this._cachedHalfHeight) * (this._cachedOffsetY - this._cachedHalfHeight))); + // Store + this._cachedWidth = this.parent.width; + this._cachedHeight = this.parent.height; + this._cachedOriginX = this.origin.x; + this._cachedOriginY = this.origin.y; + dirty = true; + } + + // 2) Rotation change + if (this.rotation != this._cachedRotation) + { + this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._cachedCosAngle = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + this._cachedSinAngle = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + + if (this.parent.texture.renderRotation) + { + this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + } + else + { + this._cachedSin = 0; + this._cachedCos = 1; + } + + // Store + this._cachedRotation = this.rotation; + dirty = true; + } + + if (dirty) + { + this._cachedCenterX = this.parent.x + this._cachedDistance * this._cachedCosAngle; + this._cachedCenterY = this.parent.y + this._cachedDistance * this._cachedSinAngle; + } + + // Scale and Skew + if (this.parent.texture.flippedX) + { + this.local.data[0] = this._cachedCos * -this.scale.x; + this.local.data[3] = (this._cachedSin * -this.scale.x) + this.skew.x; + } + else + { + this.local.data[0] = this._cachedCos * this.scale.x; + this.local.data[3] = (this._cachedSin * this.scale.x) + this.skew.x; } if (this.parent.texture.flippedY) { - this.local.data[4] = this._cos * -this.scale.y; - this.local.data[1] = -(this._sin * -this.scale.y) + this.skew.y; + this.local.data[4] = this._cachedCos * -this.scale.y; + this.local.data[1] = -(this._cachedSin * -this.scale.y) + this.skew.y; } else { - this.local.data[4] = this._cos * this.scale.y; - this.local.data[1] = -(this._sin * this.scale.y) + this.skew.y; + this.local.data[4] = this._cachedCos * this.scale.y; + this.local.data[1] = -(this._cachedSin * this.scale.y) + this.skew.y; } // Translate @@ -99,7 +190,7 @@ module Phaser.Components { public scrollFactor: Phaser.Vec2; /** - * The origin is the point around which scale and rotation takes place and defaults to the center of the sprite. + * The origin is the point around which scale and rotation takes place and defaults to the top-left of the sprite. */ public origin: Phaser.Vec2; @@ -117,17 +208,75 @@ module Phaser.Components { public rotation: number = 0; /** - * The center of the Sprite after taking scaling into consideration - */ - public get centerX(): number { - return this.parent.width / 2; + * The distance from the center of the transform to the rotation origin. + */ + public get distance(): number { + return this._cachedDistance; + //return Math.sqrt(((this.offsetX - this.halfWidth) * (this.offsetX - this.halfWidth)) + ((this.offsetY - this.halfHeight) * (this.offsetY - this.halfHeight))); } /** - * The center of the Sprite after taking scaling into consideration + * The angle between the center of the transform to the rotation origin. + */ + public get angleToCenter(): number { + return this._cachedAngleToCenter; + //return Math.atan2(this.halfHeight - this.offsetY, this.halfWidth - this.offsetX); + } + + /** + * The offset on the X axis of the origin + */ + public get offsetX(): number { + return this._cachedOffsetX; + //return this.origin.x * this.parent.width; + } + + /** + * The offset on the Y axis of the origin + */ + public get offsetY(): number { + return this._cachedOffsetY; + //return this.origin.y * this.parent.height; + } + + /** + * Half the width of the parent sprite, taking into consideration scaling + */ + public get halfWidth(): number { + return this._cachedHalfWidth; + //return this.parent.width / 2; + } + + /** + * Half the height of the parent sprite, taking into consideration scaling + */ + public get halfHeight(): number { + return this._cachedHalfHeight; + //return this.parent.height / 2; + } + + /** + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ + public get centerX(): number { + return this._cachedCenterX; + //return this.parent.x + this.distance * Math.cos((this.rotation * Math.PI / 180) + this.angleToCenter); + } + + /** + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration */ public get centerY(): number { - return this.parent.height / 2; + return this._cachedCenterY; + //return this.parent.y + this.distance * Math.sin((this.rotation * Math.PI / 180) + this.angleToCenter); + } + + public get sin(): number { + return this._cachedSin; + } + + public get cos(): number { + return this._cachedCos; } } diff --git a/Phaser/gameobjects/Sprite.ts b/Phaser/gameobjects/Sprite.ts index 7cd30f57..74d2176d 100644 --- a/Phaser/gameobjects/Sprite.ts +++ b/Phaser/gameobjects/Sprite.ts @@ -72,6 +72,8 @@ module Phaser { this.worldView = new Rectangle(x, y, this.width, this.height); this.cameraView = new Rectangle(x, y, this.width, this.height); + this.transform.setCache(); + } /** @@ -243,8 +245,10 @@ module Phaser { this.transform.update(); - this.worldView.x = this.x * this.transform.scrollFactor.x; - this.worldView.y = this.y * this.transform.scrollFactor.y; + this.worldView.x = (this.x * this.transform.scrollFactor.x) - (this.width * this.transform.origin.x); + this.worldView.y = (this.y * this.transform.scrollFactor.y) - (this.height * this.transform.origin.y); + //this.worldView.x = this.x * this.transform.scrollFactor.x; + //this.worldView.y = this.y * this.transform.scrollFactor.y; this.worldView.width = this.width; this.worldView.height = this.height; diff --git a/Phaser/renderers/CanvasRenderer.ts b/Phaser/renderers/CanvasRenderer.ts index 8535068c..c3558af4 100644 --- a/Phaser/renderers/CanvasRenderer.ts +++ b/Phaser/renderers/CanvasRenderer.ts @@ -221,8 +221,6 @@ module Phaser { return true; } - Phaser.SpriteUtils.updateCameraView(camera, sprite); - return RectangleUtils.intersects(sprite.cameraView, camera.screenView); } @@ -447,7 +445,7 @@ module Phaser { if (sprite.transform.scale.x == 0 || sprite.transform.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { - //return false; + return false; } sprite.renderOrderID = this._count; diff --git a/Phaser/utils/SpriteUtils.ts b/Phaser/utils/SpriteUtils.ts index 29b844d4..1a3e4875 100644 --- a/Phaser/utils/SpriteUtils.ts +++ b/Phaser/utils/SpriteUtils.ts @@ -38,43 +38,39 @@ module Phaser { else { // If the sprite is rotated around its center we can use this quicker method: - - // Work out bounding box - SpriteUtils._sin = Phaser.GameMath.sinA[sprite.rotation]; - SpriteUtils._cos = Phaser.GameMath.cosA[sprite.rotation]; - - if (SpriteUtils._sin < 0) + if (sprite.transform.origin.x == 0.5 && sprite.transform.origin.y == 0.5) { - SpriteUtils._sin = -SpriteUtils._sin; - } + SpriteUtils._sin = Math.sin((sprite.rotation + sprite.transform.rotationOffset) * GameMath.DEG_TO_RAD); + SpriteUtils._cos = Math.cos((sprite.rotation + sprite.transform.rotationOffset) * GameMath.DEG_TO_RAD); - if (SpriteUtils._cos < 0) - { - SpriteUtils._cos = -SpriteUtils._cos; - } + if (SpriteUtils._sin < 0) + { + SpriteUtils._sin = -SpriteUtils._sin; + } - sprite.cameraView.width = Math.round(sprite.height * SpriteUtils._sin + sprite.width * SpriteUtils._cos); - sprite.cameraView.height = Math.round(sprite.height * SpriteUtils._cos + sprite.width * SpriteUtils._sin); + if (SpriteUtils._cos < 0) + { + SpriteUtils._cos = -SpriteUtils._cos; + } - // if origin isn't 0.5 we need to work out the difference to apply to the x/y - if (sprite.transform.origin.equals(0.5)) - { - // Easy out + sprite.cameraView.width = Math.round(sprite.height * SpriteUtils._sin + sprite.width * SpriteUtils._cos); + sprite.cameraView.height = Math.round(sprite.height * SpriteUtils._cos + sprite.width * SpriteUtils._sin); sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); } else { - //var ax = sprite.cameraView.width * sprite.transform.origin.x; - //var ay = sprite.cameraView.height * sprite.transform.origin.y; - //var bx = sprite.cameraView.width * 0.5; - //var by = sprite.cameraView.height * 0.5; - //var c = sprite.game.math.distanceBetween(ax, ay, bx, by) / 2; - //console.log('actual x', ax, 'actual y', ay, 'cx', bx, 'cy', by); - sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); - sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); + + /* + // Useful to get the maximum AABB size of any given rect + + If you want a single box that covers all angles, just take the half-diagonal of your existing box as the radius of a circle. + The new box has to contain this circle, so it should be a square with side-length equal to twice the radius + (equiv. the diagonal of the original AABB) and with the same center as the original. + */ + } } @@ -91,6 +87,90 @@ module Phaser { } + static getCornersAsPoints(sprite: Sprite): Phaser.Point[] { + + var out: Phaser.Point[] = []; + + var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + + // Upper Left + out.push(new Point(sprite.x + (sprite.width / 2) * cos - (sprite.height / 2) * sin, sprite.y + (sprite.height / 2) * cos + (sprite.width / 2) * sin)); + + // Upper Right + out.push(new Point(sprite.x - (sprite.width / 2) * cos - (sprite.height / 2) * sin, sprite.y + (sprite.height / 2) * cos - (sprite.width / 2) * sin)); + + // Bottom Left + out.push(new Point(sprite.x + (sprite.width / 2) * cos + (sprite.height / 2) * sin, sprite.y - (sprite.height / 2) * cos + (sprite.width / 2) * sin)); + + // Bottom Right + out.push(new Point(sprite.x - (sprite.width / 2) * cos + (sprite.height / 2) * sin, sprite.y - (sprite.height / 2) * cos - (sprite.width / 2) * sin)); + + return out; + + } + + static getCornersAsPoints2(sprite: Sprite): Phaser.Point[] { + + var out: Phaser.Point[] = []; + + var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + + // This = the center point + var cx = sprite.x + (sprite.width / 2) * cos - (sprite.height / 2) * sin; + var cy = sprite.y + (sprite.height / 2) * cos + (sprite.width / 2) * sin; + + // Upper Left + out.push(new Point(cx + (sprite.width / 2) * cos - (sprite.height / 2) * sin, cy + (sprite.height / 2) * cos + (sprite.width / 2) * sin)); + + // Upper Right + out.push(new Point(cx - (sprite.width / 2) * cos - (sprite.height / 2) * sin, cy + (sprite.height / 2) * cos - (sprite.width / 2) * sin)); + + // Bottom Left + out.push(new Point(cx + (sprite.width / 2) * cos + (sprite.height / 2) * sin, cy - (sprite.height / 2) * cos + (sprite.width / 2) * sin)); + + // Bottom Right + out.push(new Point(cx - (sprite.width / 2) * cos + (sprite.height / 2) * sin, cy - (sprite.height / 2) * cos - (sprite.width / 2) * sin)); + + return out; + + } + + static getCornersAsPoints3(sprite: Sprite): Phaser.Point[] { + + var out: Phaser.Point[] = []; + + var sin: number = sprite.transform.sin; + var cos: number = sprite.transform.cos; + + //var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + //var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + + // This = the center point + //var cx = sprite.x + sprite.transform.distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); + //var cy = sprite.y + sprite.transform.distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); + + var cx: number = sprite.transform.centerX; + var cy: number = sprite.transform.centerY; + + // Upper Left + out.push(new Point(cx + sprite.transform.halfWidth * cos - sprite.transform.halfHeight * sin, cy + sprite.transform.halfHeight * cos + sprite.transform.halfWidth * sin)); + + // Upper Right + out.push(new Point(cx - sprite.transform.halfWidth * cos - sprite.transform.halfHeight * sin, cy + sprite.transform.halfHeight * cos - sprite.transform.halfWidth * sin)); + + // Bottom Left + out.push(new Point(cx + sprite.transform.halfWidth * cos + sprite.transform.halfHeight * sin, cy - sprite.transform.halfHeight * cos + sprite.transform.halfWidth * sin)); + + // Bottom Right + out.push(new Point(cx - sprite.transform.halfWidth * cos + sprite.transform.halfHeight * sin, cy - sprite.transform.halfHeight * cos - sprite.transform.halfWidth * sin)); + + return out; + + } + + static getAsPoints(sprite: Sprite): Phaser.Point[] { var out: Phaser.Point[] = []; diff --git a/README.md b/README.md index 8c7c8478..3abe1513 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ TODO: * Swap to using time based motion (like the tweens) rather than delta timer - it just doesn't work well on slow phones * Pointer.getWorldX(camera) needs to take camera scale into consideration * Add a 'click to bring to top' demo (+ Group feature?) +* If stage.clear set to false and game pauses, when it unpauses you still see the pause arrow - resolve this * Add clip support + shape options to Texture Component. diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index e26a5666..405475d7 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -128,6 +128,18 @@ world drag.ts + + + point1.ts + + + + point2.ts + + + + point3.ts + sprite test 1.ts diff --git a/Tests/assets/tests/200x100corners.png b/Tests/assets/tests/200x100corners.png new file mode 100644 index 0000000000000000000000000000000000000000..6cb5cda733f1b8025c9078aed99880e2b0626278 GIT binary patch literal 357 zcmeAS@N?(olHy`uVBq!ia0vp^CxAGGgAGU?ZmZ`8Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07#P_-T^vIyZoRqc$kkxL<9g7g>c6)8!n~Fny&SP;7L@#d zIB`wKYi6s*b;e%mA0|Y$i$1u^bL4A-t3rc=gMxy900##P3lkG#V}k<&5EBw&0INh% zg(B3_Z}hz1A>&bphBHTttD4%4;|2%aPJJwJglR#t48U}fi7AzZCsS=07#OE{x;TbZ+Nw+`R>B`J2u+0{y&OYQYLq-`1taL2U5cX7CI;j zEIiQV(88q6B*?{dv+St82+JnZDT%`W0yaNCoUBoJqsI0CSCGK+v^5$WE@1TJ!DDXL zMh+;-f{H@qTr>(cIkYr^P#>?Wj?5yAmUv_qP2GGfpNx30R{c%64hK%;X<8jV?{C ztLj`L)GHWL-P`2gpr9Ziz`?-+!YoWojExPrg&-O25OBZH@_pUXO@geCxZpPEPj literal 0 HcmV?d00001 diff --git a/Tests/assets/tests/320x200.png b/Tests/assets/tests/320x200.png new file mode 100644 index 0000000000000000000000000000000000000000..b88b121387dd5cbe513590164f56662164f3ea70 GIT binary patch literal 708 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoPjIjS$(bw`tAUhciEBhjaDG}zd16s2gJVj5 zQmTSyZen_BP-c4PQb83-K!hs;muZ1%j>wi9-9slm}77-?o z4h1f`bq7Fl4Gi8t**Gj1!AuGXh;3jiDIzG+4Dl4iCkX#kvlU#sbcVsDc>8%yfdW=G w0fz>KPkYuK>YrXaXBlJJr?>UTqZ=3*+P7%7PL8zw3`~{`p00i_>zopr0Msyv@c;k- literal 0 HcmV?d00001 diff --git a/Tests/assets/tests/320x200g.png b/Tests/assets/tests/320x200g.png new file mode 100644 index 0000000000000000000000000000000000000000..dcdd505e8c035ccb0bc94c0e0e9b48d97fd088be GIT binary patch literal 713 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoPjIjS$(bw`tAUhciEBhjaDG}zd16s2gJVj5 zQmTSyZen_BP-6tPJ-s$jQN`LaZpN7ZUWE=)NlycC&;cT*SNj$HqgId9~P`$F8aYgJiqSonr%~ZxfoNd zlJ8XgVc`!?U|?hsaA06eiM#h7M1wiF3EVP7Xhu?k#3XDf9>pYSez1*U+S?mz86$l2 z=L;)5;Nk%WO?O8+$8(D{x~Z!f(~7?Cf2@3f;q+R~?t?cinSp7O!PC{xWt~$(6993U BkN5xp literal 0 HcmV?d00001 diff --git a/Tests/misc/point1.js b/Tests/misc/point1.js new file mode 100644 index 00000000..5e4d49de --- /dev/null +++ b/Tests/misc/point1.js @@ -0,0 +1,97 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); + function init() { + game.load.image('box2', 'assets/tests/320x200.png'); + game.load.image('box1', 'assets/sprites/oz_pov_melting_disk.png'); + game.load.image('box', 'assets/sprites/bunny.png'); + game.load.start(); + } + var sprite; + var rotate = false; + function create() { + game.stage.backgroundColor = 'rgb(0,0,0)'; + game.stage.disablePauseScreen = true; + sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); + //sprite.transform.scale.setTo(0.5, 0.5); + sprite.transform.origin.setTo(0.3, 0.3); + game.input.onTap.add(rotateIt, this); + game.add.tween(sprite.transform.scale).to({ + x: 0.5, + y: 0.5 + }, 2000, Phaser.Easing.Linear.None, true, 0, true); + points = [ + new Phaser.Point(), + new Phaser.Point(), + new Phaser.Point(), + new Phaser.Point() + ]; + } + function rotateIt() { + if(rotate == false) { + rotate = true; + } else { + rotate = false; + } + } + function update() { + if(rotate) { + sprite.rotation++; + } + } + var points; + function render() { + /* + points = Phaser.SpriteUtils.getCornersAsPoints3(sprite); + + game.stage.context.fillStyle = 'rgb(255,255,0)'; + game.stage.context.fillRect(points[0].x, points[0].y, 2, 2); + game.stage.context.fillRect(points[1].x, points[1].y, 2, 2); + game.stage.context.fillRect(points[2].x, points[2].y, 2, 2); + game.stage.context.fillRect(points[3].x, points[3].y, 2, 2); + */ + var originX = sprite.transform.origin.x * sprite.width; + var originY = sprite.transform.origin.y * sprite.height; + var centerX = 0.5 * sprite.width; + var centerY = 0.5 * sprite.height; + var distance = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); + var originAngle = Math.atan2(centerY - originY, centerX - originX); + var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + //var px = sprite.x + distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + originAngle); + //var py = sprite.y + distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + originAngle); + // WORKS + //var px = sprite.x + sprite.transform.distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); + //var py = sprite.y + sprite.transform.distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); + // Upper Left + //points[0].setTo(px + (sprite.width / 2) * cos - (sprite.height / 2) * sin, py + (sprite.height / 2) * cos + (sprite.width / 2) * sin); + // Upper Right + //points[1].setTo(px - (sprite.width / 2) * cos - (sprite.height / 2) * sin, py + (sprite.height / 2) * cos - (sprite.width / 2) * sin); + // Bottom Left + //points[2].setTo(px + (sprite.width / 2) * cos + (sprite.height / 2) * sin, py - (sprite.height / 2) * cos + (sprite.width / 2) * sin); + // Bottom Right + //points[3].setTo(px - (sprite.width / 2) * cos + (sprite.height / 2) * sin, py - (sprite.height / 2) * cos - (sprite.width / 2) * sin); + points = Phaser.SpriteUtils.getCornersAsPoints3(sprite); + game.stage.context.save(); + game.stage.context.fillStyle = 'rgb(0,255,255)'; + //game.stage.context.fillRect(px, py, 2, 2); + game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); + game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); + game.stage.context.fillText('angle: ' + sprite.rotation, 32, 72); + game.stage.context.fillText('point of rotation x: ' + sprite.transform.origin.x + ' y: ' + sprite.transform.origin.y, 32, 92); + game.stage.context.fillText('x: ' + sprite.x + ' y: ' + sprite.y, sprite.x + 4, sprite.y); + game.stage.context.fillRect(points[0].x, points[0].y, 2, 2); + game.stage.context.fillRect(points[1].x, points[1].y, 2, 2); + game.stage.context.fillRect(points[2].x, points[2].y, 2, 2); + game.stage.context.fillRect(points[3].x, points[3].y, 2, 2); + game.stage.context.restore(); + game.stage.context.save(); + game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; + game.stage.context.beginPath(); + game.stage.context.moveTo(sprite.x, sprite.y); + game.stage.context.arc(sprite.x, sprite.y, distance, 0, Math.PI * 2); + game.stage.context.closePath(); + game.stage.context.fill(); + game.stage.context.restore(); + } +})(); diff --git a/Tests/misc/point1.ts b/Tests/misc/point1.ts new file mode 100644 index 00000000..55bf59b9 --- /dev/null +++ b/Tests/misc/point1.ts @@ -0,0 +1,123 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); + + function init() { + + game.load.image('box2', 'assets/tests/320x200.png'); + game.load.image('box1', 'assets/sprites/oz_pov_melting_disk.png'); + game.load.image('box', 'assets/sprites/bunny.png'); + game.load.start(); + + } + + var sprite: Phaser.Sprite; + var rotate: bool = false; + + function create() { + + game.stage.backgroundColor = 'rgb(0,0,0)'; + game.stage.disablePauseScreen = true; + + sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); + + //sprite.transform.scale.setTo(0.5, 0.5); + + sprite.transform.origin.setTo(0.3, 0.3); + + game.input.onTap.add(rotateIt, this); + + game.add.tween(sprite.transform.scale).to({ x: 0.5, y: 0.5 }, 2000, Phaser.Easing.Linear.None, true, 0, true); + + points = [new Phaser.Point, new Phaser.Point, new Phaser.Point, new Phaser.Point]; + + } + + function rotateIt() { + if (rotate == false) { rotate = true; } else { rotate = false; } + } + + function update() { + + if (rotate) + { + sprite.rotation++; + } + + } + + var points: Phaser.Point[]; + + function render() { + + /* + points = Phaser.SpriteUtils.getCornersAsPoints3(sprite); + + game.stage.context.fillStyle = 'rgb(255,255,0)'; + game.stage.context.fillRect(points[0].x, points[0].y, 2, 2); + game.stage.context.fillRect(points[1].x, points[1].y, 2, 2); + game.stage.context.fillRect(points[2].x, points[2].y, 2, 2); + game.stage.context.fillRect(points[3].x, points[3].y, 2, 2); + */ + + var originX: number = sprite.transform.origin.x * sprite.width; + var originY: number = sprite.transform.origin.y * sprite.height; + var centerX: number = 0.5 * sprite.width; + var centerY: number = 0.5 * sprite.height; + var distance: number = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); + var originAngle: number = Math.atan2(centerY - originY, centerX - originX); + + var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + + //var px = sprite.x + distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + originAngle); + //var py = sprite.y + distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + originAngle); + + // WORKS + //var px = sprite.x + sprite.transform.distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); + //var py = sprite.y + sprite.transform.distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); + + // Upper Left + //points[0].setTo(px + (sprite.width / 2) * cos - (sprite.height / 2) * sin, py + (sprite.height / 2) * cos + (sprite.width / 2) * sin); + + // Upper Right + //points[1].setTo(px - (sprite.width / 2) * cos - (sprite.height / 2) * sin, py + (sprite.height / 2) * cos - (sprite.width / 2) * sin); + + // Bottom Left + //points[2].setTo(px + (sprite.width / 2) * cos + (sprite.height / 2) * sin, py - (sprite.height / 2) * cos + (sprite.width / 2) * sin); + + // Bottom Right + //points[3].setTo(px - (sprite.width / 2) * cos + (sprite.height / 2) * sin, py - (sprite.height / 2) * cos - (sprite.width / 2) * sin); + + points = Phaser.SpriteUtils.getCornersAsPoints3(sprite); + + game.stage.context.save(); + game.stage.context.fillStyle = 'rgb(0,255,255)'; + //game.stage.context.fillRect(px, py, 2, 2); + game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); + game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); + game.stage.context.fillText('angle: ' + sprite.rotation , 32, 72); + game.stage.context.fillText('point of rotation x: ' + sprite.transform.origin.x + ' y: ' + sprite.transform.origin.y, 32, 92); + game.stage.context.fillText('x: ' + sprite.x + ' y: ' + sprite.y, sprite.x + 4, sprite.y); + + game.stage.context.fillRect(points[0].x, points[0].y, 2, 2); + game.stage.context.fillRect(points[1].x, points[1].y, 2, 2); + game.stage.context.fillRect(points[2].x, points[2].y, 2, 2); + game.stage.context.fillRect(points[3].x, points[3].y, 2, 2); + + game.stage.context.restore(); + + game.stage.context.save(); + game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; + game.stage.context.beginPath(); + game.stage.context.moveTo(sprite.x, sprite.y); + game.stage.context.arc(sprite.x, sprite.y, distance, 0, Math.PI * 2); + game.stage.context.closePath(); + game.stage.context.fill(); + game.stage.context.restore(); + + } + +})(); diff --git a/Tests/misc/point2.js b/Tests/misc/point2.js new file mode 100644 index 00000000..2b16e544 --- /dev/null +++ b/Tests/misc/point2.js @@ -0,0 +1,56 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); + function init() { + game.load.image('box', 'assets/tests/320x200.png'); + game.load.start(); + } + var sprite; + var rotate = false; + function create() { + game.stage.backgroundColor = 'rgb(0,0,0)'; + game.stage.disablePauseScreen = true; + sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); + sprite.transform.origin.setTo(0, 0); + game.input.onTap.add(rotateIt, this); + } + function rotateIt() { + if(rotate == false) { + rotate = true; + } else { + rotate = false; + } + } + function update() { + if(rotate) { + sprite.rotation++; + } + } + function render() { + var originX = sprite.transform.origin.x * sprite.width; + var originY = sprite.transform.origin.y * sprite.height; + var centerX = 0.5 * sprite.width; + var centerY = 0.5 * sprite.height; + var distanceX = originX - centerX; + var distanceY = originY - centerY; + var distance = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); + var px = sprite.x + distance * Math.cos(sprite.transform.rotation + 45 * Math.PI / 180); + var py = sprite.y + distance * Math.sin(sprite.transform.rotation + 45 * Math.PI / 180); + game.stage.context.save(); + game.stage.context.fillStyle = 'rgb(255,255,0)'; + game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); + game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); + game.stage.context.fillText('angle: ' + sprite.rotation, 32, 72); + game.stage.context.fillText('point of rotation x: ' + sprite.transform.origin.x + ' y: ' + sprite.transform.origin.y, 32, 92); + game.stage.context.fillText('x: ' + sprite.x + ' y: ' + sprite.y, sprite.x + 4, sprite.y); + game.stage.context.restore(); + game.stage.context.save(); + game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; + game.stage.context.beginPath(); + game.stage.context.moveTo(sprite.x, sprite.y); + game.stage.context.arc(sprite.x, sprite.y, distance, 0, Math.PI * 2); + game.stage.context.closePath(); + game.stage.context.fill(); + game.stage.context.restore(); + } +})(); diff --git a/Tests/misc/point2.ts b/Tests/misc/point2.ts new file mode 100644 index 00000000..ba3161e4 --- /dev/null +++ b/Tests/misc/point2.ts @@ -0,0 +1,76 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); + + function init() { + + game.load.image('box', 'assets/tests/320x200.png'); + game.load.start(); + + } + + var sprite: Phaser.Sprite; + var rotate: bool = false; + + function create() { + + game.stage.backgroundColor = 'rgb(0,0,0)'; + game.stage.disablePauseScreen = true; + + sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); + + sprite.transform.origin.setTo(0, 0); + + game.input.onTap.add(rotateIt, this); + + } + + function rotateIt() { + if (rotate == false) { rotate = true; } else { rotate = false; } + } + + function update() { + + if (rotate) + { + sprite.rotation++; + } + + } + + function render() { + + var originX: number = sprite.transform.origin.x * sprite.width; + var originY: number = sprite.transform.origin.y * sprite.height; + var centerX: number = 0.5 * sprite.width; + var centerY: number = 0.5 * sprite.height; + var distanceX: number = originX - centerX; + var distanceY: number = originY - centerY; + var distance: number = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); + + var px = sprite.x + distance * Math.cos(sprite.transform.rotation + 45 * Math.PI / 180); + var py = sprite.y + distance * Math.sin(sprite.transform.rotation + 45 * Math.PI / 180); + + game.stage.context.save(); + game.stage.context.fillStyle = 'rgb(255,255,0)'; + game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); + game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); + game.stage.context.fillText('angle: ' + sprite.rotation , 32, 72); + game.stage.context.fillText('point of rotation x: ' + sprite.transform.origin.x + ' y: ' + sprite.transform.origin.y, 32, 92); + game.stage.context.fillText('x: ' + sprite.x + ' y: ' + sprite.y, sprite.x + 4, sprite.y); + game.stage.context.restore(); + + game.stage.context.save(); + game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; + game.stage.context.beginPath(); + game.stage.context.moveTo(sprite.x, sprite.y); + game.stage.context.arc(sprite.x, sprite.y, distance, 0, Math.PI * 2); + game.stage.context.closePath(); + game.stage.context.fill(); + game.stage.context.restore(); + + } + +})(); diff --git a/Tests/misc/point3.js b/Tests/misc/point3.js new file mode 100644 index 00000000..5a0ce273 --- /dev/null +++ b/Tests/misc/point3.js @@ -0,0 +1,57 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); + function init() { + game.load.image('box', 'assets/tests/320x200.png'); + game.load.start(); + } + var sprite; + var rotate = false; + function create() { + game.stage.backgroundColor = 'rgb(0,0,0)'; + game.stage.disablePauseScreen = true; + sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); + sprite.transform.origin.setTo(0.3, 0.8); + game.input.onTap.add(rotateIt, this); + } + function rotateIt() { + if(rotate == false) { + rotate = true; + } else { + rotate = false; + } + } + function update() { + if(rotate) { + sprite.rotation++; + } + } + function render() { + var originX = sprite.transform.origin.x * sprite.width; + var originY = sprite.transform.origin.y * sprite.height; + var centerX = 0.5 * sprite.width; + var centerY = 0.5 * sprite.height; + var distanceX = originX - centerX; + var distanceY = originY - centerY; + var distance = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); + var px = sprite.x + distance * Math.cos(sprite.transform.rotation + 45 * Math.PI / 180); + var py = sprite.y + distance * Math.sin(sprite.transform.rotation + 45 * Math.PI / 180); + game.stage.context.save(); + game.stage.context.fillStyle = 'rgb(255,255,0)'; + game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); + game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); + game.stage.context.fillText('angle: ' + sprite.rotation, 32, 72); + game.stage.context.fillText('point of rotation x: ' + sprite.transform.origin.x + ' y: ' + sprite.transform.origin.y, 32, 92); + game.stage.context.fillText('sprite x: ' + sprite.x + ' sprite y: ' + sprite.y, 32, 112); + game.stage.context.fillRect(sprite.x, sprite.y, 2, 2); + game.stage.context.restore(); + game.stage.context.save(); + game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; + game.stage.context.beginPath(); + game.stage.context.moveTo(sprite.x, sprite.y); + game.stage.context.arc(sprite.x, sprite.y, distance, 0, Math.PI * 2); + game.stage.context.closePath(); + game.stage.context.fill(); + game.stage.context.restore(); + } +})(); diff --git a/Tests/misc/point3.ts b/Tests/misc/point3.ts new file mode 100644 index 00000000..388acec8 --- /dev/null +++ b/Tests/misc/point3.ts @@ -0,0 +1,77 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); + + function init() { + + game.load.image('box', 'assets/tests/320x200.png'); + game.load.start(); + + } + + var sprite: Phaser.Sprite; + var rotate: bool = false; + + function create() { + + game.stage.backgroundColor = 'rgb(0,0,0)'; + game.stage.disablePauseScreen = true; + + sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); + + sprite.transform.origin.setTo(0.3, 0.8); + + game.input.onTap.add(rotateIt, this); + + } + + function rotateIt() { + if (rotate == false) { rotate = true; } else { rotate = false; } + } + + function update() { + + if (rotate) + { + sprite.rotation++; + } + + } + + function render() { + + var originX: number = sprite.transform.origin.x * sprite.width; + var originY: number = sprite.transform.origin.y * sprite.height; + var centerX: number = 0.5 * sprite.width; + var centerY: number = 0.5 * sprite.height; + var distanceX: number = originX - centerX; + var distanceY: number = originY - centerY; + var distance: number = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); + + var px = sprite.x + distance * Math.cos(sprite.transform.rotation + 45 * Math.PI / 180); + var py = sprite.y + distance * Math.sin(sprite.transform.rotation + 45 * Math.PI / 180); + + game.stage.context.save(); + game.stage.context.fillStyle = 'rgb(255,255,0)'; + game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); + game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); + game.stage.context.fillText('angle: ' + sprite.rotation , 32, 72); + game.stage.context.fillText('point of rotation x: ' + sprite.transform.origin.x + ' y: ' + sprite.transform.origin.y, 32, 92); + game.stage.context.fillText('sprite x: ' + sprite.x + ' sprite y: ' + sprite.y, 32, 112); + game.stage.context.fillRect(sprite.x, sprite.y, 2, 2); + game.stage.context.restore(); + + game.stage.context.save(); + game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; + game.stage.context.beginPath(); + game.stage.context.moveTo(sprite.x, sprite.y); + game.stage.context.arc(sprite.x, sprite.y, distance, 0, Math.PI * 2); + game.stage.context.closePath(); + game.stage.context.fill(); + game.stage.context.restore(); + + } + +})(); diff --git a/Tests/phaser.js b/Tests/phaser.js index 3cd97fca..279c2dfc 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -3083,48 +3083,186 @@ var Phaser; this.scale = new Phaser.Vec2(1, 1); this.skew = new Phaser.Vec2(); } - Transform.prototype.update = function () { - // Scale & Skew - this._sin = 0; - this._cos = 1; - if(this.parent.texture.renderRotation) { - this._sin = Phaser.GameMath.sinA[this.rotation + this.rotationOffset]; - this._cos = Phaser.GameMath.cosA[this.rotation + this.rotationOffset]; - } - if(this.parent.texture.flippedX) { - this.local.data[0] = this._cos * -this.scale.x; - this.local.data[3] = (this._sin * -this.scale.x) + this.skew.x; + Transform.prototype.setCache = function () { + this._cachedHalfWidth = this.parent.width / 2; + this._cachedHalfHeight = this.parent.height / 2; + this._cachedOffsetX = this.origin.x * this.parent.width; + this._cachedOffsetY = this.origin.y * this.parent.height; + this._cachedAngleToCenter = Math.atan2(this.halfHeight - this._cachedOffsetY, this.halfWidth - this._cachedOffsetX); + this._cachedDistance = Math.sqrt(((this._cachedOffsetX - this._cachedHalfWidth) * (this._cachedOffsetX - this._cachedHalfWidth)) + ((this._cachedOffsetY - this._cachedHalfHeight) * (this._cachedOffsetY - this._cachedHalfHeight))); + this._cachedWidth = this.parent.width; + this._cachedHeight = this.parent.height; + this._cachedOriginX = this.origin.x; + this._cachedOriginY = this.origin.y; + this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._cachedCosAngle = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + this._cachedSinAngle = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + this._cachedRotation = this.rotation; + if(this.parent.texture && this.parent.texture.renderRotation) { + this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); } else { - this.local.data[0] = this._cos * this.scale.x; - this.local.data[3] = (this._sin * this.scale.x) + this.skew.x; + this._cachedSin = 0; + this._cachedCos = 1; + } + }; + Transform.prototype.update = function () { + // Check cache + var dirty = false; + // 1) Height or Width change (also triggered by a change in scale) or an Origin change + if(this.parent.width !== this._cachedWidth || this.parent.height !== this._cachedHeight || this.origin.x !== this._cachedOriginX || this.origin.y !== this._cachedOriginY) { + this._cachedHalfWidth = this.parent.width / 2; + this._cachedHalfHeight = this.parent.height / 2; + this._cachedOffsetX = this.origin.x * this.parent.width; + this._cachedOffsetY = this.origin.y * this.parent.height; + this._cachedAngleToCenter = Math.atan2(this.halfHeight - this._cachedOffsetY, this.halfWidth - this._cachedOffsetX); + this._cachedDistance = Math.sqrt(((this._cachedOffsetX - this._cachedHalfWidth) * (this._cachedOffsetX - this._cachedHalfWidth)) + ((this._cachedOffsetY - this._cachedHalfHeight) * (this._cachedOffsetY - this._cachedHalfHeight))); + // Store + this._cachedWidth = this.parent.width; + this._cachedHeight = this.parent.height; + this._cachedOriginX = this.origin.x; + this._cachedOriginY = this.origin.y; + dirty = true; + } + // 2) Rotation change + if(this.rotation != this._cachedRotation) { + this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._cachedCosAngle = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + this._cachedSinAngle = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + if(this.parent.texture.renderRotation) { + this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + } else { + this._cachedSin = 0; + this._cachedCos = 1; + } + // Store + this._cachedRotation = this.rotation; + dirty = true; + } + if(dirty) { + this._cachedCenterX = this.parent.x + this._cachedDistance * this._cachedCosAngle; + this._cachedCenterY = this.parent.y + this._cachedDistance * this._cachedSinAngle; + } + // Scale and Skew + if(this.parent.texture.flippedX) { + this.local.data[0] = this._cachedCos * -this.scale.x; + this.local.data[3] = (this._cachedSin * -this.scale.x) + this.skew.x; + } else { + this.local.data[0] = this._cachedCos * this.scale.x; + this.local.data[3] = (this._cachedSin * this.scale.x) + this.skew.x; } if(this.parent.texture.flippedY) { - this.local.data[4] = this._cos * -this.scale.y; - this.local.data[1] = -(this._sin * -this.scale.y) + this.skew.y; + this.local.data[4] = this._cachedCos * -this.scale.y; + this.local.data[1] = -(this._cachedSin * -this.scale.y) + this.skew.y; } else { - this.local.data[4] = this._cos * this.scale.y; - this.local.data[1] = -(this._sin * this.scale.y) + this.skew.y; + this.local.data[4] = this._cachedCos * this.scale.y; + this.local.data[1] = -(this._cachedSin * this.scale.y) + this.skew.y; } // Translate this.local.data[2] = this.parent.x; this.local.data[5] = this.parent.y; }; - Object.defineProperty(Transform.prototype, "centerX", { + Object.defineProperty(Transform.prototype, "distance", { get: /** - * The center of the Sprite after taking scaling into consideration + * The distance from the center of the transform to the rotation origin. */ function () { - return this.parent.width / 2; - }, + return this._cachedDistance; + //return Math.sqrt(((this.offsetX - this.halfWidth) * (this.offsetX - this.halfWidth)) + ((this.offsetY - this.halfHeight) * (this.offsetY - this.halfHeight))); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "angleToCenter", { + get: /** + * The angle between the center of the transform to the rotation origin. + */ + function () { + return this._cachedAngleToCenter; + //return Math.atan2(this.halfHeight - this.offsetY, this.halfWidth - this.offsetX); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "offsetX", { + get: /** + * The offset on the X axis of the origin + */ + function () { + return this._cachedOffsetX; + //return this.origin.x * this.parent.width; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "offsetY", { + get: /** + * The offset on the Y axis of the origin + */ + function () { + return this._cachedOffsetY; + //return this.origin.y * this.parent.height; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "halfWidth", { + get: /** + * Half the width of the parent sprite, taking into consideration scaling + */ + function () { + return this._cachedHalfWidth; + //return this.parent.width / 2; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "halfHeight", { + get: /** + * Half the height of the parent sprite, taking into consideration scaling + */ + function () { + return this._cachedHalfHeight; + //return this.parent.height / 2; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "centerX", { + get: /** + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ + function () { + return this._cachedCenterX; + //return this.parent.x + this.distance * Math.cos((this.rotation * Math.PI / 180) + this.angleToCenter); + }, enumerable: true, configurable: true }); Object.defineProperty(Transform.prototype, "centerY", { get: /** - * The center of the Sprite after taking scaling into consideration + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration */ function () { - return this.parent.height / 2; + return this._cachedCenterY; + //return this.parent.y + this.distance * Math.sin((this.rotation * Math.PI / 180) + this.angleToCenter); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "sin", { + get: function () { + return this._cachedSin; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "cos", { + get: function () { + return this._cachedCos; }, enumerable: true, configurable: true @@ -4319,6 +4457,7 @@ var Phaser; this.body = new Phaser.Physics.Body(this, bodyType); this.worldView = new Phaser.Rectangle(x, y, this.width, this.height); this.cameraView = new Phaser.Rectangle(x, y, this.width, this.height); + this.transform.setCache(); } Object.defineProperty(Sprite.prototype, "rotation", { get: /** @@ -4394,8 +4533,10 @@ var Phaser; */ function () { this.transform.update(); - this.worldView.x = this.x * this.transform.scrollFactor.x; - this.worldView.y = this.y * this.transform.scrollFactor.y; + this.worldView.x = (this.x * this.transform.scrollFactor.x) - (this.width * this.transform.origin.x); + this.worldView.y = (this.y * this.transform.scrollFactor.y) - (this.height * this.transform.origin.y); + //this.worldView.x = this.x * this.transform.scrollFactor.x; + //this.worldView.y = this.y * this.transform.scrollFactor.y; this.worldView.width = this.width; this.worldView.height = this.height; if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { @@ -4514,32 +4655,28 @@ var Phaser; sprite.cameraView.height = sprite.height; } else { // If the sprite is rotated around its center we can use this quicker method: - // Work out bounding box - SpriteUtils._sin = Phaser.GameMath.sinA[sprite.rotation]; - SpriteUtils._cos = Phaser.GameMath.cosA[sprite.rotation]; - if(SpriteUtils._sin < 0) { - SpriteUtils._sin = -SpriteUtils._sin; - } - if(SpriteUtils._cos < 0) { - SpriteUtils._cos = -SpriteUtils._cos; - } - sprite.cameraView.width = Math.round(sprite.height * SpriteUtils._sin + sprite.width * SpriteUtils._cos); - sprite.cameraView.height = Math.round(sprite.height * SpriteUtils._cos + sprite.width * SpriteUtils._sin); - // if origin isn't 0.5 we need to work out the difference to apply to the x/y - if(sprite.transform.origin.equals(0.5)) { - // Easy out + if(sprite.transform.origin.x == 0.5 && sprite.transform.origin.y == 0.5) { + SpriteUtils._sin = Math.sin((sprite.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + SpriteUtils._cos = Math.cos((sprite.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + if(SpriteUtils._sin < 0) { + SpriteUtils._sin = -SpriteUtils._sin; + } + if(SpriteUtils._cos < 0) { + SpriteUtils._cos = -SpriteUtils._cos; + } + sprite.cameraView.width = Math.round(sprite.height * SpriteUtils._sin + sprite.width * SpriteUtils._cos); + sprite.cameraView.height = Math.round(sprite.height * SpriteUtils._cos + sprite.width * SpriteUtils._sin); sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); } else { - //var ax = sprite.cameraView.width * sprite.transform.origin.x; - //var ay = sprite.cameraView.height * sprite.transform.origin.y; - //var bx = sprite.cameraView.width * 0.5; - //var by = sprite.cameraView.height * 0.5; - //var c = sprite.game.math.distanceBetween(ax, ay, bx, by) / 2; - //console.log('actual x', ax, 'actual y', ay, 'cx', bx, 'cy', by); - sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); - sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); - } + /* + // Useful to get the maximum AABB size of any given rect + + If you want a single box that covers all angles, just take the half-diagonal of your existing box as the radius of a circle. + The new box has to contain this circle, so it should be a square with side-length equal to twice the radius + (equiv. the diagonal of the original AABB) and with the same center as the original. + */ + } } if(sprite.animations.currentFrame !== null && sprite.animations.currentFrame.trimmed) { //sprite.cameraView.x += sprite.animations.currentFrame.spriteSourceSizeX; @@ -4549,6 +4686,58 @@ var Phaser; } return sprite.cameraView; }; + SpriteUtils.getCornersAsPoints = function getCornersAsPoints(sprite) { + var out = []; + var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + // Upper Left + out.push(new Phaser.Point(sprite.x + (sprite.width / 2) * cos - (sprite.height / 2) * sin, sprite.y + (sprite.height / 2) * cos + (sprite.width / 2) * sin)); + // Upper Right + out.push(new Phaser.Point(sprite.x - (sprite.width / 2) * cos - (sprite.height / 2) * sin, sprite.y + (sprite.height / 2) * cos - (sprite.width / 2) * sin)); + // Bottom Left + out.push(new Phaser.Point(sprite.x + (sprite.width / 2) * cos + (sprite.height / 2) * sin, sprite.y - (sprite.height / 2) * cos + (sprite.width / 2) * sin)); + // Bottom Right + out.push(new Phaser.Point(sprite.x - (sprite.width / 2) * cos + (sprite.height / 2) * sin, sprite.y - (sprite.height / 2) * cos - (sprite.width / 2) * sin)); + return out; + }; + SpriteUtils.getCornersAsPoints2 = function getCornersAsPoints2(sprite) { + var out = []; + var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + // This = the center point + var cx = sprite.x + (sprite.width / 2) * cos - (sprite.height / 2) * sin; + var cy = sprite.y + (sprite.height / 2) * cos + (sprite.width / 2) * sin; + // Upper Left + out.push(new Phaser.Point(cx + (sprite.width / 2) * cos - (sprite.height / 2) * sin, cy + (sprite.height / 2) * cos + (sprite.width / 2) * sin)); + // Upper Right + out.push(new Phaser.Point(cx - (sprite.width / 2) * cos - (sprite.height / 2) * sin, cy + (sprite.height / 2) * cos - (sprite.width / 2) * sin)); + // Bottom Left + out.push(new Phaser.Point(cx + (sprite.width / 2) * cos + (sprite.height / 2) * sin, cy - (sprite.height / 2) * cos + (sprite.width / 2) * sin)); + // Bottom Right + out.push(new Phaser.Point(cx - (sprite.width / 2) * cos + (sprite.height / 2) * sin, cy - (sprite.height / 2) * cos - (sprite.width / 2) * sin)); + return out; + }; + SpriteUtils.getCornersAsPoints3 = function getCornersAsPoints3(sprite) { + var out = []; + var sin = sprite.transform.sin; + var cos = sprite.transform.cos; + //var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + //var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + // This = the center point + //var cx = sprite.x + sprite.transform.distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); + //var cy = sprite.y + sprite.transform.distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); + var cx = sprite.transform.centerX; + var cy = sprite.transform.centerY; + // Upper Left + out.push(new Phaser.Point(cx + sprite.transform.halfWidth * cos - sprite.transform.halfHeight * sin, cy + sprite.transform.halfHeight * cos + sprite.transform.halfWidth * sin)); + // Upper Right + out.push(new Phaser.Point(cx - sprite.transform.halfWidth * cos - sprite.transform.halfHeight * sin, cy + sprite.transform.halfHeight * cos - sprite.transform.halfWidth * sin)); + // Bottom Left + out.push(new Phaser.Point(cx + sprite.transform.halfWidth * cos + sprite.transform.halfHeight * sin, cy - sprite.transform.halfHeight * cos + sprite.transform.halfWidth * sin)); + // Bottom Right + out.push(new Phaser.Point(cx - sprite.transform.halfWidth * cos + sprite.transform.halfHeight * sin, cy - sprite.transform.halfHeight * cos - sprite.transform.halfWidth * sin)); + return out; + }; SpriteUtils.getAsPoints = function getAsPoints(sprite) { var out = []; // top left @@ -16411,7 +16600,6 @@ var Phaser; if(sprite.transform.scrollFactor.equals(0)) { return true; } - Phaser.SpriteUtils.updateCameraView(camera, sprite); return Phaser.RectangleUtils.intersects(sprite.cameraView, camera.screenView); }; CanvasRenderer.prototype.inScreen = function (camera) { @@ -16579,8 +16767,8 @@ var Phaser; function (camera, sprite) { Phaser.SpriteUtils.updateCameraView(camera, sprite); if(sprite.transform.scale.x == 0 || sprite.transform.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { - //return false; - } + return false; + } sprite.renderOrderID = this._count; this._count++; // Reset our temp vars diff --git a/Tests/sprites/origin 5.js b/Tests/sprites/origin 5.js index cc88a6b4..e260ca76 100644 --- a/Tests/sprites/origin 5.js +++ b/Tests/sprites/origin 5.js @@ -3,17 +3,30 @@ var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); function init() { // Using Phasers asset loader we load up a PNG from the assets folder - game.load.image('fuji', 'assets/pics/atari_fujilogo.png'); + game.load.image('disk', 'assets/sprites/oz_pov_melting_disk.png'); + game.load.image('fuji', 'assets/tests/200x100corners.png'); + game.load.image('fuji2', 'assets/tests/200x100corners2.png'); + game.load.image('fuji3', 'assets/tests/320x200.png'); + game.load.image('fuji4', 'assets/tests/320x200g.png'); game.load.start(); } var fuji; - var wn; - var hn; + var fuji2; + var fuji3; function create() { - game.stage.backgroundColor = 'rgb(0,0,100)'; - game.world.setSize(2000, 1200, true); + game.stage.backgroundColor = 'rgb(0,0,0)'; + //game.world.setSize(2000, 1200, true); // The sprite is 320 x 200 pixels in size positioned in the middle of the stage - fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji'); + //fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji4'); + fuji2 = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji3'); + //fuji2 = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji2'); + //fuji3 = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji2'); + //fuji.visible = false; + //fuji2.visible = false; + //fuji.texture.alpha = 0.6; + //fuji2.texture.alpha = 0.6; + //fuji = game.add.sprite(0, 0, 'fuji'); + //fuji2 = game.add.sprite(0, 0, 'fuji'); //fuji.transform.scale.setTo(1.5, 1.5); //fuji.transform.scale.setTo(1.5, 1.5); //fuji.transform.skew.setTo(0.1, 0.1); @@ -24,13 +37,20 @@ //fuji.transform.scale.setTo(2, 2); // This sets the origin to the center //fuji.transform.origin.setTo(0.5, 0.5); + //fuji.transform.origin.setTo(0, 0); + fuji2.transform.origin.setTo(1, 1); + //fuji3.transform.origin.setTo(1, 1); game.input.onTap.add(rotateIt, this); - } + //game.stage.clear = false; + } function rotateIt() { - fuji.rotation += 20; - } + //fuji.rotation += 10; + fuji2.rotation += 10; + //fuji3.rotation += 20; + } function update() { - fuji.rotation += 1; + //fuji.rotation++; + //fuji2.rotation++; if(game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { game.camera.x -= 4; } else if(game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { @@ -41,20 +61,169 @@ } else if(game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { game.camera.y += 4; } - //Phaser.SpriteUtils.updateCameraDisplay(game.camera, fuji); - } + } + var points; + var points2; function render() { + // This = the center point + //var cx = fuji2.x + (fuji2.width / 2) * cos - (fuji2.height / 2) * sin; + //var cy = fuji2.y + (fuji2.height / 2) * cos + (fuji2.width / 2) * sin; + // This gives me the top-left of an origin 1,1 + //var cx = fuji2.x + (-fuji2.width / fuji2.transform.origin.x) * cos - (-fuji2.height / fuji2.transform.origin.y) * sin; + //var cy = fuji2.y + (-fuji2.height / fuji2.transform.origin.y) * cos + (-fuji2.width / fuji2.transform.origin.x) * sin; + // This gives me the center point of an origin 1,1 + //var cx = fuji2.x + (-(fuji2.width * fuji2.transform.origin.x) / 2) * cos - (-(fuji2.height * fuji2.transform.origin.y) / 2) * sin; + //var cy = fuji2.y + (-(fuji2.height * fuji2.transform.origin.y) / 2) * cos + (-(fuji2.width * fuji2.transform.origin.x) / 2) * sin; + //var dx = 0.5 * fuji2.transform.origin.x; + //var dy = 0.5 * fuji2.transform.origin.y; + //dx = 1; + //dy = 1; + //console.log(fuji2.width * 0); + //var cx = fuji2.x + (-(fuji2.width * fuji2.transform.origin.x) / dx) * cos - (-(fuji2.height * fuji2.transform.origin.y) / dy) * sin; + //var cy = fuji2.y + (-(fuji2.height * fuji2.transform.origin.y) / dy) * cos + (-(fuji2.width * fuji2.transform.origin.x) / dx) * sin; + // This gives me the center point of an origin 0,0 + //var cx = fuji2.x + ((fuji2.width * fuji2.transform.origin.x) / 2) * cos - ((fuji2.height * fuji2.transform.origin.y) / 2) * sin; + //var cy = fuji2.y + ((fuji2.height * fuji2.transform.origin.y) / 2) * cos + ((fuji2.width * fuji2.transform.origin.x) / 2) * sin; + // center points + //game.stage.context.fillStyle = 'rgb(255,255,0)'; + //game.stage.context.fillRect(fuji.x, fuji.y, 4, 4); + //game.stage.context.fillRect(fuji2.x, fuji2.y, 4, 4); + //game.stage.context.fillRect(cx, cy, 4, 4); + var sin = Math.sin((fuji2.transform.rotation + fuji2.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + var cos = Math.cos((fuji2.transform.rotation + fuji2.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + var originX = fuji2.transform.origin.x * fuji2.width; + var originY = fuji2.transform.origin.y * fuji2.height; + var centerX = 0.5 * fuji2.width; + var centerY = 0.5 * fuji2.height; + var distanceX = originX - centerX; + var distanceY = originY - centerY; + var distance = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); + var px = fuji2.x + distance * Math.cos(fuji2.transform.rotation + 45 * Math.PI / 180); + var py = fuji2.y + distance * Math.sin(fuji2.transform.rotation + 45 * Math.PI / 180); + game.stage.context.save(); + game.stage.context.fillStyle = 'rgb(255,255,0)'; + game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); + game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); + game.stage.context.fillText('angle: ' + fuji2.rotation, 32, 72); + game.stage.context.fillText('point of rotation x: ' + fuji2.transform.origin.x + ' y: ' + fuji2.transform.origin.y, 32, 92); + game.stage.context.fillText('x: ' + fuji2.x + ' y: ' + fuji2.y, fuji2.x + 4, fuji2.y); + game.stage.context.restore(); + game.stage.context.save(); + game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; + game.stage.context.arc(fuji2.x, fuji2.y, distance, 0, Math.PI * 2); + game.stage.context.fill(); + game.stage.context.restore(); + //points = Phaser.SpriteUtils.getCornersAsPoints(fuji); + //game.stage.context.fillStyle = 'rgb(255,255,255)'; + //game.stage.context.fillRect(points[0].x, points[0].y, 2, 2); + //game.stage.context.fillRect(points[1].x, points[1].y, 2, 2); + //game.stage.context.fillRect(points[2].x, points[2].y, 2, 2); + //game.stage.context.fillRect(points[3].x, points[3].y, 2, 2); + //points2 = Phaser.SpriteUtils.getCornersAsPoints2(fuji2); + //game.stage.context.fillStyle = 'rgb(255,0,0)'; + //game.stage.context.fillRect(points2[0].x, points2[0].y, 2, 2); + //game.stage.context.fillRect(points2[1].x, points2[1].y, 2, 2); + //game.stage.context.fillRect(points2[2].x, points2[2].y, 2, 2); + //game.stage.context.fillRect(points2[3].x, points2[3].y, 2, 2); + /* //game.stage.context.fillStyle = 'rgb(255,255,255)'; //game.stage.context.fillRect(fuji.x, fuji.y, 2, 2); - game.stage.context.fillStyle = 'rgb(255,0,0)'; - game.stage.context.fillRect(fuji.x, fuji.y, 2, 2); + + //var sin = Math.sin(game.math.degreesToRadians(fuji.rotation)); + //var cos = Math.cos(game.math.degreesToRadians(fuji.rotation)); + + //var fx = fuji.x + (fuji.width * fuji.transform.origin.x); + //var fy = fuji.y + (fuji.height * fuji.transform.origin.y); + + // center x/y + //var cx = fuji.width * 0.5; + //var cy = fuji.height * 0.5; + + //var ax = fuji.width * fuji.transform.origin.x; + //var ay = fuji.height * fuji.transform.origin.y; + + //var dx = cx - ax; + //var dy = cy - ay; + + //var fx = fuji.x - dx; + //var fy = fuji.y - dy; + + /* + var ox = fuji.x + (fuji.width * fuji.transform.origin.x); + var oy = fuji.y + (fuji.height * fuji.transform.origin.y); + var cx = fuji.x + (fuji.width * 0.5); + var cy = fuji.y + (fuji.height * 0.5); + + var dx = ox - cx; + var dy = oy - cy; + + game.stage.context.fillText('dx: ' + dx + ' dy: ' + dy, 300, 100); + + var fx = fuji.x + dx; + var fy = fuji.y + dy; + + //game.stage.context.fillStyle = 'rgb(255,0,255)'; + //game.stage.context.fillRect(cx, cy, 20, 20); + + //UL = x + ( Width / 2 ) * cos A - ( Height / 2 ) * sin A + //ul.x = fuji.x + (fuji.width / 2) * cos - (fuji.height / 2) * sin; + ul.x = fx + (fuji.width / 2) * cos - (fuji.height / 2) * sin; + + //UL = y + ( Height / 2 ) * cos A + ( Width / 2 ) * sin A + //ul.y = fuji.y + (fuji.height / 2) * cos + (fuji.width / 2) * sin; + ul.y = fy + (fuji.height / 2) * cos + (fuji.width / 2) * sin; + + //UR = x - ( Width / 2 ) * cos A - ( Height / 2 ) * sin A + //ur.x = fuji.x - (fuji.width / 2) * cos - (fuji.height / 2) * sin; + ur.x = fx - (fuji.width / 2) * cos - (fuji.height / 2) * sin; + + //UR = y + ( Height / 2 ) * cos A - ( Width / 2 ) * sin A + //ur.y = fuji.y + (fuji.height / 2) * cos - (fuji.width / 2) * sin; + ur.y = fy + (fuji.height / 2) * cos - (fuji.width / 2) * sin; + + //BL = x + ( Width / 2 ) * cos A + ( Height / 2 ) * sin A + //bl.x = fuji.x + (fuji.width / 2) * cos + (fuji.height / 2) * sin; + bl.x = fx + (fuji.width / 2) * cos + (fuji.height / 2) * sin; + + //BL = y - ( Height / 2 ) * cos A + ( Width / 2 ) * sin A + //bl.y = fuji.y - (fuji.height / 2) * cos + (fuji.width / 2) * sin; + bl.y = fy - (fuji.height / 2) * cos + (fuji.width / 2) * sin; + + //BR = x - ( Width / 2 ) * cos A + ( Height / 2 ) * sin A + //br.x = fuji.x - (fuji.width / 2) * cos + (fuji.height / 2) * sin; + br.x = fx - (fuji.width / 2) * cos + (fuji.height / 2) * sin; + + //BR = y - ( Height / 2 ) * cos A - ( Width / 2 ) * sin A + //br.y = fuji.y - (fuji.height / 2) * cos - (fuji.width / 2) * sin; + br.y = fy - (fuji.height / 2) * cos - (fuji.width / 2) * sin; + game.stage.context.fillStyle = 'rgb(255,255,0)'; - game.stage.context.fillRect(fuji.cameraView.x + fuji.cameraView.halfWidth, fuji.cameraView.y + fuji.cameraView.halfHeight, 2, 2); - game.stage.context.strokeStyle = 'rgb(255,255,0)'; - game.stage.context.strokeRect(fuji.cameraView.x, fuji.cameraView.y, fuji.cameraView.width, fuji.cameraView.height); + game.stage.context.fillRect(ul.x, ul.y, 2, 2); + game.stage.context.fillRect(ur.x, ur.y, 2, 2); + game.stage.context.fillRect(bl.x, bl.y, 2, 2); + game.stage.context.fillRect(br.x, br.y, 2, 2); + + + + //game.stage.context.fillRect(fuji.x - fuji.width / 2, fuji.y - fuji.width / 2, 2, 2); + + //game.stage.context.fillStyle = 'rgb(255,255,0)'; + //game.stage.context.fillRect(fuji2.x, fuji2.y, 2, 2); + + //game.stage.context.fillStyle = 'rgb(255,255,0)'; + //game.stage.context.fillRect(fuji.cameraView.x + fuji.cameraView.halfWidth, fuji.cameraView.y + fuji.cameraView.halfHeight, 2, 2); + + //game.stage.context.strokeStyle = 'rgb(255,255,0)'; + //game.stage.context.strokeRect(fuji.cameraView.x, fuji.cameraView.y, fuji.cameraView.width, fuji.cameraView.height); + //game.stage.context.strokeStyle = 'rgb(0,255,0)'; //game.stage.context.strokeRect(fuji.x, fuji.y, wn, hn); + //game.camera.renderDebugInfo(32, 32); - Phaser.DebugUtils.renderSpriteInfo(fuji, 32, 32); - } + + //Phaser.DebugUtils.renderSpriteInfo(fuji, 32, 32); + */ + //game.stage.context.strokeStyle = 'rgb(255,255,0)'; + //game.stage.context.strokeRect(fuji.cameraView.x, fuji.cameraView.y, fuji.cameraView.width, fuji.cameraView.height); + } })(); diff --git a/Tests/sprites/origin 5.ts b/Tests/sprites/origin 5.ts index 750f6ea0..3efd276b 100644 --- a/Tests/sprites/origin 5.ts +++ b/Tests/sprites/origin 5.ts @@ -7,23 +7,39 @@ function init() { // Using Phasers asset loader we load up a PNG from the assets folder - game.load.image('fuji', 'assets/pics/atari_fujilogo.png'); + game.load.image('disk', 'assets/sprites/oz_pov_melting_disk.png'); + game.load.image('fuji', 'assets/tests/200x100corners.png'); + game.load.image('fuji2', 'assets/tests/200x100corners2.png'); + game.load.image('fuji3', 'assets/tests/320x200.png'); + game.load.image('fuji4', 'assets/tests/320x200g.png'); game.load.start(); } var fuji: Phaser.Sprite; - var wn: number; - var hn: number; - + var fuji2: Phaser.Sprite; + var fuji3: Phaser.Sprite; function create() { - game.stage.backgroundColor = 'rgb(0,0,100)'; - game.world.setSize(2000, 1200, true); + game.stage.backgroundColor = 'rgb(0,0,0)'; + //game.world.setSize(2000, 1200, true); // The sprite is 320 x 200 pixels in size positioned in the middle of the stage - fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji'); + + //fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji4'); + fuji2 = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji3'); + //fuji2 = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji2'); + //fuji3 = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji2'); + + //fuji.visible = false; + //fuji2.visible = false; + + //fuji.texture.alpha = 0.6; + //fuji2.texture.alpha = 0.6; + + //fuji = game.add.sprite(0, 0, 'fuji'); + //fuji2 = game.add.sprite(0, 0, 'fuji'); //fuji.transform.scale.setTo(1.5, 1.5); //fuji.transform.scale.setTo(1.5, 1.5); @@ -39,17 +55,27 @@ // This sets the origin to the center //fuji.transform.origin.setTo(0.5, 0.5); + //fuji.transform.origin.setTo(0, 0); + fuji2.transform.origin.setTo(1, 1); + + //fuji3.transform.origin.setTo(1, 1); + game.input.onTap.add(rotateIt, this); + //game.stage.clear = false; + } function rotateIt() { - fuji.rotation += 20; + //fuji.rotation += 10; + fuji2.rotation += 10; + //fuji3.rotation += 20; } function update() { - fuji.rotation += 1; + //fuji.rotation++; + //fuji2.rotation++; if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { @@ -69,30 +95,195 @@ game.camera.y += 4; } - //Phaser.SpriteUtils.updateCameraDisplay(game.camera, fuji); - } + var points: Phaser.Point[]; + var points2: Phaser.Point[]; + function render() { + // This = the center point + //var cx = fuji2.x + (fuji2.width / 2) * cos - (fuji2.height / 2) * sin; + //var cy = fuji2.y + (fuji2.height / 2) * cos + (fuji2.width / 2) * sin; + + // This gives me the top-left of an origin 1,1 + //var cx = fuji2.x + (-fuji2.width / fuji2.transform.origin.x) * cos - (-fuji2.height / fuji2.transform.origin.y) * sin; + //var cy = fuji2.y + (-fuji2.height / fuji2.transform.origin.y) * cos + (-fuji2.width / fuji2.transform.origin.x) * sin; + + // This gives me the center point of an origin 1,1 + //var cx = fuji2.x + (-(fuji2.width * fuji2.transform.origin.x) / 2) * cos - (-(fuji2.height * fuji2.transform.origin.y) / 2) * sin; + //var cy = fuji2.y + (-(fuji2.height * fuji2.transform.origin.y) / 2) * cos + (-(fuji2.width * fuji2.transform.origin.x) / 2) * sin; + + //var dx = 0.5 * fuji2.transform.origin.x; + //var dy = 0.5 * fuji2.transform.origin.y; + + //dx = 1; + //dy = 1; + + //console.log(fuji2.width * 0); + + //var cx = fuji2.x + (-(fuji2.width * fuji2.transform.origin.x) / dx) * cos - (-(fuji2.height * fuji2.transform.origin.y) / dy) * sin; + //var cy = fuji2.y + (-(fuji2.height * fuji2.transform.origin.y) / dy) * cos + (-(fuji2.width * fuji2.transform.origin.x) / dx) * sin; + + // This gives me the center point of an origin 0,0 + //var cx = fuji2.x + ((fuji2.width * fuji2.transform.origin.x) / 2) * cos - ((fuji2.height * fuji2.transform.origin.y) / 2) * sin; + //var cy = fuji2.y + ((fuji2.height * fuji2.transform.origin.y) / 2) * cos + ((fuji2.width * fuji2.transform.origin.x) / 2) * sin; + + // center points + //game.stage.context.fillStyle = 'rgb(255,255,0)'; + //game.stage.context.fillRect(fuji.x, fuji.y, 4, 4); + //game.stage.context.fillRect(fuji2.x, fuji2.y, 4, 4); + //game.stage.context.fillRect(cx, cy, 4, 4); + + + var sin = Math.sin((fuji2.transform.rotation + fuji2.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + var cos = Math.cos((fuji2.transform.rotation + fuji2.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + + var originX: number = fuji2.transform.origin.x * fuji2.width; + var originY: number = fuji2.transform.origin.y * fuji2.height; + var centerX: number = 0.5 * fuji2.width; + var centerY: number = 0.5 * fuji2.height; + var distanceX: number = originX - centerX; + var distanceY: number = originY - centerY; + var distance: number = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); + + var px = fuji2.x + distance * Math.cos(fuji2.transform.rotation + 45 * Math.PI / 180); + var py = fuji2.y + distance * Math.sin(fuji2.transform.rotation + 45 * Math.PI / 180); + + game.stage.context.save(); + game.stage.context.fillStyle = 'rgb(255,255,0)'; + game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); + game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); + game.stage.context.fillText('angle: ' + fuji2.rotation , 32, 72); + game.stage.context.fillText('point of rotation x: ' + fuji2.transform.origin.x + ' y: ' + fuji2.transform.origin.y, 32, 92); + game.stage.context.fillText('x: ' + fuji2.x + ' y: ' + fuji2.y, fuji2.x + 4, fuji2.y); + game.stage.context.restore(); + + game.stage.context.save(); + game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; + game.stage.context.arc(fuji2.x, fuji2.y, distance, 0, Math.PI * 2); + game.stage.context.fill(); + game.stage.context.restore(); + + //points = Phaser.SpriteUtils.getCornersAsPoints(fuji); + + //game.stage.context.fillStyle = 'rgb(255,255,255)'; + //game.stage.context.fillRect(points[0].x, points[0].y, 2, 2); + //game.stage.context.fillRect(points[1].x, points[1].y, 2, 2); + //game.stage.context.fillRect(points[2].x, points[2].y, 2, 2); + //game.stage.context.fillRect(points[3].x, points[3].y, 2, 2); + + + //points2 = Phaser.SpriteUtils.getCornersAsPoints2(fuji2); + + //game.stage.context.fillStyle = 'rgb(255,0,0)'; + //game.stage.context.fillRect(points2[0].x, points2[0].y, 2, 2); + //game.stage.context.fillRect(points2[1].x, points2[1].y, 2, 2); + //game.stage.context.fillRect(points2[2].x, points2[2].y, 2, 2); + //game.stage.context.fillRect(points2[3].x, points2[3].y, 2, 2); + + + /* //game.stage.context.fillStyle = 'rgb(255,255,255)'; //game.stage.context.fillRect(fuji.x, fuji.y, 2, 2); - game.stage.context.fillStyle = 'rgb(255,0,0)'; - game.stage.context.fillRect(fuji.x, fuji.y, 2, 2); + //var sin = Math.sin(game.math.degreesToRadians(fuji.rotation)); + //var cos = Math.cos(game.math.degreesToRadians(fuji.rotation)); + + //var fx = fuji.x + (fuji.width * fuji.transform.origin.x); + //var fy = fuji.y + (fuji.height * fuji.transform.origin.y); + + // center x/y + //var cx = fuji.width * 0.5; + //var cy = fuji.height * 0.5; + + //var ax = fuji.width * fuji.transform.origin.x; + //var ay = fuji.height * fuji.transform.origin.y; + + //var dx = cx - ax; + //var dy = cy - ay; + + //var fx = fuji.x - dx; + //var fy = fuji.y - dy; + + /* + var ox = fuji.x + (fuji.width * fuji.transform.origin.x); + var oy = fuji.y + (fuji.height * fuji.transform.origin.y); + var cx = fuji.x + (fuji.width * 0.5); + var cy = fuji.y + (fuji.height * 0.5); + + var dx = ox - cx; + var dy = oy - cy; + + game.stage.context.fillText('dx: ' + dx + ' dy: ' + dy, 300, 100); + + var fx = fuji.x + dx; + var fy = fuji.y + dy; + + //game.stage.context.fillStyle = 'rgb(255,0,255)'; + //game.stage.context.fillRect(cx, cy, 20, 20); + + //UL = x + ( Width / 2 ) * cos A - ( Height / 2 ) * sin A + //ul.x = fuji.x + (fuji.width / 2) * cos - (fuji.height / 2) * sin; + ul.x = fx + (fuji.width / 2) * cos - (fuji.height / 2) * sin; + + //UL = y + ( Height / 2 ) * cos A + ( Width / 2 ) * sin A + //ul.y = fuji.y + (fuji.height / 2) * cos + (fuji.width / 2) * sin; + ul.y = fy + (fuji.height / 2) * cos + (fuji.width / 2) * sin; + + //UR = x - ( Width / 2 ) * cos A - ( Height / 2 ) * sin A + //ur.x = fuji.x - (fuji.width / 2) * cos - (fuji.height / 2) * sin; + ur.x = fx - (fuji.width / 2) * cos - (fuji.height / 2) * sin; + + //UR = y + ( Height / 2 ) * cos A - ( Width / 2 ) * sin A + //ur.y = fuji.y + (fuji.height / 2) * cos - (fuji.width / 2) * sin; + ur.y = fy + (fuji.height / 2) * cos - (fuji.width / 2) * sin; + + //BL = x + ( Width / 2 ) * cos A + ( Height / 2 ) * sin A + //bl.x = fuji.x + (fuji.width / 2) * cos + (fuji.height / 2) * sin; + bl.x = fx + (fuji.width / 2) * cos + (fuji.height / 2) * sin; + + //BL = y - ( Height / 2 ) * cos A + ( Width / 2 ) * sin A + //bl.y = fuji.y - (fuji.height / 2) * cos + (fuji.width / 2) * sin; + bl.y = fy - (fuji.height / 2) * cos + (fuji.width / 2) * sin; + + //BR = x - ( Width / 2 ) * cos A + ( Height / 2 ) * sin A + //br.x = fuji.x - (fuji.width / 2) * cos + (fuji.height / 2) * sin; + br.x = fx - (fuji.width / 2) * cos + (fuji.height / 2) * sin; + + //BR = y - ( Height / 2 ) * cos A - ( Width / 2 ) * sin A + //br.y = fuji.y - (fuji.height / 2) * cos - (fuji.width / 2) * sin; + br.y = fy - (fuji.height / 2) * cos - (fuji.width / 2) * sin; game.stage.context.fillStyle = 'rgb(255,255,0)'; - game.stage.context.fillRect(fuji.cameraView.x + fuji.cameraView.halfWidth, fuji.cameraView.y + fuji.cameraView.halfHeight, 2, 2); + game.stage.context.fillRect(ul.x, ul.y, 2, 2); + game.stage.context.fillRect(ur.x, ur.y, 2, 2); + game.stage.context.fillRect(bl.x, bl.y, 2, 2); + game.stage.context.fillRect(br.x, br.y, 2, 2); - game.stage.context.strokeStyle = 'rgb(255,255,0)'; - game.stage.context.strokeRect(fuji.cameraView.x, fuji.cameraView.y, fuji.cameraView.width, fuji.cameraView.height); + + + //game.stage.context.fillRect(fuji.x - fuji.width / 2, fuji.y - fuji.width / 2, 2, 2); + + //game.stage.context.fillStyle = 'rgb(255,255,0)'; + //game.stage.context.fillRect(fuji2.x, fuji2.y, 2, 2); + + //game.stage.context.fillStyle = 'rgb(255,255,0)'; + //game.stage.context.fillRect(fuji.cameraView.x + fuji.cameraView.halfWidth, fuji.cameraView.y + fuji.cameraView.halfHeight, 2, 2); + + //game.stage.context.strokeStyle = 'rgb(255,255,0)'; + //game.stage.context.strokeRect(fuji.cameraView.x, fuji.cameraView.y, fuji.cameraView.width, fuji.cameraView.height); //game.stage.context.strokeStyle = 'rgb(0,255,0)'; //game.stage.context.strokeRect(fuji.x, fuji.y, wn, hn); //game.camera.renderDebugInfo(32, 32); - Phaser.DebugUtils.renderSpriteInfo(fuji, 32, 32); + //Phaser.DebugUtils.renderSpriteInfo(fuji, 32, 32); + */ + + //game.stage.context.strokeStyle = 'rgb(255,255,0)'; + //game.stage.context.strokeRect(fuji.cameraView.x, fuji.cameraView.y, fuji.cameraView.width, fuji.cameraView.height); } diff --git a/build/phaser.d.ts b/build/phaser.d.ts index 9244f4d4..47d1ea01 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -1896,9 +1896,29 @@ module Phaser.Components { * @param parent The Sprite using this transform */ constructor(parent); - private _sin; - private _cos; + private _rotation; + private _cachedSin; + private _cachedCos; + private _cachedRotation; + private _cachedScaleX; + private _cachedScaleY; + private _cachedAngle; + private _cachedAngleToCenter; + private _cachedDistance; + private _cachedWidth; + private _cachedHeight; + private _cachedHalfWidth; + private _cachedHalfHeight; + private _cachedCosAngle; + private _cachedSinAngle; + private _cachedOffsetX; + private _cachedOffsetY; + private _cachedOriginX; + private _cachedOriginY; + private _cachedCenterX; + private _cachedCenterY; public local: Mat3; + public setCache(): void; public update(): void; /** * Reference to Phaser.Game @@ -1921,7 +1941,7 @@ module Phaser.Components { */ public scrollFactor: Vec2; /** - * The origin is the point around which scale and rotation takes place and defaults to the center of the sprite. + * The origin is the point around which scale and rotation takes place and defaults to the top-left of the sprite. */ public origin: Vec2; /** @@ -1936,13 +1956,39 @@ module Phaser.Components { */ public rotation: number; /** - * The center of the Sprite after taking scaling into consideration + * The distance from the center of the transform to the rotation origin. + */ + public distance : number; + /** + * The angle between the center of the transform to the rotation origin. + */ + public angleToCenter : number; + /** + * The offset on the X axis of the origin + */ + public offsetX : number; + /** + * The offset on the Y axis of the origin + */ + public offsetY : number; + /** + * Half the width of the parent sprite, taking into consideration scaling + */ + public halfWidth : number; + /** + * Half the height of the parent sprite, taking into consideration scaling + */ + public halfHeight : number; + /** + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration */ public centerX : number; /** - * The center of the Sprite after taking scaling into consideration + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration */ public centerY : number; + public sin : number; + public cos : number; } } /** @@ -2669,6 +2715,9 @@ module Phaser { * @return {Rectangle} A reference to the Sprite.cameraView property */ static updateCameraView(camera: Camera, sprite: Sprite): Rectangle; + static getCornersAsPoints(sprite: Sprite): Point[]; + static getCornersAsPoints2(sprite: Sprite): Point[]; + static getCornersAsPoints3(sprite: Sprite): Point[]; static getAsPoints(sprite: Sprite): Point[]; /** * Checks to see if a point in 2D world space overlaps this GameObject. diff --git a/build/phaser.js b/build/phaser.js index 3cd97fca..279c2dfc 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -3083,48 +3083,186 @@ var Phaser; this.scale = new Phaser.Vec2(1, 1); this.skew = new Phaser.Vec2(); } - Transform.prototype.update = function () { - // Scale & Skew - this._sin = 0; - this._cos = 1; - if(this.parent.texture.renderRotation) { - this._sin = Phaser.GameMath.sinA[this.rotation + this.rotationOffset]; - this._cos = Phaser.GameMath.cosA[this.rotation + this.rotationOffset]; - } - if(this.parent.texture.flippedX) { - this.local.data[0] = this._cos * -this.scale.x; - this.local.data[3] = (this._sin * -this.scale.x) + this.skew.x; + Transform.prototype.setCache = function () { + this._cachedHalfWidth = this.parent.width / 2; + this._cachedHalfHeight = this.parent.height / 2; + this._cachedOffsetX = this.origin.x * this.parent.width; + this._cachedOffsetY = this.origin.y * this.parent.height; + this._cachedAngleToCenter = Math.atan2(this.halfHeight - this._cachedOffsetY, this.halfWidth - this._cachedOffsetX); + this._cachedDistance = Math.sqrt(((this._cachedOffsetX - this._cachedHalfWidth) * (this._cachedOffsetX - this._cachedHalfWidth)) + ((this._cachedOffsetY - this._cachedHalfHeight) * (this._cachedOffsetY - this._cachedHalfHeight))); + this._cachedWidth = this.parent.width; + this._cachedHeight = this.parent.height; + this._cachedOriginX = this.origin.x; + this._cachedOriginY = this.origin.y; + this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._cachedCosAngle = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + this._cachedSinAngle = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + this._cachedRotation = this.rotation; + if(this.parent.texture && this.parent.texture.renderRotation) { + this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); } else { - this.local.data[0] = this._cos * this.scale.x; - this.local.data[3] = (this._sin * this.scale.x) + this.skew.x; + this._cachedSin = 0; + this._cachedCos = 1; + } + }; + Transform.prototype.update = function () { + // Check cache + var dirty = false; + // 1) Height or Width change (also triggered by a change in scale) or an Origin change + if(this.parent.width !== this._cachedWidth || this.parent.height !== this._cachedHeight || this.origin.x !== this._cachedOriginX || this.origin.y !== this._cachedOriginY) { + this._cachedHalfWidth = this.parent.width / 2; + this._cachedHalfHeight = this.parent.height / 2; + this._cachedOffsetX = this.origin.x * this.parent.width; + this._cachedOffsetY = this.origin.y * this.parent.height; + this._cachedAngleToCenter = Math.atan2(this.halfHeight - this._cachedOffsetY, this.halfWidth - this._cachedOffsetX); + this._cachedDistance = Math.sqrt(((this._cachedOffsetX - this._cachedHalfWidth) * (this._cachedOffsetX - this._cachedHalfWidth)) + ((this._cachedOffsetY - this._cachedHalfHeight) * (this._cachedOffsetY - this._cachedHalfHeight))); + // Store + this._cachedWidth = this.parent.width; + this._cachedHeight = this.parent.height; + this._cachedOriginX = this.origin.x; + this._cachedOriginY = this.origin.y; + dirty = true; + } + // 2) Rotation change + if(this.rotation != this._cachedRotation) { + this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._cachedCosAngle = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + this._cachedSinAngle = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + if(this.parent.texture.renderRotation) { + this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + } else { + this._cachedSin = 0; + this._cachedCos = 1; + } + // Store + this._cachedRotation = this.rotation; + dirty = true; + } + if(dirty) { + this._cachedCenterX = this.parent.x + this._cachedDistance * this._cachedCosAngle; + this._cachedCenterY = this.parent.y + this._cachedDistance * this._cachedSinAngle; + } + // Scale and Skew + if(this.parent.texture.flippedX) { + this.local.data[0] = this._cachedCos * -this.scale.x; + this.local.data[3] = (this._cachedSin * -this.scale.x) + this.skew.x; + } else { + this.local.data[0] = this._cachedCos * this.scale.x; + this.local.data[3] = (this._cachedSin * this.scale.x) + this.skew.x; } if(this.parent.texture.flippedY) { - this.local.data[4] = this._cos * -this.scale.y; - this.local.data[1] = -(this._sin * -this.scale.y) + this.skew.y; + this.local.data[4] = this._cachedCos * -this.scale.y; + this.local.data[1] = -(this._cachedSin * -this.scale.y) + this.skew.y; } else { - this.local.data[4] = this._cos * this.scale.y; - this.local.data[1] = -(this._sin * this.scale.y) + this.skew.y; + this.local.data[4] = this._cachedCos * this.scale.y; + this.local.data[1] = -(this._cachedSin * this.scale.y) + this.skew.y; } // Translate this.local.data[2] = this.parent.x; this.local.data[5] = this.parent.y; }; - Object.defineProperty(Transform.prototype, "centerX", { + Object.defineProperty(Transform.prototype, "distance", { get: /** - * The center of the Sprite after taking scaling into consideration + * The distance from the center of the transform to the rotation origin. */ function () { - return this.parent.width / 2; - }, + return this._cachedDistance; + //return Math.sqrt(((this.offsetX - this.halfWidth) * (this.offsetX - this.halfWidth)) + ((this.offsetY - this.halfHeight) * (this.offsetY - this.halfHeight))); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "angleToCenter", { + get: /** + * The angle between the center of the transform to the rotation origin. + */ + function () { + return this._cachedAngleToCenter; + //return Math.atan2(this.halfHeight - this.offsetY, this.halfWidth - this.offsetX); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "offsetX", { + get: /** + * The offset on the X axis of the origin + */ + function () { + return this._cachedOffsetX; + //return this.origin.x * this.parent.width; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "offsetY", { + get: /** + * The offset on the Y axis of the origin + */ + function () { + return this._cachedOffsetY; + //return this.origin.y * this.parent.height; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "halfWidth", { + get: /** + * Half the width of the parent sprite, taking into consideration scaling + */ + function () { + return this._cachedHalfWidth; + //return this.parent.width / 2; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "halfHeight", { + get: /** + * Half the height of the parent sprite, taking into consideration scaling + */ + function () { + return this._cachedHalfHeight; + //return this.parent.height / 2; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "centerX", { + get: /** + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ + function () { + return this._cachedCenterX; + //return this.parent.x + this.distance * Math.cos((this.rotation * Math.PI / 180) + this.angleToCenter); + }, enumerable: true, configurable: true }); Object.defineProperty(Transform.prototype, "centerY", { get: /** - * The center of the Sprite after taking scaling into consideration + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration */ function () { - return this.parent.height / 2; + return this._cachedCenterY; + //return this.parent.y + this.distance * Math.sin((this.rotation * Math.PI / 180) + this.angleToCenter); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "sin", { + get: function () { + return this._cachedSin; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Transform.prototype, "cos", { + get: function () { + return this._cachedCos; }, enumerable: true, configurable: true @@ -4319,6 +4457,7 @@ var Phaser; this.body = new Phaser.Physics.Body(this, bodyType); this.worldView = new Phaser.Rectangle(x, y, this.width, this.height); this.cameraView = new Phaser.Rectangle(x, y, this.width, this.height); + this.transform.setCache(); } Object.defineProperty(Sprite.prototype, "rotation", { get: /** @@ -4394,8 +4533,10 @@ var Phaser; */ function () { this.transform.update(); - this.worldView.x = this.x * this.transform.scrollFactor.x; - this.worldView.y = this.y * this.transform.scrollFactor.y; + this.worldView.x = (this.x * this.transform.scrollFactor.x) - (this.width * this.transform.origin.x); + this.worldView.y = (this.y * this.transform.scrollFactor.y) - (this.height * this.transform.origin.y); + //this.worldView.x = this.x * this.transform.scrollFactor.x; + //this.worldView.y = this.y * this.transform.scrollFactor.y; this.worldView.width = this.width; this.worldView.height = this.height; if(this.modified == false && (!this.transform.scale.equals(1) || !this.transform.skew.equals(0) || this.transform.rotation != 0 || this.transform.rotationOffset != 0 || this.texture.flippedX || this.texture.flippedY)) { @@ -4514,32 +4655,28 @@ var Phaser; sprite.cameraView.height = sprite.height; } else { // If the sprite is rotated around its center we can use this quicker method: - // Work out bounding box - SpriteUtils._sin = Phaser.GameMath.sinA[sprite.rotation]; - SpriteUtils._cos = Phaser.GameMath.cosA[sprite.rotation]; - if(SpriteUtils._sin < 0) { - SpriteUtils._sin = -SpriteUtils._sin; - } - if(SpriteUtils._cos < 0) { - SpriteUtils._cos = -SpriteUtils._cos; - } - sprite.cameraView.width = Math.round(sprite.height * SpriteUtils._sin + sprite.width * SpriteUtils._cos); - sprite.cameraView.height = Math.round(sprite.height * SpriteUtils._cos + sprite.width * SpriteUtils._sin); - // if origin isn't 0.5 we need to work out the difference to apply to the x/y - if(sprite.transform.origin.equals(0.5)) { - // Easy out + if(sprite.transform.origin.x == 0.5 && sprite.transform.origin.y == 0.5) { + SpriteUtils._sin = Math.sin((sprite.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + SpriteUtils._cos = Math.cos((sprite.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + if(SpriteUtils._sin < 0) { + SpriteUtils._sin = -SpriteUtils._sin; + } + if(SpriteUtils._cos < 0) { + SpriteUtils._cos = -SpriteUtils._cos; + } + sprite.cameraView.width = Math.round(sprite.height * SpriteUtils._sin + sprite.width * SpriteUtils._cos); + sprite.cameraView.height = Math.round(sprite.height * SpriteUtils._cos + sprite.width * SpriteUtils._sin); sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); } else { - //var ax = sprite.cameraView.width * sprite.transform.origin.x; - //var ay = sprite.cameraView.height * sprite.transform.origin.y; - //var bx = sprite.cameraView.width * 0.5; - //var by = sprite.cameraView.height * 0.5; - //var c = sprite.game.math.distanceBetween(ax, ay, bx, by) / 2; - //console.log('actual x', ax, 'actual y', ay, 'cx', bx, 'cy', by); - sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); - sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); - } + /* + // Useful to get the maximum AABB size of any given rect + + If you want a single box that covers all angles, just take the half-diagonal of your existing box as the radius of a circle. + The new box has to contain this circle, so it should be a square with side-length equal to twice the radius + (equiv. the diagonal of the original AABB) and with the same center as the original. + */ + } } if(sprite.animations.currentFrame !== null && sprite.animations.currentFrame.trimmed) { //sprite.cameraView.x += sprite.animations.currentFrame.spriteSourceSizeX; @@ -4549,6 +4686,58 @@ var Phaser; } return sprite.cameraView; }; + SpriteUtils.getCornersAsPoints = function getCornersAsPoints(sprite) { + var out = []; + var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + // Upper Left + out.push(new Phaser.Point(sprite.x + (sprite.width / 2) * cos - (sprite.height / 2) * sin, sprite.y + (sprite.height / 2) * cos + (sprite.width / 2) * sin)); + // Upper Right + out.push(new Phaser.Point(sprite.x - (sprite.width / 2) * cos - (sprite.height / 2) * sin, sprite.y + (sprite.height / 2) * cos - (sprite.width / 2) * sin)); + // Bottom Left + out.push(new Phaser.Point(sprite.x + (sprite.width / 2) * cos + (sprite.height / 2) * sin, sprite.y - (sprite.height / 2) * cos + (sprite.width / 2) * sin)); + // Bottom Right + out.push(new Phaser.Point(sprite.x - (sprite.width / 2) * cos + (sprite.height / 2) * sin, sprite.y - (sprite.height / 2) * cos - (sprite.width / 2) * sin)); + return out; + }; + SpriteUtils.getCornersAsPoints2 = function getCornersAsPoints2(sprite) { + var out = []; + var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + // This = the center point + var cx = sprite.x + (sprite.width / 2) * cos - (sprite.height / 2) * sin; + var cy = sprite.y + (sprite.height / 2) * cos + (sprite.width / 2) * sin; + // Upper Left + out.push(new Phaser.Point(cx + (sprite.width / 2) * cos - (sprite.height / 2) * sin, cy + (sprite.height / 2) * cos + (sprite.width / 2) * sin)); + // Upper Right + out.push(new Phaser.Point(cx - (sprite.width / 2) * cos - (sprite.height / 2) * sin, cy + (sprite.height / 2) * cos - (sprite.width / 2) * sin)); + // Bottom Left + out.push(new Phaser.Point(cx + (sprite.width / 2) * cos + (sprite.height / 2) * sin, cy - (sprite.height / 2) * cos + (sprite.width / 2) * sin)); + // Bottom Right + out.push(new Phaser.Point(cx - (sprite.width / 2) * cos + (sprite.height / 2) * sin, cy - (sprite.height / 2) * cos - (sprite.width / 2) * sin)); + return out; + }; + SpriteUtils.getCornersAsPoints3 = function getCornersAsPoints3(sprite) { + var out = []; + var sin = sprite.transform.sin; + var cos = sprite.transform.cos; + //var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + //var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + // This = the center point + //var cx = sprite.x + sprite.transform.distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); + //var cy = sprite.y + sprite.transform.distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); + var cx = sprite.transform.centerX; + var cy = sprite.transform.centerY; + // Upper Left + out.push(new Phaser.Point(cx + sprite.transform.halfWidth * cos - sprite.transform.halfHeight * sin, cy + sprite.transform.halfHeight * cos + sprite.transform.halfWidth * sin)); + // Upper Right + out.push(new Phaser.Point(cx - sprite.transform.halfWidth * cos - sprite.transform.halfHeight * sin, cy + sprite.transform.halfHeight * cos - sprite.transform.halfWidth * sin)); + // Bottom Left + out.push(new Phaser.Point(cx + sprite.transform.halfWidth * cos + sprite.transform.halfHeight * sin, cy - sprite.transform.halfHeight * cos + sprite.transform.halfWidth * sin)); + // Bottom Right + out.push(new Phaser.Point(cx - sprite.transform.halfWidth * cos + sprite.transform.halfHeight * sin, cy - sprite.transform.halfHeight * cos - sprite.transform.halfWidth * sin)); + return out; + }; SpriteUtils.getAsPoints = function getAsPoints(sprite) { var out = []; // top left @@ -16411,7 +16600,6 @@ var Phaser; if(sprite.transform.scrollFactor.equals(0)) { return true; } - Phaser.SpriteUtils.updateCameraView(camera, sprite); return Phaser.RectangleUtils.intersects(sprite.cameraView, camera.screenView); }; CanvasRenderer.prototype.inScreen = function (camera) { @@ -16579,8 +16767,8 @@ var Phaser; function (camera, sprite) { Phaser.SpriteUtils.updateCameraView(camera, sprite); if(sprite.transform.scale.x == 0 || sprite.transform.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { - //return false; - } + return false; + } sprite.renderOrderID = this._count; this._count++; // Reset our temp vars From c2533d1146fcfeb9ec36bc9b7486e2238b8cadab Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 11 Jun 2013 23:30:35 +0100 Subject: [PATCH 6/8] Finally a fully working bounding box that respects scale and rotation - the "in camera" check is now 100% accurate :) --- Phaser/components/Transform.ts | 210 ++++++++++++---------- Phaser/renderers/CanvasRenderer.ts | 3 +- Phaser/utils/SpriteUtils.ts | 103 ++--------- Tests/misc/point1.js | 93 +++------- Tests/misc/point1.ts | 100 ++++------- Tests/phaser.js | 275 +++++++++++++---------------- build/phaser.d.ts | 47 ++--- build/phaser.js | 275 +++++++++++++---------------- 8 files changed, 459 insertions(+), 647 deletions(-) diff --git a/Phaser/components/Transform.ts b/Phaser/components/Transform.ts index bc9830da..4f3976ae 100644 --- a/Phaser/components/Transform.ts +++ b/Phaser/components/Transform.ts @@ -25,62 +25,83 @@ module Phaser.Components { this.scale = new Phaser.Vec2(1, 1); this.skew = new Phaser.Vec2; + this.center = new Phaser.Point; + this.upperLeft = new Phaser.Point; + this.upperRight = new Phaser.Point; + this.bottomLeft = new Phaser.Point; + this.bottomRight = new Phaser.Point; + + this._pos = new Phaser.Point; + this._scale = new Phaser.Point; + this._size = new Phaser.Point; + this._halfSize = new Phaser.Point; + this._offset = new Phaser.Point; + this._origin = new Phaser.Point; + this._sc = new Phaser.Point; + this._scA = new Phaser.Point; + } private _rotation: number; - private _cachedSin: number; - private _cachedCos: number; - private _cachedRotation: number; - private _cachedScaleX: number; - private _cachedScaleY: number; - private _cachedAngle: number; - private _cachedAngleToCenter: number; - private _cachedDistance: number; - private _cachedWidth: number; - private _cachedHeight: number; - private _cachedHalfWidth: number; - private _cachedHalfHeight: number; - private _cachedCosAngle: number; - private _cachedSinAngle: number; - private _cachedOffsetX: number; - private _cachedOffsetY: number; - private _cachedOriginX: number; - private _cachedOriginY: number; - private _cachedCenterX: number; - private _cachedCenterY: number; + // Cache vars + private _pos: Phaser.Point; + private _scale: Phaser.Point; + private _size: Phaser.Point; + private _halfSize: Phaser.Point; + private _offset: Phaser.Point; + private _origin: Phaser.Point; + private _sc: Phaser.Point; + private _scA: Phaser.Point; + private _angle: number; + private _distance: number; + private _prevRotation: number; + + public center: Phaser.Point; + public upperLeft: Phaser.Point; + public upperRight: Phaser.Point; + public bottomLeft: Phaser.Point; + public bottomRight: Phaser.Point; public local: Mat3; public setCache() { - this._cachedHalfWidth = this.parent.width / 2; - this._cachedHalfHeight = this.parent.height / 2; - this._cachedOffsetX = this.origin.x * this.parent.width; - this._cachedOffsetY = this.origin.y * this.parent.height; - this._cachedAngleToCenter = Math.atan2(this.halfHeight - this._cachedOffsetY, this.halfWidth - this._cachedOffsetX); - this._cachedDistance = Math.sqrt(((this._cachedOffsetX - this._cachedHalfWidth) * (this._cachedOffsetX - this._cachedHalfWidth)) + ((this._cachedOffsetY - this._cachedHalfHeight) * (this._cachedOffsetY - this._cachedHalfHeight))); - this._cachedWidth = this.parent.width; - this._cachedHeight = this.parent.height; - this._cachedOriginX = this.origin.x; - this._cachedOriginY = this.origin.y; - this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); - this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); - this._cachedCosAngle = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD + this._cachedAngleToCenter); - this._cachedSinAngle = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD + this._cachedAngleToCenter); - this._cachedRotation = this.rotation; + this._pos.x = this.parent.x; + this._pos.y = this.parent.y; + this._halfSize.x = this.parent.width / 2; + this._halfSize.y = this.parent.height / 2; + this._offset.x = this.origin.x * this.parent.width; + this._offset.y = this.origin.y * this.parent.height; + this._angle = Math.atan2(this.halfHeight - this._offset.y, this.halfWidth - this._offset.x); + this._distance = Math.sqrt(((this._offset.x - this._halfSize.x) * (this._offset.x - this._halfSize.x)) + ((this._offset.y - this._halfSize.y) * (this._offset.y - this._halfSize.y))); + this._size.x = this.parent.width; + this._size.y = this.parent.height; + this._origin.x = this.origin.x; + this._origin.y = this.origin.y; + this._sc.x = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._sc.y = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._scA.y = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD + this._angle); + this._scA.x = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD + this._angle); + this._prevRotation = this.rotation; if (this.parent.texture && this.parent.texture.renderRotation) { - this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); - this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._sc.x = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._sc.y = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); } else { - this._cachedSin = 0; - this._cachedCos = 1; + this._sc.x = 0; + this._sc.y = 1; } + this.center.setTo(this.center.x, this.center.y); + this.upperLeft.setTo(this.center.x - this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); + this.upperRight.setTo(this.center.x + this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + this.bottomLeft.setTo(this.center.x - this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); + this.bottomRight.setTo(this.center.x + this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + } public update() { @@ -89,73 +110,84 @@ module Phaser.Components { var dirty: bool = false; // 1) Height or Width change (also triggered by a change in scale) or an Origin change - if (this.parent.width !== this._cachedWidth || this.parent.height !== this._cachedHeight || this.origin.x !== this._cachedOriginX|| this.origin.y !== this._cachedOriginY) + if (this.parent.width !== this._size.x || this.parent.height !== this._size.y || this.origin.x !== this._origin.x|| this.origin.y !== this._origin.y) { - this._cachedHalfWidth = this.parent.width / 2; - this._cachedHalfHeight = this.parent.height / 2; - this._cachedOffsetX = this.origin.x * this.parent.width; - this._cachedOffsetY = this.origin.y * this.parent.height; - this._cachedAngleToCenter = Math.atan2(this.halfHeight - this._cachedOffsetY, this.halfWidth - this._cachedOffsetX); - this._cachedDistance = Math.sqrt(((this._cachedOffsetX - this._cachedHalfWidth) * (this._cachedOffsetX - this._cachedHalfWidth)) + ((this._cachedOffsetY - this._cachedHalfHeight) * (this._cachedOffsetY - this._cachedHalfHeight))); + this._halfSize.x = this.parent.width / 2; + this._halfSize.y = this.parent.height / 2; + this._offset.x = this.origin.x * this.parent.width; + this._offset.y = this.origin.y * this.parent.height; + this._angle = Math.atan2(this.halfHeight - this._offset.y, this.halfWidth - this._offset.x); + this._distance = Math.sqrt(((this._offset.x - this._halfSize.x) * (this._offset.x - this._halfSize.x)) + ((this._offset.y - this._halfSize.y) * (this._offset.y - this._halfSize.y))); // Store - this._cachedWidth = this.parent.width; - this._cachedHeight = this.parent.height; - this._cachedOriginX = this.origin.x; - this._cachedOriginY = this.origin.y; + this._size.x = this.parent.width; + this._size.y = this.parent.height; + this._origin.x = this.origin.x; + this._origin.y = this.origin.y; dirty = true; } // 2) Rotation change - if (this.rotation != this._cachedRotation) + if (this.rotation != this._prevRotation) { - this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); - this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); - this._cachedCosAngle = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD + this._cachedAngleToCenter); - this._cachedSinAngle = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + this._sc.x = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._sc.y = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._scA.y = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD + this._angle); + this._scA.x = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD + this._angle); if (this.parent.texture.renderRotation) { - this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); - this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._sc.x = Math.sin((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); + this._sc.y = Math.cos((this.rotation + this.rotationOffset) * GameMath.DEG_TO_RAD); } else { - this._cachedSin = 0; - this._cachedCos = 1; + this._sc.x = 0; + this._sc.y = 1; } // Store - this._cachedRotation = this.rotation; + this._prevRotation = this.rotation; dirty = true; } - if (dirty) + // If it has moved, updated the edges and center + if (dirty || this.parent.x != this._pos.x || this.parent.y != this._pos.y) { - this._cachedCenterX = this.parent.x + this._cachedDistance * this._cachedCosAngle; - this._cachedCenterY = this.parent.y + this._cachedDistance * this._cachedSinAngle; + this.center.x = this.parent.x + this._distance * this._scA.y; + this.center.y = this.parent.y + this._distance * this._scA.x; + + this.center.setTo(this.center.x, this.center.y); + + this.upperLeft.setTo(this.center.x - this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); + this.upperRight.setTo(this.center.x + this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + this.bottomLeft.setTo(this.center.x - this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); + this.bottomRight.setTo(this.center.x + this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + + this._pos.x = this.parent.x; + this._pos.y = this.parent.y; } // Scale and Skew if (this.parent.texture.flippedX) { - this.local.data[0] = this._cachedCos * -this.scale.x; - this.local.data[3] = (this._cachedSin * -this.scale.x) + this.skew.x; + this.local.data[0] = this._sc.y * -this.scale.x; + this.local.data[3] = (this._sc.x * -this.scale.x) + this.skew.x; } else { - this.local.data[0] = this._cachedCos * this.scale.x; - this.local.data[3] = (this._cachedSin * this.scale.x) + this.skew.x; + this.local.data[0] = this._sc.y * this.scale.x; + this.local.data[3] = (this._sc.x * this.scale.x) + this.skew.x; } if (this.parent.texture.flippedY) { - this.local.data[4] = this._cachedCos * -this.scale.y; - this.local.data[1] = -(this._cachedSin * -this.scale.y) + this.skew.y; + this.local.data[4] = this._sc.y * -this.scale.y; + this.local.data[1] = -(this._sc.x * -this.scale.y) + this.skew.y; } else { - this.local.data[4] = this._cachedCos * this.scale.y; - this.local.data[1] = -(this._cachedSin * this.scale.y) + this.skew.y; + this.local.data[4] = this._sc.y * this.scale.y; + this.local.data[1] = -(this._sc.x * this.scale.y) + this.skew.y; } // Translate @@ -211,72 +243,64 @@ module Phaser.Components { * The distance from the center of the transform to the rotation origin. */ public get distance(): number { - return this._cachedDistance; - //return Math.sqrt(((this.offsetX - this.halfWidth) * (this.offsetX - this.halfWidth)) + ((this.offsetY - this.halfHeight) * (this.offsetY - this.halfHeight))); + return this._distance; } /** * The angle between the center of the transform to the rotation origin. */ public get angleToCenter(): number { - return this._cachedAngleToCenter; - //return Math.atan2(this.halfHeight - this.offsetY, this.halfWidth - this.offsetX); + return this._angle; } /** * The offset on the X axis of the origin */ public get offsetX(): number { - return this._cachedOffsetX; - //return this.origin.x * this.parent.width; + return this._offset.x; } /** * The offset on the Y axis of the origin */ public get offsetY(): number { - return this._cachedOffsetY; - //return this.origin.y * this.parent.height; + return this._offset.y; } /** * Half the width of the parent sprite, taking into consideration scaling */ public get halfWidth(): number { - return this._cachedHalfWidth; - //return this.parent.width / 2; + return this._halfSize.x; } /** * Half the height of the parent sprite, taking into consideration scaling */ public get halfHeight(): number { - return this._cachedHalfHeight; - //return this.parent.height / 2; + return this._halfSize.y; } /** * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration */ - public get centerX(): number { - return this._cachedCenterX; - //return this.parent.x + this.distance * Math.cos((this.rotation * Math.PI / 180) + this.angleToCenter); - } + //public get centerX(): number { + // return this.center.x; + //} /** * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration */ - public get centerY(): number { - return this._cachedCenterY; - //return this.parent.y + this.distance * Math.sin((this.rotation * Math.PI / 180) + this.angleToCenter); - } + //public get centerY(): number { + // return this.center.y; + //} public get sin(): number { - return this._cachedSin; + return this._sc.x; } public get cos(): number { - return this._cachedCos; + return this._sc.y; } } diff --git a/Phaser/renderers/CanvasRenderer.ts b/Phaser/renderers/CanvasRenderer.ts index c3558af4..2c61a60e 100644 --- a/Phaser/renderers/CanvasRenderer.ts +++ b/Phaser/renderers/CanvasRenderer.ts @@ -221,7 +221,8 @@ module Phaser { return true; } - return RectangleUtils.intersects(sprite.cameraView, camera.screenView); + return true; + //return RectangleUtils.intersects(sprite.cameraView, camera.screenView); } diff --git a/Phaser/utils/SpriteUtils.ts b/Phaser/utils/SpriteUtils.ts index 1a3e4875..73605f2a 100644 --- a/Phaser/utils/SpriteUtils.ts +++ b/Phaser/utils/SpriteUtils.ts @@ -40,8 +40,8 @@ module Phaser { // If the sprite is rotated around its center we can use this quicker method: if (sprite.transform.origin.x == 0.5 && sprite.transform.origin.y == 0.5) { - SpriteUtils._sin = Math.sin((sprite.rotation + sprite.transform.rotationOffset) * GameMath.DEG_TO_RAD); - SpriteUtils._cos = Math.cos((sprite.rotation + sprite.transform.rotationOffset) * GameMath.DEG_TO_RAD); + SpriteUtils._sin = sprite.transform.sin; + SpriteUtils._cos = sprite.transform.cos; if (SpriteUtils._sin < 0) { @@ -60,8 +60,23 @@ module Phaser { } else { + //var left:Number = Math.min(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x); + //var top:Number = Math.min(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y); + //var right:Number = Math.max(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x); + //var bottom:Number = Math.max(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y); + //return new Rectangle(left, top, right - left, bottom - top); + var minX: number = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + var minY: number = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + var maxX: number = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + var maxY: number = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + // (min_x,min_y), (min_x,max_y), (max_x,max_y), (max_x,min_y) + + sprite.cameraView.x = minX; + sprite.cameraView.y = minY; + sprite.cameraView.width = maxX - minX; + sprite.cameraView.height = maxY - minY; /* // Useful to get the maximum AABB size of any given rect @@ -87,90 +102,6 @@ module Phaser { } - static getCornersAsPoints(sprite: Sprite): Phaser.Point[] { - - var out: Phaser.Point[] = []; - - var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - - // Upper Left - out.push(new Point(sprite.x + (sprite.width / 2) * cos - (sprite.height / 2) * sin, sprite.y + (sprite.height / 2) * cos + (sprite.width / 2) * sin)); - - // Upper Right - out.push(new Point(sprite.x - (sprite.width / 2) * cos - (sprite.height / 2) * sin, sprite.y + (sprite.height / 2) * cos - (sprite.width / 2) * sin)); - - // Bottom Left - out.push(new Point(sprite.x + (sprite.width / 2) * cos + (sprite.height / 2) * sin, sprite.y - (sprite.height / 2) * cos + (sprite.width / 2) * sin)); - - // Bottom Right - out.push(new Point(sprite.x - (sprite.width / 2) * cos + (sprite.height / 2) * sin, sprite.y - (sprite.height / 2) * cos - (sprite.width / 2) * sin)); - - return out; - - } - - static getCornersAsPoints2(sprite: Sprite): Phaser.Point[] { - - var out: Phaser.Point[] = []; - - var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - - // This = the center point - var cx = sprite.x + (sprite.width / 2) * cos - (sprite.height / 2) * sin; - var cy = sprite.y + (sprite.height / 2) * cos + (sprite.width / 2) * sin; - - // Upper Left - out.push(new Point(cx + (sprite.width / 2) * cos - (sprite.height / 2) * sin, cy + (sprite.height / 2) * cos + (sprite.width / 2) * sin)); - - // Upper Right - out.push(new Point(cx - (sprite.width / 2) * cos - (sprite.height / 2) * sin, cy + (sprite.height / 2) * cos - (sprite.width / 2) * sin)); - - // Bottom Left - out.push(new Point(cx + (sprite.width / 2) * cos + (sprite.height / 2) * sin, cy - (sprite.height / 2) * cos + (sprite.width / 2) * sin)); - - // Bottom Right - out.push(new Point(cx - (sprite.width / 2) * cos + (sprite.height / 2) * sin, cy - (sprite.height / 2) * cos - (sprite.width / 2) * sin)); - - return out; - - } - - static getCornersAsPoints3(sprite: Sprite): Phaser.Point[] { - - var out: Phaser.Point[] = []; - - var sin: number = sprite.transform.sin; - var cos: number = sprite.transform.cos; - - //var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - //var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - - // This = the center point - //var cx = sprite.x + sprite.transform.distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); - //var cy = sprite.y + sprite.transform.distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); - - var cx: number = sprite.transform.centerX; - var cy: number = sprite.transform.centerY; - - // Upper Left - out.push(new Point(cx + sprite.transform.halfWidth * cos - sprite.transform.halfHeight * sin, cy + sprite.transform.halfHeight * cos + sprite.transform.halfWidth * sin)); - - // Upper Right - out.push(new Point(cx - sprite.transform.halfWidth * cos - sprite.transform.halfHeight * sin, cy + sprite.transform.halfHeight * cos - sprite.transform.halfWidth * sin)); - - // Bottom Left - out.push(new Point(cx + sprite.transform.halfWidth * cos + sprite.transform.halfHeight * sin, cy - sprite.transform.halfHeight * cos + sprite.transform.halfWidth * sin)); - - // Bottom Right - out.push(new Point(cx - sprite.transform.halfWidth * cos + sprite.transform.halfHeight * sin, cy - sprite.transform.halfHeight * cos - sprite.transform.halfWidth * sin)); - - return out; - - } - - static getAsPoints(sprite: Sprite): Phaser.Point[] { var out: Phaser.Point[] = []; diff --git a/Tests/misc/point1.js b/Tests/misc/point1.js index 5e4d49de..e78fa486 100644 --- a/Tests/misc/point1.js +++ b/Tests/misc/point1.js @@ -3,30 +3,21 @@ var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); function init() { game.load.image('box2', 'assets/tests/320x200.png'); - game.load.image('box1', 'assets/sprites/oz_pov_melting_disk.png'); - game.load.image('box', 'assets/sprites/bunny.png'); + game.load.image('box', 'assets/sprites/oz_pov_melting_disk.png'); + game.load.image('box1', 'assets/sprites/bunny.png'); game.load.start(); } var sprite; var rotate = false; function create() { game.stage.backgroundColor = 'rgb(0,0,0)'; - game.stage.disablePauseScreen = true; sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); //sprite.transform.scale.setTo(0.5, 0.5); - sprite.transform.origin.setTo(0.3, 0.3); + sprite.transform.origin.setTo(0, 0); + //sprite.transform.origin.setTo(0.5, 0.5); game.input.onTap.add(rotateIt, this); - game.add.tween(sprite.transform.scale).to({ - x: 0.5, - y: 0.5 - }, 2000, Phaser.Easing.Linear.None, true, 0, true); - points = [ - new Phaser.Point(), - new Phaser.Point(), - new Phaser.Point(), - new Phaser.Point() - ]; - } + //game.add.tween(sprite.transform.scale).to({ x: 0.5, y: 0.5 }, 2000, Phaser.Easing.Linear.None, true, 0, true); + } function rotateIt() { if(rotate == false) { rotate = true; @@ -39,59 +30,29 @@ sprite.rotation++; } } - var points; function render() { - /* - points = Phaser.SpriteUtils.getCornersAsPoints3(sprite); - - game.stage.context.fillStyle = 'rgb(255,255,0)'; - game.stage.context.fillRect(points[0].x, points[0].y, 2, 2); - game.stage.context.fillRect(points[1].x, points[1].y, 2, 2); - game.stage.context.fillRect(points[2].x, points[2].y, 2, 2); - game.stage.context.fillRect(points[3].x, points[3].y, 2, 2); - */ - var originX = sprite.transform.origin.x * sprite.width; - var originY = sprite.transform.origin.y * sprite.height; - var centerX = 0.5 * sprite.width; - var centerY = 0.5 * sprite.height; - var distance = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); - var originAngle = Math.atan2(centerY - originY, centerX - originX); - var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - //var px = sprite.x + distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + originAngle); - //var py = sprite.y + distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + originAngle); - // WORKS - //var px = sprite.x + sprite.transform.distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); - //var py = sprite.y + sprite.transform.distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); - // Upper Left - //points[0].setTo(px + (sprite.width / 2) * cos - (sprite.height / 2) * sin, py + (sprite.height / 2) * cos + (sprite.width / 2) * sin); - // Upper Right - //points[1].setTo(px - (sprite.width / 2) * cos - (sprite.height / 2) * sin, py + (sprite.height / 2) * cos - (sprite.width / 2) * sin); - // Bottom Left - //points[2].setTo(px + (sprite.width / 2) * cos + (sprite.height / 2) * sin, py - (sprite.height / 2) * cos + (sprite.width / 2) * sin); - // Bottom Right - //points[3].setTo(px - (sprite.width / 2) * cos + (sprite.height / 2) * sin, py - (sprite.height / 2) * cos - (sprite.width / 2) * sin); - points = Phaser.SpriteUtils.getCornersAsPoints3(sprite); game.stage.context.save(); - game.stage.context.fillStyle = 'rgb(0,255,255)'; - //game.stage.context.fillRect(px, py, 2, 2); - game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); - game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); - game.stage.context.fillText('angle: ' + sprite.rotation, 32, 72); - game.stage.context.fillText('point of rotation x: ' + sprite.transform.origin.x + ' y: ' + sprite.transform.origin.y, 32, 92); - game.stage.context.fillText('x: ' + sprite.x + ' y: ' + sprite.y, sprite.x + 4, sprite.y); - game.stage.context.fillRect(points[0].x, points[0].y, 2, 2); - game.stage.context.fillRect(points[1].x, points[1].y, 2, 2); - game.stage.context.fillRect(points[2].x, points[2].y, 2, 2); - game.stage.context.fillRect(points[3].x, points[3].y, 2, 2); - game.stage.context.restore(); - game.stage.context.save(); - game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; - game.stage.context.beginPath(); - game.stage.context.moveTo(sprite.x, sprite.y); - game.stage.context.arc(sprite.x, sprite.y, distance, 0, Math.PI * 2); - game.stage.context.closePath(); - game.stage.context.fill(); + game.stage.context.fillStyle = 'rgb(255,0,255)'; + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperLeft.x) + ' y: ' + Math.round(sprite.transform.upperLeft.y), sprite.transform.upperLeft.x, sprite.transform.upperLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperRight.x) + ' y: ' + Math.round(sprite.transform.upperRight.y), sprite.transform.upperRight.x, sprite.transform.upperRight.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomLeft.x) + ' y: ' + Math.round(sprite.transform.bottomLeft.y), sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomRight.x) + ' y: ' + Math.round(sprite.transform.bottomRight.y), sprite.transform.bottomRight.x, sprite.transform.bottomRight.y); + var minX = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + var minY = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + var maxX = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + var maxY = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + var width = maxX - minX; + var height = maxY - minY; + game.stage.context.fillText('minX: ' + minX + ' minY: ' + minY, 32, 32); + game.stage.context.fillText('maxX: ' + maxX + ' maxY: ' + maxY, 32, 64); + game.stage.context.fillRect(sprite.transform.center.x, sprite.transform.center.y, 2, 2); + game.stage.context.fillRect(sprite.transform.upperLeft.x, sprite.transform.upperLeft.y, 2, 2); + game.stage.context.fillRect(sprite.transform.upperRight.x, sprite.transform.upperRight.y, 2, 2); + game.stage.context.fillRect(sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y, 2, 2); + game.stage.context.fillRect(sprite.transform.bottomRight.x, sprite.transform.bottomRight.y, 2, 2); + game.stage.context.strokeStyle = 'rgb(255,255,0)'; + game.stage.context.strokeRect(sprite.cameraView.x, sprite.cameraView.y, sprite.cameraView.width, sprite.cameraView.height); + //game.stage.context.strokeRect(minX, minY, width, height); game.stage.context.restore(); } })(); diff --git a/Tests/misc/point1.ts b/Tests/misc/point1.ts index 55bf59b9..904d7d39 100644 --- a/Tests/misc/point1.ts +++ b/Tests/misc/point1.ts @@ -7,8 +7,8 @@ function init() { game.load.image('box2', 'assets/tests/320x200.png'); - game.load.image('box1', 'assets/sprites/oz_pov_melting_disk.png'); - game.load.image('box', 'assets/sprites/bunny.png'); + game.load.image('box', 'assets/sprites/oz_pov_melting_disk.png'); + game.load.image('box1', 'assets/sprites/bunny.png'); game.load.start(); } @@ -19,19 +19,16 @@ function create() { game.stage.backgroundColor = 'rgb(0,0,0)'; - game.stage.disablePauseScreen = true; sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); //sprite.transform.scale.setTo(0.5, 0.5); - - sprite.transform.origin.setTo(0.3, 0.3); + sprite.transform.origin.setTo(0, 0); + //sprite.transform.origin.setTo(0.5, 0.5); game.input.onTap.add(rotateIt, this); - game.add.tween(sprite.transform.scale).to({ x: 0.5, y: 0.5 }, 2000, Phaser.Easing.Linear.None, true, 0, true); - - points = [new Phaser.Point, new Phaser.Point, new Phaser.Point, new Phaser.Point]; + //game.add.tween(sprite.transform.scale).to({ x: 0.5, y: 0.5 }, 2000, Phaser.Easing.Linear.None, true, 0, true); } @@ -48,74 +45,37 @@ } - var points: Phaser.Point[]; - function render() { - /* - points = Phaser.SpriteUtils.getCornersAsPoints3(sprite); - - game.stage.context.fillStyle = 'rgb(255,255,0)'; - game.stage.context.fillRect(points[0].x, points[0].y, 2, 2); - game.stage.context.fillRect(points[1].x, points[1].y, 2, 2); - game.stage.context.fillRect(points[2].x, points[2].y, 2, 2); - game.stage.context.fillRect(points[3].x, points[3].y, 2, 2); - */ - - var originX: number = sprite.transform.origin.x * sprite.width; - var originY: number = sprite.transform.origin.y * sprite.height; - var centerX: number = 0.5 * sprite.width; - var centerY: number = 0.5 * sprite.height; - var distance: number = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); - var originAngle: number = Math.atan2(centerY - originY, centerX - originX); - - var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - - //var px = sprite.x + distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + originAngle); - //var py = sprite.y + distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + originAngle); - - // WORKS - //var px = sprite.x + sprite.transform.distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); - //var py = sprite.y + sprite.transform.distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); - - // Upper Left - //points[0].setTo(px + (sprite.width / 2) * cos - (sprite.height / 2) * sin, py + (sprite.height / 2) * cos + (sprite.width / 2) * sin); - - // Upper Right - //points[1].setTo(px - (sprite.width / 2) * cos - (sprite.height / 2) * sin, py + (sprite.height / 2) * cos - (sprite.width / 2) * sin); - - // Bottom Left - //points[2].setTo(px + (sprite.width / 2) * cos + (sprite.height / 2) * sin, py - (sprite.height / 2) * cos + (sprite.width / 2) * sin); - - // Bottom Right - //points[3].setTo(px - (sprite.width / 2) * cos + (sprite.height / 2) * sin, py - (sprite.height / 2) * cos - (sprite.width / 2) * sin); - - points = Phaser.SpriteUtils.getCornersAsPoints3(sprite); - game.stage.context.save(); - game.stage.context.fillStyle = 'rgb(0,255,255)'; - //game.stage.context.fillRect(px, py, 2, 2); - game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); - game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); - game.stage.context.fillText('angle: ' + sprite.rotation , 32, 72); - game.stage.context.fillText('point of rotation x: ' + sprite.transform.origin.x + ' y: ' + sprite.transform.origin.y, 32, 92); - game.stage.context.fillText('x: ' + sprite.x + ' y: ' + sprite.y, sprite.x + 4, sprite.y); + game.stage.context.fillStyle = 'rgb(255,0,255)'; - game.stage.context.fillRect(points[0].x, points[0].y, 2, 2); - game.stage.context.fillRect(points[1].x, points[1].y, 2, 2); - game.stage.context.fillRect(points[2].x, points[2].y, 2, 2); - game.stage.context.fillRect(points[3].x, points[3].y, 2, 2); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperLeft.x) + ' y: ' + Math.round(sprite.transform.upperLeft.y), sprite.transform.upperLeft.x, sprite.transform.upperLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperRight.x) + ' y: ' + Math.round(sprite.transform.upperRight.y), sprite.transform.upperRight.x, sprite.transform.upperRight.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomLeft.x) + ' y: ' + Math.round(sprite.transform.bottomLeft.y), sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomRight.x) + ' y: ' + Math.round(sprite.transform.bottomRight.y), sprite.transform.bottomRight.x, sprite.transform.bottomRight.y); - game.stage.context.restore(); + var minX: number = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + var minY: number = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + var maxX: number = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + var maxY: number = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + + var width = maxX - minX; + var height = maxY - minY; + + game.stage.context.fillText('minX: ' + minX + ' minY: ' + minY, 32, 32); + game.stage.context.fillText('maxX: ' + maxX + ' maxY: ' + maxY, 32, 64); + + game.stage.context.fillRect(sprite.transform.center.x, sprite.transform.center.y, 2, 2); + game.stage.context.fillRect(sprite.transform.upperLeft.x, sprite.transform.upperLeft.y, 2, 2); + game.stage.context.fillRect(sprite.transform.upperRight.x, sprite.transform.upperRight.y, 2, 2); + game.stage.context.fillRect(sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y, 2, 2); + game.stage.context.fillRect(sprite.transform.bottomRight.x, sprite.transform.bottomRight.y, 2, 2); + + game.stage.context.strokeStyle = 'rgb(255,255,0)'; + game.stage.context.strokeRect(sprite.cameraView.x, sprite.cameraView.y, sprite.cameraView.width, sprite.cameraView.height); + //game.stage.context.strokeRect(minX, minY, width, height); - game.stage.context.save(); - game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; - game.stage.context.beginPath(); - game.stage.context.moveTo(sprite.x, sprite.y); - game.stage.context.arc(sprite.x, sprite.y, distance, 0, Math.PI * 2); - game.stage.context.closePath(); - game.stage.context.fill(); game.stage.context.restore(); } diff --git a/Tests/phaser.js b/Tests/phaser.js index 279c2dfc..cc94bbce 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -3082,84 +3082,112 @@ var Phaser; this.origin = new Phaser.Vec2(); this.scale = new Phaser.Vec2(1, 1); this.skew = new Phaser.Vec2(); + this.center = new Phaser.Point(); + this.upperLeft = new Phaser.Point(); + this.upperRight = new Phaser.Point(); + this.bottomLeft = new Phaser.Point(); + this.bottomRight = new Phaser.Point(); + this._pos = new Phaser.Point(); + this._scale = new Phaser.Point(); + this._size = new Phaser.Point(); + this._halfSize = new Phaser.Point(); + this._offset = new Phaser.Point(); + this._origin = new Phaser.Point(); + this._sc = new Phaser.Point(); + this._scA = new Phaser.Point(); } Transform.prototype.setCache = function () { - this._cachedHalfWidth = this.parent.width / 2; - this._cachedHalfHeight = this.parent.height / 2; - this._cachedOffsetX = this.origin.x * this.parent.width; - this._cachedOffsetY = this.origin.y * this.parent.height; - this._cachedAngleToCenter = Math.atan2(this.halfHeight - this._cachedOffsetY, this.halfWidth - this._cachedOffsetX); - this._cachedDistance = Math.sqrt(((this._cachedOffsetX - this._cachedHalfWidth) * (this._cachedOffsetX - this._cachedHalfWidth)) + ((this._cachedOffsetY - this._cachedHalfHeight) * (this._cachedOffsetY - this._cachedHalfHeight))); - this._cachedWidth = this.parent.width; - this._cachedHeight = this.parent.height; - this._cachedOriginX = this.origin.x; - this._cachedOriginY = this.origin.y; - this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - this._cachedCosAngle = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); - this._cachedSinAngle = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); - this._cachedRotation = this.rotation; + this._pos.x = this.parent.x; + this._pos.y = this.parent.y; + this._halfSize.x = this.parent.width / 2; + this._halfSize.y = this.parent.height / 2; + this._offset.x = this.origin.x * this.parent.width; + this._offset.y = this.origin.y * this.parent.height; + this._angle = Math.atan2(this.halfHeight - this._offset.y, this.halfWidth - this._offset.x); + this._distance = Math.sqrt(((this._offset.x - this._halfSize.x) * (this._offset.x - this._halfSize.x)) + ((this._offset.y - this._halfSize.y) * (this._offset.y - this._halfSize.y))); + this._size.x = this.parent.width; + this._size.y = this.parent.height; + this._origin.x = this.origin.x; + this._origin.y = this.origin.y; + this._sc.x = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._sc.y = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._scA.y = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._angle); + this._scA.x = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._angle); + this._prevRotation = this.rotation; if(this.parent.texture && this.parent.texture.renderRotation) { - this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._sc.x = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._sc.y = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); } else { - this._cachedSin = 0; - this._cachedCos = 1; + this._sc.x = 0; + this._sc.y = 1; } + this.center.setTo(this.center.x, this.center.y); + this.upperLeft.setTo(this.center.x - this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); + this.upperRight.setTo(this.center.x + this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + this.bottomLeft.setTo(this.center.x - this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); + this.bottomRight.setTo(this.center.x + this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); }; Transform.prototype.update = function () { // Check cache var dirty = false; // 1) Height or Width change (also triggered by a change in scale) or an Origin change - if(this.parent.width !== this._cachedWidth || this.parent.height !== this._cachedHeight || this.origin.x !== this._cachedOriginX || this.origin.y !== this._cachedOriginY) { - this._cachedHalfWidth = this.parent.width / 2; - this._cachedHalfHeight = this.parent.height / 2; - this._cachedOffsetX = this.origin.x * this.parent.width; - this._cachedOffsetY = this.origin.y * this.parent.height; - this._cachedAngleToCenter = Math.atan2(this.halfHeight - this._cachedOffsetY, this.halfWidth - this._cachedOffsetX); - this._cachedDistance = Math.sqrt(((this._cachedOffsetX - this._cachedHalfWidth) * (this._cachedOffsetX - this._cachedHalfWidth)) + ((this._cachedOffsetY - this._cachedHalfHeight) * (this._cachedOffsetY - this._cachedHalfHeight))); + if(this.parent.width !== this._size.x || this.parent.height !== this._size.y || this.origin.x !== this._origin.x || this.origin.y !== this._origin.y) { + this._halfSize.x = this.parent.width / 2; + this._halfSize.y = this.parent.height / 2; + this._offset.x = this.origin.x * this.parent.width; + this._offset.y = this.origin.y * this.parent.height; + this._angle = Math.atan2(this.halfHeight - this._offset.y, this.halfWidth - this._offset.x); + this._distance = Math.sqrt(((this._offset.x - this._halfSize.x) * (this._offset.x - this._halfSize.x)) + ((this._offset.y - this._halfSize.y) * (this._offset.y - this._halfSize.y))); // Store - this._cachedWidth = this.parent.width; - this._cachedHeight = this.parent.height; - this._cachedOriginX = this.origin.x; - this._cachedOriginY = this.origin.y; + this._size.x = this.parent.width; + this._size.y = this.parent.height; + this._origin.x = this.origin.x; + this._origin.y = this.origin.y; dirty = true; } // 2) Rotation change - if(this.rotation != this._cachedRotation) { - this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - this._cachedCosAngle = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); - this._cachedSinAngle = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + if(this.rotation != this._prevRotation) { + this._sc.x = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._sc.y = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._scA.y = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._angle); + this._scA.x = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._angle); if(this.parent.texture.renderRotation) { - this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._sc.x = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._sc.y = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); } else { - this._cachedSin = 0; - this._cachedCos = 1; + this._sc.x = 0; + this._sc.y = 1; } // Store - this._cachedRotation = this.rotation; + this._prevRotation = this.rotation; dirty = true; } - if(dirty) { - this._cachedCenterX = this.parent.x + this._cachedDistance * this._cachedCosAngle; - this._cachedCenterY = this.parent.y + this._cachedDistance * this._cachedSinAngle; + // If it has moved, updated the edges and center + if(dirty || this.parent.x != this._pos.x || this.parent.y != this._pos.y) { + this.center.x = this.parent.x + this._distance * this._scA.y; + this.center.y = this.parent.y + this._distance * this._scA.x; + this.center.setTo(this.center.x, this.center.y); + this.upperLeft.setTo(this.center.x - this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); + this.upperRight.setTo(this.center.x + this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + this.bottomLeft.setTo(this.center.x - this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); + this.bottomRight.setTo(this.center.x + this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + this._pos.x = this.parent.x; + this._pos.y = this.parent.y; } // Scale and Skew if(this.parent.texture.flippedX) { - this.local.data[0] = this._cachedCos * -this.scale.x; - this.local.data[3] = (this._cachedSin * -this.scale.x) + this.skew.x; + this.local.data[0] = this._sc.y * -this.scale.x; + this.local.data[3] = (this._sc.x * -this.scale.x) + this.skew.x; } else { - this.local.data[0] = this._cachedCos * this.scale.x; - this.local.data[3] = (this._cachedSin * this.scale.x) + this.skew.x; + this.local.data[0] = this._sc.y * this.scale.x; + this.local.data[3] = (this._sc.x * this.scale.x) + this.skew.x; } if(this.parent.texture.flippedY) { - this.local.data[4] = this._cachedCos * -this.scale.y; - this.local.data[1] = -(this._cachedSin * -this.scale.y) + this.skew.y; + this.local.data[4] = this._sc.y * -this.scale.y; + this.local.data[1] = -(this._sc.x * -this.scale.y) + this.skew.y; } else { - this.local.data[4] = this._cachedCos * this.scale.y; - this.local.data[1] = -(this._cachedSin * this.scale.y) + this.skew.y; + this.local.data[4] = this._sc.y * this.scale.y; + this.local.data[1] = -(this._sc.x * this.scale.y) + this.skew.y; } // Translate this.local.data[2] = this.parent.x; @@ -3170,9 +3198,8 @@ var Phaser; * The distance from the center of the transform to the rotation origin. */ function () { - return this._cachedDistance; - //return Math.sqrt(((this.offsetX - this.halfWidth) * (this.offsetX - this.halfWidth)) + ((this.offsetY - this.halfHeight) * (this.offsetY - this.halfHeight))); - }, + return this._distance; + }, enumerable: true, configurable: true }); @@ -3181,9 +3208,8 @@ var Phaser; * The angle between the center of the transform to the rotation origin. */ function () { - return this._cachedAngleToCenter; - //return Math.atan2(this.halfHeight - this.offsetY, this.halfWidth - this.offsetX); - }, + return this._angle; + }, enumerable: true, configurable: true }); @@ -3192,9 +3218,8 @@ var Phaser; * The offset on the X axis of the origin */ function () { - return this._cachedOffsetX; - //return this.origin.x * this.parent.width; - }, + return this._offset.x; + }, enumerable: true, configurable: true }); @@ -3203,9 +3228,8 @@ var Phaser; * The offset on the Y axis of the origin */ function () { - return this._cachedOffsetY; - //return this.origin.y * this.parent.height; - }, + return this._offset.y; + }, enumerable: true, configurable: true }); @@ -3214,9 +3238,8 @@ var Phaser; * Half the width of the parent sprite, taking into consideration scaling */ function () { - return this._cachedHalfWidth; - //return this.parent.width / 2; - }, + return this._halfSize.x; + }, enumerable: true, configurable: true }); @@ -3225,44 +3248,33 @@ var Phaser; * Half the height of the parent sprite, taking into consideration scaling */ function () { - return this._cachedHalfHeight; - //return this.parent.height / 2; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Transform.prototype, "centerX", { - get: /** - * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration - */ - function () { - return this._cachedCenterX; - //return this.parent.x + this.distance * Math.cos((this.rotation * Math.PI / 180) + this.angleToCenter); - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Transform.prototype, "centerY", { - get: /** - * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration - */ - function () { - return this._cachedCenterY; - //return this.parent.y + this.distance * Math.sin((this.rotation * Math.PI / 180) + this.angleToCenter); - }, + return this._halfSize.y; + }, enumerable: true, configurable: true }); Object.defineProperty(Transform.prototype, "sin", { - get: function () { - return this._cachedSin; + get: /** + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ + //public get centerX(): number { + // return this.center.x; + //} + /** + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ + //public get centerY(): number { + // return this.center.y; + //} + function () { + return this._sc.x; }, enumerable: true, configurable: true }); Object.defineProperty(Transform.prototype, "cos", { get: function () { - return this._cachedCos; + return this._sc.y; }, enumerable: true, configurable: true @@ -4656,8 +4668,8 @@ var Phaser; } else { // If the sprite is rotated around its center we can use this quicker method: if(sprite.transform.origin.x == 0.5 && sprite.transform.origin.y == 0.5) { - SpriteUtils._sin = Math.sin((sprite.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - SpriteUtils._cos = Math.cos((sprite.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + SpriteUtils._sin = sprite.transform.sin; + SpriteUtils._cos = sprite.transform.cos; if(SpriteUtils._sin < 0) { SpriteUtils._sin = -SpriteUtils._sin; } @@ -4669,6 +4681,20 @@ var Phaser; sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); } else { + //var left:Number = Math.min(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x); + //var top:Number = Math.min(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y); + //var right:Number = Math.max(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x); + //var bottom:Number = Math.max(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y); + //return new Rectangle(left, top, right - left, bottom - top); + var minX = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + var minY = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + var maxX = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + var maxY = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + // (min_x,min_y), (min_x,max_y), (max_x,max_y), (max_x,min_y) + sprite.cameraView.x = minX; + sprite.cameraView.y = minY; + sprite.cameraView.width = maxX - minX; + sprite.cameraView.height = maxY - minY; /* // Useful to get the maximum AABB size of any given rect @@ -4686,58 +4712,6 @@ var Phaser; } return sprite.cameraView; }; - SpriteUtils.getCornersAsPoints = function getCornersAsPoints(sprite) { - var out = []; - var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - // Upper Left - out.push(new Phaser.Point(sprite.x + (sprite.width / 2) * cos - (sprite.height / 2) * sin, sprite.y + (sprite.height / 2) * cos + (sprite.width / 2) * sin)); - // Upper Right - out.push(new Phaser.Point(sprite.x - (sprite.width / 2) * cos - (sprite.height / 2) * sin, sprite.y + (sprite.height / 2) * cos - (sprite.width / 2) * sin)); - // Bottom Left - out.push(new Phaser.Point(sprite.x + (sprite.width / 2) * cos + (sprite.height / 2) * sin, sprite.y - (sprite.height / 2) * cos + (sprite.width / 2) * sin)); - // Bottom Right - out.push(new Phaser.Point(sprite.x - (sprite.width / 2) * cos + (sprite.height / 2) * sin, sprite.y - (sprite.height / 2) * cos - (sprite.width / 2) * sin)); - return out; - }; - SpriteUtils.getCornersAsPoints2 = function getCornersAsPoints2(sprite) { - var out = []; - var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - // This = the center point - var cx = sprite.x + (sprite.width / 2) * cos - (sprite.height / 2) * sin; - var cy = sprite.y + (sprite.height / 2) * cos + (sprite.width / 2) * sin; - // Upper Left - out.push(new Phaser.Point(cx + (sprite.width / 2) * cos - (sprite.height / 2) * sin, cy + (sprite.height / 2) * cos + (sprite.width / 2) * sin)); - // Upper Right - out.push(new Phaser.Point(cx - (sprite.width / 2) * cos - (sprite.height / 2) * sin, cy + (sprite.height / 2) * cos - (sprite.width / 2) * sin)); - // Bottom Left - out.push(new Phaser.Point(cx + (sprite.width / 2) * cos + (sprite.height / 2) * sin, cy - (sprite.height / 2) * cos + (sprite.width / 2) * sin)); - // Bottom Right - out.push(new Phaser.Point(cx - (sprite.width / 2) * cos + (sprite.height / 2) * sin, cy - (sprite.height / 2) * cos - (sprite.width / 2) * sin)); - return out; - }; - SpriteUtils.getCornersAsPoints3 = function getCornersAsPoints3(sprite) { - var out = []; - var sin = sprite.transform.sin; - var cos = sprite.transform.cos; - //var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - //var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - // This = the center point - //var cx = sprite.x + sprite.transform.distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); - //var cy = sprite.y + sprite.transform.distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); - var cx = sprite.transform.centerX; - var cy = sprite.transform.centerY; - // Upper Left - out.push(new Phaser.Point(cx + sprite.transform.halfWidth * cos - sprite.transform.halfHeight * sin, cy + sprite.transform.halfHeight * cos + sprite.transform.halfWidth * sin)); - // Upper Right - out.push(new Phaser.Point(cx - sprite.transform.halfWidth * cos - sprite.transform.halfHeight * sin, cy + sprite.transform.halfHeight * cos - sprite.transform.halfWidth * sin)); - // Bottom Left - out.push(new Phaser.Point(cx + sprite.transform.halfWidth * cos + sprite.transform.halfHeight * sin, cy - sprite.transform.halfHeight * cos + sprite.transform.halfWidth * sin)); - // Bottom Right - out.push(new Phaser.Point(cx - sprite.transform.halfWidth * cos + sprite.transform.halfHeight * sin, cy - sprite.transform.halfHeight * cos - sprite.transform.halfWidth * sin)); - return out; - }; SpriteUtils.getAsPoints = function getAsPoints(sprite) { var out = []; // top left @@ -16600,8 +16574,9 @@ var Phaser; if(sprite.transform.scrollFactor.equals(0)) { return true; } - return Phaser.RectangleUtils.intersects(sprite.cameraView, camera.screenView); - }; + return true; + //return RectangleUtils.intersects(sprite.cameraView, camera.screenView); + }; CanvasRenderer.prototype.inScreen = function (camera) { return true; }; diff --git a/build/phaser.d.ts b/build/phaser.d.ts index 47d1ea01..f6229317 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -1897,26 +1897,22 @@ module Phaser.Components { */ constructor(parent); private _rotation; - private _cachedSin; - private _cachedCos; - private _cachedRotation; - private _cachedScaleX; - private _cachedScaleY; - private _cachedAngle; - private _cachedAngleToCenter; - private _cachedDistance; - private _cachedWidth; - private _cachedHeight; - private _cachedHalfWidth; - private _cachedHalfHeight; - private _cachedCosAngle; - private _cachedSinAngle; - private _cachedOffsetX; - private _cachedOffsetY; - private _cachedOriginX; - private _cachedOriginY; - private _cachedCenterX; - private _cachedCenterY; + private _pos; + private _scale; + private _size; + private _halfSize; + private _offset; + private _origin; + private _sc; + private _scA; + private _angle; + private _distance; + private _prevRotation; + public center: Point; + public upperLeft: Point; + public upperRight: Point; + public bottomLeft: Point; + public bottomRight: Point; public local: Mat3; public setCache(): void; public update(): void; @@ -1979,14 +1975,6 @@ module Phaser.Components { * Half the height of the parent sprite, taking into consideration scaling */ public halfHeight : number; - /** - * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration - */ - public centerX : number; - /** - * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration - */ - public centerY : number; public sin : number; public cos : number; } @@ -2715,9 +2703,6 @@ module Phaser { * @return {Rectangle} A reference to the Sprite.cameraView property */ static updateCameraView(camera: Camera, sprite: Sprite): Rectangle; - static getCornersAsPoints(sprite: Sprite): Point[]; - static getCornersAsPoints2(sprite: Sprite): Point[]; - static getCornersAsPoints3(sprite: Sprite): Point[]; static getAsPoints(sprite: Sprite): Point[]; /** * Checks to see if a point in 2D world space overlaps this GameObject. diff --git a/build/phaser.js b/build/phaser.js index 279c2dfc..cc94bbce 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -3082,84 +3082,112 @@ var Phaser; this.origin = new Phaser.Vec2(); this.scale = new Phaser.Vec2(1, 1); this.skew = new Phaser.Vec2(); + this.center = new Phaser.Point(); + this.upperLeft = new Phaser.Point(); + this.upperRight = new Phaser.Point(); + this.bottomLeft = new Phaser.Point(); + this.bottomRight = new Phaser.Point(); + this._pos = new Phaser.Point(); + this._scale = new Phaser.Point(); + this._size = new Phaser.Point(); + this._halfSize = new Phaser.Point(); + this._offset = new Phaser.Point(); + this._origin = new Phaser.Point(); + this._sc = new Phaser.Point(); + this._scA = new Phaser.Point(); } Transform.prototype.setCache = function () { - this._cachedHalfWidth = this.parent.width / 2; - this._cachedHalfHeight = this.parent.height / 2; - this._cachedOffsetX = this.origin.x * this.parent.width; - this._cachedOffsetY = this.origin.y * this.parent.height; - this._cachedAngleToCenter = Math.atan2(this.halfHeight - this._cachedOffsetY, this.halfWidth - this._cachedOffsetX); - this._cachedDistance = Math.sqrt(((this._cachedOffsetX - this._cachedHalfWidth) * (this._cachedOffsetX - this._cachedHalfWidth)) + ((this._cachedOffsetY - this._cachedHalfHeight) * (this._cachedOffsetY - this._cachedHalfHeight))); - this._cachedWidth = this.parent.width; - this._cachedHeight = this.parent.height; - this._cachedOriginX = this.origin.x; - this._cachedOriginY = this.origin.y; - this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - this._cachedCosAngle = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); - this._cachedSinAngle = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); - this._cachedRotation = this.rotation; + this._pos.x = this.parent.x; + this._pos.y = this.parent.y; + this._halfSize.x = this.parent.width / 2; + this._halfSize.y = this.parent.height / 2; + this._offset.x = this.origin.x * this.parent.width; + this._offset.y = this.origin.y * this.parent.height; + this._angle = Math.atan2(this.halfHeight - this._offset.y, this.halfWidth - this._offset.x); + this._distance = Math.sqrt(((this._offset.x - this._halfSize.x) * (this._offset.x - this._halfSize.x)) + ((this._offset.y - this._halfSize.y) * (this._offset.y - this._halfSize.y))); + this._size.x = this.parent.width; + this._size.y = this.parent.height; + this._origin.x = this.origin.x; + this._origin.y = this.origin.y; + this._sc.x = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._sc.y = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._scA.y = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._angle); + this._scA.x = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._angle); + this._prevRotation = this.rotation; if(this.parent.texture && this.parent.texture.renderRotation) { - this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._sc.x = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._sc.y = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); } else { - this._cachedSin = 0; - this._cachedCos = 1; + this._sc.x = 0; + this._sc.y = 1; } + this.center.setTo(this.center.x, this.center.y); + this.upperLeft.setTo(this.center.x - this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); + this.upperRight.setTo(this.center.x + this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + this.bottomLeft.setTo(this.center.x - this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); + this.bottomRight.setTo(this.center.x + this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); }; Transform.prototype.update = function () { // Check cache var dirty = false; // 1) Height or Width change (also triggered by a change in scale) or an Origin change - if(this.parent.width !== this._cachedWidth || this.parent.height !== this._cachedHeight || this.origin.x !== this._cachedOriginX || this.origin.y !== this._cachedOriginY) { - this._cachedHalfWidth = this.parent.width / 2; - this._cachedHalfHeight = this.parent.height / 2; - this._cachedOffsetX = this.origin.x * this.parent.width; - this._cachedOffsetY = this.origin.y * this.parent.height; - this._cachedAngleToCenter = Math.atan2(this.halfHeight - this._cachedOffsetY, this.halfWidth - this._cachedOffsetX); - this._cachedDistance = Math.sqrt(((this._cachedOffsetX - this._cachedHalfWidth) * (this._cachedOffsetX - this._cachedHalfWidth)) + ((this._cachedOffsetY - this._cachedHalfHeight) * (this._cachedOffsetY - this._cachedHalfHeight))); + if(this.parent.width !== this._size.x || this.parent.height !== this._size.y || this.origin.x !== this._origin.x || this.origin.y !== this._origin.y) { + this._halfSize.x = this.parent.width / 2; + this._halfSize.y = this.parent.height / 2; + this._offset.x = this.origin.x * this.parent.width; + this._offset.y = this.origin.y * this.parent.height; + this._angle = Math.atan2(this.halfHeight - this._offset.y, this.halfWidth - this._offset.x); + this._distance = Math.sqrt(((this._offset.x - this._halfSize.x) * (this._offset.x - this._halfSize.x)) + ((this._offset.y - this._halfSize.y) * (this._offset.y - this._halfSize.y))); // Store - this._cachedWidth = this.parent.width; - this._cachedHeight = this.parent.height; - this._cachedOriginX = this.origin.x; - this._cachedOriginY = this.origin.y; + this._size.x = this.parent.width; + this._size.y = this.parent.height; + this._origin.x = this.origin.x; + this._origin.y = this.origin.y; dirty = true; } // 2) Rotation change - if(this.rotation != this._cachedRotation) { - this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - this._cachedCosAngle = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); - this._cachedSinAngle = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._cachedAngleToCenter); + if(this.rotation != this._prevRotation) { + this._sc.x = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._sc.y = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._scA.y = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._angle); + this._scA.x = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD + this._angle); if(this.parent.texture.renderRotation) { - this._cachedSin = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - this._cachedCos = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._sc.x = Math.sin((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + this._sc.y = Math.cos((this.rotation + this.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); } else { - this._cachedSin = 0; - this._cachedCos = 1; + this._sc.x = 0; + this._sc.y = 1; } // Store - this._cachedRotation = this.rotation; + this._prevRotation = this.rotation; dirty = true; } - if(dirty) { - this._cachedCenterX = this.parent.x + this._cachedDistance * this._cachedCosAngle; - this._cachedCenterY = this.parent.y + this._cachedDistance * this._cachedSinAngle; + // If it has moved, updated the edges and center + if(dirty || this.parent.x != this._pos.x || this.parent.y != this._pos.y) { + this.center.x = this.parent.x + this._distance * this._scA.y; + this.center.y = this.parent.y + this._distance * this._scA.x; + this.center.setTo(this.center.x, this.center.y); + this.upperLeft.setTo(this.center.x - this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); + this.upperRight.setTo(this.center.x + this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + this.bottomLeft.setTo(this.center.x - this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); + this.bottomRight.setTo(this.center.x + this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + this._pos.x = this.parent.x; + this._pos.y = this.parent.y; } // Scale and Skew if(this.parent.texture.flippedX) { - this.local.data[0] = this._cachedCos * -this.scale.x; - this.local.data[3] = (this._cachedSin * -this.scale.x) + this.skew.x; + this.local.data[0] = this._sc.y * -this.scale.x; + this.local.data[3] = (this._sc.x * -this.scale.x) + this.skew.x; } else { - this.local.data[0] = this._cachedCos * this.scale.x; - this.local.data[3] = (this._cachedSin * this.scale.x) + this.skew.x; + this.local.data[0] = this._sc.y * this.scale.x; + this.local.data[3] = (this._sc.x * this.scale.x) + this.skew.x; } if(this.parent.texture.flippedY) { - this.local.data[4] = this._cachedCos * -this.scale.y; - this.local.data[1] = -(this._cachedSin * -this.scale.y) + this.skew.y; + this.local.data[4] = this._sc.y * -this.scale.y; + this.local.data[1] = -(this._sc.x * -this.scale.y) + this.skew.y; } else { - this.local.data[4] = this._cachedCos * this.scale.y; - this.local.data[1] = -(this._cachedSin * this.scale.y) + this.skew.y; + this.local.data[4] = this._sc.y * this.scale.y; + this.local.data[1] = -(this._sc.x * this.scale.y) + this.skew.y; } // Translate this.local.data[2] = this.parent.x; @@ -3170,9 +3198,8 @@ var Phaser; * The distance from the center of the transform to the rotation origin. */ function () { - return this._cachedDistance; - //return Math.sqrt(((this.offsetX - this.halfWidth) * (this.offsetX - this.halfWidth)) + ((this.offsetY - this.halfHeight) * (this.offsetY - this.halfHeight))); - }, + return this._distance; + }, enumerable: true, configurable: true }); @@ -3181,9 +3208,8 @@ var Phaser; * The angle between the center of the transform to the rotation origin. */ function () { - return this._cachedAngleToCenter; - //return Math.atan2(this.halfHeight - this.offsetY, this.halfWidth - this.offsetX); - }, + return this._angle; + }, enumerable: true, configurable: true }); @@ -3192,9 +3218,8 @@ var Phaser; * The offset on the X axis of the origin */ function () { - return this._cachedOffsetX; - //return this.origin.x * this.parent.width; - }, + return this._offset.x; + }, enumerable: true, configurable: true }); @@ -3203,9 +3228,8 @@ var Phaser; * The offset on the Y axis of the origin */ function () { - return this._cachedOffsetY; - //return this.origin.y * this.parent.height; - }, + return this._offset.y; + }, enumerable: true, configurable: true }); @@ -3214,9 +3238,8 @@ var Phaser; * Half the width of the parent sprite, taking into consideration scaling */ function () { - return this._cachedHalfWidth; - //return this.parent.width / 2; - }, + return this._halfSize.x; + }, enumerable: true, configurable: true }); @@ -3225,44 +3248,33 @@ var Phaser; * Half the height of the parent sprite, taking into consideration scaling */ function () { - return this._cachedHalfHeight; - //return this.parent.height / 2; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Transform.prototype, "centerX", { - get: /** - * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration - */ - function () { - return this._cachedCenterX; - //return this.parent.x + this.distance * Math.cos((this.rotation * Math.PI / 180) + this.angleToCenter); - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Transform.prototype, "centerY", { - get: /** - * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration - */ - function () { - return this._cachedCenterY; - //return this.parent.y + this.distance * Math.sin((this.rotation * Math.PI / 180) + this.angleToCenter); - }, + return this._halfSize.y; + }, enumerable: true, configurable: true }); Object.defineProperty(Transform.prototype, "sin", { - get: function () { - return this._cachedSin; + get: /** + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ + //public get centerX(): number { + // return this.center.x; + //} + /** + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ + //public get centerY(): number { + // return this.center.y; + //} + function () { + return this._sc.x; }, enumerable: true, configurable: true }); Object.defineProperty(Transform.prototype, "cos", { get: function () { - return this._cachedCos; + return this._sc.y; }, enumerable: true, configurable: true @@ -4656,8 +4668,8 @@ var Phaser; } else { // If the sprite is rotated around its center we can use this quicker method: if(sprite.transform.origin.x == 0.5 && sprite.transform.origin.y == 0.5) { - SpriteUtils._sin = Math.sin((sprite.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - SpriteUtils._cos = Math.cos((sprite.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); + SpriteUtils._sin = sprite.transform.sin; + SpriteUtils._cos = sprite.transform.cos; if(SpriteUtils._sin < 0) { SpriteUtils._sin = -SpriteUtils._sin; } @@ -4669,6 +4681,20 @@ var Phaser; sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); } else { + //var left:Number = Math.min(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x); + //var top:Number = Math.min(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y); + //var right:Number = Math.max(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x); + //var bottom:Number = Math.max(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y); + //return new Rectangle(left, top, right - left, bottom - top); + var minX = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + var minY = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + var maxX = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + var maxY = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + // (min_x,min_y), (min_x,max_y), (max_x,max_y), (max_x,min_y) + sprite.cameraView.x = minX; + sprite.cameraView.y = minY; + sprite.cameraView.width = maxX - minX; + sprite.cameraView.height = maxY - minY; /* // Useful to get the maximum AABB size of any given rect @@ -4686,58 +4712,6 @@ var Phaser; } return sprite.cameraView; }; - SpriteUtils.getCornersAsPoints = function getCornersAsPoints(sprite) { - var out = []; - var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - // Upper Left - out.push(new Phaser.Point(sprite.x + (sprite.width / 2) * cos - (sprite.height / 2) * sin, sprite.y + (sprite.height / 2) * cos + (sprite.width / 2) * sin)); - // Upper Right - out.push(new Phaser.Point(sprite.x - (sprite.width / 2) * cos - (sprite.height / 2) * sin, sprite.y + (sprite.height / 2) * cos - (sprite.width / 2) * sin)); - // Bottom Left - out.push(new Phaser.Point(sprite.x + (sprite.width / 2) * cos + (sprite.height / 2) * sin, sprite.y - (sprite.height / 2) * cos + (sprite.width / 2) * sin)); - // Bottom Right - out.push(new Phaser.Point(sprite.x - (sprite.width / 2) * cos + (sprite.height / 2) * sin, sprite.y - (sprite.height / 2) * cos - (sprite.width / 2) * sin)); - return out; - }; - SpriteUtils.getCornersAsPoints2 = function getCornersAsPoints2(sprite) { - var out = []; - var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - // This = the center point - var cx = sprite.x + (sprite.width / 2) * cos - (sprite.height / 2) * sin; - var cy = sprite.y + (sprite.height / 2) * cos + (sprite.width / 2) * sin; - // Upper Left - out.push(new Phaser.Point(cx + (sprite.width / 2) * cos - (sprite.height / 2) * sin, cy + (sprite.height / 2) * cos + (sprite.width / 2) * sin)); - // Upper Right - out.push(new Phaser.Point(cx - (sprite.width / 2) * cos - (sprite.height / 2) * sin, cy + (sprite.height / 2) * cos - (sprite.width / 2) * sin)); - // Bottom Left - out.push(new Phaser.Point(cx + (sprite.width / 2) * cos + (sprite.height / 2) * sin, cy - (sprite.height / 2) * cos + (sprite.width / 2) * sin)); - // Bottom Right - out.push(new Phaser.Point(cx - (sprite.width / 2) * cos + (sprite.height / 2) * sin, cy - (sprite.height / 2) * cos - (sprite.width / 2) * sin)); - return out; - }; - SpriteUtils.getCornersAsPoints3 = function getCornersAsPoints3(sprite) { - var out = []; - var sin = sprite.transform.sin; - var cos = sprite.transform.cos; - //var sin = Math.sin((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - //var cos = Math.cos((sprite.transform.rotation + sprite.transform.rotationOffset) * Phaser.GameMath.DEG_TO_RAD); - // This = the center point - //var cx = sprite.x + sprite.transform.distance * Math.cos((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); - //var cy = sprite.y + sprite.transform.distance * Math.sin((sprite.transform.rotation * Math.PI / 180) + sprite.transform.angleToCenter); - var cx = sprite.transform.centerX; - var cy = sprite.transform.centerY; - // Upper Left - out.push(new Phaser.Point(cx + sprite.transform.halfWidth * cos - sprite.transform.halfHeight * sin, cy + sprite.transform.halfHeight * cos + sprite.transform.halfWidth * sin)); - // Upper Right - out.push(new Phaser.Point(cx - sprite.transform.halfWidth * cos - sprite.transform.halfHeight * sin, cy + sprite.transform.halfHeight * cos - sprite.transform.halfWidth * sin)); - // Bottom Left - out.push(new Phaser.Point(cx + sprite.transform.halfWidth * cos + sprite.transform.halfHeight * sin, cy - sprite.transform.halfHeight * cos + sprite.transform.halfWidth * sin)); - // Bottom Right - out.push(new Phaser.Point(cx - sprite.transform.halfWidth * cos + sprite.transform.halfHeight * sin, cy - sprite.transform.halfHeight * cos - sprite.transform.halfWidth * sin)); - return out; - }; SpriteUtils.getAsPoints = function getAsPoints(sprite) { var out = []; // top left @@ -16600,8 +16574,9 @@ var Phaser; if(sprite.transform.scrollFactor.equals(0)) { return true; } - return Phaser.RectangleUtils.intersects(sprite.cameraView, camera.screenView); - }; + return true; + //return RectangleUtils.intersects(sprite.cameraView, camera.screenView); + }; CanvasRenderer.prototype.inScreen = function (camera) { return true; }; From 2389c6c231c915086eb1ba6050b3d92a820daafd Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Jun 2013 19:53:48 +0100 Subject: [PATCH 7/8] Added ability to detect if a given point is within a sprite or not, taking rotation and scaling into account. --- Phaser/components/Transform.ts | 57 ++++++--- Phaser/renderers/CanvasRenderer.ts | 3 +- Phaser/utils/SpriteUtils.ts | 160 +++++++------------------ README.md | 24 ++-- Tests/Tests.csproj | 4 + Tests/input/point in rotated sprite.js | 39 ++++++ Tests/input/point in rotated sprite.ts | 60 ++++++++++ Tests/misc/point1.js | 15 +-- Tests/misc/point1.ts | 18 +-- Tests/misc/point2.js | 44 +++---- Tests/misc/point2.ts | 50 ++++---- Tests/misc/point3.js | 46 +++---- Tests/misc/point3.ts | 54 ++++----- Tests/phaser.js | 115 ++++++++++-------- build/phaser.d.ts | 45 ++++++- build/phaser.js | 115 ++++++++++-------- 16 files changed, 458 insertions(+), 391 deletions(-) create mode 100644 Tests/input/point in rotated sprite.js create mode 100644 Tests/input/point in rotated sprite.ts diff --git a/Phaser/components/Transform.ts b/Phaser/components/Transform.ts index 4f3976ae..1112529a 100644 --- a/Phaser/components/Transform.ts +++ b/Phaser/components/Transform.ts @@ -10,8 +10,8 @@ module Phaser.Components { export class Transform { /** - * Creates a new Sprite Transform component - * @param parent The Sprite using this transform + * Creates a new Transform component + * @param parent The game object using this transform */ constructor(parent) { @@ -57,14 +57,39 @@ module Phaser.Components { private _distance: number; private _prevRotation: number; + /** + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ public center: Phaser.Point; + + /** + * The upper-left corner of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ public upperLeft: Phaser.Point; + + /** + * The upper-right corner of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ public upperRight: Phaser.Point; + + /** + * The bottom-left corner of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ public bottomLeft: Phaser.Point; + + /** + * The bottom-right corner of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ public bottomRight: Phaser.Point; + /** + * The local transform matrix + */ public local: Mat3; + /** + * Populates the transform cache. Called by the parent object on creation. + */ public setCache() { this._pos.x = this.parent.x; @@ -96,14 +121,22 @@ module Phaser.Components { this._sc.y = 1; } - this.center.setTo(this.center.x, this.center.y); + this.center.x = this.parent.x + this._distance * this._scA.y; + this.center.y = this.parent.y + this._distance * this._scA.x; + this.upperLeft.setTo(this.center.x - this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); this.upperRight.setTo(this.center.x + this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); this.bottomLeft.setTo(this.center.x - this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); this.bottomRight.setTo(this.center.x + this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + this._pos.x = this.parent.x; + this._pos.y = this.parent.y; + } + /** + * Updates the local transform matrix and the cache values if anything has changed in the parent. + */ public update() { // Check cache @@ -156,8 +189,6 @@ module Phaser.Components { this.center.x = this.parent.x + this._distance * this._scA.y; this.center.y = this.parent.y + this._distance * this._scA.x; - this.center.setTo(this.center.x, this.center.y); - this.upperLeft.setTo(this.center.x - this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); this.upperRight.setTo(this.center.x + this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); this.bottomLeft.setTo(this.center.x - this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); @@ -282,23 +313,15 @@ module Phaser.Components { } /** - * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration + * The equivalent of Math.sin(rotation + rotationOffset) */ - //public get centerX(): number { - // return this.center.x; - //} - - /** - * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration - */ - //public get centerY(): number { - // return this.center.y; - //} - public get sin(): number { return this._sc.x; } + /** + * The equivalent of Math.cos(rotation + rotationOffset) + */ public get cos(): number { return this._sc.y; } diff --git a/Phaser/renderers/CanvasRenderer.ts b/Phaser/renderers/CanvasRenderer.ts index 2c61a60e..c3558af4 100644 --- a/Phaser/renderers/CanvasRenderer.ts +++ b/Phaser/renderers/CanvasRenderer.ts @@ -221,8 +221,7 @@ module Phaser { return true; } - return true; - //return RectangleUtils.intersects(sprite.cameraView, camera.screenView); + return RectangleUtils.intersects(sprite.cameraView, camera.screenView); } diff --git a/Phaser/utils/SpriteUtils.ts b/Phaser/utils/SpriteUtils.ts index 73605f2a..28b597d1 100644 --- a/Phaser/utils/SpriteUtils.ts +++ b/Phaser/utils/SpriteUtils.ts @@ -60,42 +60,11 @@ module Phaser { } else { - //var left:Number = Math.min(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x); - //var top:Number = Math.min(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y); - //var right:Number = Math.max(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x); - //var bottom:Number = Math.max(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y); - //return new Rectangle(left, top, right - left, bottom - top); - - var minX: number = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); - var minY: number = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); - var maxX: number = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); - var maxY: number = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); - - // (min_x,min_y), (min_x,max_y), (max_x,max_y), (max_x,min_y) - - sprite.cameraView.x = minX; - sprite.cameraView.y = minY; - sprite.cameraView.width = maxX - minX; - sprite.cameraView.height = maxY - minY; - - /* - // Useful to get the maximum AABB size of any given rect - - If you want a single box that covers all angles, just take the half-diagonal of your existing box as the radius of a circle. - The new box has to contain this circle, so it should be a square with side-length equal to twice the radius - (equiv. the diagonal of the original AABB) and with the same center as the original. - */ - + sprite.cameraView.x = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + sprite.cameraView.y = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + sprite.cameraView.width = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x) - sprite.cameraView.x; + sprite.cameraView.height = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y) - sprite.cameraView.y; } - - } - - if (sprite.animations.currentFrame !== null && sprite.animations.currentFrame.trimmed) - { - //sprite.cameraView.x += sprite.animations.currentFrame.spriteSourceSizeX; - //sprite.cameraView.y += sprite.animations.currentFrame.spriteSourceSizeY; - //this._dw = sprite.animations.currentFrame.spriteSourceSizeW; - //this._dh = sprite.animations.currentFrame.spriteSourceSizeH; } return sprite.cameraView; @@ -174,92 +143,60 @@ module Phaser { } */ - /** - * Checks to see if this GameObject were located at the given position, would it overlap the GameObject or Group? - * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size numbero account. - * WARNING: Currently tilemaps do NOT support screen space overlap checks! - * - * @param X {number} The X position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param Y {number} The Y position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param objectOrGroup {object} The object or group being tested. - * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {boolean} Whether or not the two objects overlap. - */ - /* - static overlapsAt(X: number, Y: number, objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { - - if (objectOrGroup.isGroup) - { - var results: bool = false; - var basic; - var i: number = 0; - var members = objectOrGroup.members; - - while (i < length) - { - if (this.overlapsAt(X, Y, members[i++], inScreenSpace, camera)) - { - results = true; - } - } - - return results; - } - - if (!inScreenSpace) - { - return (objectOrGroup.x + objectOrGroup.width > X) && (objectOrGroup.x < X + this.width) && - (objectOrGroup.y + objectOrGroup.height > Y) && (objectOrGroup.y < Y + this.height); - } - - if (camera == null) - { - camera = this._game.camera; - } - - var objectScreenPos: Point = objectOrGroup.getScreenXY(null, Camera); - - this._point.x = X - camera.scroll.x * this.transform.scrollFactor.x; //copied from getScreenXY() - this._point.y = Y - camera.scroll.y * this.transform.scrollFactor.y; - this._point.x += (this._point.x > 0) ? 0.0000001 : -0.0000001; - this._point.y += (this._point.y > 0) ? 0.0000001 : -0.0000001; - - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && - (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); - } - */ /** - * Checks to see if a point in 2D world space overlaps this GameObject. + * Checks to see if the given x and y coordinates overlaps this Sprite, taking scaling and rotation into account. + * The coordinates must be given in world space, not local or camera space. * - * @param point {Point} The point in world space you want to check. - * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. + * @param sprite {Sprite} The Sprite to check. It will take scaling and rotation into account. + * @param x {Number} The x coordinate in world space. + * @param y {Number} The y coordinate in world space. * * @return Whether or not the point overlaps this object. */ - static overlapsPoint(sprite: Sprite, point: Point, inScreenSpace: bool = false, camera: Camera = null): bool { + static overlapsXY(sprite: Phaser.Sprite, x: number, y: number): bool { - if (!inScreenSpace) + // if rotation == 0 then just do a rect check instead! + if (sprite.transform.rotation == 0) { - return Phaser.RectangleUtils.containsPoint(sprite.body.bounds, point); - //return (point.x > sprite.x) && (point.x < sprite.x + sprite.width) && (point.y > sprite.y) && (point.y < sprite.y + sprite.height); + return Phaser.RectangleUtils.contains(sprite.cameraView, x, y); } - if (camera == null) + if ((x - sprite.transform.upperLeft.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) < 0) { - camera = sprite.game.camera; + return false; } - //var x: number = point.x - camera.scroll.x; - //var y: number = point.y - camera.scroll.y; + if ((x - sprite.transform.upperRight.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperRight.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) > 0) + { + return false; + } - //this.getScreenXY(this._point, camera); + if ((x - sprite.transform.upperLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) < 0) + { + return false; + } - //return (x > this._point.x) && (X < this._point.x + this.width) && (Y > this._point.y) && (Y < this._point.y + this.height); + if ((x - sprite.transform.bottomLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.bottomLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) > 0) + { + return false; + } + return true; + + } + + /** + * Checks to see if the given point overlaps this Sprite, taking scaling and rotation into account. + * The point must be given in world space, not local or camera space. + * + * @param sprite {Sprite} The Sprite to check. It will take scaling and rotation into account. + * @param point {Point} The point in world space you want to check. + * + * @return Whether or not the point overlaps this object. + */ + static overlapsPoint(sprite: Sprite, point: Point): bool { + return overlapsXY(sprite, point.x, point.y); } /** @@ -346,19 +283,6 @@ module Phaser { } - static setOriginToCenter(sprite: Sprite, fromFrameBounds: bool = true, fromBody?: bool = false) { - - if (fromFrameBounds) - { - sprite.transform.origin.setTo(sprite.width / 2, sprite.height / 2); - } - else if (fromBody) - { - sprite.transform.origin.setTo(sprite.body.bounds.halfWidth, sprite.body.bounds.halfHeight); - } - - } - /** * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) diff --git a/README.md b/README.md index 3abe1513..bdc6655a 100644 --- a/README.md +++ b/README.md @@ -26,30 +26,28 @@ TODO: * Investigate why tweens don't restart after the game pauses * Fix bug in Tween yoyo + loop combo * Apply Sprite scaling to Body.bounds -* When you modify the sprite x/y directly the body position doesn't update, which leads to weird results. Need to work out who controls who. * Check that tween pausing works with the new performance.now * Game.Time should monitor pause duration * Investigate bug re: tilemap collision and animation frames * Update tests that use arrow keys and include touch/mouse support (FlxControlHandler style) -* Polygon geom primitive * If the Camera is larger than the Stage size then the rotation offset isn't correct * Texture Repeat doesn't scroll, because it's part of the camera not the world, need to think about this more * Bug: Sprite x/y gets shifted if dynamic from the original value * Input CSS cursor those little 4-way arrows on drag? * Stage CSS3 transforms!!! Color tints, sepia, greyscale, all of those cool things :) -* Cameras should have option to be input disabled + Pointers should check which camera they are over before doing Sprite selection -* Added JSON Texture Atlas object support. -* RenderOrderID won't work across cameras - but then neither do Pointers yet anyway +* Add JSON Texture Atlas object support. * Swap to using time based motion (like the tweens) rather than delta timer - it just doesn't work well on slow phones * Pointer.getWorldX(camera) needs to take camera scale into consideration * Add a 'click to bring to top' demo (+ Group feature?) * If stage.clear set to false and game pauses, when it unpauses you still see the pause arrow - resolve this - * Add clip support + shape options to Texture Component. +* Make sure I'm using Point and not Vec2 when it's not a directional vector I need +* Bug with setting scale or anything on a Sprite inside a Group, or maybe group.addNewSprite issue -Make sure I'm using Point and not Vec2 when it's not a directional vector I need - - +* Make input check use the rotated sprite check +* Sprite collision events +* See which functions in the input component can move elsewhere (utils) +* Move all of the renderDebugInfo methods to the DebugUtils class V1.0.0 @@ -98,7 +96,7 @@ V1.0.0 * Added optional frame parameter to Phaser.Sprite (and game.add.sprite) so you can set a frame ID or frame name on construction. * Fixed bug where passing a texture atlas string would incorrectly skip the frames array. * Added AnimationManager.autoUpdateBounds to control if a new frame should change the physics bounds of a sprite body or not. -* Added StageScaleMode.pageAlignHorizontally and pageAlignVertically booleans. When on Phaser will set the margin-left and top of the canvas element so that it is positioned in the middle of the page (based on window.innerWidth). +* Added StageScaleMode.pageAlignHorizontally and pageAlignVertically booleans. When true Phaser will set the margin-left and top of the canvas element so that it is positioned in the middle of the page (based only on window.innerWidth). * Added support for globalCompositeOperation, opaque and backgroundColor to the Sprite.Texture and Camera.Texture components. * Added ability for a Camera to skew and rotate around an origin. * Moved the Camera rendering into CanvasRenderer to keep things consistent. @@ -109,8 +107,12 @@ V1.0.0 * Added CameraManager.swap and CameraManager.sort methods and added a z-index property to Camera to control render order. * Added World.postUpdate loop + Group and Camera postUpdate methods. * Fixed issue stopping Pointer from working in world coordinates and fixed the world drag example. -* For consistency renamed input.scaledX/Y = input.scale. +* For consistency renamed input.scaledX/Y to input.scale. * Added input.activePointer which contains a reference to the most recently active pointer. +* Sprite.Transform now has upperLeft, upperRight, bottomLeft and bottomRight Point properties and lots of useful coordinate related methods. +* Camera.inCamera check now uses the Sprite.worldView which finally accurately updates regardless of scale, rotation or rotation origin. +* Added Math.Mat3 for Matrix3 operations (which Sprite.Transform uses) and Math.Mat3Utils for lots of use Mat3 related methods. +* Added SpriteUtils.overlapsXY and overlapsPoint to check if a point is within a sprite, taking scale and rotation into account. diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 405475d7..7d503fff 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -117,6 +117,10 @@ + + + point in rotated sprite.ts + snap 1.ts diff --git a/Tests/input/point in rotated sprite.js b/Tests/input/point in rotated sprite.js new file mode 100644 index 00000000..70fb46e0 --- /dev/null +++ b/Tests/input/point in rotated sprite.js @@ -0,0 +1,39 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); + function init() { + game.load.image('sprite', 'assets/sprites/atari130xe.png'); + game.load.start(); + } + var sprite; + var rotate = false; + function create() { + sprite = game.add.sprite(200, 200, 'sprite'); + game.input.onTap.add(rotateIt, this); + } + function rotateIt() { + if(rotate == false) { + rotate = true; + } else { + rotate = false; + } + } + var inPoint = false; + function update() { + if(rotate) { + sprite.rotation++; + } + inPoint = Phaser.SpriteUtils.overlapsXY(sprite, game.input.x, game.input.y); + } + function render() { + game.stage.context.save(); + game.stage.context.fillStyle = 'rgb(255,0,255)'; + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperLeft.x) + ' y: ' + Math.round(sprite.transform.upperLeft.y), sprite.transform.upperLeft.x, sprite.transform.upperLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperRight.x) + ' y: ' + Math.round(sprite.transform.upperRight.y), sprite.transform.upperRight.x, sprite.transform.upperRight.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomLeft.x) + ' y: ' + Math.round(sprite.transform.bottomLeft.y), sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomRight.x) + ' y: ' + Math.round(sprite.transform.bottomRight.y), sprite.transform.bottomRight.x, sprite.transform.bottomRight.y); + game.input.renderDebugInfo(32, 32); + game.stage.context.fillText('in: ' + inPoint, 300, 32); + game.stage.context.restore(); + } +})(); diff --git a/Tests/input/point in rotated sprite.ts b/Tests/input/point in rotated sprite.ts new file mode 100644 index 00000000..d3d1792f --- /dev/null +++ b/Tests/input/point in rotated sprite.ts @@ -0,0 +1,60 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); + + function init() { + + game.load.image('sprite', 'assets/sprites/atari130xe.png'); + game.load.start(); + + } + + var sprite: Phaser.Sprite; + var rotate: bool = false; + + function create() { + + sprite = game.add.sprite(200, 200, 'sprite'); + + game.input.onTap.add(rotateIt, this); + + } + + function rotateIt() { + if (rotate == false) { rotate = true; } else { rotate = false; } + } + + var inPoint: bool = false; + + function update() { + + if (rotate) + { + sprite.rotation++; + } + + inPoint = Phaser.SpriteUtils.overlapsXY(sprite, game.input.x, game.input.y); + + } + + function render() { + + game.stage.context.save(); + game.stage.context.fillStyle = 'rgb(255,0,255)'; + + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperLeft.x) + ' y: ' + Math.round(sprite.transform.upperLeft.y), sprite.transform.upperLeft.x, sprite.transform.upperLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperRight.x) + ' y: ' + Math.round(sprite.transform.upperRight.y), sprite.transform.upperRight.x, sprite.transform.upperRight.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomLeft.x) + ' y: ' + Math.round(sprite.transform.bottomLeft.y), sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomRight.x) + ' y: ' + Math.round(sprite.transform.bottomRight.y), sprite.transform.bottomRight.x, sprite.transform.bottomRight.y); + + game.input.renderDebugInfo(32, 32); + + game.stage.context.fillText('in: ' + inPoint, 300, 32); + + game.stage.context.restore(); + + } + +})(); diff --git a/Tests/misc/point1.js b/Tests/misc/point1.js index e78fa486..6b2b2b83 100644 --- a/Tests/misc/point1.js +++ b/Tests/misc/point1.js @@ -3,8 +3,8 @@ var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); function init() { game.load.image('box2', 'assets/tests/320x200.png'); - game.load.image('box', 'assets/sprites/oz_pov_melting_disk.png'); - game.load.image('box1', 'assets/sprites/bunny.png'); + game.load.image('box1', 'assets/sprites/oz_pov_melting_disk.png'); + game.load.image('box', 'assets/sprites/bunny.png'); game.load.start(); } var sprite; @@ -13,7 +13,7 @@ game.stage.backgroundColor = 'rgb(0,0,0)'; sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); //sprite.transform.scale.setTo(0.5, 0.5); - sprite.transform.origin.setTo(0, 0); + sprite.transform.origin.setTo(1, 1); //sprite.transform.origin.setTo(0.5, 0.5); game.input.onTap.add(rotateIt, this); //game.add.tween(sprite.transform.scale).to({ x: 0.5, y: 0.5 }, 2000, Phaser.Easing.Linear.None, true, 0, true); @@ -37,14 +37,6 @@ game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperRight.x) + ' y: ' + Math.round(sprite.transform.upperRight.y), sprite.transform.upperRight.x, sprite.transform.upperRight.y); game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomLeft.x) + ' y: ' + Math.round(sprite.transform.bottomLeft.y), sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y); game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomRight.x) + ' y: ' + Math.round(sprite.transform.bottomRight.y), sprite.transform.bottomRight.x, sprite.transform.bottomRight.y); - var minX = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); - var minY = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); - var maxX = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); - var maxY = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); - var width = maxX - minX; - var height = maxY - minY; - game.stage.context.fillText('minX: ' + minX + ' minY: ' + minY, 32, 32); - game.stage.context.fillText('maxX: ' + maxX + ' maxY: ' + maxY, 32, 64); game.stage.context.fillRect(sprite.transform.center.x, sprite.transform.center.y, 2, 2); game.stage.context.fillRect(sprite.transform.upperLeft.x, sprite.transform.upperLeft.y, 2, 2); game.stage.context.fillRect(sprite.transform.upperRight.x, sprite.transform.upperRight.y, 2, 2); @@ -52,7 +44,6 @@ game.stage.context.fillRect(sprite.transform.bottomRight.x, sprite.transform.bottomRight.y, 2, 2); game.stage.context.strokeStyle = 'rgb(255,255,0)'; game.stage.context.strokeRect(sprite.cameraView.x, sprite.cameraView.y, sprite.cameraView.width, sprite.cameraView.height); - //game.stage.context.strokeRect(minX, minY, width, height); game.stage.context.restore(); } })(); diff --git a/Tests/misc/point1.ts b/Tests/misc/point1.ts index 904d7d39..1dcfb0b0 100644 --- a/Tests/misc/point1.ts +++ b/Tests/misc/point1.ts @@ -7,8 +7,8 @@ function init() { game.load.image('box2', 'assets/tests/320x200.png'); - game.load.image('box', 'assets/sprites/oz_pov_melting_disk.png'); - game.load.image('box1', 'assets/sprites/bunny.png'); + game.load.image('box1', 'assets/sprites/oz_pov_melting_disk.png'); + game.load.image('box', 'assets/sprites/bunny.png'); game.load.start(); } @@ -23,7 +23,7 @@ sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); //sprite.transform.scale.setTo(0.5, 0.5); - sprite.transform.origin.setTo(0, 0); + sprite.transform.origin.setTo(1, 1); //sprite.transform.origin.setTo(0.5, 0.5); game.input.onTap.add(rotateIt, this); @@ -55,17 +55,6 @@ game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomLeft.x) + ' y: ' + Math.round(sprite.transform.bottomLeft.y), sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y); game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomRight.x) + ' y: ' + Math.round(sprite.transform.bottomRight.y), sprite.transform.bottomRight.x, sprite.transform.bottomRight.y); - var minX: number = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); - var minY: number = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); - var maxX: number = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); - var maxY: number = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); - - var width = maxX - minX; - var height = maxY - minY; - - game.stage.context.fillText('minX: ' + minX + ' minY: ' + minY, 32, 32); - game.stage.context.fillText('maxX: ' + maxX + ' maxY: ' + maxY, 32, 64); - game.stage.context.fillRect(sprite.transform.center.x, sprite.transform.center.y, 2, 2); game.stage.context.fillRect(sprite.transform.upperLeft.x, sprite.transform.upperLeft.y, 2, 2); game.stage.context.fillRect(sprite.transform.upperRight.x, sprite.transform.upperRight.y, 2, 2); @@ -74,7 +63,6 @@ game.stage.context.strokeStyle = 'rgb(255,255,0)'; game.stage.context.strokeRect(sprite.cameraView.x, sprite.cameraView.y, sprite.cameraView.width, sprite.cameraView.height); - //game.stage.context.strokeRect(minX, minY, width, height); game.stage.context.restore(); diff --git a/Tests/misc/point2.js b/Tests/misc/point2.js index 2b16e544..72448870 100644 --- a/Tests/misc/point2.js +++ b/Tests/misc/point2.js @@ -2,16 +2,17 @@ (function () { var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); function init() { - game.load.image('box', 'assets/tests/320x200.png'); + game.load.spritesheet('mummy', 'assets/sprites/metalslug_mummy37x45.png', 37, 45, 18); game.load.start(); } var sprite; var rotate = false; function create() { game.stage.backgroundColor = 'rgb(0,0,0)'; - game.stage.disablePauseScreen = true; - sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); - sprite.transform.origin.setTo(0, 0); + sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'mummy'); + sprite.animations.add('walk'); + sprite.animations.play('walk', 20, true); + sprite.transform.scale.setTo(4, 4); game.input.onTap.add(rotateIt, this); } function rotateIt() { @@ -27,30 +28,19 @@ } } function render() { - var originX = sprite.transform.origin.x * sprite.width; - var originY = sprite.transform.origin.y * sprite.height; - var centerX = 0.5 * sprite.width; - var centerY = 0.5 * sprite.height; - var distanceX = originX - centerX; - var distanceY = originY - centerY; - var distance = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); - var px = sprite.x + distance * Math.cos(sprite.transform.rotation + 45 * Math.PI / 180); - var py = sprite.y + distance * Math.sin(sprite.transform.rotation + 45 * Math.PI / 180); game.stage.context.save(); - game.stage.context.fillStyle = 'rgb(255,255,0)'; - game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); - game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); - game.stage.context.fillText('angle: ' + sprite.rotation, 32, 72); - game.stage.context.fillText('point of rotation x: ' + sprite.transform.origin.x + ' y: ' + sprite.transform.origin.y, 32, 92); - game.stage.context.fillText('x: ' + sprite.x + ' y: ' + sprite.y, sprite.x + 4, sprite.y); - game.stage.context.restore(); - game.stage.context.save(); - game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; - game.stage.context.beginPath(); - game.stage.context.moveTo(sprite.x, sprite.y); - game.stage.context.arc(sprite.x, sprite.y, distance, 0, Math.PI * 2); - game.stage.context.closePath(); - game.stage.context.fill(); + game.stage.context.fillStyle = 'rgb(255,0,255)'; + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperLeft.x) + ' y: ' + Math.round(sprite.transform.upperLeft.y), sprite.transform.upperLeft.x, sprite.transform.upperLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperRight.x) + ' y: ' + Math.round(sprite.transform.upperRight.y), sprite.transform.upperRight.x, sprite.transform.upperRight.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomLeft.x) + ' y: ' + Math.round(sprite.transform.bottomLeft.y), sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomRight.x) + ' y: ' + Math.round(sprite.transform.bottomRight.y), sprite.transform.bottomRight.x, sprite.transform.bottomRight.y); + game.stage.context.fillRect(sprite.transform.center.x, sprite.transform.center.y, 2, 2); + game.stage.context.fillRect(sprite.transform.upperLeft.x, sprite.transform.upperLeft.y, 2, 2); + game.stage.context.fillRect(sprite.transform.upperRight.x, sprite.transform.upperRight.y, 2, 2); + game.stage.context.fillRect(sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y, 2, 2); + game.stage.context.fillRect(sprite.transform.bottomRight.x, sprite.transform.bottomRight.y, 2, 2); + game.stage.context.strokeStyle = 'rgb(255,255,0)'; + game.stage.context.strokeRect(sprite.cameraView.x, sprite.cameraView.y, sprite.cameraView.width, sprite.cameraView.height); game.stage.context.restore(); } })(); diff --git a/Tests/misc/point2.ts b/Tests/misc/point2.ts index ba3161e4..499f63d6 100644 --- a/Tests/misc/point2.ts +++ b/Tests/misc/point2.ts @@ -6,7 +6,7 @@ function init() { - game.load.image('box', 'assets/tests/320x200.png'); + game.load.spritesheet('mummy', 'assets/sprites/metalslug_mummy37x45.png', 37, 45, 18); game.load.start(); } @@ -17,11 +17,13 @@ function create() { game.stage.backgroundColor = 'rgb(0,0,0)'; - game.stage.disablePauseScreen = true; - sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); + sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'mummy'); - sprite.transform.origin.setTo(0, 0); + sprite.animations.add('walk'); + sprite.animations.play('walk', 20, true); + + sprite.transform.scale.setTo(4, 4); game.input.onTap.add(rotateIt, this); @@ -42,33 +44,23 @@ function render() { - var originX: number = sprite.transform.origin.x * sprite.width; - var originY: number = sprite.transform.origin.y * sprite.height; - var centerX: number = 0.5 * sprite.width; - var centerY: number = 0.5 * sprite.height; - var distanceX: number = originX - centerX; - var distanceY: number = originY - centerY; - var distance: number = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); - - var px = sprite.x + distance * Math.cos(sprite.transform.rotation + 45 * Math.PI / 180); - var py = sprite.y + distance * Math.sin(sprite.transform.rotation + 45 * Math.PI / 180); - game.stage.context.save(); - game.stage.context.fillStyle = 'rgb(255,255,0)'; - game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); - game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); - game.stage.context.fillText('angle: ' + sprite.rotation , 32, 72); - game.stage.context.fillText('point of rotation x: ' + sprite.transform.origin.x + ' y: ' + sprite.transform.origin.y, 32, 92); - game.stage.context.fillText('x: ' + sprite.x + ' y: ' + sprite.y, sprite.x + 4, sprite.y); - game.stage.context.restore(); + game.stage.context.fillStyle = 'rgb(255,0,255)'; + + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperLeft.x) + ' y: ' + Math.round(sprite.transform.upperLeft.y), sprite.transform.upperLeft.x, sprite.transform.upperLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperRight.x) + ' y: ' + Math.round(sprite.transform.upperRight.y), sprite.transform.upperRight.x, sprite.transform.upperRight.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomLeft.x) + ' y: ' + Math.round(sprite.transform.bottomLeft.y), sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomRight.x) + ' y: ' + Math.round(sprite.transform.bottomRight.y), sprite.transform.bottomRight.x, sprite.transform.bottomRight.y); + + game.stage.context.fillRect(sprite.transform.center.x, sprite.transform.center.y, 2, 2); + game.stage.context.fillRect(sprite.transform.upperLeft.x, sprite.transform.upperLeft.y, 2, 2); + game.stage.context.fillRect(sprite.transform.upperRight.x, sprite.transform.upperRight.y, 2, 2); + game.stage.context.fillRect(sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y, 2, 2); + game.stage.context.fillRect(sprite.transform.bottomRight.x, sprite.transform.bottomRight.y, 2, 2); + + game.stage.context.strokeStyle = 'rgb(255,255,0)'; + game.stage.context.strokeRect(sprite.cameraView.x, sprite.cameraView.y, sprite.cameraView.width, sprite.cameraView.height); - game.stage.context.save(); - game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; - game.stage.context.beginPath(); - game.stage.context.moveTo(sprite.x, sprite.y); - game.stage.context.arc(sprite.x, sprite.y, distance, 0, Math.PI * 2); - game.stage.context.closePath(); - game.stage.context.fill(); game.stage.context.restore(); } diff --git a/Tests/misc/point3.js b/Tests/misc/point3.js index 5a0ce273..923e4ce0 100644 --- a/Tests/misc/point3.js +++ b/Tests/misc/point3.js @@ -2,16 +2,17 @@ (function () { var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render); function init() { - game.load.image('box', 'assets/tests/320x200.png'); + game.load.atlas('bot', 'assets/sprites/running_bot.png', null, botData); game.load.start(); } var sprite; var rotate = false; function create() { game.stage.backgroundColor = 'rgb(0,0,0)'; - game.stage.disablePauseScreen = true; - sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); - sprite.transform.origin.setTo(0.3, 0.8); + sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'bot'); + sprite.animations.add('run', null, 10, true); + sprite.animations.play('run'); + //sprite.transform.scale.setTo(4, 4); game.input.onTap.add(rotateIt, this); } function rotateIt() { @@ -27,31 +28,20 @@ } } function render() { - var originX = sprite.transform.origin.x * sprite.width; - var originY = sprite.transform.origin.y * sprite.height; - var centerX = 0.5 * sprite.width; - var centerY = 0.5 * sprite.height; - var distanceX = originX - centerX; - var distanceY = originY - centerY; - var distance = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); - var px = sprite.x + distance * Math.cos(sprite.transform.rotation + 45 * Math.PI / 180); - var py = sprite.y + distance * Math.sin(sprite.transform.rotation + 45 * Math.PI / 180); game.stage.context.save(); - game.stage.context.fillStyle = 'rgb(255,255,0)'; - game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); - game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); - game.stage.context.fillText('angle: ' + sprite.rotation, 32, 72); - game.stage.context.fillText('point of rotation x: ' + sprite.transform.origin.x + ' y: ' + sprite.transform.origin.y, 32, 92); - game.stage.context.fillText('sprite x: ' + sprite.x + ' sprite y: ' + sprite.y, 32, 112); - game.stage.context.fillRect(sprite.x, sprite.y, 2, 2); - game.stage.context.restore(); - game.stage.context.save(); - game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; - game.stage.context.beginPath(); - game.stage.context.moveTo(sprite.x, sprite.y); - game.stage.context.arc(sprite.x, sprite.y, distance, 0, Math.PI * 2); - game.stage.context.closePath(); - game.stage.context.fill(); + game.stage.context.fillStyle = 'rgb(255,0,255)'; + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperLeft.x) + ' y: ' + Math.round(sprite.transform.upperLeft.y), sprite.transform.upperLeft.x, sprite.transform.upperLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperRight.x) + ' y: ' + Math.round(sprite.transform.upperRight.y), sprite.transform.upperRight.x, sprite.transform.upperRight.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomLeft.x) + ' y: ' + Math.round(sprite.transform.bottomLeft.y), sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomRight.x) + ' y: ' + Math.round(sprite.transform.bottomRight.y), sprite.transform.bottomRight.x, sprite.transform.bottomRight.y); + game.stage.context.fillRect(sprite.transform.center.x, sprite.transform.center.y, 2, 2); + game.stage.context.fillRect(sprite.transform.upperLeft.x, sprite.transform.upperLeft.y, 2, 2); + game.stage.context.fillRect(sprite.transform.upperRight.x, sprite.transform.upperRight.y, 2, 2); + game.stage.context.fillRect(sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y, 2, 2); + game.stage.context.fillRect(sprite.transform.bottomRight.x, sprite.transform.bottomRight.y, 2, 2); + game.stage.context.strokeStyle = 'rgb(255,255,0)'; + game.stage.context.strokeRect(sprite.cameraView.x, sprite.cameraView.y, sprite.cameraView.width, sprite.cameraView.height); game.stage.context.restore(); } + var botData = '{"frames": [{"filename": "running bot.swf/0000","frame": { "x": 34, "y": 128, "w": 56, "h": 60 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 2, "w": 56, "h": 60 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0001","frame": { "x": 54, "y": 0, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0002","frame": { "x": 54, "y": 58, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0003","frame": { "x": 0, "y": 192, "w": 34, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 11, "y": 0, "w": 34, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0004","frame": { "x": 0, "y": 64, "w": 54, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 1, "y": 0, "w": 54, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0005","frame": { "x": 196, "y": 0, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0006","frame": { "x": 0, "y": 0, "w": 54, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 1, "y": 0, "w": 54, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0007","frame": { "x": 140, "y": 0, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0008","frame": { "x": 34, "y": 188, "w": 50, "h": 60 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 3, "y": 2, "w": 50, "h": 60 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0009","frame": { "x": 0, "y": 128, "w": 34, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 11, "y": 0, "w": 34, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0010","frame": { "x": 84, "y": 188, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }}]}'; })(); diff --git a/Tests/misc/point3.ts b/Tests/misc/point3.ts index 388acec8..3fd9752f 100644 --- a/Tests/misc/point3.ts +++ b/Tests/misc/point3.ts @@ -6,7 +6,7 @@ function init() { - game.load.image('box', 'assets/tests/320x200.png'); + game.load.atlas('bot', 'assets/sprites/running_bot.png', null, botData); game.load.start(); } @@ -17,11 +17,14 @@ function create() { game.stage.backgroundColor = 'rgb(0,0,0)'; - game.stage.disablePauseScreen = true; - sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'box'); + sprite = game.add.sprite(game.stage.centerX, game.stage.centerY, 'bot'); - sprite.transform.origin.setTo(0.3, 0.8); + sprite.animations.add('run', null, 10, true); + + sprite.animations.play('run'); + + //sprite.transform.scale.setTo(4, 4); game.input.onTap.add(rotateIt, this); @@ -42,36 +45,27 @@ function render() { - var originX: number = sprite.transform.origin.x * sprite.width; - var originY: number = sprite.transform.origin.y * sprite.height; - var centerX: number = 0.5 * sprite.width; - var centerY: number = 0.5 * sprite.height; - var distanceX: number = originX - centerX; - var distanceY: number = originY - centerY; - var distance: number = Math.sqrt(((originX - centerX) * (originX - centerX)) + ((originY - centerY) * (originY - centerY))); - - var px = sprite.x + distance * Math.cos(sprite.transform.rotation + 45 * Math.PI / 180); - var py = sprite.y + distance * Math.sin(sprite.transform.rotation + 45 * Math.PI / 180); - game.stage.context.save(); - game.stage.context.fillStyle = 'rgb(255,255,0)'; - game.stage.context.fillText('rect width: ' + originX + ' height: ' + originY, 32, 32); - game.stage.context.fillText('center x: ' + centerX + ' centerY: ' + centerY, 32, 52); - game.stage.context.fillText('angle: ' + sprite.rotation , 32, 72); - game.stage.context.fillText('point of rotation x: ' + sprite.transform.origin.x + ' y: ' + sprite.transform.origin.y, 32, 92); - game.stage.context.fillText('sprite x: ' + sprite.x + ' sprite y: ' + sprite.y, 32, 112); - game.stage.context.fillRect(sprite.x, sprite.y, 2, 2); - game.stage.context.restore(); + game.stage.context.fillStyle = 'rgb(255,0,255)'; + + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperLeft.x) + ' y: ' + Math.round(sprite.transform.upperLeft.y), sprite.transform.upperLeft.x, sprite.transform.upperLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.upperRight.x) + ' y: ' + Math.round(sprite.transform.upperRight.y), sprite.transform.upperRight.x, sprite.transform.upperRight.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomLeft.x) + ' y: ' + Math.round(sprite.transform.bottomLeft.y), sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y); + game.stage.context.fillText('x: ' + Math.round(sprite.transform.bottomRight.x) + ' y: ' + Math.round(sprite.transform.bottomRight.y), sprite.transform.bottomRight.x, sprite.transform.bottomRight.y); + + game.stage.context.fillRect(sprite.transform.center.x, sprite.transform.center.y, 2, 2); + game.stage.context.fillRect(sprite.transform.upperLeft.x, sprite.transform.upperLeft.y, 2, 2); + game.stage.context.fillRect(sprite.transform.upperRight.x, sprite.transform.upperRight.y, 2, 2); + game.stage.context.fillRect(sprite.transform.bottomLeft.x, sprite.transform.bottomLeft.y, 2, 2); + game.stage.context.fillRect(sprite.transform.bottomRight.x, sprite.transform.bottomRight.y, 2, 2); + + game.stage.context.strokeStyle = 'rgb(255,255,0)'; + game.stage.context.strokeRect(sprite.cameraView.x, sprite.cameraView.y, sprite.cameraView.width, sprite.cameraView.height); - game.stage.context.save(); - game.stage.context.fillStyle = 'rgba(255,255,255,0.1)'; - game.stage.context.beginPath(); - game.stage.context.moveTo(sprite.x, sprite.y); - game.stage.context.arc(sprite.x, sprite.y, distance, 0, Math.PI * 2); - game.stage.context.closePath(); - game.stage.context.fill(); game.stage.context.restore(); } + var botData = '{"frames": [{"filename": "running bot.swf/0000","frame": { "x": 34, "y": 128, "w": 56, "h": 60 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 2, "w": 56, "h": 60 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0001","frame": { "x": 54, "y": 0, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0002","frame": { "x": 54, "y": 58, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0003","frame": { "x": 0, "y": 192, "w": 34, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 11, "y": 0, "w": 34, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0004","frame": { "x": 0, "y": 64, "w": 54, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 1, "y": 0, "w": 54, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0005","frame": { "x": 196, "y": 0, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0006","frame": { "x": 0, "y": 0, "w": 54, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 1, "y": 0, "w": 54, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0007","frame": { "x": 140, "y": 0, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0008","frame": { "x": 34, "y": 188, "w": 50, "h": 60 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 3, "y": 2, "w": 50, "h": 60 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0009","frame": { "x": 0, "y": 128, "w": 34, "h": 64 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 11, "y": 0, "w": 34, "h": 64 },"sourceSize": { "w": 56, "h": 64 }},{"filename": "running bot.swf/0010","frame": { "x": 84, "y": 188, "w": 56, "h": 58 },"rotated": false,"trimmed": true,"spriteSourceSize": { "x": 0, "y": 3, "w": 56, "h": 58 },"sourceSize": { "w": 56, "h": 64 }}]}'; + })(); diff --git a/Tests/phaser.js b/Tests/phaser.js index cc94bbce..5895e09e 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -3060,8 +3060,8 @@ var Phaser; (function (Components) { var Transform = (function () { /** - * Creates a new Sprite Transform component - * @param parent The Sprite using this transform + * Creates a new Transform component + * @param parent The game object using this transform */ function Transform(parent) { /** @@ -3096,7 +3096,10 @@ var Phaser; this._sc = new Phaser.Point(); this._scA = new Phaser.Point(); } - Transform.prototype.setCache = function () { + Transform.prototype.setCache = /** + * Populates the transform cache. Called by the parent object on creation. + */ + function () { this._pos.x = this.parent.x; this._pos.y = this.parent.y; this._halfSize.x = this.parent.width / 2; @@ -3121,13 +3124,19 @@ var Phaser; this._sc.x = 0; this._sc.y = 1; } - this.center.setTo(this.center.x, this.center.y); + this.center.x = this.parent.x + this._distance * this._scA.y; + this.center.y = this.parent.y + this._distance * this._scA.x; this.upperLeft.setTo(this.center.x - this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); this.upperRight.setTo(this.center.x + this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); this.bottomLeft.setTo(this.center.x - this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); this.bottomRight.setTo(this.center.x + this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + this._pos.x = this.parent.x; + this._pos.y = this.parent.y; }; - Transform.prototype.update = function () { + Transform.prototype.update = /** + * Updates the local transform matrix and the cache values if anything has changed in the parent. + */ + function () { // Check cache var dirty = false; // 1) Height or Width change (also triggered by a change in scale) or an Origin change @@ -3166,7 +3175,6 @@ var Phaser; if(dirty || this.parent.x != this._pos.x || this.parent.y != this._pos.y) { this.center.x = this.parent.x + this._distance * this._scA.y; this.center.y = this.parent.y + this._distance * this._scA.x; - this.center.setTo(this.center.x, this.center.y); this.upperLeft.setTo(this.center.x - this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); this.upperRight.setTo(this.center.x + this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); this.bottomLeft.setTo(this.center.x - this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); @@ -3255,17 +3263,8 @@ var Phaser; }); Object.defineProperty(Transform.prototype, "sin", { get: /** - * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration + * The equivalent of Math.sin(rotation + rotationOffset) */ - //public get centerX(): number { - // return this.center.x; - //} - /** - * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration - */ - //public get centerY(): number { - // return this.center.y; - //} function () { return this._sc.x; }, @@ -3273,7 +3272,10 @@ var Phaser; configurable: true }); Object.defineProperty(Transform.prototype, "cos", { - get: function () { + get: /** + * The equivalent of Math.cos(rotation + rotationOffset) + */ + function () { return this._sc.y; }, enumerable: true, @@ -4681,35 +4683,12 @@ var Phaser; sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); } else { - //var left:Number = Math.min(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x); - //var top:Number = Math.min(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y); - //var right:Number = Math.max(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x); - //var bottom:Number = Math.max(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y); - //return new Rectangle(left, top, right - left, bottom - top); - var minX = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); - var minY = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); - var maxX = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); - var maxY = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); - // (min_x,min_y), (min_x,max_y), (max_x,max_y), (max_x,min_y) - sprite.cameraView.x = minX; - sprite.cameraView.y = minY; - sprite.cameraView.width = maxX - minX; - sprite.cameraView.height = maxY - minY; - /* - // Useful to get the maximum AABB size of any given rect - - If you want a single box that covers all angles, just take the half-diagonal of your existing box as the radius of a circle. - The new box has to contain this circle, so it should be a square with side-length equal to twice the radius - (equiv. the diagonal of the original AABB) and with the same center as the original. - */ - } + sprite.cameraView.x = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + sprite.cameraView.y = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + sprite.cameraView.width = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x) - sprite.cameraView.x; + sprite.cameraView.height = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y) - sprite.cameraView.y; + } } - if(sprite.animations.currentFrame !== null && sprite.animations.currentFrame.trimmed) { - //sprite.cameraView.x += sprite.animations.currentFrame.spriteSourceSizeX; - //sprite.cameraView.y += sprite.animations.currentFrame.spriteSourceSizeY; - //this._dw = sprite.animations.currentFrame.spriteSourceSizeW; - //this._dh = sprite.animations.currentFrame.spriteSourceSizeH; - } return sprite.cameraView; }; SpriteUtils.getAsPoints = function getAsPoints(sprite) { @@ -4724,7 +4703,7 @@ var Phaser; out.push(new Phaser.Point(sprite.x, sprite.y + sprite.height)); return out; }; - SpriteUtils.overlapsPoint = /** + SpriteUtils.overlapsXY = /** * Checks to see if some GameObject overlaps this GameObject or Group. * If the group has a LOT of things in it, it might be faster to use Collision.overlaps(). * WARNING: Currently tilemaps do NOT support screen space overlap checks! @@ -4777,7 +4756,7 @@ var Phaser; */ /** * Checks to see if this GameObject were located at the given position, would it overlap the GameObject or Group? - * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size numbero account. + * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size into account. * WARNING: Currently tilemaps do NOT support screen space overlap checks! * * @param X {number} The X position you want to check. Pretends this object (the caller, not the parameter) is located here. @@ -4832,6 +4811,43 @@ var Phaser; } */ /** + * Checks to see if the given x and y coordinates overlaps this Sprite, taking scaling and rotation into account. + * The coordinates must be given in world space, not local or camera space. + * + * @param sprite {Sprite} The Sprite to check. It will take scaling and rotation into account. + * @param x {Number} The x coordinate in world space. + * @param y {Number} The y coordinate in world space. + * + * @return Whether or not the point overlaps this object. + */ + function overlapsXY(sprite, x, y) { + // if rotation == 0 then just do a rect check instead! + if(sprite.transform.rotation == 0) { + return Phaser.RectangleUtils.contains(sprite.cameraView, x, y); + } + //var ex: number = sprite.transform.upperRight.x - sprite.transform.upperLeft.x; + //var ey: number = sprite.transform.upperRight.y - sprite.transform.upperLeft.y; + //var fx: number = sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x; + //var fy: number = sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y; + //if ((x-ax)*ex+(y-ay)*ey<0.0) return false; + if((x - sprite.transform.upperLeft.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) < 0) { + return false; + } + //if ((x-bx)*ex+(y-by)*ey>0.0) return false; + if((x - sprite.transform.upperRight.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperRight.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) > 0) { + return false; + } + //if ((x-ax)*fx+(y-ay)*fy<0.0) return false; + if((x - sprite.transform.upperLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) < 0) { + return false; + } + //if ((x-dx)*fx+(y-dy)*fy>0.0) return false; + if((x - sprite.transform.bottomLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.bottomLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) > 0) { + return false; + } + return true; + }; + SpriteUtils.overlapsPoint = /** * Checks to see if a point in 2D world space overlaps this GameObject. * * @param point {Point} The point in world space you want to check. @@ -16574,9 +16590,8 @@ var Phaser; if(sprite.transform.scrollFactor.equals(0)) { return true; } - return true; - //return RectangleUtils.intersects(sprite.cameraView, camera.screenView); - }; + return Phaser.RectangleUtils.intersects(sprite.cameraView, camera.screenView); + }; CanvasRenderer.prototype.inScreen = function (camera) { return true; }; diff --git a/build/phaser.d.ts b/build/phaser.d.ts index f6229317..768901fe 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -1892,8 +1892,8 @@ module Phaser { module Phaser.Components { class Transform { /** - * Creates a new Sprite Transform component - * @param parent The Sprite using this transform + * Creates a new Transform component + * @param parent The game object using this transform */ constructor(parent); private _rotation; @@ -1908,13 +1908,37 @@ module Phaser.Components { private _angle; private _distance; private _prevRotation; + /** + * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ public center: Point; + /** + * The upper-left corner of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ public upperLeft: Point; + /** + * The upper-right corner of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ public upperRight: Point; + /** + * The bottom-left corner of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ public bottomLeft: Point; + /** + * The bottom-right corner of the Sprite in world coordinates, after taking scaling and rotation into consideration + */ public bottomRight: Point; + /** + * The local transform matrix + */ public local: Mat3; + /** + * Populates the transform cache. Called by the parent object on creation. + */ public setCache(): void; + /** + * Updates the local transform matrix and the cache values if anything has changed in the parent. + */ public update(): void; /** * Reference to Phaser.Game @@ -1975,7 +1999,13 @@ module Phaser.Components { * Half the height of the parent sprite, taking into consideration scaling */ public halfHeight : number; + /** + * The equivalent of Math.sin(rotation + rotationOffset) + */ public sin : number; + /** + * The equivalent of Math.cos(rotation + rotationOffset) + */ public cos : number; } } @@ -2705,6 +2735,17 @@ module Phaser { static updateCameraView(camera: Camera, sprite: Sprite): Rectangle; static getAsPoints(sprite: Sprite): Point[]; /** + * Checks to see if the given x and y coordinates overlaps this Sprite, taking scaling and rotation into account. + * The coordinates must be given in world space, not local or camera space. + * + * @param sprite {Sprite} The Sprite to check. It will take scaling and rotation into account. + * @param x {Number} The x coordinate in world space. + * @param y {Number} The y coordinate in world space. + * + * @return Whether or not the point overlaps this object. + */ + static overlapsXY(sprite: Sprite, x: number, y: number): bool; + /** * Checks to see if a point in 2D world space overlaps this GameObject. * * @param point {Point} The point in world space you want to check. diff --git a/build/phaser.js b/build/phaser.js index cc94bbce..5895e09e 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -3060,8 +3060,8 @@ var Phaser; (function (Components) { var Transform = (function () { /** - * Creates a new Sprite Transform component - * @param parent The Sprite using this transform + * Creates a new Transform component + * @param parent The game object using this transform */ function Transform(parent) { /** @@ -3096,7 +3096,10 @@ var Phaser; this._sc = new Phaser.Point(); this._scA = new Phaser.Point(); } - Transform.prototype.setCache = function () { + Transform.prototype.setCache = /** + * Populates the transform cache. Called by the parent object on creation. + */ + function () { this._pos.x = this.parent.x; this._pos.y = this.parent.y; this._halfSize.x = this.parent.width / 2; @@ -3121,13 +3124,19 @@ var Phaser; this._sc.x = 0; this._sc.y = 1; } - this.center.setTo(this.center.x, this.center.y); + this.center.x = this.parent.x + this._distance * this._scA.y; + this.center.y = this.parent.y + this._distance * this._scA.x; this.upperLeft.setTo(this.center.x - this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); this.upperRight.setTo(this.center.x + this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); this.bottomLeft.setTo(this.center.x - this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); this.bottomRight.setTo(this.center.x + this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); + this._pos.x = this.parent.x; + this._pos.y = this.parent.y; }; - Transform.prototype.update = function () { + Transform.prototype.update = /** + * Updates the local transform matrix and the cache values if anything has changed in the parent. + */ + function () { // Check cache var dirty = false; // 1) Height or Width change (also triggered by a change in scale) or an Origin change @@ -3166,7 +3175,6 @@ var Phaser; if(dirty || this.parent.x != this._pos.x || this.parent.y != this._pos.y) { this.center.x = this.parent.x + this._distance * this._scA.y; this.center.y = this.parent.y + this._distance * this._scA.x; - this.center.setTo(this.center.x, this.center.y); this.upperLeft.setTo(this.center.x - this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); this.upperRight.setTo(this.center.x + this._halfSize.x * this._sc.y + this._halfSize.y * this._sc.x, this.center.y - this._halfSize.y * this._sc.y + this._halfSize.x * this._sc.x); this.bottomLeft.setTo(this.center.x - this._halfSize.x * this._sc.y - this._halfSize.y * this._sc.x, this.center.y + this._halfSize.y * this._sc.y - this._halfSize.x * this._sc.x); @@ -3255,17 +3263,8 @@ var Phaser; }); Object.defineProperty(Transform.prototype, "sin", { get: /** - * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration + * The equivalent of Math.sin(rotation + rotationOffset) */ - //public get centerX(): number { - // return this.center.x; - //} - /** - * The center of the Sprite in world coordinates, after taking scaling and rotation into consideration - */ - //public get centerY(): number { - // return this.center.y; - //} function () { return this._sc.x; }, @@ -3273,7 +3272,10 @@ var Phaser; configurable: true }); Object.defineProperty(Transform.prototype, "cos", { - get: function () { + get: /** + * The equivalent of Math.cos(rotation + rotationOffset) + */ + function () { return this._sc.y; }, enumerable: true, @@ -4681,35 +4683,12 @@ var Phaser; sprite.cameraView.x = Math.round(sprite.x - (camera.worldView.x * sprite.transform.scrollFactor.x) - (sprite.cameraView.width * sprite.transform.origin.x)); sprite.cameraView.y = Math.round(sprite.y - (camera.worldView.y * sprite.transform.scrollFactor.y) - (sprite.cameraView.height * sprite.transform.origin.y)); } else { - //var left:Number = Math.min(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x); - //var top:Number = Math.min(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y); - //var right:Number = Math.max(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x); - //var bottom:Number = Math.max(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y); - //return new Rectangle(left, top, right - left, bottom - top); - var minX = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); - var minY = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); - var maxX = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); - var maxY = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); - // (min_x,min_y), (min_x,max_y), (max_x,max_y), (max_x,min_y) - sprite.cameraView.x = minX; - sprite.cameraView.y = minY; - sprite.cameraView.width = maxX - minX; - sprite.cameraView.height = maxY - minY; - /* - // Useful to get the maximum AABB size of any given rect - - If you want a single box that covers all angles, just take the half-diagonal of your existing box as the radius of a circle. - The new box has to contain this circle, so it should be a square with side-length equal to twice the radius - (equiv. the diagonal of the original AABB) and with the same center as the original. - */ - } + sprite.cameraView.x = Math.min(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x); + sprite.cameraView.y = Math.min(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y); + sprite.cameraView.width = Math.max(sprite.transform.upperLeft.x, sprite.transform.upperRight.x, sprite.transform.bottomLeft.x, sprite.transform.bottomRight.x) - sprite.cameraView.x; + sprite.cameraView.height = Math.max(sprite.transform.upperLeft.y, sprite.transform.upperRight.y, sprite.transform.bottomLeft.y, sprite.transform.bottomRight.y) - sprite.cameraView.y; + } } - if(sprite.animations.currentFrame !== null && sprite.animations.currentFrame.trimmed) { - //sprite.cameraView.x += sprite.animations.currentFrame.spriteSourceSizeX; - //sprite.cameraView.y += sprite.animations.currentFrame.spriteSourceSizeY; - //this._dw = sprite.animations.currentFrame.spriteSourceSizeW; - //this._dh = sprite.animations.currentFrame.spriteSourceSizeH; - } return sprite.cameraView; }; SpriteUtils.getAsPoints = function getAsPoints(sprite) { @@ -4724,7 +4703,7 @@ var Phaser; out.push(new Phaser.Point(sprite.x, sprite.y + sprite.height)); return out; }; - SpriteUtils.overlapsPoint = /** + SpriteUtils.overlapsXY = /** * Checks to see if some GameObject overlaps this GameObject or Group. * If the group has a LOT of things in it, it might be faster to use Collision.overlaps(). * WARNING: Currently tilemaps do NOT support screen space overlap checks! @@ -4777,7 +4756,7 @@ var Phaser; */ /** * Checks to see if this GameObject were located at the given position, would it overlap the GameObject or Group? - * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size numbero account. + * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size into account. * WARNING: Currently tilemaps do NOT support screen space overlap checks! * * @param X {number} The X position you want to check. Pretends this object (the caller, not the parameter) is located here. @@ -4832,6 +4811,43 @@ var Phaser; } */ /** + * Checks to see if the given x and y coordinates overlaps this Sprite, taking scaling and rotation into account. + * The coordinates must be given in world space, not local or camera space. + * + * @param sprite {Sprite} The Sprite to check. It will take scaling and rotation into account. + * @param x {Number} The x coordinate in world space. + * @param y {Number} The y coordinate in world space. + * + * @return Whether or not the point overlaps this object. + */ + function overlapsXY(sprite, x, y) { + // if rotation == 0 then just do a rect check instead! + if(sprite.transform.rotation == 0) { + return Phaser.RectangleUtils.contains(sprite.cameraView, x, y); + } + //var ex: number = sprite.transform.upperRight.x - sprite.transform.upperLeft.x; + //var ey: number = sprite.transform.upperRight.y - sprite.transform.upperLeft.y; + //var fx: number = sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x; + //var fy: number = sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y; + //if ((x-ax)*ex+(y-ay)*ey<0.0) return false; + if((x - sprite.transform.upperLeft.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) < 0) { + return false; + } + //if ((x-bx)*ex+(y-by)*ey>0.0) return false; + if((x - sprite.transform.upperRight.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperRight.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) > 0) { + return false; + } + //if ((x-ax)*fx+(y-ay)*fy<0.0) return false; + if((x - sprite.transform.upperLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) < 0) { + return false; + } + //if ((x-dx)*fx+(y-dy)*fy>0.0) return false; + if((x - sprite.transform.bottomLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.bottomLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) > 0) { + return false; + } + return true; + }; + SpriteUtils.overlapsPoint = /** * Checks to see if a point in 2D world space overlaps this GameObject. * * @param point {Point} The point in world space you want to check. @@ -16574,9 +16590,8 @@ var Phaser; if(sprite.transform.scrollFactor.equals(0)) { return true; } - return true; - //return RectangleUtils.intersects(sprite.cameraView, camera.screenView); - }; + return Phaser.RectangleUtils.intersects(sprite.cameraView, camera.screenView); + }; CanvasRenderer.prototype.inScreen = function (camera) { return true; }; From 7dac2b65068969f72668d479026eb43048f8a8f4 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 13 Jun 2013 01:55:32 +0100 Subject: [PATCH 8/8] Added Group.bringToTop and updated Input component to use sprite getXY handler. --- Phaser/components/sprite/Input.ts | 41 +++++- Phaser/core/Group.ts | 45 +++++++ Phaser/gameobjects/Sprite.ts | 26 +++- Phaser/input/Input.ts | 48 +++++-- Phaser/input/Pointer.ts | 4 +- Phaser/loader/Cache.ts | 51 +++++++ README.md | 5 +- Tests/Tests.csproj | 12 +- Tests/demoscene/ballmover.js | 18 --- Tests/demoscene/ballmover.ts | 31 ----- Tests/demoscene/colorwhirl.js | 22 --- Tests/demoscene/colorwhirl.ts | 33 ----- Tests/demoscene/fruitfall.js | 44 ------ Tests/demoscene/fruitfall.ts | 50 ------- Tests/demoscene/fujiboink.js | 42 ------ Tests/demoscene/fujiboink.ts | 56 -------- Tests/demoscene/index.html | 32 ----- Tests/demoscene/metalslug.js | 22 --- Tests/demoscene/metalslug.ts | 36 ----- Tests/demoscene/scroller1.js | 12 -- Tests/demoscene/scroller1.ts | 21 --- Tests/demoscene/starray.js | 31 ----- Tests/demoscene/starray.ts | 53 -------- Tests/input/bring to top.js | 28 ++++ Tests/input/bring to top.ts | 40 ++++++ Tests/input/rotated sprites.js | 33 +++++ Tests/input/rotated sprites.ts | 49 +++++++ Tests/phaser.js | 214 +++++++++++++++--------------- Tests/scrollzones/blasteroids.js | 2 +- Tests/scrollzones/blasteroids.ts | 2 +- Tests/sprites/scale sprite 1.js | 6 +- Tests/sprites/scale sprite 1.ts | 6 +- Tests/sprites/sprite origin 3.js | 2 +- Tests/sprites/sprite origin 3.ts | 2 +- build/phaser.d.ts | 58 +++++++- build/phaser.js | 214 +++++++++++++++--------------- 36 files changed, 628 insertions(+), 763 deletions(-) delete mode 100644 Tests/demoscene/ballmover.js delete mode 100644 Tests/demoscene/ballmover.ts delete mode 100644 Tests/demoscene/colorwhirl.js delete mode 100644 Tests/demoscene/colorwhirl.ts delete mode 100644 Tests/demoscene/fruitfall.js delete mode 100644 Tests/demoscene/fruitfall.ts delete mode 100644 Tests/demoscene/fujiboink.js delete mode 100644 Tests/demoscene/fujiboink.ts delete mode 100644 Tests/demoscene/index.html delete mode 100644 Tests/demoscene/metalslug.js delete mode 100644 Tests/demoscene/metalslug.ts delete mode 100644 Tests/demoscene/scroller1.js delete mode 100644 Tests/demoscene/scroller1.ts delete mode 100644 Tests/demoscene/starray.js delete mode 100644 Tests/demoscene/starray.ts create mode 100644 Tests/input/bring to top.js create mode 100644 Tests/input/bring to top.ts create mode 100644 Tests/input/rotated sprites.js create mode 100644 Tests/input/rotated sprites.ts diff --git a/Phaser/components/sprite/Input.ts b/Phaser/components/sprite/Input.ts index 6adac87f..16d87575 100644 --- a/Phaser/components/sprite/Input.ts +++ b/Phaser/components/sprite/Input.ts @@ -48,6 +48,11 @@ module Phaser.Components.Sprite { */ public priorityID:number = 0; + /** + * The index of this Input component entry in the Game.Input manager. + */ + public indexID:number = 0; + private _dragPoint: Point; private _draggedPointerID: number; public dragOffset: Point; @@ -58,6 +63,7 @@ module Phaser.Components.Sprite { public allowHorizontalDrag: bool = true; public allowVerticalDrag: bool = true; + public bringToTop: bool = false; public snapOnDrag: bool = false; public snapOnRelease: bool = false; @@ -245,11 +251,26 @@ module Phaser.Components.Sprite { { // De-register, etc this.enabled = false; - this.game.input.removeGameObject(this.sprite); + this.game.input.removeGameObject(this.indexID); } } + /** + * Clean up memory. + */ + public destroy() { + + if (this.enabled) + { + this.game.input.removeGameObject(this.indexID); + } + + } + + /** + * Checks if the given pointer is over this Sprite. All checks are done in world coordinates. + */ public checkPointerOver(pointer: Phaser.Pointer): bool { if (this.enabled == false || this.sprite.visible == false) @@ -258,7 +279,7 @@ module Phaser.Components.Sprite { } else { - return RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY()); + return SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY()); } } @@ -279,7 +300,7 @@ module Phaser.Components.Sprite { } else if (this._pointerData[pointer.id].isOver == true) { - if (RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY())) + if (SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY())) { this._pointerData[pointer.id].x = pointer.x - this.sprite.x; this._pointerData[pointer.id].y = pointer.y - this.sprite.y; @@ -350,6 +371,11 @@ module Phaser.Components.Sprite { this.startDrag(pointer); } + if (this.bringToTop) + { + this.sprite.group.bringToTop(this.sprite); + } + } // Consume the event? @@ -493,16 +519,18 @@ module Phaser.Components.Sprite { * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback * * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. + * @param bringToTop If true the Sprite will be bought to the top of the rendering list in its current Group. * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here */ - public enableDrag(lockCenter:bool = false, pixelPerfect:bool = false, alphaThreshold:number = 255, boundsRect:Rectangle = null, boundsSprite:Phaser.Sprite = null):void + public enableDrag(lockCenter:bool = false, bringToTop:bool = false, pixelPerfect:bool = false, alphaThreshold:number = 255, boundsRect:Rectangle = null, boundsSprite:Phaser.Sprite = null):void { this._dragPoint = new Point; this.draggable = true; + this.bringToTop = bringToTop; this.dragOffset = new Point; this.dragFromCenter = lockCenter; @@ -559,6 +587,11 @@ module Phaser.Components.Sprite { this.updateDrag(pointer); + if (this.bringToTop) + { + this.sprite.group.bringToTop(this.sprite); + } + } /** diff --git a/Phaser/core/Group.ts b/Phaser/core/Group.ts index ad9397d7..812b0791 100644 --- a/Phaser/core/Group.ts +++ b/Phaser/core/Group.ts @@ -583,6 +583,14 @@ module Phaser { } + /** + * Swaps two existing game object in this Group with each other. + * + * @param {Basic} child1 The first object to swap. + * @param {Basic} child2 The second object to swap. + * + * @return {Basic} True if the two objects successfully swapped position. + */ public swap(child1, child2, sort?: bool = true): bool { if (child1.group.ID != this.ID || child2.group.ID != this.ID || child1 === child2) @@ -604,6 +612,43 @@ module Phaser { } + public bringToTop(child): bool { + + // If child not in this group, or is already at the top of the group, return false + if (child.group.ID != this.ID || child.z == this._zCounter) + { + return false; + } + + this.sort(); + + // What's the z index of the top most child? + var tempZ: number = child.z; + var childIndex: number = this._zCounter; + + this._i = 0; + + while (this._i < this.length) + { + this._member = this.members[this._i++]; + + if (this._i > childIndex) + { + this._member.z--; + } + else if (this._member.z == child.z) + { + childIndex = this._i; + this._member.z = this._zCounter; + } + } + + this.sort(); + + return true; + + } + /** * Call this function to sort the group according to a particular value and order. * For example, to sort game objects for Zelda-style overlaps you might call diff --git a/Phaser/gameobjects/Sprite.ts b/Phaser/gameobjects/Sprite.ts index 74d2176d..488bf62f 100644 --- a/Phaser/gameobjects/Sprite.ts +++ b/Phaser/gameobjects/Sprite.ts @@ -40,7 +40,6 @@ module Phaser { this.z = -1; this.group = null; - // No dependencies this.animations = new Phaser.Components.AnimationManager(this); this.input = new Phaser.Components.Sprite.Input(this); this.events = new Phaser.Components.Sprite.Events(this); @@ -74,6 +73,11 @@ module Phaser { this.transform.setCache(); + // Handy proxies + this.scale = this.transform.scale; + this.alpha = this.texture.alpha; + this.origin = this.transform.origin; + } /** @@ -194,6 +198,23 @@ module Phaser { this.transform.rotation = this.game.math.wrap(value, 360, 0); } + /** + * The scale of the Sprite. A value of 1 is original scale. 0.5 is half size. 2 is double the size. + * This is a reference to Sprite.transform.scale + */ + public scale: Phaser.Vec2; + + /** + * The alpha of the Sprite between 0 and 1, a value of 1 being fully opaque. + */ + public alpha: number; + + /** + * The origin of the Sprite around which rotation and positioning takes place. + * This is a reference to Sprite.transform.origin + */ + public origin: Phaser.Vec2; + /** * Set the animation frame by frame number. */ @@ -318,8 +339,7 @@ module Phaser { */ public destroy() { - //this.input.destroy(); - + this.input.destroy(); } diff --git a/Phaser/input/Input.ts b/Phaser/input/Input.ts index 6c76469d..32ed80cd 100644 --- a/Phaser/input/Input.ts +++ b/Phaser/input/Input.ts @@ -455,22 +455,46 @@ module Phaser { public inputObjects = []; public totalTrackedObjects: number = 0; - // Add Input Enabled array + add/remove methods and then iterate and update them during the main update - // Clear down this array on State swap??? Maybe removed from it when Sprite is destroyed - + /** + * Adds a new game object to be tracked by the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method addGameObject + **/ public addGameObject(object) { - // Lots more checks here + // Find a spare slot + for (var i = 0; i < this.inputObjects.length; i++) + { + if (this.inputObjects[i] == null) + { + this.inputObjects[i] = object; + object.input.indexID = i; + this.totalTrackedObjects++; + return; + } + } + + // If we got this far we need to push a new entry into the array + object.input.indexID = this.inputObjects.length; + this.inputObjects.push(object); + this.totalTrackedObjects++; + } - public removeGameObject(object) { - // TODO + /** + * Removes a game object from the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method removeGameObject + **/ + public removeGameObject(index: number) { + + if (this.inputObjects[index]) + { + this.inputObjects[index] = null; + } + } - - /** * Updates the Input Manager. Called by the core Game loop. * @method update @@ -521,7 +545,7 @@ module Phaser { if (this.pointer10) { this.pointer10.reset(); } this.currentPointers = 0; - + this._game.stage.canvas.style.cursor = "default"; if (hard == true) @@ -618,7 +642,7 @@ module Phaser { * @param {Any} event The event data from the Touch event * @return {Pointer} The Pointer object that was started or null if no Pointer object is available **/ - public startPointer(event):Pointer { + public startPointer(event): Pointer { if (this.maxPointers < 10 && this.totalActivePointers == this.maxPointers) { @@ -677,7 +701,7 @@ module Phaser { * @param {Any} event The event data from the Touch event * @return {Pointer} The Pointer object that was updated or null if no Pointer object is available **/ - public updatePointer(event):Pointer { + public updatePointer(event): Pointer { // Unrolled for speed if (this.pointer1.active == true && this.pointer1.identifier == event.identifier) @@ -731,7 +755,7 @@ module Phaser { * @param {Any} event The event data from the Touch event * @return {Pointer} The Pointer object that was stopped or null if no Pointer object is available **/ - public stopPointer(event):Pointer { + public stopPointer(event): Pointer { // Unrolled for speed if (this.pointer1.active == true && this.pointer1.identifier == event.identifier) diff --git a/Phaser/input/Pointer.ts b/Phaser/input/Pointer.ts index 7b89d213..b854a1ce 100644 --- a/Phaser/input/Pointer.ts +++ b/Phaser/input/Pointer.ts @@ -422,7 +422,7 @@ module Phaser { for (var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if (this.game.input.inputObjects[i].input.checkPointerOver(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) + if (this.game.input.inputObjects[i] !== null && this.game.input.inputObjects[i].input.checkPointerOver(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) { _highestRenderID = this.game.input.inputObjects[i].renderOrderID; _highestRenderObject = i; @@ -510,7 +510,7 @@ module Phaser { for (var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if (this.game.input.inputObjects[i].input.enabled) + if (this.game.input.inputObjects[i] !== null && this.game.input.inputObjects[i].input.enabled) { this.game.input.inputObjects[i].input._releasedHandler(this); } diff --git a/Phaser/loader/Cache.ts b/Phaser/loader/Cache.ts index 4cd8a1dc..94ef30b8 100644 --- a/Phaser/loader/Cache.ts +++ b/Phaser/loader/Cache.ts @@ -261,6 +261,57 @@ module Phaser { } + /** + * Returns an array containing all of the keys of Images in the Cache. + * @return {Array} The string based keys in the Cache. + */ + public getImageKeys() { + + var output = []; + + for (var item in this._images) + { + output.push(item); + } + + return output; + + } + + /** + * Returns an array containing all of the keys of Sounds in the Cache. + * @return {Array} The string based keys in the Cache. + */ + public getSoundKeys() { + + var output = []; + + for (var item in this._sounds) + { + output.push(item); + } + + return output; + + } + + /** + * Returns an array containing all of the keys of Text Files in the Cache. + * @return {Array} The string based keys in the Cache. + */ + public getTextKeys() { + + var output = []; + + for (var item in this._text) + { + output.push(item); + } + + return output; + + } + /** * Clean up cache memory. */ diff --git a/README.md b/README.md index bdc6655a..eefeff1e 100644 --- a/README.md +++ b/README.md @@ -33,18 +33,15 @@ TODO: * If the Camera is larger than the Stage size then the rotation offset isn't correct * Texture Repeat doesn't scroll, because it's part of the camera not the world, need to think about this more * Bug: Sprite x/y gets shifted if dynamic from the original value -* Input CSS cursor those little 4-way arrows on drag? * Stage CSS3 transforms!!! Color tints, sepia, greyscale, all of those cool things :) * Add JSON Texture Atlas object support. * Swap to using time based motion (like the tweens) rather than delta timer - it just doesn't work well on slow phones * Pointer.getWorldX(camera) needs to take camera scale into consideration -* Add a 'click to bring to top' demo (+ Group feature?) * If stage.clear set to false and game pauses, when it unpauses you still see the pause arrow - resolve this * Add clip support + shape options to Texture Component. * Make sure I'm using Point and not Vec2 when it's not a directional vector I need * Bug with setting scale or anything on a Sprite inside a Group, or maybe group.addNewSprite issue -* Make input check use the rotated sprite check * Sprite collision events * See which functions in the input component can move elsewhere (utils) * Move all of the renderDebugInfo methods to the DebugUtils class @@ -113,6 +110,8 @@ V1.0.0 * Camera.inCamera check now uses the Sprite.worldView which finally accurately updates regardless of scale, rotation or rotation origin. * Added Math.Mat3 for Matrix3 operations (which Sprite.Transform uses) and Math.Mat3Utils for lots of use Mat3 related methods. * Added SpriteUtils.overlapsXY and overlapsPoint to check if a point is within a sprite, taking scale and rotation into account. +* Added Cache.getImageKeys (and similar) to return an array of all the keys for all currently cached objects. +* Added Group.bringToTop feature. Will sort the Group, move the given sprites z-index to the top and shift the rest down by one. diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 7d503fff..a4bdc215 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -85,6 +85,10 @@ swap children.ts + + + bring to top.ts + drag sprite 1.ts @@ -121,6 +125,10 @@ point in rotated sprite.ts + + + rotated sprites.ts + snap 1.ts @@ -274,8 +282,6 @@ boot screen.ts - - - + \ No newline at end of file diff --git a/Tests/demoscene/ballmover.js b/Tests/demoscene/ballmover.js deleted file mode 100644 index e45c4c6d..00000000 --- a/Tests/demoscene/ballmover.js +++ /dev/null @@ -1,18 +0,0 @@ -/// -/// -(function () { - var game = new Phaser.Game(this, 'demo1', 320, 200, init, create, update); - function init() { - game.load.image('balls', '../assets/sprites/balls.png'); - game.load.start(); - } - var scroller; - function create() { - scroller = game.add.scrollZone('balls', 0, 0, 800, 612); - game.math.sinCosGenerator(256, 4, 4, 2); - } - function update() { - scroller.currentRegion.scrollSpeed.x = game.math.shiftSinTable(); - scroller.currentRegion.scrollSpeed.y = game.math.shiftCosTable(); - } -})(); diff --git a/Tests/demoscene/ballmover.ts b/Tests/demoscene/ballmover.ts deleted file mode 100644 index d1775dae..00000000 --- a/Tests/demoscene/ballmover.ts +++ /dev/null @@ -1,31 +0,0 @@ -/// -/// - -(function () { - - var game = new Phaser.Game(this, 'demo1', 320, 200, init, create, update); - - function init() { - - game.load.image('balls', '../assets/sprites/balls.png'); - game.load.start(); - - } - - var scroller: Phaser.ScrollZone; - - function create() { - - scroller = game.add.scrollZone('balls', 0, 0, 800, 612); - game.math.sinCosGenerator(256, 4, 4, 2); - - } - - function update() { - - scroller.currentRegion.scrollSpeed.x = game.math.shiftSinTable(); - scroller.currentRegion.scrollSpeed.y = game.math.shiftCosTable(); - - } - -})(); diff --git a/Tests/demoscene/colorwhirl.js b/Tests/demoscene/colorwhirl.js deleted file mode 100644 index 51595fdd..00000000 --- a/Tests/demoscene/colorwhirl.js +++ /dev/null @@ -1,22 +0,0 @@ -/// -(function () { - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - function init() { - // Using Phasers asset loader we load up a PNG from the assets folder - game.load.image('swirl', '../assets/pics/color_wheel_swirl.png'); - game.load.start(); - } - 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); - // Set the origin to the middle of the Sprite to get the effect we need - swirl.origin.setTo(swirl.frameBounds.halfWidth, swirl.frameBounds.halfHeight); - // Create a tween that rotates a full 306 degrees and then repeats (loop set to true) - game.add.tween(swirl).to({ - angle: 360 - }, 2000, Phaser.Easing.Linear.None, true, 0, true); - } -})(); diff --git a/Tests/demoscene/colorwhirl.ts b/Tests/demoscene/colorwhirl.ts deleted file mode 100644 index e4fa1a7e..00000000 --- a/Tests/demoscene/colorwhirl.ts +++ /dev/null @@ -1,33 +0,0 @@ -/// - -(function () { - - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - - function init() { - - // Using Phasers asset loader we load up a PNG from the assets folder - game.load.image('swirl', '../assets/pics/color_wheel_swirl.png'); - game.load.start(); - - } - - 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); - - // Set the origin to the middle of the Sprite to get the effect we need - swirl.origin.setTo(swirl.frameBounds.halfWidth, swirl.frameBounds.halfHeight); - - // Create a tween that rotates a full 306 degrees and then repeats (loop set to true) - game.add.tween(swirl).to({ angle: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); - - } - -})(); diff --git a/Tests/demoscene/fruitfall.js b/Tests/demoscene/fruitfall.js deleted file mode 100644 index 7487c527..00000000 --- a/Tests/demoscene/fruitfall.js +++ /dev/null @@ -1,44 +0,0 @@ -var __extends = this.__extends || function (d, b) { - function __() { this.constructor = d; } - __.prototype = b.prototype; - d.prototype = new __(); -}; -/// -/// -/// -var fruitParticle = (function (_super) { - __extends(fruitParticle, _super); - function fruitParticle(game) { - _super.call(this, game); - var s = [ - 'carrot', - 'melon', - 'eggplant', - 'mushroom', - 'pineapple' - ]; - this.texture.loadImage(game.math.getRandom(s)); - } - return fruitParticle; -})(Phaser.Particle); -(function () { - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - var emitter; - function init() { - game.load.image('carrot', '../assets/sprites/carrot.png'); - game.load.image('melon', '../assets/sprites/melon.png'); - game.load.image('eggplant', '../assets/sprites/eggplant.png'); - game.load.image('mushroom', '../assets/sprites/mushroom.png'); - game.load.image('pineapple', '../assets/sprites/pineapple.png'); - game.load.start(); - } - function create() { - emitter = game.add.emitter(game.stage.centerX, 50); - emitter.gravity = 100; - // Here we tell the emitter to use our customParticle class - // The customParticle needs to extend Particle and must take game:Game as the first constructor parameter, otherwise it's free as a bird - emitter.particleClass = fruitParticle; - emitter.makeParticles(null, 50, false, 0); - emitter.start(false, 10, 0.05); - } -})(); diff --git a/Tests/demoscene/fruitfall.ts b/Tests/demoscene/fruitfall.ts deleted file mode 100644 index 19ed08b7..00000000 --- a/Tests/demoscene/fruitfall.ts +++ /dev/null @@ -1,50 +0,0 @@ -/// -/// -/// - -class fruitParticle extends Phaser.Particle { - - constructor(game:Phaser.Game) { - - super(game); - - var s = ['carrot', 'melon', 'eggplant', 'mushroom', 'pineapple']; - - this.texture.loadImage(game.math.getRandom(s)); - } - -} - -(function () { - - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - - var emitter: Phaser.Emitter; - - function init() { - - game.load.image('carrot', '../assets/sprites/carrot.png'); - game.load.image('melon', '../assets/sprites/melon.png'); - game.load.image('eggplant', '../assets/sprites/eggplant.png'); - game.load.image('mushroom', '../assets/sprites/mushroom.png'); - game.load.image('pineapple', '../assets/sprites/pineapple.png'); - - game.load.start(); - - } - - function create() { - - emitter = game.add.emitter(game.stage.centerX, 50); - emitter.gravity = 100; - - // Here we tell the emitter to use our customParticle class - // The customParticle needs to extend Particle and must take game:Game as the first constructor parameter, otherwise it's free as a bird - emitter.particleClass = fruitParticle; - - emitter.makeParticles(null, 50, false, 0); - emitter.start(false, 10, 0.05); - - } - -})(); diff --git a/Tests/demoscene/fujiboink.js b/Tests/demoscene/fujiboink.js deleted file mode 100644 index 3817e311..00000000 --- a/Tests/demoscene/fujiboink.js +++ /dev/null @@ -1,42 +0,0 @@ -/// -(function () { - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - function init() { - // Using Phasers asset loader we load up a PNG from the assets folder - game.load.image('fuji', '../assets/pics/atari_fujilogo.png'); - game.load.start(); - } - var fuji; - 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); - game.add.tween(fuji).to({ - angle: 360 - }, 2000, Phaser.Easing.Linear.None, true, 0, true); - tweenUp = game.add.tween(fuji.scale); - tweenUp.onComplete.add(scaleDown, this); - tweenDown = game.add.tween(fuji.scale); - tweenDown.onComplete.add(scaleUp, this); - scaleUp(); - } - 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/demoscene/fujiboink.ts b/Tests/demoscene/fujiboink.ts deleted file mode 100644 index 7f8ec442..00000000 --- a/Tests/demoscene/fujiboink.ts +++ /dev/null @@ -1,56 +0,0 @@ -/// - -(function () { - - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - - function init() { - - // Using Phasers asset loader we load up a PNG from the assets folder - game.load.image('fuji', '../assets/pics/atari_fujilogo.png'); - game.load.start(); - - } - - var fuji: Phaser.Sprite; - 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); - - game.add.tween(fuji).to({ angle: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); - - tweenUp = game.add.tween(fuji.scale); - tweenUp.onComplete.add(scaleDown, this); - - tweenDown = game.add.tween(fuji.scale); - tweenDown.onComplete.add(scaleUp, this); - - scaleUp(); - - } - - 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/demoscene/index.html b/Tests/demoscene/index.html deleted file mode 100644 index f36772f0..00000000 --- a/Tests/demoscene/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - Phaser does DemoScene - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Tests/demoscene/metalslug.js b/Tests/demoscene/metalslug.js deleted file mode 100644 index 09d42f06..00000000 --- a/Tests/demoscene/metalslug.js +++ /dev/null @@ -1,22 +0,0 @@ -/// -(function () { - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - function init() { - // Using Phasers asset loader we load up a PNG from the assets folder - game.load.spritesheet('monster', '../assets/sprites/metalslug_monster39x40.png', 39, 40); - game.load.start(); - } - 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(100, 50, '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(3, 3); - } -})(); diff --git a/Tests/demoscene/metalslug.ts b/Tests/demoscene/metalslug.ts deleted file mode 100644 index 020973ca..00000000 --- a/Tests/demoscene/metalslug.ts +++ /dev/null @@ -1,36 +0,0 @@ -/// - -(function () { - - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - - function init() { - - // Using Phasers asset loader we load up a PNG from the assets folder - game.load.spritesheet('monster', '../assets/sprites/metalslug_monster39x40.png', 39, 40); - game.load.start(); - - } - - 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(100, 50, '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(3, 3); - - } - -})(); diff --git a/Tests/demoscene/scroller1.js b/Tests/demoscene/scroller1.js deleted file mode 100644 index d43079cd..00000000 --- a/Tests/demoscene/scroller1.js +++ /dev/null @@ -1,12 +0,0 @@ -/// -/// -(function () { - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - function init() { - game.load.image('crystal', '../assets/pics/jim_sachs_time_crystal.png'); - game.load.start(); - } - function create() { - game.add.scrollZone('crystal').setSpeed(4, 2); - } -})(); diff --git a/Tests/demoscene/scroller1.ts b/Tests/demoscene/scroller1.ts deleted file mode 100644 index 6bf30f32..00000000 --- a/Tests/demoscene/scroller1.ts +++ /dev/null @@ -1,21 +0,0 @@ -/// -/// - -(function () { - - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - - function init() { - - game.load.image('crystal', '../assets/pics/jim_sachs_time_crystal.png'); - game.load.start(); - - } - - function create() { - - game.add.scrollZone('crystal').setSpeed(4, 2); - - } - -})(); diff --git a/Tests/demoscene/starray.js b/Tests/demoscene/starray.js deleted file mode 100644 index 44c4601a..00000000 --- a/Tests/demoscene/starray.js +++ /dev/null @@ -1,31 +0,0 @@ -/// -/// -(function () { - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - function init() { - game.load.image('starray', '../assets/pics/auto_scroll_landscape.png'); - game.load.start(); - } - function create() { - var zone = game.add.scrollZone('starray'); - // Hide the default region (the full image) - zone.currentRegion.visible = false; - var y = 0; - var speed = 16; - // The image consists of 10px high scrolling layers, this creates them quickly (top = fastest, getting slower as we move down) - for(var z = 0; z < 32; z++) { - zone.addRegion(0, y, 640, 10, speed); - if(z <= 15) { - speed -= 1; - } else { - speed += 1; - } - if(z == 15) { - y = 240; - speed += 1; - } else { - y += 10; - } - } - } -})(); diff --git a/Tests/demoscene/starray.ts b/Tests/demoscene/starray.ts deleted file mode 100644 index dc61ab98..00000000 --- a/Tests/demoscene/starray.ts +++ /dev/null @@ -1,53 +0,0 @@ -/// -/// - -(function () { - - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - - function init() { - - game.load.image('starray', '../assets/pics/auto_scroll_landscape.png'); - - game.load.start(); - - } - - function create() { - - var zone: Phaser.ScrollZone = game.add.scrollZone('starray'); - - // Hide the default region (the full image) - zone.currentRegion.visible = false; - - var y:number = 0; - var speed:number = 16; - - // The image consists of 10px high scrolling layers, this creates them quickly (top = fastest, getting slower as we move down) - for (var z:number = 0; z < 32; z++) - { - zone.addRegion(0, y, 640, 10, speed); - - if (z <= 15) - { - speed -= 1; - } - else - { - speed += 1; - } - - if (z == 15) - { - y = 240; - speed += 1; - } - else - { - y += 10; - } - } - - } - -})(); diff --git a/Tests/input/bring to top.js b/Tests/input/bring to top.js new file mode 100644 index 00000000..4052a34f --- /dev/null +++ b/Tests/input/bring to top.js @@ -0,0 +1,28 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create, null, render); + function init() { + game.load.image('atari1', 'assets/sprites/atari130xe.png'); + game.load.image('atari2', 'assets/sprites/atari800xl.png'); + game.load.image('atari4', 'assets/sprites/atari800.png'); + game.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png'); + game.load.image('duck', 'assets/sprites/darkwing_crazy.png'); + game.load.image('firstaid', 'assets/sprites/firstaid.png'); + game.load.image('diamond', 'assets/sprites/diamond.png'); + game.load.image('mushroom', 'assets/sprites/mushroom2.png'); + game.load.start(); + } + function create() { + // This returns an array of all the image keys in the cache + var images = game.cache.getImageKeys(); + // Now let's create some random sprites and enable them all for drag and 'bring to top' + for(var i = 0; i < 20; i++) { + var tempSprite = game.add.sprite(game.stage.randomX, game.stage.randomY, game.rnd.pick(images)); + tempSprite.input.start(i, false, true); + tempSprite.input.enableDrag(false, true); + } + } + function render() { + game.input.renderDebugInfo(32, 32); + } +})(); diff --git a/Tests/input/bring to top.ts b/Tests/input/bring to top.ts new file mode 100644 index 00000000..4c647472 --- /dev/null +++ b/Tests/input/bring to top.ts @@ -0,0 +1,40 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create, null, render); + + function init() { + + game.load.image('atari1', 'assets/sprites/atari130xe.png'); + game.load.image('atari2', 'assets/sprites/atari800xl.png'); + game.load.image('atari4', 'assets/sprites/atari800.png'); + game.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png'); + game.load.image('duck', 'assets/sprites/darkwing_crazy.png'); + game.load.image('firstaid', 'assets/sprites/firstaid.png'); + game.load.image('diamond', 'assets/sprites/diamond.png'); + game.load.image('mushroom', 'assets/sprites/mushroom2.png'); + game.load.start(); + + } + + function create() { + + // This returns an array of all the image keys in the cache + var images = game.cache.getImageKeys() + + // Now let's create some random sprites and enable them all for drag and 'bring to top' + for (var i = 0; i < 20; i++) + { + var tempSprite: Phaser.Sprite = game.add.sprite(game.stage.randomX, game.stage.randomY, game.rnd.pick(images)); + tempSprite.input.start(i, false, true); + tempSprite.input.enableDrag(false, true); + } + + } + + function render() { + game.input.renderDebugInfo(32, 32); + } + +})(); diff --git a/Tests/input/rotated sprites.js b/Tests/input/rotated sprites.js new file mode 100644 index 00000000..48d927e6 --- /dev/null +++ b/Tests/input/rotated sprites.js @@ -0,0 +1,33 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create, null, render); + function init() { + // Using Phasers asset loader we load up a PNG from the assets folder + game.load.image('atari1', 'assets/sprites/atari130xe.png'); + game.load.image('atari2', 'assets/sprites/atari800xl.png'); + game.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png'); + game.load.start(); + } + var atari1; + var atari2; + var sonic; + function create() { + atari1 = game.add.sprite(200, 200, 'atari1'); + atari2 = game.add.sprite(500, 400, 'atari2'); + sonic = game.add.sprite(400, 500, 'sonic'); + atari1.origin.setTo(0.5, 0.5); + atari1.rotation = 35; + atari2.origin.setTo(1, 1); + atari2.rotation = 80; + sonic.rotation = 140; + atari1.input.start(0, false, true); + atari2.input.start(1, false, true); + sonic.input.start(2, false, true); + atari1.input.enableDrag(); + atari2.input.enableDrag(); + sonic.input.enableDrag(); + } + function render() { + game.input.renderDebugInfo(32, 32); + } +})(); diff --git a/Tests/input/rotated sprites.ts b/Tests/input/rotated sprites.ts new file mode 100644 index 00000000..d965dbe8 --- /dev/null +++ b/Tests/input/rotated sprites.ts @@ -0,0 +1,49 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create, null, render); + + function init() { + + // Using Phasers asset loader we load up a PNG from the assets folder + game.load.image('atari1', 'assets/sprites/atari130xe.png'); + game.load.image('atari2', 'assets/sprites/atari800xl.png'); + game.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png'); + game.load.start(); + + } + + var atari1: Phaser.Sprite; + var atari2: Phaser.Sprite; + var sonic: Phaser.Sprite; + + function create() { + + atari1 = game.add.sprite(200, 200, 'atari1'); + atari2 = game.add.sprite(500, 400, 'atari2'); + sonic = game.add.sprite(400, 500, 'sonic'); + + atari1.origin.setTo(0.5, 0.5); + atari1.rotation = 35; + + atari2.origin.setTo(1, 1); + atari2.rotation = 80; + + sonic.rotation = 140; + + atari1.input.start(0, false, true); + atari2.input.start(1, false, true); + sonic.input.start(2, false, true); + + atari1.input.enableDrag(); + atari2.input.enableDrag(); + sonic.input.enableDrag(); + + } + + function render() { + game.input.renderDebugInfo(32, 32); + } + +})(); diff --git a/Tests/phaser.js b/Tests/phaser.js index 5895e09e..6826f466 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -3310,10 +3310,15 @@ var Phaser; * The PriorityID controls which Sprite receives an Input event first if they should overlap. */ this.priorityID = 0; + /** + * The index of this Input component entry in the Game.Input manager. + */ + this.indexID = 0; this.isDragged = false; this.dragPixelPerfect = false; this.allowHorizontalDrag = true; this.allowVerticalDrag = true; + this.bringToTop = false; this.snapOnDrag = false; this.snapOnRelease = false; this.snapX = 0; @@ -3497,14 +3502,25 @@ var Phaser; } else { // De-register, etc this.enabled = false; - this.game.input.removeGameObject(this.sprite); + this.game.input.removeGameObject(this.indexID); } }; - Input.prototype.checkPointerOver = function (pointer) { + Input.prototype.destroy = /** + * Clean up memory. + */ + function () { + if(this.enabled) { + this.game.input.removeGameObject(this.indexID); + } + }; + Input.prototype.checkPointerOver = /** + * Checks if the given pointer is over this Sprite. All checks are done in world coordinates. + */ + function (pointer) { if(this.enabled == false || this.sprite.visible == false) { return false; } else { - return Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY()); + return Phaser.SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY()); } }; Input.prototype.update = /** @@ -3517,7 +3533,7 @@ var Phaser; if(this.draggable && this._draggedPointerID == pointer.id) { return this.updateDrag(pointer); } else if(this._pointerData[pointer.id].isOver == true) { - if(Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY())) { + if(Phaser.SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY())) { this._pointerData[pointer.id].x = pointer.x - this.sprite.x; this._pointerData[pointer.id].y = pointer.y - this.sprite.y; return true; @@ -3561,6 +3577,9 @@ var Phaser; if(this.draggable && this.isDragged == false) { this.startDrag(pointer); } + if(this.bringToTop) { + this.sprite.group.bringToTop(this.sprite); + } } // Consume the event? return this.consumePointerEvent; @@ -3674,19 +3693,22 @@ var Phaser; * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback * * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. + * @param bringToTop If true the Sprite will be bought to the top of the rendering list in its current Group. * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here */ - function (lockCenter, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) { + function (lockCenter, bringToTop, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) { if (typeof lockCenter === "undefined") { lockCenter = false; } + if (typeof bringToTop === "undefined") { bringToTop = false; } if (typeof pixelPerfect === "undefined") { pixelPerfect = false; } if (typeof alphaThreshold === "undefined") { alphaThreshold = 255; } if (typeof boundsRect === "undefined") { boundsRect = null; } if (typeof boundsSprite === "undefined") { boundsSprite = null; } this._dragPoint = new Phaser.Point(); this.draggable = true; + this.bringToTop = bringToTop; this.dragOffset = new Phaser.Point(); this.dragFromCenter = lockCenter; this.dragPixelPerfect = pixelPerfect; @@ -3725,6 +3747,9 @@ var Phaser; this._dragPoint.setTo(this.sprite.x - pointer.x, this.sprite.y - pointer.y); } this.updateDrag(pointer); + if(this.bringToTop) { + this.sprite.group.bringToTop(this.sprite); + } }; Input.prototype.stopDrag = /** * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. @@ -4450,7 +4475,6 @@ var Phaser; this.y = y; this.z = -1; this.group = null; - // No dependencies this.animations = new Phaser.Components.AnimationManager(this); this.input = new Phaser.Components.Sprite.Input(this); this.events = new Phaser.Components.Sprite.Events(this); @@ -4472,6 +4496,10 @@ var Phaser; this.worldView = new Phaser.Rectangle(x, y, this.width, this.height); this.cameraView = new Phaser.Rectangle(x, y, this.width, this.height); this.transform.setCache(); + // Handy proxies + this.scale = this.transform.scale; + this.alpha = this.texture.alpha; + this.origin = this.transform.origin; } Object.defineProperty(Sprite.prototype, "rotation", { get: /** @@ -4608,8 +4636,8 @@ var Phaser; * Clean up memory. */ function () { - //this.input.destroy(); - }; + this.input.destroy(); + }; Sprite.prototype.kill = /** * Handy for "killing" game objects. * Default behavior is to flag them as nonexistent AND dead. @@ -4750,62 +4778,6 @@ var Phaser; this.getScreenXY(this._point, camera); - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && - (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); - } - */ - /** - * Checks to see if this GameObject were located at the given position, would it overlap the GameObject or Group? - * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size into account. - * WARNING: Currently tilemaps do NOT support screen space overlap checks! - * - * @param X {number} The X position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param Y {number} The Y position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param objectOrGroup {object} The object or group being tested. - * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {boolean} Whether or not the two objects overlap. - */ - /* - static overlapsAt(X: number, Y: number, objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { - - if (objectOrGroup.isGroup) - { - var results: bool = false; - var basic; - var i: number = 0; - var members = objectOrGroup.members; - - while (i < length) - { - if (this.overlapsAt(X, Y, members[i++], inScreenSpace, camera)) - { - results = true; - } - } - - return results; - } - - if (!inScreenSpace) - { - return (objectOrGroup.x + objectOrGroup.width > X) && (objectOrGroup.x < X + this.width) && - (objectOrGroup.y + objectOrGroup.height > Y) && (objectOrGroup.y < Y + this.height); - } - - if (camera == null) - { - camera = this._game.camera; - } - - var objectScreenPos: Point = objectOrGroup.getScreenXY(null, Camera); - - this._point.x = X - camera.scroll.x * this.transform.scrollFactor.x; //copied from getScreenXY() - this._point.y = Y - camera.scroll.y * this.transform.scrollFactor.y; - this._point.x += (this._point.x > 0) ? 0.0000001 : -0.0000001; - this._point.y += (this._point.y > 0) ? 0.0000001 : -0.0000001; - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); } @@ -4825,52 +4797,32 @@ var Phaser; if(sprite.transform.rotation == 0) { return Phaser.RectangleUtils.contains(sprite.cameraView, x, y); } - //var ex: number = sprite.transform.upperRight.x - sprite.transform.upperLeft.x; - //var ey: number = sprite.transform.upperRight.y - sprite.transform.upperLeft.y; - //var fx: number = sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x; - //var fy: number = sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y; - //if ((x-ax)*ex+(y-ay)*ey<0.0) return false; if((x - sprite.transform.upperLeft.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) < 0) { return false; } - //if ((x-bx)*ex+(y-by)*ey>0.0) return false; if((x - sprite.transform.upperRight.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperRight.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) > 0) { return false; } - //if ((x-ax)*fx+(y-ay)*fy<0.0) return false; if((x - sprite.transform.upperLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) < 0) { return false; } - //if ((x-dx)*fx+(y-dy)*fy>0.0) return false; if((x - sprite.transform.bottomLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.bottomLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) > 0) { return false; } return true; }; SpriteUtils.overlapsPoint = /** - * Checks to see if a point in 2D world space overlaps this GameObject. + * Checks to see if the given point overlaps this Sprite, taking scaling and rotation into account. + * The point must be given in world space, not local or camera space. * + * @param sprite {Sprite} The Sprite to check. It will take scaling and rotation into account. * @param point {Point} The point in world space you want to check. - * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. * * @return Whether or not the point overlaps this object. */ - function overlapsPoint(sprite, point, inScreenSpace, camera) { - if (typeof inScreenSpace === "undefined") { inScreenSpace = false; } - if (typeof camera === "undefined") { camera = null; } - if(!inScreenSpace) { - return Phaser.RectangleUtils.containsPoint(sprite.body.bounds, point); - //return (point.x > sprite.x) && (point.x < sprite.x + sprite.width) && (point.y > sprite.y) && (point.y < sprite.y + sprite.height); - } - if(camera == null) { - camera = sprite.game.camera; - } - //var x: number = point.x - camera.scroll.x; - //var y: number = point.y - camera.scroll.y; - //this.getScreenXY(this._point, camera); - //return (x > this._point.x) && (X < this._point.x + this.width) && (Y > this._point.y) && (Y < this._point.y + this.height); - }; + function overlapsPoint(sprite, point) { + return SpriteUtils.overlapsXY(sprite, point.x, point.y); + }; SpriteUtils.onScreen = /** * Check and see if this object is currently on screen. * @@ -4940,15 +4892,6 @@ var Phaser; sprite.body.position.x = x; sprite.body.position.y = y; }; - SpriteUtils.setOriginToCenter = function setOriginToCenter(sprite, fromFrameBounds, fromBody) { - if (typeof fromFrameBounds === "undefined") { fromFrameBounds = true; } - if (typeof fromBody === "undefined") { fromBody = false; } - if(fromFrameBounds) { - sprite.transform.origin.setTo(sprite.width / 2, sprite.height / 2); - } else if(fromBody) { - sprite.transform.origin.setTo(sprite.body.bounds.halfWidth, sprite.body.bounds.halfHeight); - } - }; SpriteUtils.setBounds = /** * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) @@ -5535,7 +5478,15 @@ var Phaser; this.members[this._i] = newObject; return newObject; }; - Group.prototype.swap = function (child1, child2, sort) { + Group.prototype.swap = /** + * Swaps two existing game object in this Group with each other. + * + * @param {Basic} child1 The first object to swap. + * @param {Basic} child2 The second object to swap. + * + * @return {Basic} True if the two objects successfully swapped position. + */ + function (child1, child2, sort) { if (typeof sort === "undefined") { sort = true; } if(child1.group.ID != this.ID || child2.group.ID != this.ID || child1 === child2) { return false; @@ -5548,6 +5499,28 @@ var Phaser; } return true; }; + Group.prototype.bringToTop = function (child) { + // If child not in this group, or is already at the top of the group, return false + if(child.group.ID != this.ID || child.z == this._zCounter) { + return false; + } + this.sort(); + // What's the z index of the top most child? + var tempZ = child.z; + var childIndex = this._zCounter; + this._i = 0; + while(this._i < this.length) { + this._member = this.members[this._i++]; + if(this._i > childIndex) { + this._member.z--; + } else if(this._member.z == child.z) { + childIndex = this._i; + this._member.z = this._zCounter; + } + } + this.sort(); + return true; + }; Group.prototype.sort = /** * Call this function to sort the group according to a particular value and order. * For example, to sort game objects for Zelda-style overlaps you might call @@ -6832,6 +6805,13 @@ var Phaser; } return null; }; + Cache.prototype.getImageKeys = function () { + var output = []; + for(var item in this._images) { + output.push(item); + } + return output; + }; Cache.prototype.destroy = /** * Clean up cache memory. */ @@ -14951,7 +14931,7 @@ var Phaser; var _highestRenderID = -1; var _highestRenderObject = -1; for(var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if(this.game.input.inputObjects[i].input.checkPointerOver(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) { + if(this.game.input.inputObjects[i] !== null && this.game.input.inputObjects[i].input.checkPointerOver(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) { _highestRenderID = this.game.input.inputObjects[i].renderOrderID; _highestRenderObject = i; } @@ -15010,7 +14990,7 @@ var Phaser; this.game.input.currentPointers--; } for(var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if(this.game.input.inputObjects[i].input.enabled) { + if(this.game.input.inputObjects[i] !== null && this.game.input.inputObjects[i].input.enabled) { this.game.input.inputObjects[i].input._releasedHandler(this); } } @@ -16055,16 +16035,34 @@ var Phaser; this.gestures.start(); this.mousePointer.active = true; }; - Input.prototype.addGameObject = // Add Input Enabled array + add/remove methods and then iterate and update them during the main update - // Clear down this array on State swap??? Maybe removed from it when Sprite is destroyed + Input.prototype.addGameObject = /** + * Adds a new game object to be tracked by the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method addGameObject + **/ function (object) { - // Lots more checks here + // Find a spare slot + for(var i = 0; i < this.inputObjects.length; i++) { + if(this.inputObjects[i] == null) { + this.inputObjects[i] = object; + object.input.indexID = i; + this.totalTrackedObjects++; + return; + } + } + // If we got this far we need to push a new entry into the array + object.input.indexID = this.inputObjects.length; this.inputObjects.push(object); this.totalTrackedObjects++; }; - Input.prototype.removeGameObject = function (object) { - // TODO - }; + Input.prototype.removeGameObject = /** + * Removes a game object from the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method removeGameObject + **/ + function (index) { + if(this.inputObjects[index]) { + this.inputObjects[index] = null; + } + }; Input.prototype.update = /** * Updates the Input Manager. Called by the core Game loop. * @method update diff --git a/Tests/scrollzones/blasteroids.js b/Tests/scrollzones/blasteroids.js index 474a7023..580e2761 100644 --- a/Tests/scrollzones/blasteroids.js +++ b/Tests/scrollzones/blasteroids.js @@ -36,7 +36,7 @@ bullets.add(tempBullet); } ship = game.add.sprite(game.stage.centerX, game.stage.centerY, 'nashwan', Phaser.Types.BODY_DYNAMIC); - Phaser.SpriteUtils.setOriginToCenter(ship); + ship.transform.origin.setTo(0.5, 0.5); // We do this because the ship was drawn facing up, but 0 degrees is pointing to the right ship.transform.rotationOffset = 90; game.input.onDown.add(test, this); diff --git a/Tests/scrollzones/blasteroids.ts b/Tests/scrollzones/blasteroids.ts index 2877fed1..84bad9e4 100644 --- a/Tests/scrollzones/blasteroids.ts +++ b/Tests/scrollzones/blasteroids.ts @@ -53,7 +53,7 @@ } ship = game.add.sprite(game.stage.centerX, game.stage.centerY, 'nashwan', Phaser.Types.BODY_DYNAMIC); - Phaser.SpriteUtils.setOriginToCenter(ship); + ship.transform.origin.setTo(0.5, 0.5); // We do this because the ship was drawn facing up, but 0 degrees is pointing to the right ship.transform.rotationOffset = 90; diff --git a/Tests/sprites/scale sprite 1.js b/Tests/sprites/scale sprite 1.js index 33b0e381..5cec160e 100644 --- a/Tests/sprites/scale sprite 1.js +++ b/Tests/sprites/scale sprite 1.js @@ -12,9 +12,9 @@ smallBunny = game.add.sprite(0, 0, 'bunny'); // And now let's scale the sprite by half // You can do either: - // smallBunny.transform.scale.x = 0.5; - // smallBunny.transform.scale.y = 0.5; + //smallBunny.scale.x = 0.5; + //smallBunny.scale.y = 0.5; // Or you can set them both at the same time using setTo: - smallBunny.transform.scale.setTo(0.5, 0.5); + smallBunny.scale.setTo(0.5, 0.5); } })(); diff --git a/Tests/sprites/scale sprite 1.ts b/Tests/sprites/scale sprite 1.ts index bc04c51e..3c182607 100644 --- a/Tests/sprites/scale sprite 1.ts +++ b/Tests/sprites/scale sprite 1.ts @@ -22,11 +22,11 @@ // And now let's scale the sprite by half // You can do either: - // smallBunny.transform.scale.x = 0.5; - // smallBunny.transform.scale.y = 0.5; + //smallBunny.scale.x = 0.5; + //smallBunny.scale.y = 0.5; // Or you can set them both at the same time using setTo: - smallBunny.transform.scale.setTo(0.5, 0.5); + smallBunny.scale.setTo(0.5, 0.5); } diff --git a/Tests/sprites/sprite origin 3.js b/Tests/sprites/sprite origin 3.js index 907f6a1b..20ea3979 100644 --- a/Tests/sprites/sprite origin 3.js +++ b/Tests/sprites/sprite origin 3.js @@ -14,7 +14,7 @@ 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 be the bottom-right of the sprite - fuji.transform.origin.setTo(320, 200); + fuji.origin.setTo(320, 200); game.add.tween(fuji).to({ rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); diff --git a/Tests/sprites/sprite origin 3.ts b/Tests/sprites/sprite origin 3.ts index ba966bff..c61f1a3a 100644 --- a/Tests/sprites/sprite origin 3.ts +++ b/Tests/sprites/sprite origin 3.ts @@ -24,7 +24,7 @@ // The sprite is 320 x 200 pixels in size // Here we set the origin to be the bottom-right of the sprite - fuji.transform.origin.setTo(320, 200); + fuji.origin.setTo(320, 200); game.add.tween(fuji).to({ rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); diff --git a/build/phaser.d.ts b/build/phaser.d.ts index 768901fe..8584ca5c 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -2039,6 +2039,10 @@ module Phaser.Components.Sprite { * The PriorityID controls which Sprite receives an Input event first if they should overlap. */ public priorityID: number; + /** + * The index of this Input component entry in the Game.Input manager. + */ + public indexID: number; private _dragPoint; private _draggedPointerID; public dragOffset: Point; @@ -2048,6 +2052,7 @@ module Phaser.Components.Sprite { public dragPixelPerfectAlpha: number; public allowHorizontalDrag: bool; public allowVerticalDrag: bool; + public bringToTop: bool; public snapOnDrag: bool; public snapOnRelease: bool; public snapOffset: Point; @@ -2148,6 +2153,13 @@ module Phaser.Components.Sprite { public start(priority?: number, checkBody?: bool, useHandCursor?: bool): Sprite; public reset(): void; public stop(): void; + /** + * Clean up memory. + */ + public destroy(): void; + /** + * Checks if the given pointer is over this Sprite. All checks are done in world coordinates. + */ public checkPointerOver(pointer: Pointer): bool; /** * Update @@ -2200,12 +2212,13 @@ module Phaser.Components.Sprite { * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback * * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. + * @param bringToTop If true the Sprite will be bought to the top of the rendering list in its current Group. * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here */ - public enableDrag(lockCenter?: bool, pixelPerfect?: bool, alphaThreshold?: number, boundsRect?: Rectangle, boundsSprite?: Sprite): void; + public enableDrag(lockCenter?: bool, bringToTop?: bool, pixelPerfect?: bool, alphaThreshold?: number, boundsRect?: Rectangle, boundsSprite?: Sprite): void; /** * Stops this sprite from being able to be dragged. If it is currently the target of an active drag it will be stopped immediately. Also disables any set callbacks. */ @@ -2670,6 +2683,20 @@ module Phaser { */ public rotation : number; /** + * The scale of the Sprite. A value of 1 is original scale. 0.5 is half size. 2 is double the size. + * This is a reference to Sprite.transform.scale + */ + public scale: Vec2; + /** + * The alpha of the Sprite between 0 and 1, a value of 1 being fully opaque. + */ + public alpha: number; + /** + * The origin of the Sprite around which rotation and positioning takes place. + * This is a reference to Sprite.transform.origin + */ + public origin: Vec2; + /** * Get the animation frame number. */ /** @@ -2746,15 +2773,15 @@ module Phaser { */ static overlapsXY(sprite: Sprite, x: number, y: number): bool; /** - * Checks to see if a point in 2D world space overlaps this GameObject. + * Checks to see if the given point overlaps this Sprite, taking scaling and rotation into account. + * The point must be given in world space, not local or camera space. * + * @param sprite {Sprite} The Sprite to check. It will take scaling and rotation into account. * @param point {Point} The point in world space you want to check. - * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. * * @return Whether or not the point overlaps this object. */ - static overlapsPoint(sprite: Sprite, point: Point, inScreenSpace?: bool, camera?: Camera): bool; + static overlapsPoint(sprite: Sprite, point: Point): bool; /** * Check and see if this object is currently on screen. * @@ -2780,7 +2807,6 @@ module Phaser { * @param y {number} The new Y position of this object. */ static reset(sprite: Sprite, x: number, y: number): void; - static setOriginToCenter(sprite: Sprite, fromFrameBounds?: bool, fromBody?: bool): void; /** * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) @@ -3139,7 +3165,16 @@ module Phaser { * @return {Basic} The new object. */ public replace(oldObject, newObject); + /** + * Swaps two existing game object in this Group with each other. + * + * @param {Basic} child1 The first object to swap. + * @param {Basic} child2 The second object to swap. + * + * @return {Basic} True if the two objects successfully swapped position. + */ public swap(child1, child2, sort?: bool): bool; + public bringToTop(child): bool; /** * Call this function to sort the group according to a particular value and order. * For example, to sort game objects for Zelda-style overlaps you might call @@ -3797,6 +3832,7 @@ module Phaser { * @return {object} The text data you want. */ public getText(key: string); + public getImageKeys(): any[]; /** * Clean up cache memory. */ @@ -8656,8 +8692,16 @@ module Phaser { public boot(): void; public inputObjects: any[]; public totalTrackedObjects: number; + /** + * Adds a new game object to be tracked by the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method addGameObject + **/ public addGameObject(object): void; - public removeGameObject(object): void; + /** + * Removes a game object from the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method removeGameObject + **/ + public removeGameObject(index: number): void; /** * Updates the Input Manager. Called by the core Game loop. * @method update diff --git a/build/phaser.js b/build/phaser.js index 5895e09e..6826f466 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -3310,10 +3310,15 @@ var Phaser; * The PriorityID controls which Sprite receives an Input event first if they should overlap. */ this.priorityID = 0; + /** + * The index of this Input component entry in the Game.Input manager. + */ + this.indexID = 0; this.isDragged = false; this.dragPixelPerfect = false; this.allowHorizontalDrag = true; this.allowVerticalDrag = true; + this.bringToTop = false; this.snapOnDrag = false; this.snapOnRelease = false; this.snapX = 0; @@ -3497,14 +3502,25 @@ var Phaser; } else { // De-register, etc this.enabled = false; - this.game.input.removeGameObject(this.sprite); + this.game.input.removeGameObject(this.indexID); } }; - Input.prototype.checkPointerOver = function (pointer) { + Input.prototype.destroy = /** + * Clean up memory. + */ + function () { + if(this.enabled) { + this.game.input.removeGameObject(this.indexID); + } + }; + Input.prototype.checkPointerOver = /** + * Checks if the given pointer is over this Sprite. All checks are done in world coordinates. + */ + function (pointer) { if(this.enabled == false || this.sprite.visible == false) { return false; } else { - return Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY()); + return Phaser.SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY()); } }; Input.prototype.update = /** @@ -3517,7 +3533,7 @@ var Phaser; if(this.draggable && this._draggedPointerID == pointer.id) { return this.updateDrag(pointer); } else if(this._pointerData[pointer.id].isOver == true) { - if(Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY())) { + if(Phaser.SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY())) { this._pointerData[pointer.id].x = pointer.x - this.sprite.x; this._pointerData[pointer.id].y = pointer.y - this.sprite.y; return true; @@ -3561,6 +3577,9 @@ var Phaser; if(this.draggable && this.isDragged == false) { this.startDrag(pointer); } + if(this.bringToTop) { + this.sprite.group.bringToTop(this.sprite); + } } // Consume the event? return this.consumePointerEvent; @@ -3674,19 +3693,22 @@ var Phaser; * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback * * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. + * @param bringToTop If true the Sprite will be bought to the top of the rendering list in its current Group. * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here */ - function (lockCenter, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) { + function (lockCenter, bringToTop, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) { if (typeof lockCenter === "undefined") { lockCenter = false; } + if (typeof bringToTop === "undefined") { bringToTop = false; } if (typeof pixelPerfect === "undefined") { pixelPerfect = false; } if (typeof alphaThreshold === "undefined") { alphaThreshold = 255; } if (typeof boundsRect === "undefined") { boundsRect = null; } if (typeof boundsSprite === "undefined") { boundsSprite = null; } this._dragPoint = new Phaser.Point(); this.draggable = true; + this.bringToTop = bringToTop; this.dragOffset = new Phaser.Point(); this.dragFromCenter = lockCenter; this.dragPixelPerfect = pixelPerfect; @@ -3725,6 +3747,9 @@ var Phaser; this._dragPoint.setTo(this.sprite.x - pointer.x, this.sprite.y - pointer.y); } this.updateDrag(pointer); + if(this.bringToTop) { + this.sprite.group.bringToTop(this.sprite); + } }; Input.prototype.stopDrag = /** * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. @@ -4450,7 +4475,6 @@ var Phaser; this.y = y; this.z = -1; this.group = null; - // No dependencies this.animations = new Phaser.Components.AnimationManager(this); this.input = new Phaser.Components.Sprite.Input(this); this.events = new Phaser.Components.Sprite.Events(this); @@ -4472,6 +4496,10 @@ var Phaser; this.worldView = new Phaser.Rectangle(x, y, this.width, this.height); this.cameraView = new Phaser.Rectangle(x, y, this.width, this.height); this.transform.setCache(); + // Handy proxies + this.scale = this.transform.scale; + this.alpha = this.texture.alpha; + this.origin = this.transform.origin; } Object.defineProperty(Sprite.prototype, "rotation", { get: /** @@ -4608,8 +4636,8 @@ var Phaser; * Clean up memory. */ function () { - //this.input.destroy(); - }; + this.input.destroy(); + }; Sprite.prototype.kill = /** * Handy for "killing" game objects. * Default behavior is to flag them as nonexistent AND dead. @@ -4750,62 +4778,6 @@ var Phaser; this.getScreenXY(this._point, camera); - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && - (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); - } - */ - /** - * Checks to see if this GameObject were located at the given position, would it overlap the GameObject or Group? - * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size into account. - * WARNING: Currently tilemaps do NOT support screen space overlap checks! - * - * @param X {number} The X position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param Y {number} The Y position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param objectOrGroup {object} The object or group being tested. - * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {boolean} Whether or not the two objects overlap. - */ - /* - static overlapsAt(X: number, Y: number, objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { - - if (objectOrGroup.isGroup) - { - var results: bool = false; - var basic; - var i: number = 0; - var members = objectOrGroup.members; - - while (i < length) - { - if (this.overlapsAt(X, Y, members[i++], inScreenSpace, camera)) - { - results = true; - } - } - - return results; - } - - if (!inScreenSpace) - { - return (objectOrGroup.x + objectOrGroup.width > X) && (objectOrGroup.x < X + this.width) && - (objectOrGroup.y + objectOrGroup.height > Y) && (objectOrGroup.y < Y + this.height); - } - - if (camera == null) - { - camera = this._game.camera; - } - - var objectScreenPos: Point = objectOrGroup.getScreenXY(null, Camera); - - this._point.x = X - camera.scroll.x * this.transform.scrollFactor.x; //copied from getScreenXY() - this._point.y = Y - camera.scroll.y * this.transform.scrollFactor.y; - this._point.x += (this._point.x > 0) ? 0.0000001 : -0.0000001; - this._point.y += (this._point.y > 0) ? 0.0000001 : -0.0000001; - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); } @@ -4825,52 +4797,32 @@ var Phaser; if(sprite.transform.rotation == 0) { return Phaser.RectangleUtils.contains(sprite.cameraView, x, y); } - //var ex: number = sprite.transform.upperRight.x - sprite.transform.upperLeft.x; - //var ey: number = sprite.transform.upperRight.y - sprite.transform.upperLeft.y; - //var fx: number = sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x; - //var fy: number = sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y; - //if ((x-ax)*ex+(y-ay)*ey<0.0) return false; if((x - sprite.transform.upperLeft.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) < 0) { return false; } - //if ((x-bx)*ex+(y-by)*ey>0.0) return false; if((x - sprite.transform.upperRight.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperRight.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) > 0) { return false; } - //if ((x-ax)*fx+(y-ay)*fy<0.0) return false; if((x - sprite.transform.upperLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) < 0) { return false; } - //if ((x-dx)*fx+(y-dy)*fy>0.0) return false; if((x - sprite.transform.bottomLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.bottomLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) > 0) { return false; } return true; }; SpriteUtils.overlapsPoint = /** - * Checks to see if a point in 2D world space overlaps this GameObject. + * Checks to see if the given point overlaps this Sprite, taking scaling and rotation into account. + * The point must be given in world space, not local or camera space. * + * @param sprite {Sprite} The Sprite to check. It will take scaling and rotation into account. * @param point {Point} The point in world space you want to check. - * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. * * @return Whether or not the point overlaps this object. */ - function overlapsPoint(sprite, point, inScreenSpace, camera) { - if (typeof inScreenSpace === "undefined") { inScreenSpace = false; } - if (typeof camera === "undefined") { camera = null; } - if(!inScreenSpace) { - return Phaser.RectangleUtils.containsPoint(sprite.body.bounds, point); - //return (point.x > sprite.x) && (point.x < sprite.x + sprite.width) && (point.y > sprite.y) && (point.y < sprite.y + sprite.height); - } - if(camera == null) { - camera = sprite.game.camera; - } - //var x: number = point.x - camera.scroll.x; - //var y: number = point.y - camera.scroll.y; - //this.getScreenXY(this._point, camera); - //return (x > this._point.x) && (X < this._point.x + this.width) && (Y > this._point.y) && (Y < this._point.y + this.height); - }; + function overlapsPoint(sprite, point) { + return SpriteUtils.overlapsXY(sprite, point.x, point.y); + }; SpriteUtils.onScreen = /** * Check and see if this object is currently on screen. * @@ -4940,15 +4892,6 @@ var Phaser; sprite.body.position.x = x; sprite.body.position.y = y; }; - SpriteUtils.setOriginToCenter = function setOriginToCenter(sprite, fromFrameBounds, fromBody) { - if (typeof fromFrameBounds === "undefined") { fromFrameBounds = true; } - if (typeof fromBody === "undefined") { fromBody = false; } - if(fromFrameBounds) { - sprite.transform.origin.setTo(sprite.width / 2, sprite.height / 2); - } else if(fromBody) { - sprite.transform.origin.setTo(sprite.body.bounds.halfWidth, sprite.body.bounds.halfHeight); - } - }; SpriteUtils.setBounds = /** * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) @@ -5535,7 +5478,15 @@ var Phaser; this.members[this._i] = newObject; return newObject; }; - Group.prototype.swap = function (child1, child2, sort) { + Group.prototype.swap = /** + * Swaps two existing game object in this Group with each other. + * + * @param {Basic} child1 The first object to swap. + * @param {Basic} child2 The second object to swap. + * + * @return {Basic} True if the two objects successfully swapped position. + */ + function (child1, child2, sort) { if (typeof sort === "undefined") { sort = true; } if(child1.group.ID != this.ID || child2.group.ID != this.ID || child1 === child2) { return false; @@ -5548,6 +5499,28 @@ var Phaser; } return true; }; + Group.prototype.bringToTop = function (child) { + // If child not in this group, or is already at the top of the group, return false + if(child.group.ID != this.ID || child.z == this._zCounter) { + return false; + } + this.sort(); + // What's the z index of the top most child? + var tempZ = child.z; + var childIndex = this._zCounter; + this._i = 0; + while(this._i < this.length) { + this._member = this.members[this._i++]; + if(this._i > childIndex) { + this._member.z--; + } else if(this._member.z == child.z) { + childIndex = this._i; + this._member.z = this._zCounter; + } + } + this.sort(); + return true; + }; Group.prototype.sort = /** * Call this function to sort the group according to a particular value and order. * For example, to sort game objects for Zelda-style overlaps you might call @@ -6832,6 +6805,13 @@ var Phaser; } return null; }; + Cache.prototype.getImageKeys = function () { + var output = []; + for(var item in this._images) { + output.push(item); + } + return output; + }; Cache.prototype.destroy = /** * Clean up cache memory. */ @@ -14951,7 +14931,7 @@ var Phaser; var _highestRenderID = -1; var _highestRenderObject = -1; for(var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if(this.game.input.inputObjects[i].input.checkPointerOver(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) { + if(this.game.input.inputObjects[i] !== null && this.game.input.inputObjects[i].input.checkPointerOver(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) { _highestRenderID = this.game.input.inputObjects[i].renderOrderID; _highestRenderObject = i; } @@ -15010,7 +14990,7 @@ var Phaser; this.game.input.currentPointers--; } for(var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if(this.game.input.inputObjects[i].input.enabled) { + if(this.game.input.inputObjects[i] !== null && this.game.input.inputObjects[i].input.enabled) { this.game.input.inputObjects[i].input._releasedHandler(this); } } @@ -16055,16 +16035,34 @@ var Phaser; this.gestures.start(); this.mousePointer.active = true; }; - Input.prototype.addGameObject = // Add Input Enabled array + add/remove methods and then iterate and update them during the main update - // Clear down this array on State swap??? Maybe removed from it when Sprite is destroyed + Input.prototype.addGameObject = /** + * Adds a new game object to be tracked by the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method addGameObject + **/ function (object) { - // Lots more checks here + // Find a spare slot + for(var i = 0; i < this.inputObjects.length; i++) { + if(this.inputObjects[i] == null) { + this.inputObjects[i] = object; + object.input.indexID = i; + this.totalTrackedObjects++; + return; + } + } + // If we got this far we need to push a new entry into the array + object.input.indexID = this.inputObjects.length; this.inputObjects.push(object); this.totalTrackedObjects++; }; - Input.prototype.removeGameObject = function (object) { - // TODO - }; + Input.prototype.removeGameObject = /** + * Removes a game object from the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method removeGameObject + **/ + function (index) { + if(this.inputObjects[index]) { + this.inputObjects[index] = null; + } + }; Input.prototype.update = /** * Updates the Input Manager. Called by the core Game loop. * @method update