From 526067f7b6a5120f67b55f1d8c531c80cb0ed538 Mon Sep 17 00:00:00 2001 From: Stuart Lindstrom Date: Tue, 9 Oct 2018 14:34:47 -0400 Subject: [PATCH 001/221] Fix #4104 --- src/tilemaps/dynamiclayer/DynamicTilemapLayerWebGLRenderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tilemaps/dynamiclayer/DynamicTilemapLayerWebGLRenderer.js b/src/tilemaps/dynamiclayer/DynamicTilemapLayerWebGLRenderer.js index 21d8b6cab..7e7358c5f 100644 --- a/src/tilemaps/dynamiclayer/DynamicTilemapLayerWebGLRenderer.js +++ b/src/tilemaps/dynamiclayer/DynamicTilemapLayerWebGLRenderer.js @@ -90,7 +90,7 @@ var DynamicTilemapLayerWebGLRenderer = function (renderer, src, interpolationPer src, texture, texture.width, texture.height, - (tw + x + tile.pixelX) * sx, (th + y + tile.pixelY) * sy, + x + ((tw + tile.pixelX) * sx), y + ((th + tile.pixelY) * sy), tile.width, tile.height, sx, sy, tile.rotation, From 0e10d50bd8cfde7d27611f0f54aafba50e33d9bf Mon Sep 17 00:00:00 2001 From: samme Date: Sat, 27 Oct 2018 10:30:52 -0700 Subject: [PATCH 002/221] Revise descriptions for BaseCamera centerX, centerY --- src/cameras/2d/BaseCamera.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cameras/2d/BaseCamera.js b/src/cameras/2d/BaseCamera.js index 7134714c5..78ba5f84f 100644 --- a/src/cameras/2d/BaseCamera.js +++ b/src/cameras/2d/BaseCamera.js @@ -1701,7 +1701,7 @@ var BaseCamera = new Class({ }, /** - * The x position of the center of the Camera's viewport, relative to the top-left of the game canvas. + * The horizontal position of the center of the Camera's viewport, relative to the left of the game canvas. * * @name Phaser.Cameras.Scene2D.BaseCamera#centerX * @type {number} @@ -1718,7 +1718,7 @@ var BaseCamera = new Class({ }, /** - * The y position of the center of the Camera's viewport, relative to the top-left of the game canvas. + * The vertical position of the center of the Camera's viewport, relative to the top of the game canvas. * * @name Phaser.Cameras.Scene2D.BaseCamera#centerY * @type {number} From 03ffe7842f2b7f6a57fd3b7b929192662d0698af Mon Sep 17 00:00:00 2001 From: Sercan Turkmen Date: Wed, 31 Oct 2018 02:03:34 +0200 Subject: [PATCH 003/221] Fix rotating normal map bug (issue #3870) --- .../pipelines/ForwardDiffuseLightPipeline.js | 38 +++++++++++++++++++ .../webgl/shaders/ForwardDiffuse-frag.js | 3 +- .../webgl/shaders/src/ForwardDiffuse.frag | 3 +- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js b/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js index 1545eea0e..7bc268840 100644 --- a/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js +++ b/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js @@ -48,6 +48,15 @@ var ForwardDiffuseLightPipeline = new Class({ * @since 3.11.0 */ this.defaultNormalMap; + + /** + * Inverse rotation matrix for normal map rotation fixing. + */ + this.inverseRotationMatrix = new Float32Array([ + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + ]); }, /** @@ -244,6 +253,7 @@ var ForwardDiffuseLightPipeline = new Class({ } this.setTexture2D(normalTexture.glTexture, 1); + this.setNormalMapRotation(rotation); var camMatrix = this._tempMatrix1; var spriteMatrix = this._tempMatrix2; @@ -412,6 +422,33 @@ var ForwardDiffuseLightPipeline = new Class({ this.renderer.setPipeline(gameObject.defaultPipeline); }, + /** + * Rotates the normal map vectors inversely by the given angle. + * Only works in 2D space. + * @param {number} rotation rotation in angles + */ + setNormalMapRotation: function (rotation) + { + var inverseRotationMatrix = this.inverseRotationMatrix; + if (rotation) + { + var rot = -rotation; + var c = Math.cos(rot); + var s = Math.sin(rot); + + inverseRotationMatrix[1] = s; + inverseRotationMatrix[3] = -s; + inverseRotationMatrix[0] = inverseRotationMatrix[4] = c; + } + else + { + inverseRotationMatrix[0] = inverseRotationMatrix[4] = 1; + inverseRotationMatrix[1] = inverseRotationMatrix[3] = 0; + } + + this.renderer.setMatrix3(this.program, 'uInverseRotationMatrix', false, inverseRotationMatrix); + }, + /** * Takes a Sprite Game Object, or any object that extends it, which has a normal texture and adds it to the batch. * @@ -437,6 +474,7 @@ var ForwardDiffuseLightPipeline = new Class({ this.renderer.setPipeline(this); this.setTexture2D(normalTexture.glTexture, 1); + this.setNormalMapRotation(sprite.rotation); TextureTintPipeline.prototype.batchSprite.call(this, sprite, camera, parentTransformMatrix); } diff --git a/src/renderer/webgl/shaders/ForwardDiffuse-frag.js b/src/renderer/webgl/shaders/ForwardDiffuse-frag.js index 36fb4bfb4..ec391f178 100644 --- a/src/renderer/webgl/shaders/ForwardDiffuse-frag.js +++ b/src/renderer/webgl/shaders/ForwardDiffuse-frag.js @@ -19,6 +19,7 @@ module.exports = [ 'uniform sampler2D uNormSampler;', 'uniform vec3 uAmbientLightColor;', 'uniform Light uLights[kMaxLights];', + 'uniform mat3 uInverseRotationMatrix;', '', 'varying vec2 outTexCoord;', 'varying vec4 outTint;', @@ -28,7 +29,7 @@ module.exports = [ ' vec3 finalColor = vec3(0.0, 0.0, 0.0);', ' vec4 color = texture2D(uMainSampler, outTexCoord) * vec4(outTint.rgb * outTint.a, outTint.a);', ' vec3 normalMap = texture2D(uNormSampler, outTexCoord).rgb;', - ' vec3 normal = normalize(vec3(normalMap * 2.0 - 1.0));', + ' vec3 normal = normalize(uInverseRotationMatrix * vec3(normalMap * 2.0 - 1.0));', ' vec2 res = vec2(min(uResolution.x, uResolution.y)) * uCamera.w;', '', ' for (int index = 0; index < kMaxLights; ++index)', diff --git a/src/renderer/webgl/shaders/src/ForwardDiffuse.frag b/src/renderer/webgl/shaders/src/ForwardDiffuse.frag index bc737f9a4..eecef7c0e 100644 --- a/src/renderer/webgl/shaders/src/ForwardDiffuse.frag +++ b/src/renderer/webgl/shaders/src/ForwardDiffuse.frag @@ -18,6 +18,7 @@ uniform sampler2D uMainSampler; uniform sampler2D uNormSampler; uniform vec3 uAmbientLightColor; uniform Light uLights[kMaxLights]; +uniform mat3 uInverseRotationMatrix; varying vec2 outTexCoord; varying vec4 outTint; @@ -27,7 +28,7 @@ void main() vec3 finalColor = vec3(0.0, 0.0, 0.0); vec4 color = texture2D(uMainSampler, outTexCoord) * vec4(outTint.rgb * outTint.a, outTint.a); vec3 normalMap = texture2D(uNormSampler, outTexCoord).rgb; - vec3 normal = normalize(vec3(normalMap * 2.0 - 1.0)); + vec3 normal = normalize(uInverseRotationMatrix * vec3(normalMap * 2.0 - 1.0)); vec2 res = vec2(min(uResolution.x, uResolution.y)) * uCamera.w; for (int index = 0; index < kMaxLights; ++index) From a01726f57e56fe14a90599910f69f3be43c3bae9 Mon Sep 17 00:00:00 2001 From: kainage Date: Tue, 6 Nov 2018 06:38:36 -0800 Subject: [PATCH 004/221] Fix Scene Add Data Data was not being passed in to the scene manager when adding a scene via `add`. --- src/scene/ScenePlugin.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/scene/ScenePlugin.js b/src/scene/ScenePlugin.js index c33b7963c..6414c97eb 100644 --- a/src/scene/ScenePlugin.js +++ b/src/scene/ScenePlugin.js @@ -210,7 +210,7 @@ var ScenePlugin = new Class({ * * @method Phaser.Scenes.ScenePlugin#restart * @since 3.4.0 - * + * * @param {object} [data] - The Scene data. * * @return {Phaser.Scenes.ScenePlugin} This ScenePlugin object. @@ -227,7 +227,7 @@ var ScenePlugin = new Class({ /** * @typedef {object} Phaser.Scenes.ScenePlugin.SceneTransitionConfig - * + * * @property {string} target - The Scene key to transition to. * @property {integer} [duration=1000] - The duration, in ms, for the transition to last. * @property {boolean} [sleep=false] - Will the Scene responsible for the transition be sent to sleep on completion (`true`), or stopped? (`false`) @@ -241,24 +241,24 @@ var ScenePlugin = new Class({ /** * This will start a transition from the current Scene to the target Scene given. - * + * * The transition will last for the duration specified in milliseconds. - * + * * You can have the target Scene moved above or below this one in the display list. - * + * * You can specify an update callback. This callback will be invoked _every frame_ for the duration * of the transition. * * This Scene can either be sent to sleep at the end of the transition, or stopped. The default is to stop. - * + * * There are also 5 transition related events: This scene will emit the event `transitionto` when * the transition begins, which is typically the frame after calling this method. - * + * * The target Scene will emit the event `transitioninit` when that Scene's `init` method is called. * It will then emit the event `transitionstart` when its `create` method is called. * If the Scene was sleeping and has been woken up, it will emit the event `transitionwake` instead of these two, * as the Scenes `init` and `create` methods are not invoked when a Scene wakes up. - * + * * When the duration of the transition has elapsed it will emit the event `transitioncomplete`. * These events are cleared of all listeners when the Scene shuts down, but not if it is sent to sleep. * @@ -268,7 +268,7 @@ var ScenePlugin = new Class({ * this Scenes update loop to stop, then the transition will also pause for that duration. There are * checks in place to prevent you accidentally stopping a transitioning Scene but if you've got code to * override this understand that until the target Scene completes it might never be unlocked for input events. - * + * * @method Phaser.Scenes.ScenePlugin#transition * @since 3.5.0 * @@ -443,12 +443,13 @@ var ScenePlugin = new Class({ * @param {string} key - The Scene key. * @param {(Phaser.Scene|Phaser.Scenes.Settings.Config|function)} sceneConfig - The config for the Scene. * @param {boolean} autoStart - Whether to start the Scene after it's added. + * @param {object} [data] - The Scene data. * * @return {Phaser.Scenes.ScenePlugin} This ScenePlugin object. */ - add: function (key, sceneConfig, autoStart) + add: function (key, sceneConfig, autoStart, data) { - this.manager.add(key, sceneConfig, autoStart); + this.manager.add(key, sceneConfig, autoStart, data); return this; }, @@ -476,7 +477,7 @@ var ScenePlugin = new Class({ /** * Runs the given Scene, but does not change the state of this Scene. - * + * * If the given Scene is paused, it will resume it. If sleeping, it will wake it. * If not running at all, it will be started. * From 83e2de2bafb6ed0661bd9f5c2d6084d42267a7ec Mon Sep 17 00:00:00 2001 From: samme Date: Wed, 7 Nov 2018 09:40:31 -0800 Subject: [PATCH 005/221] Docs for Group Add GroupClassTypeConstructor type --- src/gameobjects/group/Group.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/gameobjects/group/Group.js b/src/gameobjects/group/Group.js index ab5663f6d..57f2ebc05 100644 --- a/src/gameobjects/group/Group.js +++ b/src/gameobjects/group/Group.js @@ -28,7 +28,7 @@ var Sprite = require('../sprite/Sprite'); /** * @typedef {object} GroupConfig * - * @property {?object} [classType=Sprite] - Sets {@link Phaser.GameObjects.Group#classType}. + * @property {?GroupClassTypeConstructor} [classType=Sprite] - Sets {@link Phaser.GameObjects.Group#classType}. * @property {?boolean} [active=true] - Sets {@link Phaser.GameObjects.Group#active}. * @property {?number} [maxSize=-1] - Sets {@link Phaser.GameObjects.Group#maxSize}. * @property {?string} [defaultKey=null] - Sets {@link Phaser.GameObjects.Group#defaultKey}. @@ -52,7 +52,7 @@ var Sprite = require('../sprite/Sprite'); * * `key` is required. {@link Phaser.GameObjects.Group#defaultKey} is not used. * - * @property {?object} [classType] - The class of each new Game Object. + * @property {?GroupClassTypeConstructor} [classType] - The class of each new Game Object. * @property {string} [key] - The texture key of each new Game Object. * @property {?(string|integer)} [frame=null] - The texture frame of each new Game Object. * @property {?boolean} [visible=true] - The visible state of each new Game Object. @@ -93,6 +93,18 @@ var Sprite = require('../sprite/Sprite'); * @see Phaser.Utils.Array.Range */ +/** + * A constructor function (class) that can be assigned to `classType`. + * @callback GroupClassTypeConstructor + * @param {Phaser.Scene} scene - The Scene to which this Game Object belongs. A Game Object can only belong to one Scene at a time. + * @param {number} x - The horizontal position of this Game Object in the world. + * @param {number} y - The vertical position of this Game Object in the world. + * @param {string} texture - The key of the Texture this Game Object will use to render with, as stored in the Texture Manager. + * @param {(string|integer)} [frame] - An optional frame from the Texture this Game Object is rendering with. + * + * @see Phaser.GameObjects.Group#classType + */ + /** * @classdesc A Group is a way for you to create, manipulate, or recycle similar Game Objects. * @@ -185,7 +197,7 @@ var Group = new Class({ * The class to create new group members from. * * @name Phaser.GameObjects.Group#classType - * @type {object} + * @type {GroupClassTypeConstructor} * @since 3.0.0 * @default Phaser.GameObjects.Sprite */ From b5a2d9d0cf71c9e6b63053a2d554c747eb49dd53 Mon Sep 17 00:00:00 2001 From: samme Date: Wed, 7 Nov 2018 09:43:43 -0800 Subject: [PATCH 006/221] Docs for Arcade Physics Minor additions/corrections --- src/physics/arcade/ArcadeImage.js | 8 +++----- src/physics/arcade/ArcadeSprite.js | 12 ++++-------- src/physics/arcade/Body.js | 8 +++++--- src/physics/arcade/Collider.js | 2 +- src/physics/arcade/Factory.js | 4 ++-- src/physics/arcade/PhysicsGroup.js | 2 +- src/physics/arcade/StaticBody.js | 19 ++++++++++++------- src/physics/arcade/StaticPhysicsGroup.js | 2 +- src/physics/arcade/World.js | 10 +++++----- 9 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/physics/arcade/ArcadeImage.js b/src/physics/arcade/ArcadeImage.js index 310eb9dfc..13e7ae587 100644 --- a/src/physics/arcade/ArcadeImage.js +++ b/src/physics/arcade/ArcadeImage.js @@ -10,12 +10,10 @@ var Image = require('../../gameobjects/image/Image'); /** * @classdesc - * An Arcade Physics Image Game Object. + * An Arcade Physics Image is an Image with an Arcade Physics body and related components. + * The body can be dynamic or static. * - * An Image is a light-weight Game Object useful for the display of static images in your game, - * such as logos, backgrounds, scenery or other non-animated elements. Images can have input - * events and physics bodies, or be tweened, tinted or scrolled. The main difference between an - * Image and a Sprite is that you cannot animate an Image as they do not have the Animation component. + * The main difference between an Arcade Image and an Arcade Sprite is that you cannot animate an Arcade Image. * * @class Image * @extends Phaser.GameObjects.Image diff --git a/src/physics/arcade/ArcadeSprite.js b/src/physics/arcade/ArcadeSprite.js index bddb664fe..cd5954ae6 100644 --- a/src/physics/arcade/ArcadeSprite.js +++ b/src/physics/arcade/ArcadeSprite.js @@ -10,15 +10,11 @@ var Sprite = require('../../gameobjects/sprite/Sprite'); /** * @classdesc - * An Arcade Physics Sprite Game Object. + * An Arcade Physics Sprite is a Sprite with an Arcade Physics body and related components. + * The body can be dynamic or static. * - * A Sprite Game Object is used for the display of both static and animated images in your game. - * Sprites can have input events and physics bodies. They can also be tweened, tinted, scrolled - * and animated. - * - * The main difference between a Sprite and an Image Game Object is that you cannot animate Images. - * As such, Sprites take a fraction longer to process and have a larger API footprint due to the Animation - * Component. If you do not require animation then you can safely use Images to replace Sprites in all cases. + * The main difference between an Arcade Sprite and an Arcade Image is that you cannot animate an Arcade Image. + * If you do not require animation then you can safely use Arcade Images instead of Arcade Sprites. * * @class Sprite * @extends Phaser.GameObjects.Sprite diff --git a/src/physics/arcade/Body.js b/src/physics/arcade/Body.js index 5c2cf6545..f61ba0ddb 100644 --- a/src/physics/arcade/Body.js +++ b/src/physics/arcade/Body.js @@ -623,7 +623,7 @@ var Body = new Class({ this.overlapR = 0; /** - * Whether this Body is overlapped with another and both have zero velocity. + * Whether this Body is overlapped with another and both are not moving. * * @name Phaser.Physics.Arcade.Body#embedded * @type {boolean} @@ -718,6 +718,7 @@ var Body = new Class({ * @name Phaser.Physics.Arcade.Body#physicsType * @type {integer} * @readonly + * @default Phaser.Physics.Arcade.DYNAMIC_BODY * @since 3.0.0 */ this.physicsType = CONST.DYNAMIC_BODY; @@ -787,7 +788,8 @@ var Body = new Class({ }, /** - * Updates this Body's transform, dimensions, and position from its Game Object. + * Updates the Body's `transform`, `width`, `height`, and `center` from its Game Object. + * The Body's `position` isn't changed. * * @method Phaser.Physics.Arcade.Body#updateBounds * @since 3.0.0 @@ -874,7 +876,7 @@ var Body = new Class({ * @fires Phaser.Physics.Arcade.World#worldbounds * @since 3.0.0 * - * @param {number} delta - The delta time, in ms, elapsed since the last frame. + * @param {number} delta - The delta time, in seconds, elapsed since the last frame. */ update: function (delta) { diff --git a/src/physics/arcade/Collider.js b/src/physics/arcade/Collider.js index 22f05239e..5a35ecbc7 100644 --- a/src/physics/arcade/Collider.js +++ b/src/physics/arcade/Collider.js @@ -40,7 +40,7 @@ var Collider = new Class({ this.world = world; /** - * The name of the collider (unused by phaser). + * The name of the collider (unused by Phaser). * * @name Phaser.Physics.Arcade.Collider#name * @type {string} diff --git a/src/physics/arcade/Factory.js b/src/physics/arcade/Factory.js index b93b6e433..ac87f1005 100644 --- a/src/physics/arcade/Factory.js +++ b/src/physics/arcade/Factory.js @@ -58,7 +58,7 @@ var Factory = new Class({ }, /** - * Create a new Arcade Physics Collider object. + * Creates a new Arcade Physics Collider object. * * @method Phaser.Physics.Arcade.Factory#collider * @since 3.0.0 @@ -77,7 +77,7 @@ var Factory = new Class({ }, /** - * Create a new Arcade Physics Collider Overlap object. + * Creates a new Arcade Physics Collider Overlap object. * * @method Phaser.Physics.Arcade.Factory#overlap * @since 3.0.0 diff --git a/src/physics/arcade/PhysicsGroup.js b/src/physics/arcade/PhysicsGroup.js index 14556f439..a83f1e8e0 100644 --- a/src/physics/arcade/PhysicsGroup.js +++ b/src/physics/arcade/PhysicsGroup.js @@ -154,7 +154,7 @@ var PhysicsGroup = new Class({ * * @name Phaser.Physics.Arcade.Group#physicsType * @type {integer} - * @default DYNAMIC_BODY + * @default Phaser.Physics.Arcade.DYNAMIC_BODY * @since 3.0.0 */ this.physicsType = CONST.DYNAMIC_BODY; diff --git a/src/physics/arcade/StaticBody.js b/src/physics/arcade/StaticBody.js index 9cff64ab5..5205748f3 100644 --- a/src/physics/arcade/StaticBody.js +++ b/src/physics/arcade/StaticBody.js @@ -219,10 +219,12 @@ var StaticBody = new Class({ // If true this Body will dispatch events /** - * Whether the simulation emits a `worldbounds` event when this StaticBody collides with the world boundary (and `collideWorldBounds` is also true). + * Whether the simulation emits a `worldbounds` event when this StaticBody collides with the world boundary. + * Always false for a Static Body. (Static Bodies never collide with the world boundary and never trigger a `worldbounds` event.) * * @name Phaser.Physics.Arcade.StaticBody#onWorldBounds * @type {boolean} + * @readonly * @default false * @since 3.0.0 */ @@ -269,7 +271,7 @@ var StaticBody = new Class({ this.immovable = true; /** - * A flag disabling the default horizontal separation of colliding bodies. Pass your own `processHandler` to the collider. + * A flag disabling the default horizontal separation of colliding bodies. Pass your own `collideHandler` to the collider. * * @name Phaser.Physics.Arcade.StaticBody#customSeparateX * @type {boolean} @@ -279,7 +281,7 @@ var StaticBody = new Class({ this.customSeparateX = false; /** - * A flag disabling the default vertical separation of colliding bodies. Pass your own `processHandler` to the collider. + * A flag disabling the default vertical separation of colliding bodies. Pass your own `collideHandler` to the collider. * * @name Phaser.Physics.Arcade.StaticBody#customSeparateY * @type {boolean} @@ -319,7 +321,7 @@ var StaticBody = new Class({ this.overlapR = 0; /** - * Whether this StaticBody is overlapped with another and both have zero velocity. + * Whether this StaticBody has ever overlapped with another while both were not moving. * * @name Phaser.Physics.Arcade.StaticBody#embedded * @type {boolean} @@ -330,9 +332,11 @@ var StaticBody = new Class({ /** * Whether this StaticBody interacts with the world boundary. + * Always false for a Static Body. (Static Bodies never collide with the world boundary.) * * @name Phaser.Physics.Arcade.StaticBody#collideWorldBounds * @type {boolean} + * @readonly * @default false * @since 3.0.0 */ @@ -348,7 +352,7 @@ var StaticBody = new Class({ this.checkCollision = { none: false, up: true, down: true, left: true, right: true }; /** - * Whether this StaticBody is colliding with another and in which direction. + * Whether this StaticBody has ever collided with another body and in which direction. * * @name Phaser.Physics.Arcade.StaticBody#touching * @type {ArcadeBodyCollision} @@ -357,7 +361,7 @@ var StaticBody = new Class({ this.touching = { none: true, up: false, down: false, left: false, right: false }; /** - * Whether this StaticBody was colliding with another during the last step, and in which direction. + * Whether this StaticBody was colliding with another body during the last step or any previous step, and in which direction. * * @name Phaser.Physics.Arcade.StaticBody#wasTouching * @type {ArcadeBodyCollision} @@ -366,7 +370,7 @@ var StaticBody = new Class({ this.wasTouching = { none: true, up: false, down: false, left: false, right: false }; /** - * Whether this StaticBody is colliding with a tile or the world boundary. + * Whether this StaticBody has ever collided with a tile or the world boundary. * * @name Phaser.Physics.Arcade.StaticBody#blocked * @type {ArcadeBodyCollision} @@ -379,6 +383,7 @@ var StaticBody = new Class({ * * @name Phaser.Physics.Arcade.StaticBody#physicsType * @type {integer} + * @default Phaser.Physics.Arcade.STATIC_BODY * @since 3.0.0 */ this.physicsType = CONST.STATIC_BODY; diff --git a/src/physics/arcade/StaticPhysicsGroup.js b/src/physics/arcade/StaticPhysicsGroup.js index 4e240337f..796efa125 100644 --- a/src/physics/arcade/StaticPhysicsGroup.js +++ b/src/physics/arcade/StaticPhysicsGroup.js @@ -86,7 +86,7 @@ var StaticPhysicsGroup = new Class({ * * @name Phaser.Physics.Arcade.StaticGroup#physicsType * @type {integer} - * @default STATIC_BODY + * @default Phaser.Physics.Arcade.STATIC_BODY * @since 3.0.0 */ this.physicsType = CONST.STATIC_BODY; diff --git a/src/physics/arcade/World.js b/src/physics/arcade/World.js index 51d73049a..b8d58c429 100644 --- a/src/physics/arcade/World.js +++ b/src/physics/arcade/World.js @@ -1046,12 +1046,12 @@ var World = new Class({ }, /** - * Advances the simulation by one step. + * Advances the simulation by a time increment. * * @method Phaser.Physics.Arcade.World#step * @since 3.10.0 * - * @param {number} delta - The delta time amount, in ms, by which to advance the simulation. + * @param {number} delta - The delta time amount, in seconds, by which to advance the simulation. */ step: function (delta) { @@ -1190,7 +1190,7 @@ var World = new Class({ * @since 3.0.0 * * @param {Phaser.Physics.Arcade.Body} body - The Body to be updated. - * @param {number} delta - The delta value to be used in the motion calculations. + * @param {number} delta - The delta value to be used in the motion calculations, in seconds. */ updateMotion: function (body, delta) { @@ -1209,7 +1209,7 @@ var World = new Class({ * @since 3.10.0 * * @param {Phaser.Physics.Arcade.Body} body - The Body to compute the velocity for. - * @param {number} delta - The delta value to be used in the calculation. + * @param {number} delta - The delta value to be used in the calculation, in seconds. */ computeAngularVelocity: function (body, delta) { @@ -1255,7 +1255,7 @@ var World = new Class({ * @since 3.0.0 * * @param {Phaser.Physics.Arcade.Body} body - The Body to compute the velocity for. - * @param {number} delta - The delta value to be used in the calculation. + * @param {number} delta - The delta value to be used in the calculation, in seconds. */ computeVelocity: function (body, delta) { From 361708a22b6729f2312bc4ce4c8e82d64a9e252f Mon Sep 17 00:00:00 2001 From: Piotr 'Waclaw I' Hanusiak Date: Wed, 7 Nov 2018 19:08:48 +0100 Subject: [PATCH 007/221] Setting HTML5AudioSound's volume and mute is now working. --- src/sound/html5/HTML5AudioSound.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sound/html5/HTML5AudioSound.js b/src/sound/html5/HTML5AudioSound.js index 9f8317f8d..344317584 100644 --- a/src/sound/html5/HTML5AudioSound.js +++ b/src/sound/html5/HTML5AudioSound.js @@ -634,6 +634,7 @@ var HTML5AudioSound = new Class({ { return; } + this.updateMute(); this.emit('mute', this, value); } @@ -686,6 +687,7 @@ var HTML5AudioSound = new Class({ { return; } + this.updateVolume(); this.emit('volume', this, value); } From e5ebfe861ffb59912244f4e958f617e4a3c4fd08 Mon Sep 17 00:00:00 2001 From: Ram Kaniyur Date: Thu, 8 Nov 2018 21:27:16 +1100 Subject: [PATCH 008/221] Fix Tile.tileset to return just the containing tileset instead of all of them. --- src/tilemaps/Tile.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/tilemaps/Tile.js b/src/tilemaps/Tile.js index 28bdb1631..c6714daba 100644 --- a/src/tilemaps/Tile.js +++ b/src/tilemaps/Tile.js @@ -761,8 +761,9 @@ var Tile = new Class({ }, /** - * The tileset that contains this Tile. This will only return null if accessed from a LayerData - * instance before the tile is placed within a StaticTilemapLayer or DynamicTilemapLayer. + * The tileset that contains this Tile. This is null if accessed from a LayerData instance + * before the tile is placed in a StaticTilemapLayer or DynamicTilemapLayer, or if the tile has + * an index that doesn't correspond to any of the map's tilesets. * * @name Phaser.Tilemaps.Tile#tileset * @type {?Phaser.Tilemaps.Tileset} @@ -773,7 +774,12 @@ var Tile = new Class({ get: function () { var tilemapLayer = this.tilemapLayer; - return tilemapLayer ? tilemapLayer.tileset : null; + if (!tilemapLayer) return null; + + var tileset = tilemapLayer.gidMap[this.index]; + if (!tileset) return null; + + return tileset; } }, From 49e5e5c3a9f3b80c000d1723b7a64cb35b97a9b5 Mon Sep 17 00:00:00 2001 From: Rory O'Connell <19547+RoryO@users.noreply.github.com> Date: Sat, 10 Nov 2018 14:29:49 -0800 Subject: [PATCH 009/221] callbackScope is an optional param --- src/structs/Set.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structs/Set.js b/src/structs/Set.js index 2716d52fc..2c8a4656f 100644 --- a/src/structs/Set.js +++ b/src/structs/Set.js @@ -179,7 +179,7 @@ var Set = new Class({ * @genericUse {Phaser.Structs.Set.} - [$return] * * @param {EachSetCallback} callback - The callback to be invoked and passed each value this Set contains. - * @param {*} callbackScope - The scope of the callback. + * @param {*} [callbackScope] - The scope of the callback. * * @return {Phaser.Structs.Set} This Set object. */ @@ -224,7 +224,7 @@ var Set = new Class({ * @genericUse {Phaser.Structs.Set.} - [$return] * * @param {EachSetCallback} callback - The callback to be invoked and passed each value this Set contains. - * @param {*} callbackScope - The scope of the callback. + * @param {*} [callbackScope] - The scope of the callback. * * @return {Phaser.Structs.Set} This Set object. */ From 0557ee071b2dc8898c6b1e0e203cf04b8ff9f49e Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 12 Nov 2018 12:38:18 +0000 Subject: [PATCH 010/221] Updated setScore handling --- CHANGELOG.md | 8 ++++++- plugins/fbinstant/src/Leaderboard.js | 34 +++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9adacf16a..7a80b6a4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## Version 3.16.0 - Ishikawa - in development +### Facebook Instant Games Updates and Fixes + +* The `loadPlayerPhoto` function in the Instant Games plugin now listens for the updated Loader event correctly, causing the `photocomplete` event to fire properly. +* `Leaderboard.setScore` now emits the LeaderboardScore object with the `setscore` event, as the documentation said it did. +* `Leaderboard.getPlayerScore` now only populates the `playerScore` property if the entry isn't `null`. +* If the `setScore` or `getPlayerScore` calls fail, it will return `null` as the score instance, instead of causing a run-time error. + ### New Features * The data object being sent to the Dynamic Bitmap Text callback now has a new property `parent`, which is a reference to the Bitmap Text instance that owns the data object (thanks ornyth) @@ -29,7 +36,6 @@ ### Bug Fixes -* The `loadPlayerPhoto` function in the Instant Games plugin now listens for the updated Loader event correctly, causing the `photocomplete` event to fire properly. * The Rectangle Shape object wouldn't render if it didn't have a stroke, or any other objects on the display list (thanks mliko) * When using a font string instead of setting `fontFamily`, `fontSize` and `fontStyle` in either `Text.setStyle` or `setFont`, the style properties wouldn't get set. This isn't a problem while creating the text object, only if modifying it later (thanks @DotTheGreat) * Disabling camera bounds and then moving the camera to an area in a Tilemap that did not have any tile information would throw an `Uncaught Reference error` as it tried to access tiles that did not exist (thanks @Siyalatas) diff --git a/plugins/fbinstant/src/Leaderboard.js b/plugins/fbinstant/src/Leaderboard.js index ca0646091..93f9bf003 100644 --- a/plugins/fbinstant/src/Leaderboard.js +++ b/plugins/fbinstant/src/Leaderboard.js @@ -139,7 +139,9 @@ var Leaderboard = new Class({ * * The data is requested in an async call, so the result isn't available immediately. * - * When the call completes this Leaderboard will emit the `setscore` event along with the score, any extra data and the name of the Leaderboard. + * When the call completes this Leaderboard will emit the `setscore` event along with the LeaderboardScore object and the name of the Leaderboard. + * + * If the save fails the event will send `null` as the score value. * * @method Phaser.FacebookInstantGamesPlugin.Leaderboard#setScore * @since 3.13.0 @@ -157,7 +159,18 @@ var Leaderboard = new Class({ this.ref.setScoreAsync(score, data).then(function (entry) { - _this.emit('setscore', entry.getScore(), entry.getExtraData(), _this.name); + if (entry) + { + var score = LeaderboardScore(entry); + + _this.playerScore = score; + + _this.emit('setscore', score, _this.name); + } + else + { + _this.emit('setscore', null, _this.name); + } }).catch(function (e) { @@ -173,6 +186,8 @@ var Leaderboard = new Class({ * The data is requested in an async call, so the result isn't available immediately. * * When the call completes this Leaderboard will emit the `getplayerscore` event along with the score and the name of the Leaderboard. + * + * If the player has not yet saved a score, the event will send `null` as the score value, and `playerScore` will be set to `null` as well. * * @method Phaser.FacebookInstantGamesPlugin.Leaderboard#getPlayerScore * @since 3.13.0 @@ -185,11 +200,18 @@ var Leaderboard = new Class({ this.ref.getPlayerEntryAsync().then(function (entry) { - var score = LeaderboardScore(entry); + if (entry) + { + var score = LeaderboardScore(entry); - _this.playerScore = score; - - _this.emit('getplayerscore', score, _this.name); + _this.playerScore = score; + + _this.emit('getplayerscore', score, _this.name); + } + else + { + _this.emit('getplayerscore', null, _this.name); + } }).catch(function (e) { From 23cc8b84e35a0fd955e596704df6ccf6b8e4aebc Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 12 Nov 2018 17:15:00 +0000 Subject: [PATCH 011/221] Added getConnectedScores method --- CHANGELOG.md | 2 ++ plugins/fbinstant/src/Leaderboard.js | 50 ++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a80b6a4c..f39de3759 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,12 @@ ### Facebook Instant Games Updates and Fixes +* Added the `Leaderboard.getConnectedScores` method, to get a list of scores from player connected entries. * The `loadPlayerPhoto` function in the Instant Games plugin now listens for the updated Loader event correctly, causing the `photocomplete` event to fire properly. * `Leaderboard.setScore` now emits the LeaderboardScore object with the `setscore` event, as the documentation said it did. * `Leaderboard.getPlayerScore` now only populates the `playerScore` property if the entry isn't `null`. * If the `setScore` or `getPlayerScore` calls fail, it will return `null` as the score instance, instead of causing a run-time error. +* You can now pass an object or a string to `setScore` and objects will be automatically stringified. ### New Features diff --git a/plugins/fbinstant/src/Leaderboard.js b/plugins/fbinstant/src/Leaderboard.js index 93f9bf003..b20070766 100644 --- a/plugins/fbinstant/src/Leaderboard.js +++ b/plugins/fbinstant/src/Leaderboard.js @@ -147,7 +147,7 @@ var Leaderboard = new Class({ * @since 3.13.0 * * @param {integer} score - The new score for the player. Must be a 64-bit integer number. - * @param {string} [data] - Metadata to associate with the stored score. Must be less than 2KB in size. + * @param {(string|any)} [data] - Metadata to associate with the stored score. Must be less than 2KB in size. If an object is given it will be passed to `JSON.stringify`. * * @return {this} This Leaderboard instance. */ @@ -155,6 +155,11 @@ var Leaderboard = new Class({ { if (data === undefined) { data = ''; } + if (typeof data === 'object') + { + data = JSON.stringify(data); + } + var _this = this; this.ref.setScoreAsync(score, data).then(function (entry) @@ -226,7 +231,7 @@ var Leaderboard = new Class({ * * The data is requested in an async call, so the result isn't available immediately. * - * When the call completes this Leaderboard will emit the `getplayerscore` event along with the score and the name of the Leaderboard. + * When the call completes this Leaderboard will emit the `getscores` event along with an array of LeaderboardScore entries and the name of the Leaderboard. * * @method Phaser.FacebookInstantGamesPlugin.Leaderboard#getScores * @since 3.13.0 @@ -259,6 +264,47 @@ var Leaderboard = new Class({ console.warn(e); }); + return this; + }, + + /** + * Retrieves a set of leaderboard entries, based on the current player's connected players (including the current player), ordered by local rank within the set of connected players. + * + * The data is requested in an async call, so the result isn't available immediately. + * + * When the call completes this Leaderboard will emit the `getconnectedscores` event along with an array of LeaderboardScore entries and the name of the Leaderboard. + * + * @method Phaser.FacebookInstantGamesPlugin.Leaderboard#getConnectedScores + * @since 3.16.0 + * + * @param {integer} [count=10] - The number of entries to attempt to fetch from the leaderboard. Currently, up to a maximum of 100 entries may be fetched per query. + * @param {integer} [offset=0] - The offset from the top of the leaderboard that entries will be fetched from. + * + * @return {this} This Leaderboard instance. + */ + getConnectedScores: function (count, offset) + { + if (count === undefined) { count = 10; } + if (offset === undefined) { offset = 0; } + + var _this = this; + + this.ref.getConnectedPlayerEntriesAsync().then(function (entries) + { + _this.scores = []; + + entries.forEach(function (entry) + { + _this.scores.push(LeaderboardScore(entry)); + }); + + _this.emit('getconnectedscores', _this.scores, _this.name); + + }).catch(function (e) + { + console.warn(e); + }); + return this; } From 5f92b05fd7575ad01dc4ef79835e34007696e8d3 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 12 Nov 2018 22:22:12 +0000 Subject: [PATCH 012/221] Added game config keyboard capture flag for global preventDefault handling. --- CHANGELOG.md | 2 ++ src/boot/Config.js | 8 +++++++- src/input/keyboard/KeyboardPlugin.js | 21 +++++++++++++++++++-- src/input/keyboard/keys/ProcessKeyDown.js | 5 ----- src/input/keyboard/keys/ProcessKeyUp.js | 5 ----- 5 files changed, 28 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9adacf16a..0376d75f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ * The WebGL Renderer has a new method `clearPipeline`, which will clear down the current pipeline and reset the blend mode, ready for the context to be passed to a 3rd party library. * The WebGL Renderer has a new method `rebindPipeline`, which will rebind the given pipeline instance, reset the blank texture and reset the blend mode. Which is useful for recovering from 3rd party libs that have modified the gl context. * Game Objects have a new property called `state`. Use this to track the state of a Game Object during its lifetime. For example, it could move from a state of 'moving', to 'attacking', to 'dead'. Phaser itself will never set this property, although plugins are allowed to. +* The Keyboard Plugin will now call `preventDefault` on all key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create ` Key` object to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the config settings: +* There is a new Game Config setting `input.keyboard.capture` which allows you to set if the Keyboard Plugin will capture all key events or not. You can also set this in a Scene Config, in which case it will override the Game Config setting. ### Updates diff --git a/src/boot/Config.js b/src/boot/Config.js index fbfac092c..be05e10e7 100644 --- a/src/boot/Config.js +++ b/src/boot/Config.js @@ -56,13 +56,14 @@ var ValueToColor = require('../display/color/ValueToColor'); * @typedef {object} MouseInputConfig * * @property {*} [target=null] - Where the Mouse Manager listens for mouse input events. The default is the game canvas. - * @property {boolean} [capture=true] - Whether mouse input events have preventDefault() called on them. + * @property {boolean} [capture=true] - Whether mouse input events have `preventDefault` called on them. */ /** * @typedef {object} KeyboardInputConfig * * @property {*} [target=window] - Where the Keyboard Manager listens for keyboard input events. + * @property {boolean} [capture=true] - Whether keyboard input events have `preventDefault` called on them automatically. */ /** @@ -413,6 +414,11 @@ var Config = new Class({ */ this.inputKeyboardEventTarget = GetValue(config, 'input.keyboard.target', window); + /** + * @const {boolean} Phaser.Boot.Config#inputKeyboardCapture - Should `preventDefault` be called automatically on every key press (true), or let each Key object set it (false) + */ + this.inputKeyboardCapture = GetValue(config, 'input.keyboard.capture', true); + /** * @const {(boolean|object)} Phaser.Boot.Config#inputMouse - Enable the Mouse Plugin. This can be disabled in games that don't need mouse input. */ diff --git a/src/input/keyboard/KeyboardPlugin.js b/src/input/keyboard/KeyboardPlugin.js index 6fa665d9b..b431b20e2 100644 --- a/src/input/keyboard/KeyboardPlugin.js +++ b/src/input/keyboard/KeyboardPlugin.js @@ -163,6 +163,23 @@ var KeyboardPlugin = new Class({ */ this.time = 0; + /** + * A flag that controls if all keys pressed have `preventDefault` called on them or not. + * + * By default this is `true`. + * + * You can set this flag to stop any key from triggering the default browser action, or if you need + * more specific control, you can create Key objects and set the flag on each of those instead. + * + * This flag can be set in the Game Config by setting the `input.keyboard.capture` boolean, or you + * can set it in the Scene Config, in which case the Scene Config setting overrides the Game Config one. + * + * @name Phaser.Input.Keyboard.KeyboardPlugin#preventDefault + * @type {boolean} + * @since 3.16.0 + */ + this.preventDefault = true; + sceneInputPlugin.pluginEvents.once('boot', this.boot, this); sceneInputPlugin.pluginEvents.on('start', this.start, this); }, @@ -182,6 +199,7 @@ var KeyboardPlugin = new Class({ this.enabled = GetValue(settings, 'keyboard', config.inputKeyboard); this.target = GetValue(settings, 'keyboard.target', config.inputKeyboardEventTarget); + this.preventDefault = GetValue(settings, 'keyboard.capture', config.inputKeyboardCapture); this.sceneInputPlugin.pluginEvents.once('destroy', this.destroy, this); }, @@ -242,11 +260,10 @@ var KeyboardPlugin = new Class({ var key = _this.keys[event.keyCode]; - if (key && key.preventDefault) + if (_this.preventDefault || key && key.preventDefault) { event.preventDefault(); } - }; this.onKeyHandler = handler; diff --git a/src/input/keyboard/keys/ProcessKeyDown.js b/src/input/keyboard/keys/ProcessKeyDown.js index 702fc889b..308a0e190 100644 --- a/src/input/keyboard/keys/ProcessKeyDown.js +++ b/src/input/keyboard/keys/ProcessKeyDown.js @@ -20,11 +20,6 @@ var ProcessKeyDown = function (key, event) { key.originalEvent = event; - if (key.preventDefault) - { - event.preventDefault(); - } - if (!key.enabled) { return; diff --git a/src/input/keyboard/keys/ProcessKeyUp.js b/src/input/keyboard/keys/ProcessKeyUp.js index 496d77605..af834261e 100644 --- a/src/input/keyboard/keys/ProcessKeyUp.js +++ b/src/input/keyboard/keys/ProcessKeyUp.js @@ -20,11 +20,6 @@ var ProcessKeyUp = function (key, event) { key.originalEvent = event; - if (key.preventDefault) - { - event.preventDefault(); - } - if (!key.enabled) { return; From 2f4f0d89addc009ceb6498bb475d2bc1a8f45aa7 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 12 Nov 2018 22:22:26 +0000 Subject: [PATCH 013/221] Bumped version. --- src/const.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/const.js b/src/const.js index 93b83b958..32742e231 100644 --- a/src/const.js +++ b/src/const.js @@ -20,7 +20,7 @@ var CONST = { * @type {string} * @since 3.0.0 */ - VERSION: '3.16.0 Beta 1', + VERSION: '3.16.0 Beta 2', BlendModes: require('./renderer/BlendModes'), From d8b0bf7a294656eaf793d8d38be58e987b3d9e74 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 12 Nov 2018 23:00:56 +0000 Subject: [PATCH 014/221] Added metaKey support --- src/input/keyboard/keys/Key.js | 12 ++++++++++++ src/input/keyboard/keys/ProcessKeyDown.js | 1 + 2 files changed, 13 insertions(+) diff --git a/src/input/keyboard/keys/Key.js b/src/input/keyboard/keys/Key.js index d811e1b14..0ca137a43 100644 --- a/src/input/keyboard/keys/Key.js +++ b/src/input/keyboard/keys/Key.js @@ -112,6 +112,17 @@ var Key = new Class({ */ this.shiftKey = false; + /** + * The down state of the Meta key, if pressed at the same time as this key. + * On a Mac the Meta Key is the Command key. On Windows keyboards, it's the Windows key. + * + * @name Phaser.Input.Keyboard.Key#metaKey + * @type {boolean} + * @default false + * @since 3.16.0 + */ + this.metaKey = false; + /** * The location of the modifier key. 0 for standard (or unknown), 1 for left, 2 for right, 3 for numpad. * @@ -212,6 +223,7 @@ var Key = new Class({ this.altKey = false; this.ctrlKey = false; this.shiftKey = false; + this.metaKey = false; this.timeDown = 0; this.duration = 0; this.timeUp = 0; diff --git a/src/input/keyboard/keys/ProcessKeyDown.js b/src/input/keyboard/keys/ProcessKeyDown.js index 308a0e190..5a98f9661 100644 --- a/src/input/keyboard/keys/ProcessKeyDown.js +++ b/src/input/keyboard/keys/ProcessKeyDown.js @@ -28,6 +28,7 @@ var ProcessKeyDown = function (key, event) key.altKey = event.altKey; key.ctrlKey = event.ctrlKey; key.shiftKey = event.shiftKey; + key.metaKey = event.metaKey; key.location = event.location; if (key.isDown === false) From 696e3dc6b8d09f78f76b9bc082c2a168a10adc22 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 12 Nov 2018 23:01:30 +0000 Subject: [PATCH 015/221] Prevent non-modified keys only --- src/boot/Config.js | 2 +- src/input/keyboard/KeyboardPlugin.js | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/boot/Config.js b/src/boot/Config.js index be05e10e7..fd70fe6d4 100644 --- a/src/boot/Config.js +++ b/src/boot/Config.js @@ -415,7 +415,7 @@ var Config = new Class({ this.inputKeyboardEventTarget = GetValue(config, 'input.keyboard.target', window); /** - * @const {boolean} Phaser.Boot.Config#inputKeyboardCapture - Should `preventDefault` be called automatically on every key press (true), or let each Key object set it (false) + * @const {boolean} Phaser.Boot.Config#inputKeyboardCapture - Should `preventDefault` be called automatically on every key non-modified press (true), or let each Key object set it (false) */ this.inputKeyboardCapture = GetValue(config, 'input.keyboard.capture', true); diff --git a/src/input/keyboard/KeyboardPlugin.js b/src/input/keyboard/KeyboardPlugin.js index b431b20e2..d4d4d35b9 100644 --- a/src/input/keyboard/KeyboardPlugin.js +++ b/src/input/keyboard/KeyboardPlugin.js @@ -164,10 +164,15 @@ var KeyboardPlugin = new Class({ this.time = 0; /** - * A flag that controls if all keys pressed have `preventDefault` called on them or not. + * A flag that controls if all non-modified keys pressed have `preventDefault` called on them or not. * * By default this is `true`. * + * A non-modified key is one that doesn't have a modifier key held down with it. The modifier keys are + * shift, control, alt and the meta key (Command on a Mac, the Windows Key on Windows). + * Therefore, if the user presses shift + r, it won't prevent this combination, because of the modifier. + * However, if the user presses just the r key on its own, it will have its event prevented. + * * You can set this flag to stop any key from triggering the default browser action, or if you need * more specific control, you can create Key objects and set the flag on each of those instead. * @@ -260,7 +265,9 @@ var KeyboardPlugin = new Class({ var key = _this.keys[event.keyCode]; - if (_this.preventDefault || key && key.preventDefault) + var modified = (event.altKey || event.ctrlKey || event.shiftKey || event.metaKey); + + if (_this.preventDefault && !modified || key && key.preventDefault) { event.preventDefault(); } From 38b11b894718d8bd6ce7ec9f60201c381969073b Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 12 Nov 2018 23:01:34 +0000 Subject: [PATCH 016/221] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0376d75f4..dfe18cfab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,9 @@ * The WebGL Renderer has a new method `clearPipeline`, which will clear down the current pipeline and reset the blend mode, ready for the context to be passed to a 3rd party library. * The WebGL Renderer has a new method `rebindPipeline`, which will rebind the given pipeline instance, reset the blank texture and reset the blend mode. Which is useful for recovering from 3rd party libs that have modified the gl context. * Game Objects have a new property called `state`. Use this to track the state of a Game Object during its lifetime. For example, it could move from a state of 'moving', to 'attacking', to 'dead'. Phaser itself will never set this property, although plugins are allowed to. -* The Keyboard Plugin will now call `preventDefault` on all key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create ` Key` object to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the config settings: +* The Keyboard Plugin will now call `preventDefault` on all non-modified key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create ` Key` object to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the config settings: * There is a new Game Config setting `input.keyboard.capture` which allows you to set if the Keyboard Plugin will capture all key events or not. You can also set this in a Scene Config, in which case it will override the Game Config setting. +* The Key object has a new boolean `metaKey` which indicates if the Meta Key was held down when the Key was pressed. On a Mac the Meta Key is Command. On a Windows keyboard, it's the Windows key. ### Updates From 837cc4e86da2d38b5ac5d33b5c37a4997ef4905f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 12 Nov 2018 23:19:49 +0000 Subject: [PATCH 017/221] Swapped hit area size detection priority --- src/input/InputPlugin.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/input/InputPlugin.js b/src/input/InputPlugin.js index c7552c86b..5a55b9022 100644 --- a/src/input/InputPlugin.js +++ b/src/input/InputPlugin.js @@ -1704,20 +1704,20 @@ var InputPlugin = new Class({ var width = 0; var height = 0; - if (frame) - { - width = frame.realWidth; - height = frame.realHeight; - } - else if (gameObject.width) + if (gameObject.width) { width = gameObject.width; height = gameObject.height; } + else if (frame) + { + width = frame.realWidth; + height = frame.realHeight; + } if (gameObject.type === 'Container' && (width === 0 || height === 0)) { - console.warn('Container.setInteractive() must specify a Shape or call setSize() first'); + console.warn('Container.setInteractive must specify a Shape or call setSize() first'); continue; } From c75b23322694a0598ae7a79d7a968c4d5e7f8d22 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 12 Nov 2018 23:19:53 +0000 Subject: [PATCH 018/221] Update CHANGELOG.md --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfe18cfab..530993382 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,14 +8,15 @@ * The WebGL Renderer has a new method `clearPipeline`, which will clear down the current pipeline and reset the blend mode, ready for the context to be passed to a 3rd party library. * The WebGL Renderer has a new method `rebindPipeline`, which will rebind the given pipeline instance, reset the blank texture and reset the blend mode. Which is useful for recovering from 3rd party libs that have modified the gl context. * Game Objects have a new property called `state`. Use this to track the state of a Game Object during its lifetime. For example, it could move from a state of 'moving', to 'attacking', to 'dead'. Phaser itself will never set this property, although plugins are allowed to. -* The Keyboard Plugin will now call `preventDefault` on all non-modified key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create ` Key` object to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the config settings: -* There is a new Game Config setting `input.keyboard.capture` which allows you to set if the Keyboard Plugin will capture all key events or not. You can also set this in a Scene Config, in which case it will override the Game Config setting. +* The Keyboard Plugin will now call `preventDefault` on all non-modified key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create `Key` objects to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the following config settings: +* There is a new Game and Scene Config setting `input.keyboard.capture` which allows you to set if the Keyboard Plugin will capture all non-modified key events or not. You can also set this in a Scene Config, in which case it will override the Game Config value. * The Key object has a new boolean `metaKey` which indicates if the Meta Key was held down when the Key was pressed. On a Mac the Meta Key is Command. On a Windows keyboard, it's the Windows key. ### Updates * The Mouse Manager class has been updated to remove some commented out code and refine the `startListeners` method. * The following Key Codes have been added, which include some missing alphabet letters in Persian and Arabic: `SEMICOLON_FIREFOX`, `COLON`, `COMMA_FIREFOX_WINDOWS`, `COMMA_FIREFOX`, `BRACKET_RIGHT_FIREFOX` and `BRACKET_LEFT_FIREFOX` (thanks @wmateam) +* When enabling a Game Object for input it will now use the `width` and `height` properties of the Game Object first, falling back to the frame size if not found. This stops a bug when enabling BitmapText objects for input and it using the font texture as the hit area size, rather than the text itself. * You can now modify `this.physics.world.debugGraphic.defaultStrokeWidth` to set the stroke width of any debug drawn body, previously it was always 1 (thanks @samme) * `TextStyle.setFont` has a new optional argument `updateText` which will sets if the text should be automatically updated or not (thanks @DotTheGreat) * `ProcessQueue.destroy` now sets the internal `toProcess` counter to zero. From 7d202111f191d70ec32d20fc1867674d6afe3db2 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 10:31:44 +0000 Subject: [PATCH 019/221] Update CHANGELOG.md --- CHANGELOG.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e46b8c4a..75de7794f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,21 +11,24 @@ * If the `setScore` or `getPlayerScore` calls fail, it will return `null` as the score instance, instead of causing a run-time error. * You can now pass an object or a string to `setScore` and objects will be automatically stringified. +### Input Updates and Fixes + +* The Keyboard Plugin will now call `preventDefault` on all non-modified key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create `Key` objects to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the following config settings: +* There is a new Game and Scene Config setting `input.keyboard.capture` which allows you to set if the Keyboard Plugin will capture all non-modified key events or not. You can also set this in a Scene Config, in which case it will override the Game Config value. +* The Key object has a new boolean `metaKey` which indicates if the Meta Key was held down when the Key was pressed. On a Mac the Meta Key is Command. On a Windows keyboard, it's the Windows key. +* The Mouse Manager class has been updated to remove some commented out code and refine the `startListeners` method. +* The following Key Codes have been added, which include some missing alphabet letters in Persian and Arabic: `SEMICOLON_FIREFOX`, `COLON`, `COMMA_FIREFOX_WINDOWS`, `COMMA_FIREFOX`, `BRACKET_RIGHT_FIREFOX` and `BRACKET_LEFT_FIREFOX` (thanks @wmateam) +* When enabling a Game Object for input it will now use the `width` and `height` properties of the Game Object first, falling back to the frame size if not found. This stops a bug when enabling BitmapText objects for input and it using the font texture as the hit area size, rather than the text itself. + ### New Features * The data object being sent to the Dynamic Bitmap Text callback now has a new property `parent`, which is a reference to the Bitmap Text instance that owns the data object (thanks ornyth) * The WebGL Renderer has a new method `clearPipeline`, which will clear down the current pipeline and reset the blend mode, ready for the context to be passed to a 3rd party library. * The WebGL Renderer has a new method `rebindPipeline`, which will rebind the given pipeline instance, reset the blank texture and reset the blend mode. Which is useful for recovering from 3rd party libs that have modified the gl context. * Game Objects have a new property called `state`. Use this to track the state of a Game Object during its lifetime. For example, it could move from a state of 'moving', to 'attacking', to 'dead'. Phaser itself will never set this property, although plugins are allowed to. -* The Keyboard Plugin will now call `preventDefault` on all non-modified key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create `Key` objects to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the following config settings: -* There is a new Game and Scene Config setting `input.keyboard.capture` which allows you to set if the Keyboard Plugin will capture all non-modified key events or not. You can also set this in a Scene Config, in which case it will override the Game Config value. -* The Key object has a new boolean `metaKey` which indicates if the Meta Key was held down when the Key was pressed. On a Mac the Meta Key is Command. On a Windows keyboard, it's the Windows key. ### Updates -* The Mouse Manager class has been updated to remove some commented out code and refine the `startListeners` method. -* The following Key Codes have been added, which include some missing alphabet letters in Persian and Arabic: `SEMICOLON_FIREFOX`, `COLON`, `COMMA_FIREFOX_WINDOWS`, `COMMA_FIREFOX`, `BRACKET_RIGHT_FIREFOX` and `BRACKET_LEFT_FIREFOX` (thanks @wmateam) -* When enabling a Game Object for input it will now use the `width` and `height` properties of the Game Object first, falling back to the frame size if not found. This stops a bug when enabling BitmapText objects for input and it using the font texture as the hit area size, rather than the text itself. * You can now modify `this.physics.world.debugGraphic.defaultStrokeWidth` to set the stroke width of any debug drawn body, previously it was always 1 (thanks @samme) * `TextStyle.setFont` has a new optional argument `updateText` which will sets if the text should be automatically updated or not (thanks @DotTheGreat) * `ProcessQueue.destroy` now sets the internal `toProcess` counter to zero. From a1273e42b8d869552eaa105d4cbeb5629076780e Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 10:31:56 +0000 Subject: [PATCH 020/221] Added ERASE blend mode --- src/gameobjects/components/BlendMode.js | 1 + src/renderer/canvas/utils/GetBlendModes.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/gameobjects/components/BlendMode.js b/src/gameobjects/components/BlendMode.js index dbfefc7c7..4e3f801de 100644 --- a/src/gameobjects/components/BlendMode.js +++ b/src/gameobjects/components/BlendMode.js @@ -37,6 +37,7 @@ var BlendMode = { * * ADD * * MULTIPLY * * SCREEN + * * ERASE * * Canvas has more available depending on browser support. * diff --git a/src/renderer/canvas/utils/GetBlendModes.js b/src/renderer/canvas/utils/GetBlendModes.js index 7f2e383b6..59a1179a1 100644 --- a/src/renderer/canvas/utils/GetBlendModes.js +++ b/src/renderer/canvas/utils/GetBlendModes.js @@ -38,6 +38,7 @@ var GetBlendModes = function () output[modes.SATURATION] = (useNew) ? 'saturation' : so; output[modes.COLOR] = (useNew) ? 'color' : so; output[modes.LUMINOSITY] = (useNew) ? 'luminosity' : so; + output[modes.ERASE] = 'destination-out'; return output; }; From 76918e76b02e6afb0d897c5eb71d750b29a99f10 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 10:32:24 +0000 Subject: [PATCH 021/221] ERASE tests --- .../rendertexture/RenderTexture.js | 30 ++++--- src/renderer/webgl/WebGLRenderer.js | 78 ++++++++++++++++++- 2 files changed, 98 insertions(+), 10 deletions(-) diff --git a/src/gameobjects/rendertexture/RenderTexture.js b/src/gameobjects/rendertexture/RenderTexture.js index 0cee5fd50..87ed0aef6 100644 --- a/src/gameobjects/rendertexture/RenderTexture.js +++ b/src/gameobjects/rendertexture/RenderTexture.js @@ -853,11 +853,23 @@ var RenderTexture = new Class({ var prevX = gameObject.x; var prevY = gameObject.y; + if (this._eraseMode) + { + var blendMode = gameObject.blendMode; + + gameObject.blendMode = BlendModes.ERASE; + } + gameObject.setPosition(x, y); gameObject.renderCanvas(this.renderer, gameObject, 0, this.camera, null); gameObject.setPosition(prevX, prevY); + + if (this._eraseMode) + { + gameObject.blendMode = blendMode; + } }, /** @@ -905,19 +917,19 @@ var RenderTexture = new Class({ if (this.gl) { - if (this._eraseMode) - { - var blendMode = this.renderer.currentBlendMode; + // if (this._eraseMode) + // { + // var blendMode = this.renderer.currentBlendMode; - this.renderer.setBlendMode(BlendModes.ERASE); - } + // this.renderer.setBlendMode(BlendModes.ERASE); + // } this.pipeline.batchTextureFrame(textureFrame, x, y, tint, alpha, this.camera.matrix, null); - if (this._eraseMode) - { - this.renderer.setBlendMode(blendMode); - } + // if (this._eraseMode) + // { + // this.renderer.setBlendMode(blendMode); + // } } else { diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index ed755da19..fba95401c 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -510,11 +510,87 @@ var WebGLRenderer = new Class({ this.blendModes.push({ func: [ gl.ONE, gl.ONE_MINUS_SRC_ALPHA ], equation: gl.FUNC_ADD }); } + // ADD this.blendModes[1].func = [ gl.ONE, gl.DST_ALPHA ]; + + // MULTIPLY this.blendModes[2].func = [ gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA ]; + + // SCREEN this.blendModes[3].func = [ gl.ONE, gl.ONE_MINUS_SRC_COLOR ]; + + // ERASE this.blendModes[17].func = [ gl.ZERO, gl.ONE_MINUS_SRC_ALPHA ]; + // This is like an inversed erase! alpha areas go black + // this.blendModes[17].func = [ gl.ONE_MINUS_SRC_ALPHA, gl.SRC_ALPHA, gl.ONE, gl.ONE ]; + + // src RGB + // dst RGB + // src Alpha + // dst Alpha + + // gl.ZERO, + // gl.ONE, + // gl.SRC_COLOR, + // gl.ONE_MINUS_SRC_COLOR, + // gl.DST_COLOR, + // gl.ONE_MINUS_DST_COLOR, + // gl.SRC_ALPHA, + // gl.ONE_MINUS_SRC_ALPHA, + // gl.DST_ALPHA, + // gl.ONE_MINUS_DST_ALPHA, + // gl.CONSTANT_COLOR, + // gl.ONE_MINUS_CONSTANT_COLOR, + // gl.CONSTANT_ALPHA, + // gl.ONE_MINUS_CONSTANT_ALPHA, + // gl.SRC_ALPHA_SATURATE + + // BLACK (with ADD) + + // this.blendModes[17].func = [ + // gl.ZERO, + // gl.ONE_MINUS_SRC_ALPHA, + // gl.ONE, + // gl.ONE + // ]; + + // this.blendModes[17].func = [ + // gl.ONE, + // gl.ZERO, + // gl.ONE, + // gl.ZERO + // ]; + + + // this.blendModes[17].equation = gl.FUNC_ADD; + // this.blendModes[17].equation = gl.FUNC_SUBTRACT; + this.blendModes[17].equation = gl.FUNC_REVERSE_SUBTRACT; + + // 0, 1, 2, 3 + // blendFuncSeparate(this._srcRGB, this._dstRGB, this._srcAlpha, this._dstAlpha); + + + // this._srcRGB = this.gl.SRC_ALPHA; + // this._dstRGB = this.gl.ONE; + // this._srcAlpha = this.gl.ONE; + // this._dstAlpha = this.gl.ONE; + // this._modeRGB = this.gl.FUNC_ADD; + // this._modeAlpha = this.gl.FUNC_ADD; + + + + + // this._srcRGB = this.gl.SRC_ALPHA; + // this._dstRGB = this.gl.ONE_MINUS_SRC_ALPHA; + // this._srcAlpha = this.gl.ONE; + // this._dstAlpha = this.gl.ONE; + // this._modeRGB = this.gl.FUNC_REVERSE_SUBTRACT; + // this._modeAlpha = this.gl.FUNC_REVERSE_SUBTRACT; + + // gl.blendEquationSeparate(this._modeRGB, this._modeAlpha); + // gl.blendFuncSeparate(this._srcRGB, this._dstRGB, this._srcAlpha, this._dstAlpha); + this.glFormats[0] = gl.BYTE; this.glFormats[1] = gl.SHORT; this.glFormats[2] = gl.UNSIGNED_BYTE; @@ -1016,7 +1092,7 @@ var WebGLRenderer = new Class({ this.flush(); gl.enable(gl.BLEND); - gl.blendEquation(blendMode.equation); + gl.blendEquation(blendMode.equation, blendMode.equation); if (blendMode.func.length > 2) { From 16ef9df977c2e2880e4dfbed8758983cb01809d6 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 15:05:35 +0000 Subject: [PATCH 022/221] Updated capture docs and values --- src/boot/Config.js | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/boot/Config.js b/src/boot/Config.js index fd70fe6d4..4cfdb4ced 100644 --- a/src/boot/Config.js +++ b/src/boot/Config.js @@ -11,6 +11,7 @@ var GetFastValue = require('../utils/object/GetFastValue'); var GetValue = require('../utils/object/GetValue'); var IsPlainObject = require('../utils/object/IsPlainObject'); var MATH = require('../math/const'); +var NumberArray = require('../utils/array/NumberArray'); var RND = require('../math/random-data-generator/RandomDataGenerator'); var NOOP = require('../utils/NOOP'); var DefaultPlugins = require('../plugins/DefaultPlugins'); @@ -63,7 +64,7 @@ var ValueToColor = require('../display/color/ValueToColor'); * @typedef {object} KeyboardInputConfig * * @property {*} [target=window] - Where the Keyboard Manager listens for keyboard input events. - * @property {boolean} [capture=true] - Whether keyboard input events have `preventDefault` called on them automatically. + * @property {(boolean|integer[])} [capture] - `preventDefault` will be called on every non-modified key which has a key code in this array. By default, it's set to all the space key, cursors and all alphanumeric keys. Or, set to 'false' to disable. */ /** @@ -415,9 +416,21 @@ var Config = new Class({ this.inputKeyboardEventTarget = GetValue(config, 'input.keyboard.target', window); /** - * @const {boolean} Phaser.Boot.Config#inputKeyboardCapture - Should `preventDefault` be called automatically on every key non-modified press (true), or let each Key object set it (false) + * @const {(boolean|integer[])} Phaser.Boot.Config#inputKeyboardCapture - `preventDefault` will be called on every non-modified key which has a key code in this array. By default, it's set to all alphanumeric keys. Or, set to 'false' to disable. */ - this.inputKeyboardCapture = GetValue(config, 'input.keyboard.capture', true); + var defaultCaptures = [ 32, 38, 39, 40, 42 ]; + + defaultCaptures = defaultCaptures.concat(NumberArray(48, 57)); + defaultCaptures = defaultCaptures.concat(NumberArray(65, 90)); + + var keyboardCapture = GetValue(config, 'input.keyboard.capture', defaultCaptures); + + if (!Array.isArray(keyboardCapture)) + { + keyboardCapture = []; + } + + this.inputKeyboardCapture = keyboardCapture; /** * @const {(boolean|object)} Phaser.Boot.Config#inputMouse - Enable the Mouse Plugin. This can be disabled in games that don't need mouse input. @@ -575,7 +588,7 @@ var Config = new Class({ var bgc = GetValue(config, 'backgroundColor', 0); /** - * @const {Phaser.Display.Color} Phaser.Boot.Config#backgroundColor - The background color of the game canvas. The default is black. + * @const {Phaser.Display.Color} Phaser.Boot.Config#backgroundColor - The background color of the game canvas. The default is black. This value is ignored if `transparent` is set to `true`. */ this.backgroundColor = ValueToColor(bgc); From 355bc2e1eebbf5da22241fe25d0dde0c258965f4 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 15:05:59 +0000 Subject: [PATCH 023/221] If not transparent, then set backgroundColor to the canvas itself. --- src/boot/CreateRenderer.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/boot/CreateRenderer.js b/src/boot/CreateRenderer.js index 893adfb66..a7cc05b9f 100644 --- a/src/boot/CreateRenderer.js +++ b/src/boot/CreateRenderer.js @@ -72,6 +72,12 @@ var CreateRenderer = function (game) game.canvas.style = config.canvasStyle; } + // Background color + if (!config.transparent) + { + game.canvas.style.backgroundColor = config.backgroundColor.rgba; + } + // Pixel Art mode? if (!config.antialias) { From 8de7973c9276bb43235861fe0bd0d24e03ff3afc Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 15:09:18 +0000 Subject: [PATCH 024/221] Added new captures array. --- src/input/keyboard/KeyboardPlugin.js | 41 +++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/input/keyboard/KeyboardPlugin.js b/src/input/keyboard/KeyboardPlugin.js index d4d4d35b9..cdcbb13c4 100644 --- a/src/input/keyboard/KeyboardPlugin.js +++ b/src/input/keyboard/KeyboardPlugin.js @@ -164,19 +164,18 @@ var KeyboardPlugin = new Class({ this.time = 0; /** - * A flag that controls if all non-modified keys pressed have `preventDefault` called on them or not. - * - * By default this is `true`. + * A flag that controls if the non-modified keys, matching those stored in the `captures` array, + * have `preventDefault` called on them or not. By default this is `true`. * * A non-modified key is one that doesn't have a modifier key held down with it. The modifier keys are * shift, control, alt and the meta key (Command on a Mac, the Windows Key on Windows). * Therefore, if the user presses shift + r, it won't prevent this combination, because of the modifier. * However, if the user presses just the r key on its own, it will have its event prevented. * - * You can set this flag to stop any key from triggering the default browser action, or if you need + * You can set this flag to stop any capture key from triggering the default browser action, or if you need * more specific control, you can create Key objects and set the flag on each of those instead. * - * This flag can be set in the Game Config by setting the `input.keyboard.capture` boolean, or you + * This flag can be set in the Game Config by setting the `input.keyboard.capture` to a `false` boolean, or you * can set it in the Scene Config, in which case the Scene Config setting overrides the Game Config one. * * @name Phaser.Input.Keyboard.KeyboardPlugin#preventDefault @@ -185,6 +184,33 @@ var KeyboardPlugin = new Class({ */ this.preventDefault = true; + /** + * An array of Key Code values that will automatically have `preventDefault` called on them, + * as long as the `KeyboardPlugin.preventDefault` boolean is set to `true`. + * + * By default the array contains: The Space Key, the Cursor Keys, 0 to 9 and A to Z. + * + * The key must be non-modified when pressed in order to be captured. + * + * A non-modified key is one that doesn't have a modifier key held down with it. The modifier keys are + * shift, control, alt and the meta key (Command on a Mac, the Windows Key on Windows). + * Therefore, if the user presses shift + r, it won't prevent this combination, because of the modifier. + * However, if the user presses just the r key on its own, it will have its event prevented. + * + * If you wish to stop capturing the keys, for example switching out to a DOM based element, then + * you can toggle the `KeyboardPlugin.preventDefault` boolean at run-time. + * + * If you need more specific control, you can create Key objects and set the flag on each of those instead. + * + * This array can be populated via the Game Config by setting the `input.keyboard.capture` array, or you + * can set it in the Scene Config, in which case the Scene Config array overrides the Game Config one. + * + * @name Phaser.Input.Keyboard.KeyboardPlugin#captures + * @type {integer[]} + * @since 3.16.0 + */ + this.captures = []; + sceneInputPlugin.pluginEvents.once('boot', this.boot, this); sceneInputPlugin.pluginEvents.on('start', this.start, this); }, @@ -204,7 +230,8 @@ var KeyboardPlugin = new Class({ this.enabled = GetValue(settings, 'keyboard', config.inputKeyboard); this.target = GetValue(settings, 'keyboard.target', config.inputKeyboardEventTarget); - this.preventDefault = GetValue(settings, 'keyboard.capture', config.inputKeyboardCapture); + this.captures = GetValue(settings, 'keyboard.capture', config.inputKeyboardCapture); + this.preventDefault = this.captures.length > 0; this.sceneInputPlugin.pluginEvents.once('destroy', this.destroy, this); }, @@ -267,7 +294,7 @@ var KeyboardPlugin = new Class({ var modified = (event.altKey || event.ctrlKey || event.shiftKey || event.metaKey); - if (_this.preventDefault && !modified || key && key.preventDefault) + if ((_this.preventDefault && !modified && _this.captures.indexOf(event.keyCode) > -1) || (key && key.preventDefault)) { event.preventDefault(); } From 1b51ef1130805255eaf4e66f33f74ae6b448fe12 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 15:09:42 +0000 Subject: [PATCH 025/221] Remove fillRect. CSS now handles the background color. --- src/renderer/canvas/CanvasRenderer.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/renderer/canvas/CanvasRenderer.js b/src/renderer/canvas/CanvasRenderer.js index 3be055bfd..1d9b37ea0 100644 --- a/src/renderer/canvas/CanvasRenderer.js +++ b/src/renderer/canvas/CanvasRenderer.js @@ -314,7 +314,7 @@ var CanvasRenderer = new Class({ * @method Phaser.Renderer.Canvas.CanvasRenderer#setBlendMode * @since 3.0.0 * - * @param {number} blendMode - The new blend mode which should be used. + * @param {string} blendMode - The new blend mode which should be used. * * @return {this} This CanvasRenderer object. */ @@ -382,12 +382,6 @@ var CanvasRenderer = new Class({ ctx.clearRect(0, 0, width, height); } - if (!config.transparent) - { - ctx.fillStyle = config.backgroundColor.rgba; - ctx.fillRect(0, 0, width, height); - } - ctx.save(); this.drawCount = 0; From 48686881dc64ece9c0c8d6618d568672cdfc3543 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 15:10:10 +0000 Subject: [PATCH 026/221] Removed clearColor. CSS now handles this. Context always transparent. --- src/renderer/webgl/WebGLRenderer.js | 84 +++-------------------------- 1 file changed, 7 insertions(+), 77 deletions(-) diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index fba95401c..41388ef6d 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -62,8 +62,8 @@ var WebGLRenderer = new Class({ var gameConfig = game.config; var contextCreationConfig = { - alpha: gameConfig.transparent, - depth: false, // enable when 3D is added in the future + alpha: true, + depth: false, antialias: gameConfig.antialias, premultipliedAlpha: gameConfig.premultipliedAlpha, stencil: true, @@ -505,7 +505,7 @@ var WebGLRenderer = new Class({ // Set it back into the Game, so developers can access it from there too this.game.context = gl; - for (var i = 0; i <= 17; i++) + for (var i = 0; i <= 27; i++) { this.blendModes.push({ func: [ gl.ONE, gl.ONE_MINUS_SRC_ALPHA ], equation: gl.FUNC_ADD }); } @@ -520,76 +520,7 @@ var WebGLRenderer = new Class({ this.blendModes[3].func = [ gl.ONE, gl.ONE_MINUS_SRC_COLOR ]; // ERASE - this.blendModes[17].func = [ gl.ZERO, gl.ONE_MINUS_SRC_ALPHA ]; - - // This is like an inversed erase! alpha areas go black - // this.blendModes[17].func = [ gl.ONE_MINUS_SRC_ALPHA, gl.SRC_ALPHA, gl.ONE, gl.ONE ]; - - // src RGB - // dst RGB - // src Alpha - // dst Alpha - - // gl.ZERO, - // gl.ONE, - // gl.SRC_COLOR, - // gl.ONE_MINUS_SRC_COLOR, - // gl.DST_COLOR, - // gl.ONE_MINUS_DST_COLOR, - // gl.SRC_ALPHA, - // gl.ONE_MINUS_SRC_ALPHA, - // gl.DST_ALPHA, - // gl.ONE_MINUS_DST_ALPHA, - // gl.CONSTANT_COLOR, - // gl.ONE_MINUS_CONSTANT_COLOR, - // gl.CONSTANT_ALPHA, - // gl.ONE_MINUS_CONSTANT_ALPHA, - // gl.SRC_ALPHA_SATURATE - - // BLACK (with ADD) - - // this.blendModes[17].func = [ - // gl.ZERO, - // gl.ONE_MINUS_SRC_ALPHA, - // gl.ONE, - // gl.ONE - // ]; - - // this.blendModes[17].func = [ - // gl.ONE, - // gl.ZERO, - // gl.ONE, - // gl.ZERO - // ]; - - - // this.blendModes[17].equation = gl.FUNC_ADD; - // this.blendModes[17].equation = gl.FUNC_SUBTRACT; - this.blendModes[17].equation = gl.FUNC_REVERSE_SUBTRACT; - - // 0, 1, 2, 3 - // blendFuncSeparate(this._srcRGB, this._dstRGB, this._srcAlpha, this._dstAlpha); - - - // this._srcRGB = this.gl.SRC_ALPHA; - // this._dstRGB = this.gl.ONE; - // this._srcAlpha = this.gl.ONE; - // this._dstAlpha = this.gl.ONE; - // this._modeRGB = this.gl.FUNC_ADD; - // this._modeAlpha = this.gl.FUNC_ADD; - - - - - // this._srcRGB = this.gl.SRC_ALPHA; - // this._dstRGB = this.gl.ONE_MINUS_SRC_ALPHA; - // this._srcAlpha = this.gl.ONE; - // this._dstAlpha = this.gl.ONE; - // this._modeRGB = this.gl.FUNC_REVERSE_SUBTRACT; - // this._modeAlpha = this.gl.FUNC_REVERSE_SUBTRACT; - - // gl.blendEquationSeparate(this._modeRGB, this._modeAlpha); - // gl.blendFuncSeparate(this._srcRGB, this._dstRGB, this._srcAlpha, this._dstAlpha); + this.blendModes[17] = { func: [ gl.ZERO, gl.ONE_MINUS_SRC_ALPHA ], equation: gl.FUNC_REVERSE_SUBTRACT }; this.glFormats[0] = gl.BYTE; this.glFormats[1] = gl.SHORT; @@ -619,12 +550,13 @@ var WebGLRenderer = new Class({ this.supportedExtensions = exts; - // Setup initial WebGL state + // Setup initial WebGL state gl.disable(gl.DEPTH_TEST); gl.disable(gl.CULL_FACE); gl.enable(gl.BLEND); - gl.clearColor(clearColor.redGL, clearColor.greenGL, clearColor.blueGL, 1.0); + + // gl.clearColor(clearColor.redGL, clearColor.greenGL, clearColor.blueGL, 1); // Initialize all textures to null for (var index = 0; index < this.currentTextures.length; ++index) @@ -1834,12 +1766,10 @@ var WebGLRenderer = new Class({ if (this.contextLost) { return; } var gl = this.gl; - var color = this.config.backgroundColor; var pipelines = this.pipelines; if (this.config.clearBeforeRender) { - gl.clearColor(color.redGL, color.greenGL, color.blueGL, color.alphaGL); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); } From 5147fb281a297ebf26dcb07a5d97e4eb6c6cf82a Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 15:10:25 +0000 Subject: [PATCH 027/221] Added new Blend Modes. --- src/gameobjects/components/BlendMode.js | 3 +- src/renderer/BlendModes.js | 135 ++++++++++++++++++--- src/renderer/canvas/utils/GetBlendModes.js | 10 ++ 3 files changed, 128 insertions(+), 20 deletions(-) diff --git a/src/gameobjects/components/BlendMode.js b/src/gameobjects/components/BlendMode.js index 4e3f801de..f535a15ab 100644 --- a/src/gameobjects/components/BlendMode.js +++ b/src/gameobjects/components/BlendMode.js @@ -86,6 +86,7 @@ var BlendMode = { * * ADD * * MULTIPLY * * SCREEN + * * ERASE (only works when rendering to a framebuffer, like a Render Texture) * * Canvas has more available depending on browser support. * @@ -93,7 +94,7 @@ var BlendMode = { * * Blend modes have different effects under Canvas and WebGL, and from browser to browser, depending * on support. Blend Modes also cause a WebGL batch flush should it encounter a new blend mode. For these - * reasons try to be careful about the construction of your Scene and the frequency of which blend modes + * reasons try to be careful about the construction of your Scene and the frequency in which blend modes * are used. * * @method Phaser.GameObjects.Components.BlendMode#setBlendMode diff --git a/src/renderer/BlendModes.js b/src/renderer/BlendModes.js index b295d08b5..761b69e2a 100644 --- a/src/renderer/BlendModes.js +++ b/src/renderer/BlendModes.js @@ -24,129 +24,226 @@ module.exports = { SKIP_CHECK: -1, /** - * Normal blend mode. + * Normal blend mode. For Canvas and WebGL. + * This is the default setting and draws new shapes on top of the existing canvas content. * * @name Phaser.BlendModes.NORMAL */ NORMAL: 0, /** - * Add blend mode. + * Add blend mode. For Canvas and WebGL. + * Where both shapes overlap the color is determined by adding color values. * * @name Phaser.BlendModes.ADD */ ADD: 1, /** - * Multiply blend mode. + * Multiply blend mode. For Canvas and WebGL. + * The pixels are of the top layer are multiplied with the corresponding pixel of the bottom layer. A darker picture is the result. * * @name Phaser.BlendModes.MULTIPLY */ MULTIPLY: 2, /** - * Screen blend mode. + * Screen blend mode. For Canvas and WebGL. + * The pixels are inverted, multiplied, and inverted again. A lighter picture is the result (opposite of multiply) * * @name Phaser.BlendModes.SCREEN */ SCREEN: 3, /** - * Overlay blend mode. + * Overlay blend mode. For Canvas only. + * A combination of multiply and screen. Dark parts on the base layer become darker, and light parts become lighter. * * @name Phaser.BlendModes.OVERLAY */ OVERLAY: 4, /** - * Darken blend mode. + * Darken blend mode. For Canvas only. + * Retains the darkest pixels of both layers. * * @name Phaser.BlendModes.DARKEN */ DARKEN: 5, /** - * Lighten blend mode. + * Lighten blend mode. For Canvas only. + * Retains the lightest pixels of both layers. * * @name Phaser.BlendModes.LIGHTEN */ LIGHTEN: 6, /** - * Color Dodge blend mode. + * Color Dodge blend mode. For Canvas only. + * Divides the bottom layer by the inverted top layer. * * @name Phaser.BlendModes.COLOR_DODGE */ COLOR_DODGE: 7, /** - * Color Burn blend mode. + * Color Burn blend mode. For Canvas only. + * Divides the inverted bottom layer by the top layer, and then inverts the result. * * @name Phaser.BlendModes.COLOR_BURN */ COLOR_BURN: 8, /** - * Hard Light blend mode. + * Hard Light blend mode. For Canvas only. + * A combination of multiply and screen like overlay, but with top and bottom layer swapped. * * @name Phaser.BlendModes.HARD_LIGHT */ HARD_LIGHT: 9, /** - * Soft Light blend mode. + * Soft Light blend mode. For Canvas only. + * A softer version of hard-light. Pure black or white does not result in pure black or white. * * @name Phaser.BlendModes.SOFT_LIGHT */ SOFT_LIGHT: 10, /** - * Difference blend mode. + * Difference blend mode. For Canvas only. + * Subtracts the bottom layer from the top layer or the other way round to always get a positive value. * * @name Phaser.BlendModes.DIFFERENCE */ DIFFERENCE: 11, /** - * Exclusion blend mode. + * Exclusion blend mode. For Canvas only. + * Like difference, but with lower contrast. * * @name Phaser.BlendModes.EXCLUSION */ EXCLUSION: 12, /** - * Hue blend mode. + * Hue blend mode. For Canvas only. + * Preserves the luma and chroma of the bottom layer, while adopting the hue of the top layer. * * @name Phaser.BlendModes.HUE */ HUE: 13, /** - * Saturation blend mode. + * Saturation blend mode. For Canvas only. + * Preserves the luma and hue of the bottom layer, while adopting the chroma of the top layer. * * @name Phaser.BlendModes.SATURATION */ SATURATION: 14, /** - * Color blend mode. + * Color blend mode. For Canvas only. + * Preserves the luma of the bottom layer, while adopting the hue and chroma of the top layer. * * @name Phaser.BlendModes.COLOR */ COLOR: 15, /** - * Luminosity blend mode. + * Luminosity blend mode. For Canvas only. + * Preserves the hue and chroma of the bottom layer, while adopting the luma of the top layer. * * @name Phaser.BlendModes.LUMINOSITY */ LUMINOSITY: 16, /** - * Alpha erase blend mode. + * Alpha erase blend mode. For Canvas and WebGL. * * @name Phaser.BlendModes.ERASE */ - ERASE: 17 + ERASE: 17, + + /** + * Source-in blend mode. For Canvas only. + * The new shape is drawn only where both the new shape and the destination canvas overlap. Everything else is made transparent. + * + * @name Phaser.BlendModes.SOURCE_IN + */ + SOURCE_IN: 18, + + /** + * Source-out blend mode. For Canvas only. + * The new shape is drawn where it doesn't overlap the existing canvas content. + * + * @name Phaser.BlendModes.SOURCE_OUT + */ + SOURCE_OUT: 19, + + /** + * Source-out blend mode. For Canvas only. + * The new shape is only drawn where it overlaps the existing canvas content. + * + * @name Phaser.BlendModes.SOURCE_ATOP + */ + SOURCE_ATOP: 20, + + /** + * Destination-over blend mode. For Canvas only. + * New shapes are drawn behind the existing canvas content. + * + * @name Phaser.BlendModes.DESTINATION_OVER + */ + DESTINATION_OVER: 21, + + /** + * Destination-in blend mode. For Canvas only. + * The existing canvas content is kept where both the new shape and existing canvas content overlap. Everything else is made transparent. + * + * @name Phaser.BlendModes.DESTINATION_IN + */ + DESTINATION_IN: 22, + + /** + * Destination-out blend mode. For Canvas only. + * The existing content is kept where it doesn't overlap the new shape. + * + * @name Phaser.BlendModes.DESTINATION_OUT + */ + DESTINATION_OUT: 23, + + /** + * Destination-out blend mode. For Canvas only. + * The existing canvas is only kept where it overlaps the new shape. The new shape is drawn behind the canvas content. + * + * @name Phaser.BlendModes.DESTINATION_ATOP + */ + DESTINATION_ATOP: 24, + + /** + * Lighten blend mode. For Canvas only. + * Where both shapes overlap the color is determined by adding color values. + * + * @name Phaser.BlendModes.LIGHTER + */ + LIGHTER: 25, + + /** + * Copy blend mode. For Canvas only. + * Only the new shape is shown. + * + * @name Phaser.BlendModes.COPY + */ + COPY: 26, + + /** + * xor blend mode. For Canvas only. + * Shapes are made transparent where both overlap and drawn normal everywhere else. + * + * @name Phaser.BlendModes.XOR + */ + XOR: 27 }; diff --git a/src/renderer/canvas/utils/GetBlendModes.js b/src/renderer/canvas/utils/GetBlendModes.js index 59a1179a1..4670f58d4 100644 --- a/src/renderer/canvas/utils/GetBlendModes.js +++ b/src/renderer/canvas/utils/GetBlendModes.js @@ -39,6 +39,16 @@ var GetBlendModes = function () output[modes.COLOR] = (useNew) ? 'color' : so; output[modes.LUMINOSITY] = (useNew) ? 'luminosity' : so; output[modes.ERASE] = 'destination-out'; + output[modes.SOURCE_IN] = 'source-in'; + output[modes.SOURCE_OUT] = 'source-out'; + output[modes.SOURCE_ATOP] = 'source-atop'; + output[modes.DESTINATION_OVER] = 'destination-over'; + output[modes.DESTINATION_IN] = 'destination-in'; + output[modes.DESTINATION_OUT] = 'destination-out'; + output[modes.DESTINATION_ATOP] = 'destination-atop'; + output[modes.LIGHTER] = 'lighter'; + output[modes.COPY] = 'copy'; + output[modes.XOR] = 'xor'; return output; }; From 9e36f80105cb793fd4b0a151aa047e1b4cf72144 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 15:15:43 +0000 Subject: [PATCH 028/221] Update CHANGELOG.md --- CHANGELOG.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75de7794f..44e304606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,9 @@ ### Input Updates and Fixes -* The Keyboard Plugin will now call `preventDefault` on all non-modified key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create `Key` objects to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the following config settings: -* There is a new Game and Scene Config setting `input.keyboard.capture` which allows you to set if the Keyboard Plugin will capture all non-modified key events or not. You can also set this in a Scene Config, in which case it will override the Game Config value. +* The Keyboard Plugin will now call `preventDefault` on all non-modified alphanumeric key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create `Key` objects to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the following config settings: +* There is a new Game and Scene Config setting `input.keyboard.capture` which is an array of KeyCodes that the Keyboard Plugin will capture all non-modified key events on. By default it is populated with the space key, cursors, 0 - 9 and A - Z. You can also set this in a Scene Config, in which case it will override the Game Config value. +* The Keyboard Plugin has a new property called `captures` which is an array of keycodes, as populated by the Game Config. Any key code in the array will have `preventDefault` called on it if pressed. Modify this by changing the game config, or altering the array contents at run-time. * The Key object has a new boolean `metaKey` which indicates if the Meta Key was held down when the Key was pressed. On a Mac the Meta Key is Command. On a Windows keyboard, it's the Windows key. * The Mouse Manager class has been updated to remove some commented out code and refine the `startListeners` method. * The following Key Codes have been added, which include some missing alphabet letters in Persian and Arabic: `SEMICOLON_FIREFOX`, `COLON`, `COMMA_FIREFOX_WINDOWS`, `COMMA_FIREFOX`, `BRACKET_RIGHT_FIREFOX` and `BRACKET_LEFT_FIREFOX` (thanks @wmateam) @@ -26,9 +27,21 @@ * The WebGL Renderer has a new method `clearPipeline`, which will clear down the current pipeline and reset the blend mode, ready for the context to be passed to a 3rd party library. * The WebGL Renderer has a new method `rebindPipeline`, which will rebind the given pipeline instance, reset the blank texture and reset the blend mode. Which is useful for recovering from 3rd party libs that have modified the gl context. * Game Objects have a new property called `state`. Use this to track the state of a Game Object during its lifetime. For example, it could move from a state of 'moving', to 'attacking', to 'dead'. Phaser itself will never set this property, although plugins are allowed to. +* `BlendModes.ERASE` is a new blend mode that will erase the object being drawn. When used in conjunction with a Render Texture it allows for effects that let you erase parts of the texture, in either Canvas or WebGL. When used with a transparent game canvas, it allows you to erase parts of the canvas, showing the web page background through. +* `BlendModes.SOURCE_IN` is a new Canvas-only blend mode, that allows you to use the `source-in` composite operation when rendering Game Objects. +* `BlendModes.SOURCE_OUT` is a new Canvas-only blend mode, that allows you to use the `source-out` composite operation when rendering Game Objects. +* `BlendModes.SOURCE_ATOP` is a new Canvas-only blend mode, that allows you to use the `source-atop` composite operation when rendering Game Objects. +* `BlendModes.DESTINATION_OVER` is a new Canvas-only blend mode, that allows you to use the `destination-over` composite operation when rendering Game Objects. +* `BlendModes.DESTINATION_IN` is a new Canvas-only blend mode, that allows you to use the `destination-in` composite operation when rendering Game Objects. +* `BlendModes.DESTINATION_OUT` is a new Canvas-only blend mode, that allows you to use the `destination-out` composite operation when rendering Game Objects. +* `BlendModes.DESTINATION_ATOP` is a new Canvas-only blend mode, that allows you to use the `destination-atop` composite operation when rendering Game Objects. +* `BlendModes.LIGHTER` is a new Canvas-only blend mode, that allows you to use the `lighter` composite operation when rendering Game Objects. +* `BlendModes.COPY` is a new Canvas-only blend mode, that allows you to use the `copy` composite operation when rendering Game Objects. +* `BlendModes.XOR` is a new Canvas-only blend mode, that allows you to use the `xor` composite operation when rendering Game Objects. ### Updates +* The `backgroundColor` property of the Game Config is now used to set the CSS backgroundColor property of the game Canvas element. This avoids a `fillRect` call in Canvas mode and allows for 'punch through' effects to be created. If `transparent` is true, the CSS property is not set. * You can now modify `this.physics.world.debugGraphic.defaultStrokeWidth` to set the stroke width of any debug drawn body, previously it was always 1 (thanks @samme) * `TextStyle.setFont` has a new optional argument `updateText` which will sets if the text should be automatically updated or not (thanks @DotTheGreat) * `ProcessQueue.destroy` now sets the internal `toProcess` counter to zero. From e584fbfb8fb9ee1fea5eca1b5b25633976640a71 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 15:27:42 +0000 Subject: [PATCH 029/221] Tidying up erase code --- src/gameobjects/rendertexture/RenderTexture.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/gameobjects/rendertexture/RenderTexture.js b/src/gameobjects/rendertexture/RenderTexture.js index 87ed0aef6..e33e87a3d 100644 --- a/src/gameobjects/rendertexture/RenderTexture.js +++ b/src/gameobjects/rendertexture/RenderTexture.js @@ -917,19 +917,7 @@ var RenderTexture = new Class({ if (this.gl) { - // if (this._eraseMode) - // { - // var blendMode = this.renderer.currentBlendMode; - - // this.renderer.setBlendMode(BlendModes.ERASE); - // } - this.pipeline.batchTextureFrame(textureFrame, x, y, tint, alpha, this.camera.matrix, null); - - // if (this._eraseMode) - // { - // this.renderer.setBlendMode(blendMode); - // } } else { From fb768e6262bbfd44e9109b7ab76653b044065273 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 15:27:46 +0000 Subject: [PATCH 030/221] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44e304606..3d49b2d72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ * `BlendModes.LIGHTER` is a new Canvas-only blend mode, that allows you to use the `lighter` composite operation when rendering Game Objects. * `BlendModes.COPY` is a new Canvas-only blend mode, that allows you to use the `copy` composite operation when rendering Game Objects. * `BlendModes.XOR` is a new Canvas-only blend mode, that allows you to use the `xor` composite operation when rendering Game Objects. +* `RenderTexture.erase` is a new method that will take an object, or array of objects, and draw them to the Render Texture using an ERASE blend mode, resulting in them being removed from the Render Texture. This is really handy for making a bitmap masked texture in Canvas or WebGL (without using an actual mask), or for 'cutting away' part of a texture. ### Updates From 578158cfcb3e714aaeec2a32701195de06d7028f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 17:04:31 +0000 Subject: [PATCH 031/221] Updated docs --- CHANGELOG.md | 3 ++- src/input/keyboard/KeyboardPlugin.js | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d49b2d72..26737d03d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,9 @@ ### Input Updates and Fixes -* The Keyboard Plugin will now call `preventDefault` on all non-modified alphanumeric key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create `Key` objects to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the following config settings: +* The Keyboard Plugin will now call `preventDefault` on all non-modified alphanumeric key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create `Key` objects to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the following config setting. * There is a new Game and Scene Config setting `input.keyboard.capture` which is an array of KeyCodes that the Keyboard Plugin will capture all non-modified key events on. By default it is populated with the space key, cursors, 0 - 9 and A - Z. You can also set this in a Scene Config, in which case it will override the Game Config value. +* If you have multiple parallel Scenes, each trying to get keyboard input, be sure to disable capture on them to stop them from stealing input from another Scene in the list. You can do this with `this.input.keyboard.enabled = false` within the Scene to stop all input, or `this.input.keyboard.preventDefault = false` to stop a Scene halting input on another Scene. * The Keyboard Plugin has a new property called `captures` which is an array of keycodes, as populated by the Game Config. Any key code in the array will have `preventDefault` called on it if pressed. Modify this by changing the game config, or altering the array contents at run-time. * The Key object has a new boolean `metaKey` which indicates if the Meta Key was held down when the Key was pressed. On a Mac the Meta Key is Command. On a Windows keyboard, it's the Windows key. * The Mouse Manager class has been updated to remove some commented out code and refine the `startListeners` method. diff --git a/src/input/keyboard/KeyboardPlugin.js b/src/input/keyboard/KeyboardPlugin.js index cdcbb13c4..59f136f91 100644 --- a/src/input/keyboard/KeyboardPlugin.js +++ b/src/input/keyboard/KeyboardPlugin.js @@ -41,6 +41,10 @@ var SnapFloor = require('../../math/snap/SnapFloor'); * ```javascript * var spaceBar = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE); * ``` + * + * If you have multiple parallel Scenes, each trying to get keyboard input, be sure to disable capture on them to stop them from + * stealing input from another Scene in the list. You can do this with `this.input.keyboard.enabled = false` within the + * Scene to stop all input, or `this.input.keyboard.preventDefault = false` to stop a Scene halting input on another Scene. * * _Note_: Many keyboards are unable to process certain combinations of keys due to hardware limitations known as ghosting. * See http://www.html5gamedevs.com/topic/4876-impossible-to-use-more-than-2-keyboard-input-buttons-at-the-same-time/ for more details. From 476a31093ad5b1d723392720401be83541878b04 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 13 Nov 2018 19:47:47 +0000 Subject: [PATCH 032/221] onFocus and onBlur ignore if locked --- CHANGELOG.md | 2 ++ src/sound/webaudio/WebAudioSoundManager.js | 24 ++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26737d03d..d5f02b7b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,8 @@ * The method `DisplayList.sortGameObjects` has been removed. It has thrown a runtime error since v3.3.0! which no-one even spotted, a good indication of how little the method is used. The display list is automatically sorted anyway, so if you need to sort a small section of it, just use the standard JavaScript Array sort method (thanks ornyth) * The method `DisplayList.getTopGameObject` has been removed. It has thrown a runtime error since v3.3.0! which no-one even spotted, a good indication of how little the method is used (thanks ornyth) * `WebGLRenderer.setFramebuffer` has a new optional boolean argument `updateScissor`, which will reset the scissor to match the framebuffer size, or clear it. +* `WebAudioSoundManager.onFocus` will not try to resume the Audio Context if it's still locked. +* `WebAudioSoundManager.onBlur` will not try to suspend the Audio Context if it's still locked. ### Bug Fixes diff --git a/src/sound/webaudio/WebAudioSoundManager.js b/src/sound/webaudio/WebAudioSoundManager.js index 30677f5e1..15bbc5b33 100644 --- a/src/sound/webaudio/WebAudioSoundManager.js +++ b/src/sound/webaudio/WebAudioSoundManager.js @@ -144,13 +144,13 @@ var WebAudioSoundManager = new Class({ { var _this = this; - var unlock = function () + var unlockHandler = function unlockHandler () { _this.context.resume().then(function () { - document.body.removeEventListener('touchstart', unlock); - document.body.removeEventListener('touchend', unlock); - document.body.removeEventListener('click', unlock); + document.body.removeEventListener('touchstart', unlockHandler); + document.body.removeEventListener('touchend', unlockHandler); + document.body.removeEventListener('click', unlockHandler); _this.unlocked = true; }); @@ -158,9 +158,9 @@ var WebAudioSoundManager = new Class({ if (document.body) { - document.body.addEventListener('touchstart', unlock, false); - document.body.addEventListener('touchend', unlock, false); - document.body.addEventListener('click', unlock, false); + document.body.addEventListener('touchstart', unlockHandler, false); + document.body.addEventListener('touchend', unlockHandler, false); + document.body.addEventListener('click', unlockHandler, false); } }, @@ -174,7 +174,10 @@ var WebAudioSoundManager = new Class({ */ onBlur: function () { - this.context.suspend(); + if (!this.locked) + { + this.context.suspend(); + } }, /** @@ -187,7 +190,10 @@ var WebAudioSoundManager = new Class({ */ onFocus: function () { - this.context.resume(); + if (!this.locked) + { + this.context.resume(); + } }, /** From 41343e3102157041af7ca964d0c9ce7dd76eee10 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 16 Nov 2018 10:46:22 +0000 Subject: [PATCH 033/221] Removed copy paste error --- src/renderer/webgl/WebGLRenderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index 41388ef6d..ad9ffe366 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -1024,7 +1024,7 @@ var WebGLRenderer = new Class({ this.flush(); gl.enable(gl.BLEND); - gl.blendEquation(blendMode.equation, blendMode.equation); + gl.blendEquation(blendMode.equation); if (blendMode.func.length > 2) { From f85a79c0d7bb715e95fc236b2f75c0863a3b523e Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 16 Nov 2018 10:46:30 +0000 Subject: [PATCH 034/221] There is a new boolean Game Config property called `customEnvironment`. If set to `true` it will skip the internal Feature checks when working out which type of renderer to create, allowing you to run Phaser under non-native web environments. If using this value, you _must_ set an explicit `renderType` of either CANVAS or WEBGL. It cannot be left as AUTO. Fix #4166 --- CHANGELOG.md | 1 + src/boot/Config.js | 5 +++++ src/boot/CreateRenderer.js | 7 ++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5f02b7b4..16c2f9426 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ * `BlendModes.COPY` is a new Canvas-only blend mode, that allows you to use the `copy` composite operation when rendering Game Objects. * `BlendModes.XOR` is a new Canvas-only blend mode, that allows you to use the `xor` composite operation when rendering Game Objects. * `RenderTexture.erase` is a new method that will take an object, or array of objects, and draw them to the Render Texture using an ERASE blend mode, resulting in them being removed from the Render Texture. This is really handy for making a bitmap masked texture in Canvas or WebGL (without using an actual mask), or for 'cutting away' part of a texture. +* There is a new boolean Game Config property called `customEnvironment`. If set to `true` it will skip the internal Feature checks when working out which type of renderer to create, allowing you to run Phaser under non-native web environments. If using this value, you _must_ set an explicit `renderType` of either CANVAS or WEBGL. It cannot be left as AUTO. Fix #4166 (thanks @jcyuan) ### Updates diff --git a/src/boot/Config.js b/src/boot/Config.js index 4cfdb4ced..cee096fa4 100644 --- a/src/boot/Config.js +++ b/src/boot/Config.js @@ -357,6 +357,11 @@ var Config = new Class({ */ this.canvasStyle = GetValue(config, 'canvasStyle', null); + /** + * @const {boolean} Phaser.Boot.Config#customEnvironment - Is Phaser running under a custom (non-native web) environment? If so, set this to `true` to skip internal Feature detection. If `true` the `renderType` cannot be left as `AUTO`. + */ + this.customEnvironment = GetValue(config, 'customEnvironment', false); + /** * @const {?object} Phaser.Boot.Config#sceneConfig - The default Scene configuration object. */ diff --git a/src/boot/CreateRenderer.js b/src/boot/CreateRenderer.js index a7cc05b9f..4aeb1aa3d 100644 --- a/src/boot/CreateRenderer.js +++ b/src/boot/CreateRenderer.js @@ -26,7 +26,7 @@ var CreateRenderer = function (game) // Game either requested Canvas, // or requested AUTO or WEBGL but the browser doesn't support it, so fall back to Canvas - if (config.renderType !== CONST.HEADLESS) + if ((config.customEnvironment || config.canvas) && config.renderType !== CONST.HEADLESS) { if (config.renderType === CONST.CANVAS || (config.renderType !== CONST.CANVAS && !Features.webGL)) { @@ -47,6 +47,11 @@ var CreateRenderer = function (game) } } + if (config.customEnvironment && config.renderType === CONST.AUTO) + { + throw new Error('Must set renderType in custom environment'); + } + // Pixel Art mode? if (!config.antialias) { From eb5da1f26d1712ff3e6f0c3026ab956154325692 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 16 Nov 2018 10:56:43 +0000 Subject: [PATCH 035/221] Docs update --- CHANGELOG.md | 3 ++- src/renderer/webgl/WebGLRenderer.js | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16c2f9426..6d13aca09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ * `WebGLRenderer.setFramebuffer` has a new optional boolean argument `updateScissor`, which will reset the scissor to match the framebuffer size, or clear it. * `WebAudioSoundManager.onFocus` will not try to resume the Audio Context if it's still locked. * `WebAudioSoundManager.onBlur` will not try to suspend the Audio Context if it's still locked. +* When using `ScenePlugin.add`, to add a new Scene to the Scene Manager, it didn't allow you to include the optional Scene data object. You can now pass this in the call (thanks @kainage) ### Bug Fixes @@ -82,7 +83,7 @@ Thanks to the following for helping with the Phaser 3 Examples and TypeScript definitions, either by reporting errors, or even better, fixing them: -@guilhermehto @samvieten @darkwebdev +@guilhermehto @samvieten @darkwebdev @RoryO ### Phaser Doc Jam diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index ad9ffe366..7a32088b0 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -1795,8 +1795,14 @@ var WebGLRenderer = new Class({ }, /** - * The core render step for a Scene. + * The core render step for a Scene Camera. + * * Iterates through the given Game Object's array and renders them with the given Camera. + * + * This is called by the `CameraManager.render` method. The Camera Manager instance belongs to a Scene, and is invoked + * by the Scene Systems.render method. + * + * This method is not called if `Camera.visible` is `false`, or `Camera.alpha` is zero. * * @method Phaser.Renderer.WebGL.WebGLRenderer#render * @since 3.0.0 From 0ac7decfff226c02d676a4d4b1f7790b8fd89ea4 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 16 Nov 2018 10:57:24 +0000 Subject: [PATCH 036/221] Clarified the docs --- src/scene/ScenePlugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scene/ScenePlugin.js b/src/scene/ScenePlugin.js index 6414c97eb..e48162406 100644 --- a/src/scene/ScenePlugin.js +++ b/src/scene/ScenePlugin.js @@ -443,7 +443,7 @@ var ScenePlugin = new Class({ * @param {string} key - The Scene key. * @param {(Phaser.Scene|Phaser.Scenes.Settings.Config|function)} sceneConfig - The config for the Scene. * @param {boolean} autoStart - Whether to start the Scene after it's added. - * @param {object} [data] - The Scene data. + * @param {object} [data] - Optional data object. This will be set as Scene.settings.data and passed to `Scene.init`. * * @return {Phaser.Scenes.ScenePlugin} This ScenePlugin object. */ From 202c6c9c1a9e1484ae326af4aaaae398e829b5d1 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 16 Nov 2018 14:34:09 +0000 Subject: [PATCH 037/221] Added `nextFrame` and `previousFrame` to the Animation component --- CHANGELOG.md | 2 ++ src/gameobjects/components/Animation.js | 44 +++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d13aca09..4c950300a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ * `BlendModes.XOR` is a new Canvas-only blend mode, that allows you to use the `xor` composite operation when rendering Game Objects. * `RenderTexture.erase` is a new method that will take an object, or array of objects, and draw them to the Render Texture using an ERASE blend mode, resulting in them being removed from the Render Texture. This is really handy for making a bitmap masked texture in Canvas or WebGL (without using an actual mask), or for 'cutting away' part of a texture. * There is a new boolean Game Config property called `customEnvironment`. If set to `true` it will skip the internal Feature checks when working out which type of renderer to create, allowing you to run Phaser under non-native web environments. If using this value, you _must_ set an explicit `renderType` of either CANVAS or WEBGL. It cannot be left as AUTO. Fix #4166 (thanks @jcyuan) +* `Animation.nextFrame` will advance an animation to the next frame in the sequence instantly, regardless of the animation time or state. You can call this on a Sprite: `sprite.anims.nextFrame()` (thanks rgk25) +* `Animation.previousFrame` will set an animation to the previous frame in the sequence instantly, regardless of the animation time or state. You can call this on a Sprite: `sprite.anims.previousFrame()` (thanks rgk25) ### Updates diff --git a/src/gameobjects/components/Animation.js b/src/gameobjects/components/Animation.js index 09cec8841..160f4f4a9 100644 --- a/src/gameobjects/components/Animation.js +++ b/src/gameobjects/components/Animation.js @@ -1019,6 +1019,50 @@ var Animation = new Class({ } }, + /** + * Advances the animation to the next frame, regardless of the time or animation state. + * If the animation is set to repeat, or yoyo, this will still take effect. + * + * Calling this does not change the direction of the animation. I.e. if it was currently + * playing in reverse, calling this method doesn't then change the direction to forwards. + * + * @method Phaser.GameObjects.Components.Animation#nextFrame + * @since 3.16.0 + * + * @return {Phaser.GameObjects.GameObject} The Game Object this Animation Component belongs to. + */ + nextFrame: function () + { + if (this.currentAnim) + { + this.currentAnim.nextFrame(this); + } + + return this.parent; + }, + + /** + * Advances the animation to the previous frame, regardless of the time or animation state. + * If the animation is set to repeat, or yoyo, this will still take effect. + * + * Calling this does not change the direction of the animation. I.e. if it was currently + * playing in forwards, calling this method doesn't then change the direction to backwards. + * + * @method Phaser.GameObjects.Components.Animation#previousFrame + * @since 3.16.0 + * + * @return {Phaser.GameObjects.GameObject} The Game Object this Animation Component belongs to. + */ + previousFrame: function () + { + if (this.currentAnim) + { + this.currentAnim.previousFrame(this); + } + + return this.parent; + }, + /** * Sets if the current Animation will yoyo when it reaches the end. * A yoyo'ing animation will play through consecutively, and then reverse-play back to the start again. From a3965cb6092470c3839f6fa92e05edbef88f8694 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Fri, 16 Nov 2018 17:43:53 +0100 Subject: [PATCH 038/221] issue/4168 draw circular StaticBody as circle in drawDebug --- src/physics/arcade/StaticBody.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/physics/arcade/StaticBody.js b/src/physics/arcade/StaticBody.js index 9cff64ab5..c4827adbe 100644 --- a/src/physics/arcade/StaticBody.js +++ b/src/physics/arcade/StaticBody.js @@ -788,10 +788,21 @@ var StaticBody = new Class({ { var pos = this.position; + var x = pos.x + this.halfWidth; + var y = pos.y + this.halfHeight; + if (this.debugShowBody) { graphic.lineStyle(1, this.debugBodyColor, 1); - graphic.strokeRect(pos.x, pos.y, this.width, this.height); + if (this.isCircle) + { + graphic.strokeCircle(x, y, this.width / 2); + } + else + { + graphic.strokeRect(pos.x, pos.y, this.width, this.height); + } + } }, From 7b9f7f0217af8898e00aa2892bee92caa8768b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Rouvi=C3=A8re?= Date: Mon, 19 Nov 2018 00:08:36 +0100 Subject: [PATCH 039/221] Fix: Cannot read property 'index' of undefined at GetTileAt and RemoveTileAt --- src/tilemaps/components/GetTileAt.js | 2 +- src/tilemaps/components/RemoveTileAt.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tilemaps/components/GetTileAt.js b/src/tilemaps/components/GetTileAt.js index 5c3aa47be..d23c6f783 100644 --- a/src/tilemaps/components/GetTileAt.js +++ b/src/tilemaps/components/GetTileAt.js @@ -27,7 +27,7 @@ var GetTileAt = function (tileX, tileY, nonNull, layer) if (IsInLayerBounds(tileX, tileY, layer)) { - var tile = layer.data[tileY][tileX]; + var tile = layer.data[tileY][tileX] || null; if (tile === null) { return null; diff --git a/src/tilemaps/components/RemoveTileAt.js b/src/tilemaps/components/RemoveTileAt.js index b69c4563f..ff2194f07 100644 --- a/src/tilemaps/components/RemoveTileAt.js +++ b/src/tilemaps/components/RemoveTileAt.js @@ -30,7 +30,7 @@ var RemoveTileAt = function (tileX, tileY, replaceWithNull, recalculateFaces, la if (recalculateFaces === undefined) { recalculateFaces = true; } if (!IsInLayerBounds(tileX, tileY, layer)) { return null; } - var tile = layer.data[tileY][tileX]; + var tile = layer.data[tileY][tileX] || null; if (tile === null) { return null; From 51223c518a1616f1326278d2b11996f4ebac0a87 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 19 Nov 2018 11:09:53 +0000 Subject: [PATCH 040/221] Added Graphics.fill and Graphics.stroke --- CHANGELOG.md | 2 ++ src/gameobjects/graphics/Graphics.js | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c950300a..66827a30a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,8 @@ * `WebAudioSoundManager.onFocus` will not try to resume the Audio Context if it's still locked. * `WebAudioSoundManager.onBlur` will not try to suspend the Audio Context if it's still locked. * When using `ScenePlugin.add`, to add a new Scene to the Scene Manager, it didn't allow you to include the optional Scene data object. You can now pass this in the call (thanks @kainage) +* `Graphics.stroke` is a new alias for the `strokePath` method, to keep the calls consistent with the Canvas Rendering Context API. +* `Graphics.fill` is a new alias for the `fillPath` method, to keep the calls consistent with the Canvas Rendering Context API. ### Bug Fixes diff --git a/src/gameobjects/graphics/Graphics.js b/src/gameobjects/graphics/Graphics.js index 45770af7c..4a926a5d1 100644 --- a/src/gameobjects/graphics/Graphics.js +++ b/src/gameobjects/graphics/Graphics.js @@ -523,6 +523,26 @@ var Graphics = new Class({ return this; }, + /** + * Stroke the current path. + * + * This is an alias for `Graphics.strokePath` and does the same thing. + * It was added to match calls found in the Canvas API. + * + * @method Phaser.GameObjects.Graphics#stroke + * @since 3.16.0 + * + * @return {Phaser.GameObjects.Graphics} This Game Object. + */ + stroke: function () + { + this.commandBuffer.push( + Commands.STROKE_PATH + ); + + return this; + }, + /** * Fill the given circle. * From a6ef139f2028c5d327240508813a42cee5e9b54c Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 19 Nov 2018 11:10:27 +0000 Subject: [PATCH 041/221] Added fill method. --- src/gameobjects/graphics/Graphics.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/gameobjects/graphics/Graphics.js b/src/gameobjects/graphics/Graphics.js index 4a926a5d1..2d6399838 100644 --- a/src/gameobjects/graphics/Graphics.js +++ b/src/gameobjects/graphics/Graphics.js @@ -506,6 +506,26 @@ var Graphics = new Class({ return this; }, + /** + * Fill the current path. + * + * This is an alias for `Graphics.fillPath` and does the same thing. + * It was added to match the CanvasRenderingContext 2D API. + * + * @method Phaser.GameObjects.Graphics#fill + * @since 3.16.0 + * + * @return {Phaser.GameObjects.Graphics} This Game Object. + */ + fill: function () + { + this.commandBuffer.push( + Commands.FILL_PATH + ); + + return this; + }, + /** * Stroke the current path. * @@ -527,7 +547,7 @@ var Graphics = new Class({ * Stroke the current path. * * This is an alias for `Graphics.strokePath` and does the same thing. - * It was added to match calls found in the Canvas API. + * It was added to match the CanvasRenderingContext 2D API. * * @method Phaser.GameObjects.Graphics#stroke * @since 3.16.0 From 8fca5ab575b5cbffad1639d5ac394cf92e28ca8b Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 19 Nov 2018 15:30:21 +0000 Subject: [PATCH 042/221] Added `InputSmoothFactor` config property. --- src/boot/Config.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/boot/Config.js b/src/boot/Config.js index cee096fa4..3f92d8d07 100644 --- a/src/boot/Config.js +++ b/src/boot/Config.js @@ -51,6 +51,7 @@ var ValueToColor = require('../display/color/ValueToColor'); * @property {(boolean|TouchInputConfig)} [touch=true] - Touch input configuration. `true` uses the default configuration and `false` disables touch input. * @property {(boolean|GamepadInputConfig)} [gamepad=false] - Gamepad input configuration. `true` enables gamepad input. * @property {integer} [activePointers=1] - The maximum number of touch pointers. See {@link Phaser.Input.InputManager#pointers}. + * @property {number} [smoothFactor=0] - The smoothing factor to apply during Pointer movement. See {@link Phaser.Input.Pointer#smoothFactor}. */ /** @@ -472,6 +473,11 @@ var Config = new Class({ */ this.inputActivePointers = GetValue(config, 'input.activePointers', 1); + /** + * @const {integer} Phaser.Boot.Config#inputSmoothFactor - The smoothing factor to apply during Pointer movement. See {@link Phaser.Input.Pointer#smoothFactor}. + */ + this.inputSmoothFactor = GetValue(config, 'input.smoothFactor', 0); + /** * @const {boolean} Phaser.Boot.Config#inputGamepad - Enable the Gamepad Plugin. This can be disabled in games that don't need gamepad input. */ From 57084cb65e57e8af05b03949fa9b940a938a0852 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 19 Nov 2018 15:30:42 +0000 Subject: [PATCH 043/221] Added `Pointer.smoothFactor` property, and pass new boolean to input manager. --- src/input/Pointer.js | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/input/Pointer.js b/src/input/Pointer.js index e7b5a3634..7cc0797b2 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -120,6 +120,25 @@ var Pointer = new Class({ */ this.prevPosition = new Vector2(); + /** + * The smoothing factor to apply to the Pointer position. + * + * Due to their nature, pointer positions are inherently noisy. While this is fine for lots of games, if you need cleaner positions + * then you can set this value to apply an automatic smoothing to the positions as they are recorded. + * + * The default value of zero means 'no smoothing'. + * Set to a small value, such as 0.2, to apply an average level of smoothing between positions. + * Values above 1 will introduce excess jitter into the positions. + * + * Positions are only smoothed when the pointer moves. Up and Down positions are always precise. + * + * @name Phaser.Input.Pointer#smoothFactor + * @type {number} + * @default 0 + * @since 3.16.0 + */ + this.smoothFactor = 0; + /** * The x position of this Pointer, translated into the coordinate space of the most recent Camera it interacted with. * @@ -403,7 +422,7 @@ var Pointer = new Class({ this.event = event; // Sets the local x/y properties - this.manager.transformPointer(this, event.pageX, event.pageY); + this.manager.transformPointer(this, event.pageX, event.pageY, false); // 0: Main button pressed, usually the left button or the un-initialized state if (event.button === 0) @@ -442,7 +461,7 @@ var Pointer = new Class({ this.event = event; // Sets the local x/y properties - this.manager.transformPointer(this, event.pageX, event.pageY); + this.manager.transformPointer(this, event.pageX, event.pageY, false); // 0: Main button pressed, usually the left button or the un-initialized state if (event.button === 0) @@ -481,7 +500,7 @@ var Pointer = new Class({ this.event = event; // Sets the local x/y properties - this.manager.transformPointer(this, event.pageX, event.pageY); + this.manager.transformPointer(this, event.pageX, event.pageY, true); if (this.manager.mouse.locked) { @@ -523,7 +542,7 @@ var Pointer = new Class({ this.event = event; // Sets the local x/y properties - this.manager.transformPointer(this, event.pageX, event.pageY); + this.manager.transformPointer(this, event.pageX, event.pageY, false); this.primaryDown = true; this.downX = this.x; @@ -554,7 +573,7 @@ var Pointer = new Class({ this.event = event; // Sets the local x/y properties - this.manager.transformPointer(this, event.pageX, event.pageY); + this.manager.transformPointer(this, event.pageX, event.pageY, true); this.justMoved = true; @@ -580,7 +599,7 @@ var Pointer = new Class({ this.event = event; // Sets the local x/y properties - this.manager.transformPointer(this, event.pageX, event.pageY); + this.manager.transformPointer(this, event.pageX, event.pageY, false); this.primaryDown = false; this.upX = this.x; From 0c43da02112b366cf84afa998411b126b4eda65e Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 19 Nov 2018 15:31:06 +0000 Subject: [PATCH 044/221] Fixed jsdoc link, added smooth factor setter and updated `transformPointer` method. --- src/input/InputManager.js | 44 +++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/input/InputManager.js b/src/input/InputManager.js index 5896b989d..24f91571b 100644 --- a/src/input/InputManager.js +++ b/src/input/InputManager.js @@ -63,10 +63,10 @@ var InputManager = new Class({ this.canvas; /** - * The Input Configuration object, as set in the Game Config. + * The Game Configuration object, as set during the game boot. * * @name Phaser.Input.InputManager#config - * @type {object} + * @type {Phaser.Boot.Config} * @since 3.0.0 */ this.config = config; @@ -226,7 +226,11 @@ var InputManager = new Class({ for (var i = 0; i <= this.pointersTotal; i++) { - this.pointers.push(new Pointer(this, i)); + var pointer = new Pointer(this, i); + + pointer.smoothFactor = config.inputSmoothFactor; + + this.pointers.push(pointer); } /** @@ -768,6 +772,8 @@ var InputManager = new Class({ var pointer = new Pointer(this, id); + pointer.smoothFactor = this.config.inputSmoothFactor; + this.pointers.push(pointer); this.pointersTotal++; @@ -1310,15 +1316,35 @@ var InputManager = new Class({ * @param {Phaser.Input.Pointer} pointer - The Pointer to transform the values for. * @param {number} pageX - The Page X value. * @param {number} pageY - The Page Y value. + * @param {boolean} wasMove - Are we transforming the Pointer from a move event, or an up / down event? */ - transformPointer: function (pointer, pageX, pageY) + transformPointer: function (pointer, pageX, pageY, wasMove) { - // Store the previous position - pointer.prevPosition.x = pointer.x; - pointer.prevPosition.y = pointer.y; + var p0 = pointer.position; + var p1 = pointer.prevPosition; - pointer.x = (pageX - this.bounds.left) * this.scale.x; - pointer.y = (pageY - this.bounds.top) * this.scale.y; + // Store previous position + p1.x = p0.x; + p1.y = p0.y; + + // Translate coordinates + var x = (pageX - this.bounds.left) * this.scale.x; + var y = (pageY - this.bounds.top) * this.scale.y; + + var a = pointer.smoothFactor; + + if (!wasMove || a === 0) + { + // Set immediately + p0.x = x; + p0.y = y; + } + else + { + // Apply smoothing + p0.x = x * a + p1.x * (1 - a); + p0.y = y * a + p1.y * (1 - a); + } }, /** From 068ba0f7cd23863b7019d4f41557a868a8b8d1bc Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 19 Nov 2018 15:31:09 +0000 Subject: [PATCH 045/221] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66827a30a..b8aac4e4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ * The Mouse Manager class has been updated to remove some commented out code and refine the `startListeners` method. * The following Key Codes have been added, which include some missing alphabet letters in Persian and Arabic: `SEMICOLON_FIREFOX`, `COLON`, `COMMA_FIREFOX_WINDOWS`, `COMMA_FIREFOX`, `BRACKET_RIGHT_FIREFOX` and `BRACKET_LEFT_FIREFOX` (thanks @wmateam) * When enabling a Game Object for input it will now use the `width` and `height` properties of the Game Object first, falling back to the frame size if not found. This stops a bug when enabling BitmapText objects for input and it using the font texture as the hit area size, rather than the text itself. +* `Pointer.smoothFactor` is a float-value that allows you to automatically apply smoothing to the Pointer position as it moves. This is ideal when you want something smoothly tracking a pointer in a game, or are need a smooth drawing motion for an art package. The default value is zero, meaning disabled. Set to a small number, such as 0.2, to enable. +* `Config.inputSmoothFactor` is a new property that allows you to set the smoothing factor for all Pointers the game creators. The default value is zero, which is disabled. Set in the game config as `input: { smoothFactor: value }`. +* `InputManager.transformPointer` has a new boolean argument `wasMove`, which controls if the pointer is being transformed after a move or up/down event. ### New Features From f45ee83fc461cf737a8d19f42d5571d0d77b5e60 Mon Sep 17 00:00:00 2001 From: Diego Teixeira Date: Mon, 19 Nov 2018 14:54:56 -0200 Subject: [PATCH 046/221] Using statAt Including usage to startAt for startFollow method --- src/gameobjects/pathfollower/PathFollower.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gameobjects/pathfollower/PathFollower.js b/src/gameobjects/pathfollower/PathFollower.js index 52db800cd..28ee8fd76 100644 --- a/src/gameobjects/pathfollower/PathFollower.js +++ b/src/gameobjects/pathfollower/PathFollower.js @@ -23,6 +23,7 @@ var Vector2 = require('../../math/Vector2'); * @property {boolean} [positionOnPath=false] - Whether to position the PathFollower on the Path using its path offset. * @property {boolean} [rotateToPath=false] - Should the PathFollower automatically rotate to point in the direction of the Path? * @property {number} [rotationOffset=0] - If the PathFollower is rotating to match the Path, this value is added to the rotation value. This allows you to rotate objects to a path but control the angle of the rotation as well. + * @property {number} [startAt=0] - Current start position of the path follow, between 0 and 1. */ /** @@ -245,6 +246,7 @@ var PathFollower = new Class({ // Override in case they've been specified in the config config.from = 0; config.to = 1; + config.startAt = startAt; // Can also read extra values out of the config: From 1db9e15a7695bf4f8c2bc7d79f12ab1c789560cd Mon Sep 17 00:00:00 2001 From: Diego Teixeira Date: Mon, 19 Nov 2018 16:14:48 -0200 Subject: [PATCH 047/221] Getting startAt Getting startAt config and using for current --- src/tweens/builders/NumberTweenBuilder.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tweens/builders/NumberTweenBuilder.js b/src/tweens/builders/NumberTweenBuilder.js index 151665b8b..9ee7fe978 100644 --- a/src/tweens/builders/NumberTweenBuilder.js +++ b/src/tweens/builders/NumberTweenBuilder.js @@ -45,6 +45,7 @@ var NumberTweenBuilder = function (parent, config, defaults) var from = GetValue(config, 'from', 0); var to = GetValue(config, 'to', 1); + var current = GetValue(config, 'startAt', from); var targets = [ { value: from } ]; @@ -78,7 +79,7 @@ var NumberTweenBuilder = function (parent, config, defaults) ); tweenData.start = from; - tweenData.current = from; + tweenData.current = current; tweenData.to = to; data.push(tweenData); From 1cbceb215d7b21989e84cac57e1f8a2a7167313b Mon Sep 17 00:00:00 2001 From: Diego Teixeira Date: Mon, 19 Nov 2018 16:24:53 -0200 Subject: [PATCH 048/221] Setting initial current Setting initial current location --- src/tweens/tween/Tween.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tweens/tween/Tween.js b/src/tweens/tween/Tween.js index 6d0ffc505..a5462730c 100644 --- a/src/tweens/tween/Tween.js +++ b/src/tweens/tween/Tween.js @@ -1208,6 +1208,10 @@ var Tween = new Class({ tweenData.state = TWEEN_CONST.COMPLETE; break; } + + if (!tweenData.elapsed && tweenData.current) { + tweenData.elapsed = tweenData.duration * tweenData.current; + } var elapsed = tweenData.elapsed; var duration = tweenData.duration; @@ -1319,7 +1323,7 @@ var Tween = new Class({ tweenData.end = tweenData.getEndValue(tweenData.target, tweenData.key, tweenData.start); - tweenData.current = tweenData.start; + tweenData.current = tweenData.current || tweenData.start; tweenData.target[tweenData.key] = tweenData.start; From 319e4de0a10d87b55cff40d0ad69c89c444838c2 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 20 Nov 2018 09:46:49 +0000 Subject: [PATCH 049/221] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8aac4e4e..df361aa8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ * When using `ScenePlugin.add`, to add a new Scene to the Scene Manager, it didn't allow you to include the optional Scene data object. You can now pass this in the call (thanks @kainage) * `Graphics.stroke` is a new alias for the `strokePath` method, to keep the calls consistent with the Canvas Rendering Context API. * `Graphics.fill` is a new alias for the `fillPath` method, to keep the calls consistent with the Canvas Rendering Context API. +* Circular Arcade Physics Bodies now render as circles in the debug display, instead of showing their rectangle bounds (thanks @maikthomas) ### Bug Fixes @@ -85,6 +86,7 @@ * Render Textures created larger than the size of the default canvas would be automatically clipped when drawn to in WebGL. They now reset the gl scissor and drawing height property in order to draw to their full size, regardless of the canvas size. Fix #4139 (thanks @chaoyang805 @iamchristopher) * The `cameraFilter` property of a Game Object will now allow full bitmasks to be set (a value of -1), instead of just those > 0 (thanks @stuartkeith) * When using a Particle Emitter, the array of dead particles (`this.dead`) wasn't being filled correctly. Dead particles are now moved to it as they should be (thanks @Waclaw-I) +* The `PathFollower.startFollow` method now properly uses the `startAt` argument to the method, so you can start a follower off at any point along the path. Fix #3688 (thanks @DannyT @diteix) ### Examples and TypeScript From f06bb3d420396d4a5178b0f80f17180aead57101 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 20 Nov 2018 10:21:02 +0000 Subject: [PATCH 050/221] Formatting fix --- src/physics/arcade/StaticBody.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/physics/arcade/StaticBody.js b/src/physics/arcade/StaticBody.js index c4827adbe..92e0a348a 100644 --- a/src/physics/arcade/StaticBody.js +++ b/src/physics/arcade/StaticBody.js @@ -794,6 +794,7 @@ var StaticBody = new Class({ if (this.debugShowBody) { graphic.lineStyle(1, this.debugBodyColor, 1); + if (this.isCircle) { graphic.strokeCircle(x, y, this.width / 2); From e9274601a984eb69d86667fac7406a0946045a62 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 20 Nov 2018 10:21:06 +0000 Subject: [PATCH 051/221] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df361aa8e..50247fa89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,7 +68,6 @@ * When using `ScenePlugin.add`, to add a new Scene to the Scene Manager, it didn't allow you to include the optional Scene data object. You can now pass this in the call (thanks @kainage) * `Graphics.stroke` is a new alias for the `strokePath` method, to keep the calls consistent with the Canvas Rendering Context API. * `Graphics.fill` is a new alias for the `fillPath` method, to keep the calls consistent with the Canvas Rendering Context API. -* Circular Arcade Physics Bodies now render as circles in the debug display, instead of showing their rectangle bounds (thanks @maikthomas) ### Bug Fixes @@ -87,6 +86,7 @@ * The `cameraFilter` property of a Game Object will now allow full bitmasks to be set (a value of -1), instead of just those > 0 (thanks @stuartkeith) * When using a Particle Emitter, the array of dead particles (`this.dead`) wasn't being filled correctly. Dead particles are now moved to it as they should be (thanks @Waclaw-I) * The `PathFollower.startFollow` method now properly uses the `startAt` argument to the method, so you can start a follower off at any point along the path. Fix #3688 (thanks @DannyT @diteix) +* Static Circular Arcade Physics Bodies now render as circles in the debug display, instead of showing their rectangle bounds (thanks @maikthomas) ### Examples and TypeScript From 274f86cc97c63e15d179c2b7c3a549fb3bb43191 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 20 Nov 2018 10:31:26 +0000 Subject: [PATCH 052/221] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50247fa89..8d19f4205 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,6 +87,7 @@ * When using a Particle Emitter, the array of dead particles (`this.dead`) wasn't being filled correctly. Dead particles are now moved to it as they should be (thanks @Waclaw-I) * The `PathFollower.startFollow` method now properly uses the `startAt` argument to the method, so you can start a follower off at any point along the path. Fix #3688 (thanks @DannyT @diteix) * Static Circular Arcade Physics Bodies now render as circles in the debug display, instead of showing their rectangle bounds (thanks @maikthomas) +* Changing the volume or mute on an `HTML5AudioSound` instance, via the setter, no works, as it does via the Sound Manager (thanks @Waclaw-I) ### Examples and TypeScript From 10878f9c7b416ec667a0bbdff124913de5bf23d9 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 20 Nov 2018 10:33:07 +0000 Subject: [PATCH 053/221] Formatting fix --- src/sound/html5/HTML5AudioSound.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sound/html5/HTML5AudioSound.js b/src/sound/html5/HTML5AudioSound.js index 344317584..49aa1ed22 100644 --- a/src/sound/html5/HTML5AudioSound.js +++ b/src/sound/html5/HTML5AudioSound.js @@ -634,6 +634,7 @@ var HTML5AudioSound = new Class({ { return; } + this.updateMute(); this.emit('mute', this, value); @@ -687,6 +688,7 @@ var HTML5AudioSound = new Class({ { return; } + this.updateVolume(); this.emit('volume', this, value); From ec570a639d28981080c4c6ba5a81cb4b72f89192 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 20 Nov 2018 10:33:09 +0000 Subject: [PATCH 054/221] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d19f4205..13fa9cbb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,7 +87,8 @@ * When using a Particle Emitter, the array of dead particles (`this.dead`) wasn't being filled correctly. Dead particles are now moved to it as they should be (thanks @Waclaw-I) * The `PathFollower.startFollow` method now properly uses the `startAt` argument to the method, so you can start a follower off at any point along the path. Fix #3688 (thanks @DannyT @diteix) * Static Circular Arcade Physics Bodies now render as circles in the debug display, instead of showing their rectangle bounds (thanks @maikthomas) -* Changing the volume or mute on an `HTML5AudioSound` instance, via the setter, no works, as it does via the Sound Manager (thanks @Waclaw-I) +* Changing the mute flag on an `HTML5AudioSound` instance, via the `mute` setter, now works, as it does via the Sound Manager (thanks @Waclaw-I) +* Changing the volume on an `HTML5AudioSound` instance, via the `volume` setter, now works, as it does via the Sound Manager (thanks @Waclaw-I) ### Examples and TypeScript From 8cd45a72b2853f4544976db8f9e12f1f11c48e30 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 20 Nov 2018 11:02:19 +0000 Subject: [PATCH 055/221] ESLint fixes --- CHANGELOG.md | 4 ++-- src/gameobjects/extern/Extern.js | 6 ++++-- src/physics/arcade/PhysicsGroup.js | 2 +- src/renderer/webgl/WebGLRenderer.js | 4 ++-- src/tweens/tween/Tween.js | 3 ++- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13fa9cbb3..298d02453 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,7 @@ ### Updates -* The `backgroundColor` property of the Game Config is now used to set the CSS backgroundColor property of the game Canvas element. This avoids a `fillRect` call in Canvas mode and allows for 'punch through' effects to be created. If `transparent` is true, the CSS property is not set. +* The `backgroundColor` property of the Game Config is now used to set the CSS backgroundColor property of the game Canvas element. This avoids a `fillRect` call in Canvas mode and allows for 'punch through' effects to be created. If `transparent` is true, the CSS property is not set and no background color is drawn in either WebGL or Canvas, allowing the canvas to be fully transparent. * You can now modify `this.physics.world.debugGraphic.defaultStrokeWidth` to set the stroke width of any debug drawn body, previously it was always 1 (thanks @samme) * `TextStyle.setFont` has a new optional argument `updateText` which will sets if the text should be automatically updated or not (thanks @DotTheGreat) * `ProcessQueue.destroy` now sets the internal `toProcess` counter to zero. @@ -87,7 +87,7 @@ * When using a Particle Emitter, the array of dead particles (`this.dead`) wasn't being filled correctly. Dead particles are now moved to it as they should be (thanks @Waclaw-I) * The `PathFollower.startFollow` method now properly uses the `startAt` argument to the method, so you can start a follower off at any point along the path. Fix #3688 (thanks @DannyT @diteix) * Static Circular Arcade Physics Bodies now render as circles in the debug display, instead of showing their rectangle bounds (thanks @maikthomas) -* Changing the mute flag on an `HTML5AudioSound` instance, via the `mute` setter, now works, as it does via the Sound Manager (thanks @Waclaw-I) +* Changing the mute flag on an `HTML5AudioSound` instance, via the `mute` setter, now works, as it does via the Sound Manager (thanks @Waclaw-I @neon-dev) * Changing the volume on an `HTML5AudioSound` instance, via the `volume` setter, now works, as it does via the Sound Manager (thanks @Waclaw-I) ### Examples and TypeScript diff --git a/src/gameobjects/extern/Extern.js b/src/gameobjects/extern/Extern.js index 88fb61dc3..f39a7d2f6 100644 --- a/src/gameobjects/extern/Extern.js +++ b/src/gameobjects/extern/Extern.js @@ -61,14 +61,16 @@ var Extern = new Class({ GameObject.call(this, scene, 'Extern'); }, - preUpdate: function (time, delta) + preUpdate: function () { // override this! + // Arguments: time, delta }, - render: function (renderer, camera, calcMatrix) + render: function () { // override this! + // Arguments: renderer, camera, calcMatrix } }); diff --git a/src/physics/arcade/PhysicsGroup.js b/src/physics/arcade/PhysicsGroup.js index 14556f439..963b6df4b 100644 --- a/src/physics/arcade/PhysicsGroup.js +++ b/src/physics/arcade/PhysicsGroup.js @@ -127,7 +127,7 @@ var PhysicsGroup = new Class({ config = { createCallback: this.createCallbackHandler, removeCallback: this.removeCallbackHandler - } + }; } /** diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index 7a32088b0..2575c1daa 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -62,7 +62,7 @@ var WebGLRenderer = new Class({ var gameConfig = game.config; var contextCreationConfig = { - alpha: true, + alpha: gameConfig.transparent, depth: false, antialias: gameConfig.antialias, premultipliedAlpha: gameConfig.premultipliedAlpha, @@ -556,7 +556,7 @@ var WebGLRenderer = new Class({ gl.enable(gl.BLEND); - // gl.clearColor(clearColor.redGL, clearColor.greenGL, clearColor.blueGL, 1); + gl.clearColor(clearColor.redGL, clearColor.greenGL, clearColor.blueGL, 1); // Initialize all textures to null for (var index = 0; index < this.currentTextures.length; ++index) diff --git a/src/tweens/tween/Tween.js b/src/tweens/tween/Tween.js index a5462730c..ddd35efa3 100644 --- a/src/tweens/tween/Tween.js +++ b/src/tweens/tween/Tween.js @@ -1209,7 +1209,8 @@ var Tween = new Class({ break; } - if (!tweenData.elapsed && tweenData.current) { + if (!tweenData.elapsed && tweenData.current) + { tweenData.elapsed = tweenData.duration * tweenData.current; } From c22edb548aec25e1cf4b95ba6e7dd69ce0bb490c Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 20 Nov 2018 11:07:50 +0000 Subject: [PATCH 056/221] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 298d02453..7b24d18e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,6 +89,7 @@ * Static Circular Arcade Physics Bodies now render as circles in the debug display, instead of showing their rectangle bounds (thanks @maikthomas) * Changing the mute flag on an `HTML5AudioSound` instance, via the `mute` setter, now works, as it does via the Sound Manager (thanks @Waclaw-I @neon-dev) * Changing the volume on an `HTML5AudioSound` instance, via the `volume` setter, now works, as it does via the Sound Manager (thanks @Waclaw-I) +* The Dynamic Tilemap Layer WebGL renderer was drawing tiles at the incorrect position if the layer was scaled. Fix #4104 (thanks @the-realest-stu) ### Examples and TypeScript From 5c45b477b3a32dfaffe0a7822cbea13e8c7562cb Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 20 Nov 2018 12:33:08 +0000 Subject: [PATCH 057/221] Fixed lint errors in #4152 --- src/tilemaps/Tile.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/tilemaps/Tile.js b/src/tilemaps/Tile.js index c6714daba..64d20d405 100644 --- a/src/tilemaps/Tile.js +++ b/src/tilemaps/Tile.js @@ -771,16 +771,24 @@ var Tile = new Class({ * @since 3.0.0 */ tileset: { + get: function () { - var tilemapLayer = this.tilemapLayer; - if (!tilemapLayer) return null; + var tilemapLayer = this.layer.tilemapLayer; - var tileset = tilemapLayer.gidMap[this.index]; - if (!tileset) return null; + if (tilemapLayer) + { + var tileset = tilemapLayer.gidMap[this.index]; - return tileset; + if (tileset) + { + return tileset; + } + } + + return null; } + }, /** From 625955178eab7d38e20b42ddd84ff1aa49ae3f2d Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 20 Nov 2018 12:45:47 +0000 Subject: [PATCH 058/221] Updated docs --- CHANGELOG.md | 4 +++ .../dynamiclayer/DynamicTilemapLayer.js | 36 +++++++------------ 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b24d18e1..501c5a7b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,10 @@ * Changing the mute flag on an `HTML5AudioSound` instance, via the `mute` setter, now works, as it does via the Sound Manager (thanks @Waclaw-I @neon-dev) * Changing the volume on an `HTML5AudioSound` instance, via the `volume` setter, now works, as it does via the Sound Manager (thanks @Waclaw-I) * The Dynamic Tilemap Layer WebGL renderer was drawing tiles at the incorrect position if the layer was scaled. Fix #4104 (thanks @the-realest-stu) +* `Tile.tileset` now returns the specific Tileset associated with the tile, rather than an array of them. Fix #4095 (thanks @quadrupleslap) +* `Tile.getCollisionGroup` wouldn't return the correct Group after the change to support multiple Tilesets. It now returns the group properly (thanks @jbpuryear) +* `Tile.getTileData` wouldn't return the correct data after the change to support multiple Tilesets. It now returns the tile data properly (thanks @jbpuryear) +* The `GetTileAt` and `RemoveTileAt` components would error with "Cannot read property 'index' of undefined" if the tile was undefined rather than null. It now handles both cases (thanks @WaSa42) ### Examples and TypeScript diff --git a/src/tilemaps/dynamiclayer/DynamicTilemapLayer.js b/src/tilemaps/dynamiclayer/DynamicTilemapLayer.js index 71a62e5b1..297af6db6 100644 --- a/src/tilemaps/dynamiclayer/DynamicTilemapLayer.js +++ b/src/tilemaps/dynamiclayer/DynamicTilemapLayer.js @@ -976,10 +976,8 @@ var DynamicTilemapLayer = new Class({ * @since 3.0.0 * * @param {(integer|array)} indexes - Either a single tile index, or an array of tile indexes. - * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear - * collision. - * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the - * update. + * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision. + * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the update. * * @return {Phaser.Tilemaps.DynamicTilemapLayer} This Tilemap Layer object. */ @@ -1001,10 +999,8 @@ var DynamicTilemapLayer = new Class({ * * @param {integer} start - The first index of the tile to be set for collision. * @param {integer} stop - The last index of the tile to be set for collision. - * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear - * collision. - * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the - * update. + * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision. + * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the update. * * @return {Phaser.Tilemaps.DynamicTilemapLayer} This Tilemap Layer object. */ @@ -1027,12 +1023,9 @@ var DynamicTilemapLayer = new Class({ * @method Phaser.Tilemaps.DynamicTilemapLayer#setCollisionByProperty * @since 3.0.0 * - * @param {object} properties - An object with tile properties and corresponding values that should - * be checked. - * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear - * collision. - * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the - * update. + * @param {object} properties - An object with tile properties and corresponding values that should be checked. + * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision. + * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the update. * * @return {Phaser.Tilemaps.DynamicTilemapLayer} This Tilemap Layer object. */ @@ -1052,10 +1045,8 @@ var DynamicTilemapLayer = new Class({ * @since 3.0.0 * * @param {integer[]} indexes - An array of the tile indexes to not be counted for collision. - * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear - * collision. - * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the - * update. + * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision. + * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the update. * * @return {Phaser.Tilemaps.DynamicTilemapLayer} This Tilemap Layer object. */ @@ -1075,10 +1066,8 @@ var DynamicTilemapLayer = new Class({ * @method Phaser.Tilemaps.DynamicTilemapLayer#setCollisionFromCollisionGroup * @since 3.0.0 * - * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear - * collision. - * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the - * update. + * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision. + * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the update. * * @return {Phaser.Tilemaps.DynamicTilemapLayer} This Tilemap Layer object. */ @@ -1098,8 +1087,7 @@ var DynamicTilemapLayer = new Class({ * @method Phaser.Tilemaps.DynamicTilemapLayer#setTileIndexCallback * @since 3.0.0 * - * @param {(integer|array)} indexes - Either a single tile index, or an array of tile indexes to have a - * collision callback set for. + * @param {(integer|array)} indexes - Either a single tile index, or an array of tile indexes to have a collision callback set for. * @param {function} callback - The callback that will be invoked when the tile is collided with. * @param {object} callbackContext - The context under which the callback is called. * From f1fdc5dcf5dfa32b1e1a4eaa70bc29b08ca38483 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 20 Nov 2018 15:32:15 +0000 Subject: [PATCH 059/221] Changing `TileSprite.width` or `TileSprite.height` will now flag the texture as dirty and call `updateDisplayOrigin`, allowing you to resize TileSprites dynamically in both Canvas and WebGL. --- CHANGELOG.md | 1 + src/gameobjects/tilesprite/TileSprite.js | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 501c5a7b7..e5f9f3fd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -94,6 +94,7 @@ * `Tile.getCollisionGroup` wouldn't return the correct Group after the change to support multiple Tilesets. It now returns the group properly (thanks @jbpuryear) * `Tile.getTileData` wouldn't return the correct data after the change to support multiple Tilesets. It now returns the tile data properly (thanks @jbpuryear) * The `GetTileAt` and `RemoveTileAt` components would error with "Cannot read property 'index' of undefined" if the tile was undefined rather than null. It now handles both cases (thanks @WaSa42) +* Changing `TileSprite.width` or `TileSprite.height` will now flag the texture as dirty and call `updateDisplayOrigin`, allowing you to resize TileSprites dynamically in both Canvas and WebGL. ### Examples and TypeScript diff --git a/src/gameobjects/tilesprite/TileSprite.js b/src/gameobjects/tilesprite/TileSprite.js index 64c75e9cd..2efc54e20 100644 --- a/src/gameobjects/tilesprite/TileSprite.js +++ b/src/gameobjects/tilesprite/TileSprite.js @@ -470,6 +470,9 @@ var TileSprite = new Class({ canvas.height = this.height; this.frame.setSize(this.width, this.height); + this.updateDisplayOrigin(); + + this.dirty = true; } if (!this.dirty || this.renderer && this.renderer.gl) From 7c00bd4dc8d95b09e783da1befd604600fa1a55e Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 20 Nov 2018 17:03:22 +0000 Subject: [PATCH 060/221] Added Pointer.velocity and Pointer.angle as they're so common for gesture calculations. --- CHANGELOG.md | 2 ++ src/input/Pointer.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5f9f3fd1..9689fd91e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ * `Pointer.smoothFactor` is a float-value that allows you to automatically apply smoothing to the Pointer position as it moves. This is ideal when you want something smoothly tracking a pointer in a game, or are need a smooth drawing motion for an art package. The default value is zero, meaning disabled. Set to a small number, such as 0.2, to enable. * `Config.inputSmoothFactor` is a new property that allows you to set the smoothing factor for all Pointers the game creators. The default value is zero, which is disabled. Set in the game config as `input: { smoothFactor: value }`. * `InputManager.transformPointer` has a new boolean argument `wasMove`, which controls if the pointer is being transformed after a move or up/down event. +* `Pointer.velocity` is a new Vector2 that contains the velocity of the Pointer, based on the previous and current position. This is updated whenever the Pointer moves, regardless of button states. If you find the velocity is too erratic, consider enabling the `smoothFactor`. +* `Pointer.angle` is a new property that contains the angle of the Pointer, in radians, based on the previous and current position. This is updated whenever the Pointer moves, regardless of button states. If you find the angle is too erratic, consider enabling the `smoothFactor`. ### New Features diff --git a/src/input/Pointer.js b/src/input/Pointer.js index 7cc0797b2..51164d9c2 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -120,6 +120,32 @@ var Pointer = new Class({ */ this.prevPosition = new Vector2(); + /** + * The current velocity of the Pointer, based on its previous and current position. + * + * This is updated whenever the Pointer moves, regardless of the state of any Pointer buttons. + * + * If you are finding the velocity value too erratic, then consider enabling the `Pointer.smoothFactor`. + * + * @name Phaser.Input.Pointer#velocity + * @type {Phaser.Math.Vector2} + * @since 3.16.0 + */ + this.velocity = new Vector2(); + + /** + * The current angle the Pointer is moving, in radians, based on its previous and current position. + * + * This is updated whenever the Pointer moves, regardless of the state of any Pointer buttons. + * + * If you are finding the angle value too erratic, then consider enabling the `Pointer.smoothFactor`. + * + * @name Phaser.Input.Pointer#angle + * @type {number} + * @since 3.16.0 + */ + this.angle = new Vector2(); + /** * The smoothing factor to apply to the Pointer position. * @@ -502,6 +528,16 @@ var Pointer = new Class({ // Sets the local x/y properties this.manager.transformPointer(this, event.pageX, event.pageY, true); + var x1 = this.position.x; + var y1 = this.position.y; + + var x2 = this.prevPosition.x; + var y2 = this.prevPosition.y; + + this.velocity.x = x1 - x2; + this.velocity.y = y1 - y2; + this.angle = Math.atan2(y2 - y1, x2 - x1); + if (this.manager.mouse.locked) { // Multiple DOM events may occur within one frame, but only one Phaser event will fire From 80cd8352dccb7fe3034f03ca0e1852d679ca9b32 Mon Sep 17 00:00:00 2001 From: samme Date: Tue, 20 Nov 2018 16:30:30 -0800 Subject: [PATCH 061/221] Correct docs for Phaser.Boot.Config#audio --- src/boot/Config.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/boot/Config.js b/src/boot/Config.js index 3f92d8d07..b3cec21f0 100644 --- a/src/boot/Config.js +++ b/src/boot/Config.js @@ -32,15 +32,13 @@ var ValueToColor = require('../display/color/ValueToColor'); /** * Config object containing various sound settings. * - * @typedef {object} SoundConfig + * @typedef {object} AudioConfig * - * @property {boolean} [mute=false] - Boolean indicating whether the sound should be muted or not. - * @property {number} [volume=1] - A value between 0 (silence) and 1 (full volume). - * @property {number} [rate=1] - Defines the speed at which the sound should be played. - * @property {number} [detune=0] - Represents detuning of sound in [cents](https://en.wikipedia.org/wiki/Cent_%28music%29). - * @property {number} [seek=0] - Position of playback for this sound, in seconds. - * @property {boolean} [loop=false] - Whether or not the sound or current sound marker should loop. - * @property {number} [delay=0] - Time, in seconds, that should elapse before the sound actually starts its playback. + * @property {boolean} [disableWebAudio=false] - Use HTML5 Audio instead of Web Audio. + * @property {AudioContext} [context] - An existing Web Audio context. + * @property {boolean} [noAudio=false] - Disable all audio output. + * + * @see Phaser.Sound.SoundManagerCreator */ /** @@ -494,7 +492,7 @@ var Config = new Class({ this.disableContextMenu = GetValue(config, 'disableContextMenu', false); /** - * @const {SoundConfig} Phaser.Boot.Config#audio - The Audio Configuration object. + * @const {AudioConfig} Phaser.Boot.Config#audio - The Audio Configuration object. */ this.audio = GetValue(config, 'audio'); From ab85d480a7d9b5f6fce8bb02f1a75113db24e2ec Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 21 Nov 2018 02:24:54 +0000 Subject: [PATCH 062/221] Added setState method. --- CHANGELOG.md | 1 + src/gameobjects/GameObject.js | 28 ++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9689fd91e..69499f103 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ * The WebGL Renderer has a new method `clearPipeline`, which will clear down the current pipeline and reset the blend mode, ready for the context to be passed to a 3rd party library. * The WebGL Renderer has a new method `rebindPipeline`, which will rebind the given pipeline instance, reset the blank texture and reset the blend mode. Which is useful for recovering from 3rd party libs that have modified the gl context. * Game Objects have a new property called `state`. Use this to track the state of a Game Object during its lifetime. For example, it could move from a state of 'moving', to 'attacking', to 'dead'. Phaser itself will never set this property, although plugins are allowed to. +* Game Objects have a new method called `setState` which will set the state property in a chainable call. * `BlendModes.ERASE` is a new blend mode that will erase the object being drawn. When used in conjunction with a Render Texture it allows for effects that let you erase parts of the texture, in either Canvas or WebGL. When used with a transparent game canvas, it allows you to erase parts of the canvas, showing the web page background through. * `BlendModes.SOURCE_IN` is a new Canvas-only blend mode, that allows you to use the `source-in` composite operation when rendering Game Objects. * `BlendModes.SOURCE_OUT` is a new Canvas-only blend mode, that allows you to use the `source-out` composite operation when rendering Game Objects. diff --git a/src/gameobjects/GameObject.js b/src/gameobjects/GameObject.js index fa0faa868..c2f168223 100644 --- a/src/gameobjects/GameObject.js +++ b/src/gameobjects/GameObject.js @@ -61,8 +61,8 @@ var GameObject = new Class({ * Phaser itself will never modify this value, although plugins may do so. * * Use this property to track the state of a Game Object during its lifetime. For example, it could move from - * a state of 'moving', to 'attacking', to 'dead'. The state value should typically be an integer (ideally mapped to a constant - * in your game code), but could also be a string, or any other data-type. It is recommended to keep it light and simple. + * a state of 'moving', to 'attacking', to 'dead'. The state value should be an integer (ideally mapped to a constant + * in your game code), or a string. These are recommended to keep it light and simple, with fast comparisons. * If you need to store complex data about your Game Object, look at using the Data Component instead. * * @name Phaser.GameObjects.GameObject#state @@ -227,6 +227,30 @@ var GameObject = new Class({ return this; }, + /** + * Sets the current state of this Game Object. + * + * Phaser itself will never modify the State of a Game Object, although plugins may do so. + * + * For example, a Game Object could change from a state of 'moving', to 'attacking', to 'dead'. + * The state value should typically be an integer (ideally mapped to a constant + * in your game code), but could also be a string. It is recommended to keep it light and simple. + * If you need to store complex data about your Game Object, look at using the Data Component instead. + * + * @method Phaser.GameObjects.GameObject#setState + * @since 3.16.0 + * + * @param {(integer|string)} value - The state of the Game Object. + * + * @return {this} This GameObject. + */ + setState: function (value) + { + this.state = value; + + return this; + }, + /** * Adds a Data Manager component to this Game Object. * From db0be547371fd42a798a06811bb4cc68b3b00f46 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 21 Nov 2018 10:17:48 +0000 Subject: [PATCH 063/221] Fixed breaking Tween loop change and implemented PathFollower startAt in a slightly different way --- src/gameobjects/pathfollower/PathFollower.js | 17 ++++++++++++++++- src/tweens/builders/NumberTweenBuilder.js | 3 +-- src/tweens/tween/Tween.js | 8 +------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/gameobjects/pathfollower/PathFollower.js b/src/gameobjects/pathfollower/PathFollower.js index 28ee8fd76..07c9c6706 100644 --- a/src/gameobjects/pathfollower/PathFollower.js +++ b/src/gameobjects/pathfollower/PathFollower.js @@ -246,7 +246,6 @@ var PathFollower = new Class({ // Override in case they've been specified in the config config.from = 0; config.to = 1; - config.startAt = startAt; // Can also read extra values out of the config: @@ -255,6 +254,22 @@ var PathFollower = new Class({ this.rotateToPath = GetBoolean(config, 'rotateToPath', false); this.pathRotationOffset = GetValue(config, 'rotationOffset', 0); + // This works, but it's not an ideal way of doing it as the follower jumps position + var seek = GetValue(config, 'startAt', startAt); + + if (seek) + { + config.onStart = function (tween) + { + var tweenData = tween.data[0]; + tweenData.progress = seek; + tweenData.elapsed = tweenData.duration * seek; + var v = tweenData.ease(tweenData.progress); + tweenData.current = tweenData.start + ((tweenData.end - tweenData.start) * v); + tweenData.target[tweenData.key] = tweenData.current; + }; + } + this.pathTween = this.scene.sys.tweens.addCounter(config); // The starting point of the path, relative to this follower diff --git a/src/tweens/builders/NumberTweenBuilder.js b/src/tweens/builders/NumberTweenBuilder.js index 9ee7fe978..151665b8b 100644 --- a/src/tweens/builders/NumberTweenBuilder.js +++ b/src/tweens/builders/NumberTweenBuilder.js @@ -45,7 +45,6 @@ var NumberTweenBuilder = function (parent, config, defaults) var from = GetValue(config, 'from', 0); var to = GetValue(config, 'to', 1); - var current = GetValue(config, 'startAt', from); var targets = [ { value: from } ]; @@ -79,7 +78,7 @@ var NumberTweenBuilder = function (parent, config, defaults) ); tweenData.start = from; - tweenData.current = current; + tweenData.current = from; tweenData.to = to; data.push(tweenData); diff --git a/src/tweens/tween/Tween.js b/src/tweens/tween/Tween.js index ddd35efa3..23b36650f 100644 --- a/src/tweens/tween/Tween.js +++ b/src/tweens/tween/Tween.js @@ -1183,7 +1183,6 @@ var Tween = new Class({ return TWEEN_CONST.COMPLETE; }, - // /** * [description] * @@ -1208,11 +1207,6 @@ var Tween = new Class({ tweenData.state = TWEEN_CONST.COMPLETE; break; } - - if (!tweenData.elapsed && tweenData.current) - { - tweenData.elapsed = tweenData.duration * tweenData.current; - } var elapsed = tweenData.elapsed; var duration = tweenData.duration; @@ -1324,7 +1318,7 @@ var Tween = new Class({ tweenData.end = tweenData.getEndValue(tweenData.target, tweenData.key, tweenData.start); - tweenData.current = tweenData.current || tweenData.start; + tweenData.current = tweenData.start; tweenData.target[tweenData.key] = tweenData.start; From dbdfb0e95c1557e0a9b328928a6753f8e0e0ce3f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 21 Nov 2018 11:23:48 +0000 Subject: [PATCH 064/221] `RandomDataGenerator.shuffle` has been fixed to use the proper modifier in the calculation, allowing for a more even distribution --- src/math/random-data-generator/RandomDataGenerator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/random-data-generator/RandomDataGenerator.js b/src/math/random-data-generator/RandomDataGenerator.js index 2bc45ae6d..5b1e6efe4 100644 --- a/src/math/random-data-generator/RandomDataGenerator.js +++ b/src/math/random-data-generator/RandomDataGenerator.js @@ -478,7 +478,7 @@ var RandomDataGenerator = new Class({ for (var i = len; i > 0; i--) { - var randomIndex = Math.floor(this.frac() * (len + 1)); + var randomIndex = Math.floor(this.frac() * (i + 1)); var itemAtIndex = array[randomIndex]; array[randomIndex] = array[i]; From fca695f63265eafcc1ac34e7d5b8eec0030d7fb8 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 21 Nov 2018 11:53:21 +0000 Subject: [PATCH 065/221] Removed Particle.index as it's no longer required --- src/gameobjects/particles/Particle.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/gameobjects/particles/Particle.js b/src/gameobjects/particles/Particle.js index 1d577e580..cfdd5e800 100644 --- a/src/gameobjects/particles/Particle.js +++ b/src/gameobjects/particles/Particle.js @@ -47,16 +47,6 @@ var Particle = new Class({ */ this.frame = null; - /** - * The position of this Particle within its Emitter's particle pool. - * - * @name Phaser.GameObjects.Particles.Particle#index - * @type {number} - * @default 0 - * @since 3.0.0 - */ - this.index = 0; - /** * The x coordinate of this Particle. * @@ -276,6 +266,18 @@ var Particle = new Class({ return (this.lifeCurrent > 0); }, + /** + * Resets the position of this particle back to zero. + * + * @method Phaser.GameObjects.Particles.Particle#resetPosition + * @since 3.16.0 + */ + resetPosition: function () + { + this.x = 0; + this.y = 0; + }, + /** * Starts this Particle from the given coordinates. * @@ -382,8 +384,6 @@ var Particle = new Class({ this.alpha = emitter.alpha.onEmit(this, 'alpha'); this.tint = emitter.tint.onEmit(this, 'tint'); - - this.index = emitter.alive.length; }, /** From 18af31ffb762c66ea0be3022d1c0d045e66881e6 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 21 Nov 2018 11:53:46 +0000 Subject: [PATCH 066/221] Fixed how dead particles are managed, reduced gc churn and reset particle positions. Also removed un-needed stable sort. --- src/gameobjects/particles/ParticleEmitter.js | 70 ++++++++------------ 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/src/gameobjects/particles/ParticleEmitter.js b/src/gameobjects/particles/ParticleEmitter.js index c3cb9692a..71b3f3567 100644 --- a/src/gameobjects/particles/ParticleEmitter.js +++ b/src/gameobjects/particles/ParticleEmitter.js @@ -2012,13 +2012,9 @@ var ParticleEmitter = new Class({ for (var i = 0; i < count; i++) { - var particle; + var particle = dead.pop(); - if (dead.length > 0) - { - particle = dead.pop(); - } - else + if (!particle) { particle = new this.particleClass(this); } @@ -2073,47 +2069,49 @@ var ParticleEmitter = new Class({ var processors = this.manager.getProcessors(); var particles = this.alive; + var dead = this.dead; + + var i = 0; + var rip = []; var length = particles.length; - for (var index = 0; index < length; index++) + for (i = 0; i < length; i++) { - var particle = particles[index]; + var particle = particles[i]; - // update returns `true` if the particle is now dead (lifeStep < 0) + // update returns `true` if the particle is now dead (lifeCurrent <= 0) if (particle.update(delta, step, processors)) { - // Moves the dead particle to the end of the particles array (ready for splicing out later) - var last = particles[length - 1]; - - particles[length - 1] = particle; - particles[index] = last; - - index -= 1; - length -= 1; + rip.push({ index: i, particle: particle }); } } // Move dead particles to the dead array - var deadLength = particles.length - length; + length = rip.length; - if (deadLength > 0) + if (length > 0) { - var rip = particles.splice(particles.length - deadLength, deadLength); - var deathCallback = this.deathCallback; var deathCallbackScope = this.deathCallbackScope; - if (deathCallback) + for (i = length - 1; i >= 0; i--) { - for (var i = 0; i < rip.length; i++) + var entry = rip[i]; + + // Remove from particles array + particles.splice(entry.index, 1); + + // Add to dead array + dead.push(entry.particle); + + // Callback + if (deathCallback) { - deathCallback.call(deathCallbackScope, rip[i]); + deathCallback.call(deathCallbackScope, entry.particle); } + + entry.particle.resetPosition(); } - - this.dead = this.dead.concat(rip); - - StableSort.inplace(particles, this.indexSortCallback); } if (!this.on) @@ -2153,22 +2151,6 @@ var ParticleEmitter = new Class({ depthSortCallback: function (a, b) { return a.y - b.y; - }, - - /** - * Calculates the difference of two particles, for sorting them by index. - * - * @method Phaser.GameObjects.Particles.ParticleEmitter#indexSortCallback - * @since 3.0.0 - * - * @param {object} a - The first particle. - * @param {object} b - The second particle. - * - * @return {integer} The difference of a and b's `index` properties. - */ - indexSortCallback: function (a, b) - { - return a.index - b.index; } }); From 31e0f9595474a1fe1af87a3d55f56a8c3a39904c Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 21 Nov 2018 11:53:50 +0000 Subject: [PATCH 067/221] Update CHANGELOG.md --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69499f103..b26e930a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,7 +87,6 @@ * Starting with version 3.13 in the Canvas Renderer, it was possible for long-running scripts to start to get bogged-down in `fillRect` calls if the game had a background color set. The context is now saved properly to avoid this. Fix #4056 (thanks @Aveyder) * Render Textures created larger than the size of the default canvas would be automatically clipped when drawn to in WebGL. They now reset the gl scissor and drawing height property in order to draw to their full size, regardless of the canvas size. Fix #4139 (thanks @chaoyang805 @iamchristopher) * The `cameraFilter` property of a Game Object will now allow full bitmasks to be set (a value of -1), instead of just those > 0 (thanks @stuartkeith) -* When using a Particle Emitter, the array of dead particles (`this.dead`) wasn't being filled correctly. Dead particles are now moved to it as they should be (thanks @Waclaw-I) * The `PathFollower.startFollow` method now properly uses the `startAt` argument to the method, so you can start a follower off at any point along the path. Fix #3688 (thanks @DannyT @diteix) * Static Circular Arcade Physics Bodies now render as circles in the debug display, instead of showing their rectangle bounds (thanks @maikthomas) * Changing the mute flag on an `HTML5AudioSound` instance, via the `mute` setter, now works, as it does via the Sound Manager (thanks @Waclaw-I @neon-dev) @@ -98,6 +97,12 @@ * `Tile.getTileData` wouldn't return the correct data after the change to support multiple Tilesets. It now returns the tile data properly (thanks @jbpuryear) * The `GetTileAt` and `RemoveTileAt` components would error with "Cannot read property 'index' of undefined" if the tile was undefined rather than null. It now handles both cases (thanks @WaSa42) * Changing `TileSprite.width` or `TileSprite.height` will now flag the texture as dirty and call `updateDisplayOrigin`, allowing you to resize TileSprites dynamically in both Canvas and WebGL. +* `RandomDataGenerator.shuffle` has been fixed to use the proper modifier in the calculation, allowing for a more even distribution (thanks wayfinder) +* The Particle Emitter was not recycling dead particles correctly, so it was creating new objects every time it emitted (the old particles were then left to the browsers gc to clear up). This has now been recoded, so the emitter will properly keep track of dead particles and re-use them (thanks @Waclaw-I for the initial PR) +* `ParticleEmitter.indexSortCallback` has been removed as it's no longer required. +* `Particle.index` has been removed, as it's no longer required. Particles don't need to keep track of their index any more. +* The Particle Emitter no longer needs to call the StableSort.inplace during its preUpdate, saving cpu. +* `Particle.resetPosition` is a new method that is called when a particle dies, preparing it ready for firing again in the future. ### Examples and TypeScript From e181a98aa2961288b0f2a2cda8c8cded781762c2 Mon Sep 17 00:00:00 2001 From: Taran van Groenigen Date: Thu, 22 Nov 2018 09:40:10 +0100 Subject: [PATCH 068/221] Fixed a mistake that would cause fontFamily to hold all font data when using the font shorthand & fixes photonstorm/phaser#4141 I noticed this while investigating photonstorm/phaser#4141 --- src/gameobjects/text/TextStyle.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gameobjects/text/TextStyle.js b/src/gameobjects/text/TextStyle.js index 4d0206c9c..bb9ab95b8 100644 --- a/src/gameobjects/text/TextStyle.js +++ b/src/gameobjects/text/TextStyle.js @@ -537,9 +537,9 @@ var TextStyle = new Class({ var i = 0; - this.fontStyle = (fontSplit.length > 2) ? fontSplit[i++] : ''; - this.fontSize = fontSplit[i++] || '16px'; - this.fontFamily = fontSplit[i++] || 'Courier'; + fontStyle = (fontSplit.length > 2) ? fontSplit[i++] : ''; + fontSize = fontSplit[i++] || '16px'; + fontFamily = fontSplit[i++] || 'Courier'; } if (fontFamily !== this.fontFamily || fontSize !== this.fontSize || fontStyle !== this.fontStyle) From d6bee1bbd1f8e425787069b3211f7bdff759c4eb Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 22 Nov 2018 17:18:31 +0000 Subject: [PATCH 069/221] Working through event debugging - don't pull this version unless you want logs everywhere! --- src/boot/Game.js | 4 + src/const.js | 2 +- src/input/InputManager.js | 126 +++++++++++++++-------------- src/input/InputPlugin.js | 10 +-- src/input/Pointer.js | 50 +++++++++--- src/input/mouse/MouseManager.js | 136 ++++++++++++++++++++++++++++++++ 6 files changed, 252 insertions(+), 76 deletions(-) diff --git a/src/boot/Game.js b/src/boot/Game.js index 628b80aaa..3fd83e618 100644 --- a/src/boot/Game.js +++ b/src/boot/Game.js @@ -340,6 +340,8 @@ var Game = new Class({ */ this.isOver = true; + this.frame = 0; + // Wait for the DOM Ready event, then call boot. DOMContentLoaded(this.boot.bind(this)); }, @@ -574,6 +576,8 @@ var Game = new Class({ // The final event before the step repeats. Your last chance to do anything to the canvas before it all starts again. eventEmitter.emit('postrender', renderer, time, delta); + + this.frame++; }, /** diff --git a/src/const.js b/src/const.js index 32742e231..dcbbc7d1d 100644 --- a/src/const.js +++ b/src/const.js @@ -20,7 +20,7 @@ var CONST = { * @type {string} * @since 3.0.0 */ - VERSION: '3.16.0 Beta 2', + VERSION: '3.16.0 Beta 3', BlendModes: require('./renderer/BlendModes'), diff --git a/src/input/InputManager.js b/src/input/InputManager.js index 24f91571b..32477a8da 100644 --- a/src/input/InputManager.js +++ b/src/input/InputManager.js @@ -427,7 +427,7 @@ var InputManager = new Class({ * * @param {number} time - The time stamp value of this game step. */ - update: function (time) + update: function (time, delta) { var i; @@ -443,69 +443,79 @@ var InputManager = new Class({ var pointers = this.pointers; + this.mouse.pre(); + for (i = 0; i < this.pointersTotal; i++) { - pointers[i].reset(); + pointers[i].reset(delta); } - if (!this.enabled || len === 0) + // if (!this.enabled || len === 0) + // { + // return; + // } + + if (this.enabled && len > 0) { - return; - } + this.dirty = true; - this.dirty = true; - - this.updateBounds(); - - this.scale.x = this.game.config.width / this.bounds.width; - this.scale.y = this.game.config.height / this.bounds.height; - - // Clears the queue array, and also means we don't work on array data that could potentially - // be modified during the processing phase - var queue = this.queue.splice(0, len); - var mouse = this.mousePointer; - - // Process the event queue, dispatching all of the events that have stored up - for (i = 0; i < len; i += 2) - { - var type = queue[i]; - var event = queue[i + 1]; - - switch (type) + this.updateBounds(); + + this.scale.x = this.game.config.width / this.bounds.width; + this.scale.y = this.game.config.height / this.bounds.height; + + // Clears the queue array, and also means we don't work on array data that could potentially + // be modified during the processing phase + var queue = this.queue.splice(0, len); + var mouse = this.mousePointer; + + // Process the event queue, dispatching all of the events that have stored up + for (i = 0; i < len; i += 2) { - case CONST.MOUSE_DOWN: - mouse.down(event, time); - break; - - case CONST.MOUSE_MOVE: - mouse.move(event, time); - break; - - case CONST.MOUSE_UP: - mouse.up(event, time); - break; - - case CONST.TOUCH_START: - this.startPointer(event, time); - break; - - case CONST.TOUCH_MOVE: - this.updatePointer(event, time); - break; - - case CONST.TOUCH_END: - this.stopPointer(event, time); - break; - - case CONST.TOUCH_CANCEL: - this.cancelPointer(event, time); - break; - - case CONST.POINTER_LOCK_CHANGE: - this.events.emit('pointerlockchange', event, this.mouse.locked); - break; + var type = queue[i]; + var event = queue[i + 1]; + + switch (type) + { + case CONST.MOUSE_DOWN: + mouse.down(event, time); + break; + + case CONST.MOUSE_MOVE: + mouse.move(event, time); + break; + + case CONST.MOUSE_UP: + mouse.up(event, time); + break; + + case CONST.TOUCH_START: + this.startPointer(event, time); + break; + + case CONST.TOUCH_MOVE: + this.updatePointer(event, time); + break; + + case CONST.TOUCH_END: + this.stopPointer(event, time); + break; + + case CONST.TOUCH_CANCEL: + this.cancelPointer(event, time); + break; + + case CONST.POINTER_LOCK_CHANGE: + this.events.emit('pointerlockchange', event, this.mouse.locked); + break; + } } } + + for (i = 0; i < this.pointersTotal; i++) + { + pointers[i].updateMotion(); + } }, /** @@ -525,6 +535,8 @@ var InputManager = new Class({ { this.canvas.style.cursor = this.defaultCursor; } + + this.mouse.post(); }, /** @@ -1323,10 +1335,6 @@ var InputManager = new Class({ var p0 = pointer.position; var p1 = pointer.prevPosition; - // Store previous position - p1.x = p0.x; - p1.y = p0.y; - // Translate coordinates var x = (pageX - this.bounds.left) * this.scale.x; var y = (pageY - this.bounds.top) * this.scale.y; diff --git a/src/input/InputPlugin.js b/src/input/InputPlugin.js index 5a55b9022..35c1b10f9 100644 --- a/src/input/InputPlugin.js +++ b/src/input/InputPlugin.js @@ -548,16 +548,16 @@ var InputPlugin = new Class({ total += this.processDownEvents(pointer); } - if (pointer.justUp) - { - total += this.processUpEvents(pointer); - } - if (pointer.justMoved) { total += this.processMoveEvents(pointer); } + if (pointer.justUp) + { + total += this.processUpEvents(pointer); + } + if (total > 0 && manager.globalTopOnly) { // We interacted with an event in this Scene, so block any Scenes below us from doing the same this frame diff --git a/src/input/Pointer.js b/src/input/Pointer.js index 51164d9c2..aa032edd8 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -389,6 +389,10 @@ var Pointer = new Class({ * @since 3.10.0 */ this.active = (id === 0) ? true : false; + + this.deltaTime = 0; + this.prevDeltaTime = Date.now(); + this.speed = 0; }, /** @@ -416,7 +420,7 @@ var Pointer = new Class({ * @private * @since 3.0.0 */ - reset: function () + reset: function (now) { this.dirty = false; @@ -426,6 +430,40 @@ var Pointer = new Class({ this.movementX = 0; this.movementY = 0; + + this.deltaTime = now; + + // this.velocity.x = 0; + // this.velocity.y = 0; + }, + + updateMotion: function () + { + var x1 = this.position.x; + var y1 = this.position.y; + + var x2 = this.prevPosition.x; + var y2 = this.prevPosition.y; + + var deltaX = x1 - x2; + var deltaY = y1 - y2; + + this.velocity.x = deltaX / this.deltaTime || 0; + this.velocity.y = deltaY / this.deltaTime || 0; + this.speed = (Math.abs(this.velocity.x) > Math.abs(this.velocity.y)) ? this.velocity.x : this.velocity.y; + + /* + this.velocity.x = x1 - x2; + this.velocity.y = y1 - y2; + + this.angle = Math.atan2(y2 - y1, x2 - x1); + */ + + // Store previous position + this.prevPosition.x = this.position.x; + this.prevPosition.y = this.position.y; + + this.prevDeltaTime = this.deltaTime; }, /** @@ -528,16 +566,6 @@ var Pointer = new Class({ // Sets the local x/y properties this.manager.transformPointer(this, event.pageX, event.pageY, true); - var x1 = this.position.x; - var y1 = this.position.y; - - var x2 = this.prevPosition.x; - var y2 = this.prevPosition.y; - - this.velocity.x = x1 - x2; - this.velocity.y = y1 - y2; - this.angle = Math.atan2(y2 - y1, x2 - x1); - if (this.manager.mouse.locked) { // Multiple DOM events may occur within one frame, but only one Phaser event will fire diff --git a/src/input/mouse/MouseManager.js b/src/input/mouse/MouseManager.js index 863fcd1e6..c8f2aca8b 100644 --- a/src/input/mouse/MouseManager.js +++ b/src/input/mouse/MouseManager.js @@ -8,6 +8,9 @@ var Class = require('../../utils/Class'); var Features = require('../../device/Features'); var NOOP = require('../../utils/Class'); +var Linear = require('../../math/Linear'); +var FuzzyEqual = require('../../math/fuzzy/Equal'); + // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md @@ -126,6 +129,27 @@ var MouseManager = new Class({ */ this.pointerLockChange = NOOP; + this.prevTime = 0; + this.currentTime = 0; + this.deltaTime = 0; + this.deltaX = 0; + this.deltaY = 0; + + this.mx = 0; + this.my = 0; + this.prevX = -1; + this.prevY = -1; + this.currentX = -1; + this.currentY = -1; + this.isMoving = false; + + this.upX = 0; + this.upY = 0; + + this.counter = 0; + + this.moveFrame = 0; + inputManager.events.once('boot', this.boot, this); }, @@ -247,6 +271,49 @@ var MouseManager = new Class({ return; } + _this.currentTime = event.timeStamp; + + // Apply smoothing + + // var x = event.pageX - _this.manager.bounds.left; + // var y = event.pageY - _this.manager.bounds.top; + + var x = event.pageX - _this.manager.bounds.left; + var y = event.pageY - _this.manager.bounds.top; + var a = 0.2; + + if (_this.prevX === -1) + { + _this.currentX = x; + _this.currentY = y; + + _this.prevX = x; + _this.prevY = y; + } + else + { + _this.prevX = _this.currentX; + _this.prevY = _this.currentY; + + // _this.currentX = x * a + _this.prevX * (1 - a); + // _this.currentY = y * a + _this.prevY * (1 - a); + + _this.currentX = x; + _this.currentY = y; + } + + _this.deltaX = _this.currentX - _this.prevX; + _this.deltaY = _this.currentY - _this.prevY; + + // console.log('move', _this.moveFrame, _this.deltaX, _this.deltaY); + + // _this.mx = Math.max(Math.abs(_this.deltaX), _this.mx); + // _this.my = Math.max(Math.abs(_this.deltaY), _this.my); + + _this.moveFrame = _this.manager.game.frame; + + _this.counter++; + _this.manager.queueMouseMove(event); if (_this.capture) @@ -263,6 +330,19 @@ var MouseManager = new Class({ return; } + _this.currentTime = event.timeStamp; + + console.log('mdown', _this.moveFrame, _this.manager.game.frame, '=', _this.deltaX, _this.deltaY); + + // _this.prevX = _this.currentX; + // _this.prevY = _this.currentY; + + // _this.currentX = event.pageX - _this.manager.bounds.left; + // _this.currentY = event.pageY - _this.manager.bounds.top; + + // _this.deltaX = _this.currentX - _this.prevX; + // _this.deltaY = _this.currentY - _this.prevY; + _this.manager.queueMouseDown(event); if (_this.capture) @@ -279,6 +359,22 @@ var MouseManager = new Class({ return; } + _this.currentTime = event.timeStamp; + + _this.upX = _this.deltaX; + _this.upY = _this.deltaY; + + console.log('mup', _this.moveFrame, _this.manager.game.frame, '=', _this.deltaX, _this.deltaY, 'mc', _this.counter); + + // _this.prevX = _this.currentX; + // _this.prevY = _this.currentY; + + // _this.currentX = event.pageX - _this.manager.bounds.left; + // _this.currentY = event.pageY - _this.manager.bounds.top; + + // _this.deltaX = _this.currentX - _this.prevX; + // _this.deltaY = _this.currentY - _this.prevY; + _this.manager.queueMouseUp(event); if (_this.capture) @@ -329,6 +425,46 @@ var MouseManager = new Class({ this.enabled = true; }, + pre: function () + { + // calculate deltas + this.deltaTime = this.currentTime - this.prevTime; + }, + + post: function () + { + return; + + // reset + this.prevTime = this.currentTime; + + if (this.deltaX !== 0) + { + this.deltaX *= 0.95; + + // this.deltaX = Linear(0, this.deltaX, 0.999); + + if (FuzzyEqual(this.deltaX, 0, 0.1)) + { + this.deltaX = 0; + } + } + + if (this.deltaY !== 0) + { + this.deltaY *= 0.95; + + // this.deltaY = Linear(0, this.deltaY, 0.999); + + if (FuzzyEqual(this.deltaY, 0, 0.1)) + { + this.deltaY = 0; + } + } + + this.isMoving = (this.deltaX !== 0 || this.deltaY !== 0); + }, + /** * Stops the Mouse Event listeners. * This is called automatically and does not need to be manually invoked. From 19a0638fb37514f6d0cbed69e40457fbeff64cb6 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 23 Nov 2018 16:19:18 +0000 Subject: [PATCH 070/221] Added Game.getFrame and Game.getTime methods. --- src/boot/Game.js | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/boot/Game.js b/src/boot/Game.js index 3fd83e618..12e953bf2 100644 --- a/src/boot/Game.js +++ b/src/boot/Game.js @@ -340,8 +340,6 @@ var Game = new Class({ */ this.isOver = true; - this.frame = 0; - // Wait for the DOM Ready event, then call boot. DOMContentLoaded(this.boot.bind(this)); }, @@ -576,8 +574,6 @@ var Game = new Class({ // The final event before the step repeats. Your last chance to do anything to the canvas before it all starts again. eventEmitter.emit('postrender', renderer, time, delta); - - this.frame++; }, /** @@ -747,6 +743,34 @@ var Game = new Class({ this.events.emit('resize', width, height); }, + /** + * Returns the current game frame. + * When the game starts running, the frame is incremented every time Request Animation Frame, or Set Timeout, fires. + * + * @method Phaser.Game#getFrame + * @since 3.16.0 + * + * @return {number} The current game frame. + */ + getFrame: function () + { + return this.loop.frame; + }, + + /** + * Returns the current game timestamp. + * When the game starts running, the frame is incremented every time Request Animation Frame, or Set Timeout, fires. + * + * @method Phaser.Game#getTime + * @since 3.16.0 + * + * @return {number} The current game timestamp. + */ + getTime: function () + { + return this.loop.frame.time; + }, + /** * Game Destroy event. * From 50a167a960c8788f60936cf64852af6ccc0b72f6 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 23 Nov 2018 16:19:44 +0000 Subject: [PATCH 071/221] Fixed issue with seamless delta reset and moved frame increment to below callback --- src/boot/TimeStep.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/boot/TimeStep.js b/src/boot/TimeStep.js index f2415a6f7..e3da9403f 100644 --- a/src/boot/TimeStep.js +++ b/src/boot/TimeStep.js @@ -445,13 +445,11 @@ var TimeStep = new Class({ * * @method Phaser.Boot.TimeStep#step * @since 3.0.0 - * + * * @param {number} time - The current time. Either a High Resolution Timer value if it comes from Request Animation Frame, or Date.now if using SetTimeout. */ step: function (time) { - this.frame++; - var before = time - this.lastTime; if (before < 0) @@ -561,6 +559,8 @@ var TimeStep = new Class({ // Shift time value over this.lastTime = time; + + this.frame++; }, /** @@ -607,7 +607,7 @@ var TimeStep = new Class({ } else if (seamless) { - this.startTime += -this.lastTime + (this.lastTime = window.performance.now()); + this.startTime += -this.lastTime + (this.lastTime + window.performance.now()); } this.raf.start(this.step.bind(this), this.useRAF); From 4681bb888d574b485ce0ab405031ac6e31f9c437 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 23 Nov 2018 16:20:26 +0000 Subject: [PATCH 072/221] Moved request below callback. Ignore the argument and use performance.now instead for consistency with input events. --- src/dom/RequestAnimationFrame.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/dom/RequestAnimationFrame.js b/src/dom/RequestAnimationFrame.js index f66934fc3..e101a0e8c 100644 --- a/src/dom/RequestAnimationFrame.js +++ b/src/dom/RequestAnimationFrame.js @@ -92,16 +92,19 @@ var RequestAnimationFrame = new Class({ * @type {FrameRequestCallback} * @since 3.0.0 */ - this.step = function step (timestamp) + this.step = function step () { + // Because we cannot trust the time passed to this callback from the browser and need it kept in sync with event times + var timestamp = window.performance.now(); + // DOMHighResTimeStamp _this.lastTime = _this.tick; _this.tick = timestamp; - _this.timeOutID = window.requestAnimationFrame(step); - _this.callback(timestamp); + + _this.timeOutID = window.requestAnimationFrame(step); }; /** @@ -122,9 +125,9 @@ var RequestAnimationFrame = new Class({ _this.tick = d; - _this.timeOutID = window.setTimeout(stepTimeout, delay); - _this.callback(d); + + _this.timeOutID = window.setTimeout(stepTimeout, delay); }; }, From 69a0dcc9cffd25d804f632b9d161e98dc736a5b3 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 23 Nov 2018 16:23:47 +0000 Subject: [PATCH 073/221] Remove debug data. --- src/input/mouse/MouseManager.js | 136 -------------------------------- 1 file changed, 136 deletions(-) diff --git a/src/input/mouse/MouseManager.js b/src/input/mouse/MouseManager.js index c8f2aca8b..863fcd1e6 100644 --- a/src/input/mouse/MouseManager.js +++ b/src/input/mouse/MouseManager.js @@ -8,9 +8,6 @@ var Class = require('../../utils/Class'); var Features = require('../../device/Features'); var NOOP = require('../../utils/Class'); -var Linear = require('../../math/Linear'); -var FuzzyEqual = require('../../math/fuzzy/Equal'); - // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md @@ -129,27 +126,6 @@ var MouseManager = new Class({ */ this.pointerLockChange = NOOP; - this.prevTime = 0; - this.currentTime = 0; - this.deltaTime = 0; - this.deltaX = 0; - this.deltaY = 0; - - this.mx = 0; - this.my = 0; - this.prevX = -1; - this.prevY = -1; - this.currentX = -1; - this.currentY = -1; - this.isMoving = false; - - this.upX = 0; - this.upY = 0; - - this.counter = 0; - - this.moveFrame = 0; - inputManager.events.once('boot', this.boot, this); }, @@ -271,49 +247,6 @@ var MouseManager = new Class({ return; } - _this.currentTime = event.timeStamp; - - // Apply smoothing - - // var x = event.pageX - _this.manager.bounds.left; - // var y = event.pageY - _this.manager.bounds.top; - - var x = event.pageX - _this.manager.bounds.left; - var y = event.pageY - _this.manager.bounds.top; - var a = 0.2; - - if (_this.prevX === -1) - { - _this.currentX = x; - _this.currentY = y; - - _this.prevX = x; - _this.prevY = y; - } - else - { - _this.prevX = _this.currentX; - _this.prevY = _this.currentY; - - // _this.currentX = x * a + _this.prevX * (1 - a); - // _this.currentY = y * a + _this.prevY * (1 - a); - - _this.currentX = x; - _this.currentY = y; - } - - _this.deltaX = _this.currentX - _this.prevX; - _this.deltaY = _this.currentY - _this.prevY; - - // console.log('move', _this.moveFrame, _this.deltaX, _this.deltaY); - - // _this.mx = Math.max(Math.abs(_this.deltaX), _this.mx); - // _this.my = Math.max(Math.abs(_this.deltaY), _this.my); - - _this.moveFrame = _this.manager.game.frame; - - _this.counter++; - _this.manager.queueMouseMove(event); if (_this.capture) @@ -330,19 +263,6 @@ var MouseManager = new Class({ return; } - _this.currentTime = event.timeStamp; - - console.log('mdown', _this.moveFrame, _this.manager.game.frame, '=', _this.deltaX, _this.deltaY); - - // _this.prevX = _this.currentX; - // _this.prevY = _this.currentY; - - // _this.currentX = event.pageX - _this.manager.bounds.left; - // _this.currentY = event.pageY - _this.manager.bounds.top; - - // _this.deltaX = _this.currentX - _this.prevX; - // _this.deltaY = _this.currentY - _this.prevY; - _this.manager.queueMouseDown(event); if (_this.capture) @@ -359,22 +279,6 @@ var MouseManager = new Class({ return; } - _this.currentTime = event.timeStamp; - - _this.upX = _this.deltaX; - _this.upY = _this.deltaY; - - console.log('mup', _this.moveFrame, _this.manager.game.frame, '=', _this.deltaX, _this.deltaY, 'mc', _this.counter); - - // _this.prevX = _this.currentX; - // _this.prevY = _this.currentY; - - // _this.currentX = event.pageX - _this.manager.bounds.left; - // _this.currentY = event.pageY - _this.manager.bounds.top; - - // _this.deltaX = _this.currentX - _this.prevX; - // _this.deltaY = _this.currentY - _this.prevY; - _this.manager.queueMouseUp(event); if (_this.capture) @@ -425,46 +329,6 @@ var MouseManager = new Class({ this.enabled = true; }, - pre: function () - { - // calculate deltas - this.deltaTime = this.currentTime - this.prevTime; - }, - - post: function () - { - return; - - // reset - this.prevTime = this.currentTime; - - if (this.deltaX !== 0) - { - this.deltaX *= 0.95; - - // this.deltaX = Linear(0, this.deltaX, 0.999); - - if (FuzzyEqual(this.deltaX, 0, 0.1)) - { - this.deltaX = 0; - } - } - - if (this.deltaY !== 0) - { - this.deltaY *= 0.95; - - // this.deltaY = Linear(0, this.deltaY, 0.999); - - if (FuzzyEqual(this.deltaY, 0, 0.1)) - { - this.deltaY = 0; - } - } - - this.isMoving = (this.deltaX !== 0 || this.deltaY !== 0); - }, - /** * Stops the Mouse Event listeners. * This is called automatically and does not need to be manually invoked. From 370ccb6854005b74c5529b47bd656336ffef1f56 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 23 Nov 2018 16:25:31 +0000 Subject: [PATCH 074/221] Removed debug properties. --- src/input/InputManager.js | 126 ++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 67 deletions(-) diff --git a/src/input/InputManager.js b/src/input/InputManager.js index 32477a8da..24f91571b 100644 --- a/src/input/InputManager.js +++ b/src/input/InputManager.js @@ -427,7 +427,7 @@ var InputManager = new Class({ * * @param {number} time - The time stamp value of this game step. */ - update: function (time, delta) + update: function (time) { var i; @@ -443,78 +443,68 @@ var InputManager = new Class({ var pointers = this.pointers; - this.mouse.pre(); - for (i = 0; i < this.pointersTotal; i++) { - pointers[i].reset(delta); + pointers[i].reset(); } - // if (!this.enabled || len === 0) - // { - // return; - // } - - if (this.enabled && len > 0) + if (!this.enabled || len === 0) { - this.dirty = true; + return; + } - this.updateBounds(); - - this.scale.x = this.game.config.width / this.bounds.width; - this.scale.y = this.game.config.height / this.bounds.height; - - // Clears the queue array, and also means we don't work on array data that could potentially - // be modified during the processing phase - var queue = this.queue.splice(0, len); - var mouse = this.mousePointer; - - // Process the event queue, dispatching all of the events that have stored up - for (i = 0; i < len; i += 2) + this.dirty = true; + + this.updateBounds(); + + this.scale.x = this.game.config.width / this.bounds.width; + this.scale.y = this.game.config.height / this.bounds.height; + + // Clears the queue array, and also means we don't work on array data that could potentially + // be modified during the processing phase + var queue = this.queue.splice(0, len); + var mouse = this.mousePointer; + + // Process the event queue, dispatching all of the events that have stored up + for (i = 0; i < len; i += 2) + { + var type = queue[i]; + var event = queue[i + 1]; + + switch (type) { - var type = queue[i]; - var event = queue[i + 1]; - - switch (type) - { - case CONST.MOUSE_DOWN: - mouse.down(event, time); - break; - - case CONST.MOUSE_MOVE: - mouse.move(event, time); - break; - - case CONST.MOUSE_UP: - mouse.up(event, time); - break; - - case CONST.TOUCH_START: - this.startPointer(event, time); - break; - - case CONST.TOUCH_MOVE: - this.updatePointer(event, time); - break; - - case CONST.TOUCH_END: - this.stopPointer(event, time); - break; - - case CONST.TOUCH_CANCEL: - this.cancelPointer(event, time); - break; - - case CONST.POINTER_LOCK_CHANGE: - this.events.emit('pointerlockchange', event, this.mouse.locked); - break; - } - } - } + case CONST.MOUSE_DOWN: + mouse.down(event, time); + break; - for (i = 0; i < this.pointersTotal; i++) - { - pointers[i].updateMotion(); + case CONST.MOUSE_MOVE: + mouse.move(event, time); + break; + + case CONST.MOUSE_UP: + mouse.up(event, time); + break; + + case CONST.TOUCH_START: + this.startPointer(event, time); + break; + + case CONST.TOUCH_MOVE: + this.updatePointer(event, time); + break; + + case CONST.TOUCH_END: + this.stopPointer(event, time); + break; + + case CONST.TOUCH_CANCEL: + this.cancelPointer(event, time); + break; + + case CONST.POINTER_LOCK_CHANGE: + this.events.emit('pointerlockchange', event, this.mouse.locked); + break; + } } }, @@ -535,8 +525,6 @@ var InputManager = new Class({ { this.canvas.style.cursor = this.defaultCursor; } - - this.mouse.post(); }, /** @@ -1335,6 +1323,10 @@ var InputManager = new Class({ var p0 = pointer.position; var p1 = pointer.prevPosition; + // Store previous position + p1.x = p0.x; + p1.y = p0.y; + // Translate coordinates var x = (pageX - this.bounds.left) * this.scale.x; var y = (pageY - this.bounds.top) * this.scale.y; From 16508578785b9415c70150450a423a6628f9e34b Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 23 Nov 2018 16:26:49 +0000 Subject: [PATCH 075/221] Removed debug tests --- src/input/Pointer.js | 50 ++++++++++---------------------------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/src/input/Pointer.js b/src/input/Pointer.js index aa032edd8..51164d9c2 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -389,10 +389,6 @@ var Pointer = new Class({ * @since 3.10.0 */ this.active = (id === 0) ? true : false; - - this.deltaTime = 0; - this.prevDeltaTime = Date.now(); - this.speed = 0; }, /** @@ -420,7 +416,7 @@ var Pointer = new Class({ * @private * @since 3.0.0 */ - reset: function (now) + reset: function () { this.dirty = false; @@ -430,40 +426,6 @@ var Pointer = new Class({ this.movementX = 0; this.movementY = 0; - - this.deltaTime = now; - - // this.velocity.x = 0; - // this.velocity.y = 0; - }, - - updateMotion: function () - { - var x1 = this.position.x; - var y1 = this.position.y; - - var x2 = this.prevPosition.x; - var y2 = this.prevPosition.y; - - var deltaX = x1 - x2; - var deltaY = y1 - y2; - - this.velocity.x = deltaX / this.deltaTime || 0; - this.velocity.y = deltaY / this.deltaTime || 0; - this.speed = (Math.abs(this.velocity.x) > Math.abs(this.velocity.y)) ? this.velocity.x : this.velocity.y; - - /* - this.velocity.x = x1 - x2; - this.velocity.y = y1 - y2; - - this.angle = Math.atan2(y2 - y1, x2 - x1); - */ - - // Store previous position - this.prevPosition.x = this.position.x; - this.prevPosition.y = this.position.y; - - this.prevDeltaTime = this.deltaTime; }, /** @@ -566,6 +528,16 @@ var Pointer = new Class({ // Sets the local x/y properties this.manager.transformPointer(this, event.pageX, event.pageY, true); + var x1 = this.position.x; + var y1 = this.position.y; + + var x2 = this.prevPosition.x; + var y2 = this.prevPosition.y; + + this.velocity.x = x1 - x2; + this.velocity.y = y1 - y2; + this.angle = Math.atan2(y2 - y1, x2 - x1); + if (this.manager.mouse.locked) { // Multiple DOM events may occur within one frame, but only one Phaser event will fire From 64d2b2639800994d70419195885a33855f26c7b1 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 23 Nov 2018 18:58:01 +0000 Subject: [PATCH 076/221] Tidied up the control flow --- src/math/interpolation/LinearInterpolation.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/math/interpolation/LinearInterpolation.js b/src/math/interpolation/LinearInterpolation.js index ae46d8d26..1fce7a2ab 100644 --- a/src/math/interpolation/LinearInterpolation.js +++ b/src/math/interpolation/LinearInterpolation.js @@ -28,13 +28,14 @@ var LinearInterpolation = function (v, k) { return Linear(v[0], v[1], f); } - - if (k > 1) + else if (k > 1) { return Linear(v[m], v[m - 1], m - f); } - - return Linear(v[i], v[(i + 1 > m) ? m : i + 1], f - i); + else + { + return Linear(v[i], v[(i + 1 > m) ? m : i + 1], f - i); + } }; module.exports = LinearInterpolation; From b9fb1ddbf4bf35a94d2d800810beb7bfaec2fc4b Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 23 Nov 2018 18:58:13 +0000 Subject: [PATCH 077/221] Added call to updateMotion --- src/input/InputManager.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/input/InputManager.js b/src/input/InputManager.js index 24f91571b..105dbd544 100644 --- a/src/input/InputManager.js +++ b/src/input/InputManager.js @@ -450,6 +450,11 @@ var InputManager = new Class({ if (!this.enabled || len === 0) { + for (i = 0; i < this.pointersTotal; i++) + { + pointers[i].updateMotion(); + } + return; } @@ -506,6 +511,11 @@ var InputManager = new Class({ break; } } + + for (i = 0; i < this.pointersTotal; i++) + { + pointers[i].updateMotion(); + } }, /** @@ -1320,6 +1330,10 @@ var InputManager = new Class({ */ transformPointer: function (pointer, pageX, pageY, wasMove) { + pointer.x = (pageX - this.bounds.left) * this.scale.x; + pointer.y = (pageY - this.bounds.top) * this.scale.y; + + /* var p0 = pointer.position; var p1 = pointer.prevPosition; @@ -1345,6 +1359,7 @@ var InputManager = new Class({ p0.x = x * a + p1.x * (1 - a); p0.y = y * a + p1.y * (1 - a); } + */ }, /** From 21fa1960f3e9e93eddb5dbef68c2257463e30482 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 23 Nov 2018 19:06:47 +0000 Subject: [PATCH 078/221] Testing delta store --- src/input/mouse/MouseManager.js | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/input/mouse/MouseManager.js b/src/input/mouse/MouseManager.js index 863fcd1e6..42a0bb4cf 100644 --- a/src/input/mouse/MouseManager.js +++ b/src/input/mouse/MouseManager.js @@ -7,6 +7,7 @@ var Class = require('../../utils/Class'); var Features = require('../../device/Features'); var NOOP = require('../../utils/Class'); +var Vector2 = require('../../math/Vector2'); // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md @@ -126,6 +127,10 @@ var MouseManager = new Class({ */ this.pointerLockChange = NOOP; + // Testing ... + this.prevPosition = new Vector2(); + this.position = new Vector2(); + inputManager.events.once('boot', this.boot, this); }, @@ -239,6 +244,21 @@ var MouseManager = new Class({ { var _this = this; + /* + var storeDelta = function (event) + { + var x1 = _this.position.x; + var y1 = _this.position.y; + + var x2 = _this.prevPosition.x; + var y2 = _this.prevPosition.y; + + event._deltaX = x1 - x2; + event._deltaY = y1 - y2; + event._angle = Math.atan2(y2 - y1, x2 - x1); + }; + */ + this.onMouseMove = function (event) { if (event.defaultPrevented || !_this.enabled || !_this.manager) @@ -246,7 +266,9 @@ var MouseManager = new Class({ // Do nothing if event already handled return; } - + + // storeDelta(event); + _this.manager.queueMouseMove(event); if (_this.capture) @@ -263,6 +285,8 @@ var MouseManager = new Class({ return; } + // storeDelta(event); + _this.manager.queueMouseDown(event); if (_this.capture) @@ -279,6 +303,8 @@ var MouseManager = new Class({ return; } + // storeDelta(event); + _this.manager.queueMouseUp(event); if (_this.capture) From 51a9b3bd4a32b4f40bbe3be7d416ed963b28b3d8 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 23 Nov 2018 19:06:59 +0000 Subject: [PATCH 079/221] Recording positon tests --- src/input/Pointer.js | 92 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 83 insertions(+), 9 deletions(-) diff --git a/src/input/Pointer.js b/src/input/Pointer.js index 51164d9c2..380bd476c 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -6,6 +6,8 @@ var Class = require('../utils/Class'); var Distance = require('../math/distance/DistanceBetween'); +var Linear = require('../math/Linear'); +var FuzzyEqual = require('../math/fuzzy/Equal'); var SmoothStepInterpolation = require('../math/interpolation/SmoothStepInterpolation'); var Vector2 = require('../math/Vector2'); @@ -117,8 +119,8 @@ var Pointer = new Class({ * @name Phaser.Input.Pointer#prevPosition * @type {Phaser.Math.Vector2} * @since 3.11.0 - */ this.prevPosition = new Vector2(); + */ /** * The current velocity of the Pointer, based on its previous and current position. @@ -185,6 +187,16 @@ var Pointer = new Class({ */ this.worldY = 0; + /** + * Time when this Pointer was most recently moved (regardless of the state of its buttons, if any) + * + * @name Phaser.Input.Pointer#moveTime + * @type {number} + * @default 0 + * @since 3.0.0 + */ + this.moveTime = 0; + /** * X coordinate of the Pointer when Button 1 (left button), or Touch, was pressed, used for dragging objects. * @@ -389,6 +401,8 @@ var Pointer = new Class({ * @since 3.10.0 */ this.active = (id === 0) ? true : false; + + this.history = []; }, /** @@ -428,6 +442,60 @@ var Pointer = new Class({ this.movementY = 0; }, + recordPosition: function (time) + { + var history = this.history; + + var msSinceLastMove = time - this.moveTime; + + if (msSinceLastMove > 50) + { + // Use acceleration instead of velocity + } + + history.push({ x: this.x, y: this.y }); + + if (history.length > 1) + { + history.unshift(); + } + + // Average out the positions to get the delta and angle + var x = 0; + var y = 0; + + for (var i = 0; i < history.length; i++) + { + x += history[i].x; + y += history[i].y; + } + + this.velocity.x = this.x - (x / history.length); + this.velocity.y = this.y - (y / history.length); + + this.moveTime = time; + }, + + updateMotion: function () + { + // this.velocity.x = Linear(this.velocity.x, 0, 0.1); + // this.velocity.y = Linear(this.velocity.y, 0, 0.1); + + // Or + this.velocity.x *= 0.9; + this.velocity.y *= 0.9; + + if (FuzzyEqual(this.velocity.x, 0, 0.1)) + { + this.velocity.x = 0; + } + + if (FuzzyEqual(this.velocity.y, 0, 0.1)) + { + this.velocity.y = 0; + } + }, + /** * Internal method to handle a Mouse Up Event. * @@ -516,7 +584,7 @@ var Pointer = new Class({ * @param {MouseEvent} event - The Mouse Event to process. * @param {integer} time - The current timestamp as generated by the Request Animation Frame or SetTimeout. */ - move: function (event) + move: function (event, time) { if (event.buttons) { @@ -528,15 +596,21 @@ var Pointer = new Class({ // Sets the local x/y properties this.manager.transformPointer(this, event.pageX, event.pageY, true); - var x1 = this.position.x; - var y1 = this.position.y; + this.recordPosition(time); - var x2 = this.prevPosition.x; - var y2 = this.prevPosition.y; + // this.velocity.x = event._deltaX; + // this.velocity.y = event._deltaY; + // this.angle = event._angle; - this.velocity.x = x1 - x2; - this.velocity.y = y1 - y2; - this.angle = Math.atan2(y2 - y1, x2 - x1); + // var x1 = this.position.x; + // var y1 = this.position.y; + + // var x2 = this.prevPosition.x; + // var y2 = this.prevPosition.y; + + // this.velocity.x = x1 - x2; + // this.velocity.y = y1 - y2; + // this.angle = Math.atan2(y2 - y1, x2 - x1); if (this.manager.mouse.locked) { From 390f34c8d998317324a42b2a926f39b12908af52 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Sat, 24 Nov 2018 12:46:49 +0000 Subject: [PATCH 080/221] Removed test code --- src/input/mouse/MouseManager.js | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/input/mouse/MouseManager.js b/src/input/mouse/MouseManager.js index 42a0bb4cf..4b2e105be 100644 --- a/src/input/mouse/MouseManager.js +++ b/src/input/mouse/MouseManager.js @@ -244,21 +244,6 @@ var MouseManager = new Class({ { var _this = this; - /* - var storeDelta = function (event) - { - var x1 = _this.position.x; - var y1 = _this.position.y; - - var x2 = _this.prevPosition.x; - var y2 = _this.prevPosition.y; - - event._deltaX = x1 - x2; - event._deltaY = y1 - y2; - event._angle = Math.atan2(y2 - y1, x2 - x1); - }; - */ - this.onMouseMove = function (event) { if (event.defaultPrevented || !_this.enabled || !_this.manager) @@ -267,8 +252,6 @@ var MouseManager = new Class({ return; } - // storeDelta(event); - _this.manager.queueMouseMove(event); if (_this.capture) @@ -285,8 +268,6 @@ var MouseManager = new Class({ return; } - // storeDelta(event); - _this.manager.queueMouseDown(event); if (_this.capture) @@ -303,8 +284,6 @@ var MouseManager = new Class({ return; } - // storeDelta(event); - _this.manager.queueMouseUp(event); if (_this.capture) From 0f97be3624f321237782b92ea2e91cc4604ebe04 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Sat, 24 Nov 2018 12:47:01 +0000 Subject: [PATCH 081/221] Restored pointer smoothing --- src/input/InputManager.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/input/InputManager.js b/src/input/InputManager.js index 105dbd544..7b7cacdf6 100644 --- a/src/input/InputManager.js +++ b/src/input/InputManager.js @@ -1330,10 +1330,6 @@ var InputManager = new Class({ */ transformPointer: function (pointer, pageX, pageY, wasMove) { - pointer.x = (pageX - this.bounds.left) * this.scale.x; - pointer.y = (pageY - this.bounds.top) * this.scale.y; - - /* var p0 = pointer.position; var p1 = pointer.prevPosition; @@ -1359,7 +1355,6 @@ var InputManager = new Class({ p0.x = x * a + p1.x * (1 - a); p0.y = y * a + p1.y * (1 - a); } - */ }, /** From c32a69acaffe125afd068723fd3c02841ea2c725 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Sat, 24 Nov 2018 12:47:19 +0000 Subject: [PATCH 082/221] Added midPoint and updateMotion calculations --- src/input/Pointer.js | 108 ++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 64 deletions(-) diff --git a/src/input/Pointer.js b/src/input/Pointer.js index 380bd476c..bff31480b 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -119,8 +119,18 @@ var Pointer = new Class({ * @name Phaser.Input.Pointer#prevPosition * @type {Phaser.Math.Vector2} * @since 3.11.0 - this.prevPosition = new Vector2(); */ + this.prevPosition = new Vector2(); + + /** + * An internal vector used for calculations of the pointer speed and angle. + * + * @name Phaser.Input.Pointer#midPoint + * @type {Phaser.Math.Vector2} + * @private + * @since 3.16.0 + */ + this.midPoint = new Vector2(); /** * The current velocity of the Pointer, based on its previous and current position. @@ -156,13 +166,12 @@ var Pointer = new Class({ * * The default value of zero means 'no smoothing'. * Set to a small value, such as 0.2, to apply an average level of smoothing between positions. - * Values above 1 will introduce excess jitter into the positions. * * Positions are only smoothed when the pointer moves. Up and Down positions are always precise. * * @name Phaser.Input.Pointer#smoothFactor * @type {number} - * @default 0 + * @default 1 * @since 3.16.0 */ this.smoothFactor = 0; @@ -424,7 +433,7 @@ var Pointer = new Class({ /** * Resets the temporal properties of this Pointer. - * Called automatically by the Input Plugin each update. + * This method is called automatically each frame by the Input Manager. * * @method Phaser.Input.Pointer#reset * @private @@ -442,58 +451,41 @@ var Pointer = new Class({ this.movementY = 0; }, - recordPosition: function (time) - { - var history = this.history; - - var msSinceLastMove = time - this.moveTime; - - if (msSinceLastMove > 50) - { - // Use acceleration instead of velocity - } - - history.push({ x: this.x, y: this.y }); - - if (history.length > 1) - { - history.unshift(); - } - - // Average out the positions to get the delta and angle - var x = 0; - var y = 0; - - for (var i = 0; i < history.length; i++) - { - x += history[i].x; - y += history[i].y; - } - - this.velocity.x = this.x - (x / history.length); - this.velocity.y = this.y - (y / history.length); - - this.moveTime = time; - }, - + /** + * Calculates the motion of this Pointer, including its velocity and angle of movement. + * This method is called automatically each frame by the Input Manager. + * + * @method Phaser.Input.Pointer#updateMotion + * @private + * @since 3.16.0 + */ updateMotion: function () { - // this.velocity.x = Linear(this.velocity.x, 0, 0.1); - // this.velocity.y = Linear(this.velocity.y, 0, 0.1); + var px = this.midPoint.x; + var py = this.midPoint.y; - // Or - this.velocity.x *= 0.9; - this.velocity.y *= 0.9; + var cx = this.position.x; + var cy = this.position.y; - if (FuzzyEqual(this.velocity.x, 0, 0.1)) + // Moving towards our goal ... + var vx = SmoothStepInterpolation(0.2, px, cx); + var vy = SmoothStepInterpolation(0.2, py, cy); + + if (FuzzyEqual(vx, cx, 0.1)) { - this.velocity.x = 0; + vx = cx; } - if (FuzzyEqual(this.velocity.y, 0, 0.1)) + if (FuzzyEqual(vy, cy, 0.1)) { - this.velocity.y = 0; + vy = cy; } + + this.midPoint.set(vx, vy); + + this.velocity.set(cx - vx, cy - vy); + + this.angle = Math.atan2(cy - vy, cx - vx); }, /** @@ -596,22 +588,6 @@ var Pointer = new Class({ // Sets the local x/y properties this.manager.transformPointer(this, event.pageX, event.pageY, true); - this.recordPosition(time); - - // this.velocity.x = event._deltaX; - // this.velocity.y = event._deltaY; - // this.angle = event._angle; - - // var x1 = this.position.x; - // var y1 = this.position.y; - - // var x2 = this.prevPosition.x; - // var y2 = this.prevPosition.y; - - // this.velocity.x = x1 - x2; - // this.velocity.y = y1 - y2; - // this.angle = Math.atan2(y2 - y1, x2 - x1); - if (this.manager.mouse.locked) { // Multiple DOM events may occur within one frame, but only one Phaser event will fire @@ -621,6 +597,8 @@ var Pointer = new Class({ this.justMoved = true; + this.moveTime = time; + this.dirty = true; this.wasTouch = false; @@ -678,7 +656,7 @@ var Pointer = new Class({ * @param {TouchEvent} event - The Touch Event to process. * @param {integer} time - The current timestamp as generated by the Request Animation Frame or SetTimeout. */ - touchmove: function (event) + touchmove: function (event, time) { this.event = event; @@ -687,6 +665,8 @@ var Pointer = new Class({ this.justMoved = true; + this.moveTime = time; + this.dirty = true; this.wasTouch = true; From f6efccb29a96e38469e826986d3204085f36a4f2 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Sat, 24 Nov 2018 12:52:20 +0000 Subject: [PATCH 083/221] Added motionFactor property. --- src/input/Pointer.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/input/Pointer.js b/src/input/Pointer.js index bff31480b..cfa82bbc0 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -171,11 +171,27 @@ var Pointer = new Class({ * * @name Phaser.Input.Pointer#smoothFactor * @type {number} - * @default 1 + * @default 0 * @since 3.16.0 */ this.smoothFactor = 0; + /** + * The factor applied to the motion smoothing each frame. + * + * This value is passed to the Smooth Step Interpolation that is used to calculate the velocity + * and angle of the Pointer. It's applied every frame, until the midPoint reaches the current + * position of the Pointer. 0.2 provides a good average but can be increased if you need a + * quicker update and are working in a high performance environment. Never set this value to + * zero. + * + * @name Phaser.Input.Pointer#motionFactor + * @type {number} + * @default 0.2 + * @since 3.16.0 + */ + this.motionFactor = 0.2; + /** * The x position of this Pointer, translated into the coordinate space of the most recent Camera it interacted with. * @@ -468,8 +484,8 @@ var Pointer = new Class({ var cy = this.position.y; // Moving towards our goal ... - var vx = SmoothStepInterpolation(0.2, px, cx); - var vy = SmoothStepInterpolation(0.2, py, cy); + var vx = SmoothStepInterpolation(this.motionFactor, px, cx); + var vy = SmoothStepInterpolation(this.motionFactor, py, cy); if (FuzzyEqual(vx, cx, 0.1)) { From d596fbd8c058e867416bf5e775ad256e6e1f759d Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Sat, 24 Nov 2018 13:04:14 +0000 Subject: [PATCH 084/221] Added distance property. --- src/input/Pointer.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/input/Pointer.js b/src/input/Pointer.js index cfa82bbc0..cb688d9cd 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -158,6 +158,10 @@ var Pointer = new Class({ */ this.angle = new Vector2(); + this.distance = 0; + + + /** * The smoothing factor to apply to the Pointer position. * @@ -477,15 +481,12 @@ var Pointer = new Class({ */ updateMotion: function () { - var px = this.midPoint.x; - var py = this.midPoint.y; - var cx = this.position.x; var cy = this.position.y; // Moving towards our goal ... - var vx = SmoothStepInterpolation(this.motionFactor, px, cx); - var vy = SmoothStepInterpolation(this.motionFactor, py, cy); + var vx = SmoothStepInterpolation(this.motionFactor, this.midPoint.x, cx); + var vy = SmoothStepInterpolation(this.motionFactor, this.midPoint.y, cy); if (FuzzyEqual(vx, cx, 0.1)) { @@ -499,9 +500,14 @@ var Pointer = new Class({ this.midPoint.set(vx, vy); - this.velocity.set(cx - vx, cy - vy); + var dx = cx - vx; + var dy = cy - vy; - this.angle = Math.atan2(cy - vy, cx - vx); + this.velocity.set(dx, dy); + + this.angle = Math.atan2(dy, dx); + + this.distance = Math.sqrt(dx * dx + dy * dy); }, /** From 93a76475ea12a5dafcaf8fe71f5d890b83a25780 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 26 Nov 2018 11:13:25 +0000 Subject: [PATCH 085/221] The Input Plugin was emitting a `preUpdate` event, with the capital U, instead of `preupdate`. This has now been corrected. Fix #4185 --- CHANGELOG.md | 1 + src/input/InputPlugin.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b26e930a2..c835d3482 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ * `InputManager.transformPointer` has a new boolean argument `wasMove`, which controls if the pointer is being transformed after a move or up/down event. * `Pointer.velocity` is a new Vector2 that contains the velocity of the Pointer, based on the previous and current position. This is updated whenever the Pointer moves, regardless of button states. If you find the velocity is too erratic, consider enabling the `smoothFactor`. * `Pointer.angle` is a new property that contains the angle of the Pointer, in radians, based on the previous and current position. This is updated whenever the Pointer moves, regardless of button states. If you find the angle is too erratic, consider enabling the `smoothFactor`. +* The Input Plugin was emitting a `preUpdate` event, with the capital U, instead of `preupdate`. This has now been corrected. Fix #4185 (thanks @gadelan) ### New Features diff --git a/src/input/InputPlugin.js b/src/input/InputPlugin.js index 35c1b10f9..f73b7cc5a 100644 --- a/src/input/InputPlugin.js +++ b/src/input/InputPlugin.js @@ -406,7 +406,7 @@ var InputPlugin = new Class({ preUpdate: function () { // Registered input plugins listen for this - this.pluginEvents.emit('preUpdate'); + this.pluginEvents.emit('preupdate'); var removeList = this._pendingRemoval; var insertList = this._pendingInsertion; From f51de18bb29c5478a0857ea6708d74fbb0cf3e2b Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 26 Nov 2018 11:27:02 +0000 Subject: [PATCH 086/221] Updated docs and added quick bail-out clause --- CHANGELOG.md | 8 +++--- src/input/Pointer.js | 62 ++++++++++++++++++++++++++++++++------------ 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c835d3482..fe812b5a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ ### Input Updates and Fixes -* The Keyboard Plugin will now call `preventDefault` on all non-modified alphanumeric key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create `Key` objects to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the following config setting. +* The Keyboard Plugin will now call `preventDefault` on all non-modified alphanumeric key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create `Key` objects to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the `keyboard.capture` config setting. * There is a new Game and Scene Config setting `input.keyboard.capture` which is an array of KeyCodes that the Keyboard Plugin will capture all non-modified key events on. By default it is populated with the space key, cursors, 0 - 9 and A - Z. You can also set this in a Scene Config, in which case it will override the Game Config value. * If you have multiple parallel Scenes, each trying to get keyboard input, be sure to disable capture on them to stop them from stealing input from another Scene in the list. You can do this with `this.input.keyboard.enabled = false` within the Scene to stop all input, or `this.input.keyboard.preventDefault = false` to stop a Scene halting input on another Scene. * The Keyboard Plugin has a new property called `captures` which is an array of keycodes, as populated by the Game Config. Any key code in the array will have `preventDefault` called on it if pressed. Modify this by changing the game config, or altering the array contents at run-time. @@ -24,8 +24,10 @@ * `Pointer.smoothFactor` is a float-value that allows you to automatically apply smoothing to the Pointer position as it moves. This is ideal when you want something smoothly tracking a pointer in a game, or are need a smooth drawing motion for an art package. The default value is zero, meaning disabled. Set to a small number, such as 0.2, to enable. * `Config.inputSmoothFactor` is a new property that allows you to set the smoothing factor for all Pointers the game creators. The default value is zero, which is disabled. Set in the game config as `input: { smoothFactor: value }`. * `InputManager.transformPointer` has a new boolean argument `wasMove`, which controls if the pointer is being transformed after a move or up/down event. -* `Pointer.velocity` is a new Vector2 that contains the velocity of the Pointer, based on the previous and current position. This is updated whenever the Pointer moves, regardless of button states. If you find the velocity is too erratic, consider enabling the `smoothFactor`. -* `Pointer.angle` is a new property that contains the angle of the Pointer, in radians, based on the previous and current position. This is updated whenever the Pointer moves, regardless of button states. If you find the angle is too erratic, consider enabling the `smoothFactor`. +* `Pointer.velocity` is a new Vector2 that contains the velocity of the Pointer, based on the current and previous positions. The velocity is smoothed out each frame, according to the `Pointer.motionFactor` property. This is done for more accurate gesture recognition. The velocity is updated based on Pointer movement, it doesn't require a button to be pressed first. +* `Pointer.angle` is a new property that contains the angle of the Pointer, in radians, based on the current and previous positions. The angle is smoothed out each frame, according to the `Pointer.motionFactor` property. This is done for more accurate gesture recognition. The angle is updated based on Pointer movement, it doesn't require a button to be pressed first. +* `Pointer.distance` is a new property that contains the distance of the Pointer, in radians, based on the current and previous positions. The distance is smoothed out each frame, according to the `Pointer.motionFactor` property. This is done for more accurate gesture recognition. The distance is updated based on Pointer movement, it doesn't require a button to be pressed first. +* `Pointer.motionFactor` is a new property that controls how much smoothing to apply to the Pointer positions each frame. This value is passed to the Smooth Step Interpolation that is used to calculate the velocity, angle and distance of the Pointer. It's applied every frame, until the midPoint reaches the current position of the Pointer. The default value is 0.2. * The Input Plugin was emitting a `preUpdate` event, with the capital U, instead of `preupdate`. This has now been corrected. Fix #4185 (thanks @gadelan) ### New Features diff --git a/src/input/Pointer.js b/src/input/Pointer.js index cb688d9cd..a24afdac0 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -104,6 +104,7 @@ var Pointer = new Class({ * * @name Phaser.Input.Pointer#position * @type {Phaser.Math.Vector2} + * @readonly * @since 3.0.0 */ this.position = new Vector2(); @@ -113,11 +114,11 @@ var Pointer = new Class({ * * The old x and y values are stored in here during the InputManager.transformPointer call. * - * You can use it to track how fast the pointer is moving, or to smoothly interpolate between the old and current position. - * See the `Pointer.getInterpolatedPosition` method to assist in this. + * Use the properties `velocity`, `angle` and `distance` to create your own gesture recognition. * * @name Phaser.Input.Pointer#prevPosition * @type {Phaser.Math.Vector2} + * @readonly * @since 3.11.0 */ this.prevPosition = new Vector2(); @@ -130,17 +131,19 @@ var Pointer = new Class({ * @private * @since 3.16.0 */ - this.midPoint = new Vector2(); + this.midPoint = new Vector2(-1, -1); /** - * The current velocity of the Pointer, based on its previous and current position. + * The current velocity of the Pointer, based on its current and previous positions. * - * This is updated whenever the Pointer moves, regardless of the state of any Pointer buttons. + * This value is smoothed out each frame, according to the `motionFactor` property. * - * If you are finding the velocity value too erratic, then consider enabling the `Pointer.smoothFactor`. + * This property is updated whenever the Pointer moves, regardless of any button states. In other words, + * it changes based on movement alone - a button doesn't have to be pressed first. * * @name Phaser.Input.Pointer#velocity * @type {Phaser.Math.Vector2} + * @readonly * @since 3.16.0 */ this.velocity = new Vector2(); @@ -148,20 +151,34 @@ var Pointer = new Class({ /** * The current angle the Pointer is moving, in radians, based on its previous and current position. * - * This is updated whenever the Pointer moves, regardless of the state of any Pointer buttons. - * - * If you are finding the angle value too erratic, then consider enabling the `Pointer.smoothFactor`. + * This property is updated whenever the Pointer moves, regardless of any button states. In other words, + * it changes based on movement alone - a button doesn't have to be pressed first. * * @name Phaser.Input.Pointer#angle * @type {number} + * @readonly * @since 3.16.0 */ this.angle = new Vector2(); + /** + * The distance the Pointer has moved, based on its previous and current position. + * + * This value is smoothed out each frame, according to the `motionFactor` property. + * + * This property is updated whenever the Pointer moves, regardless of any button states. In other words, + * it changes based on movement alone - a button doesn't have to be pressed first. + * + * If you need the total distance travelled since the primary buttons was pressed down, + * then use the `Pointer.getDistance` method. + * + * @name Phaser.Input.Pointer#distance + * @type {number} + * @readonly + * @since 3.16.0 + */ this.distance = 0; - - /** * The smoothing factor to apply to the Pointer position. * @@ -169,9 +186,11 @@ var Pointer = new Class({ * then you can set this value to apply an automatic smoothing to the positions as they are recorded. * * The default value of zero means 'no smoothing'. - * Set to a small value, such as 0.2, to apply an average level of smoothing between positions. + * Set to a small value, such as 0.2, to apply an average level of smoothing between positions. You can do this by changing this + * value directly, or by setting the `input.smoothFactor` property in the Game Config. * - * Positions are only smoothed when the pointer moves. Up and Down positions are always precise. + * Positions are only smoothed when the pointer moves. If the primary button on this Pointer enters an Up or Down state, then the position + * is always precise, and not smoothed. * * @name Phaser.Input.Pointer#smoothFactor * @type {number} @@ -183,8 +202,8 @@ var Pointer = new Class({ /** * The factor applied to the motion smoothing each frame. * - * This value is passed to the Smooth Step Interpolation that is used to calculate the velocity - * and angle of the Pointer. It's applied every frame, until the midPoint reaches the current + * This value is passed to the Smooth Step Interpolation that is used to calculate the velocity, + * angle and distance of the Pointer. It's applied every frame, until the midPoint reaches the current * position of the Pointer. 0.2 provides a good average but can be increased if you need a * quicker update and are working in a high performance environment. Never set this value to * zero. @@ -484,9 +503,18 @@ var Pointer = new Class({ var cx = this.position.x; var cy = this.position.y; + var mx = this.midPoint.x; + var my = this.midPoint.y; + + if (cx === mx && cy === my) + { + // Nothing to do here + return; + } + // Moving towards our goal ... - var vx = SmoothStepInterpolation(this.motionFactor, this.midPoint.x, cx); - var vy = SmoothStepInterpolation(this.motionFactor, this.midPoint.y, cy); + var vx = SmoothStepInterpolation(this.motionFactor, mx, cx); + var vy = SmoothStepInterpolation(this.motionFactor, my, cy); if (FuzzyEqual(vx, cx, 0.1)) { From 449c6a3ca51e9402075261c43116606c05077ae3 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 26 Nov 2018 11:28:24 +0000 Subject: [PATCH 087/221] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe812b5a9..9fd58de9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ * If the `setScore` or `getPlayerScore` calls fail, it will return `null` as the score instance, instead of causing a run-time error. * You can now pass an object or a string to `setScore` and objects will be automatically stringified. -### Input Updates and Fixes +### Input - New Features, Updates and Fixes * The Keyboard Plugin will now call `preventDefault` on all non-modified alphanumeric key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create `Key` objects to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the `keyboard.capture` config setting. * There is a new Game and Scene Config setting `input.keyboard.capture` which is an array of KeyCodes that the Keyboard Plugin will capture all non-modified key events on. By default it is populated with the space key, cursors, 0 - 9 and A - Z. You can also set this in a Scene Config, in which case it will override the Game Config value. @@ -29,6 +29,7 @@ * `Pointer.distance` is a new property that contains the distance of the Pointer, in radians, based on the current and previous positions. The distance is smoothed out each frame, according to the `Pointer.motionFactor` property. This is done for more accurate gesture recognition. The distance is updated based on Pointer movement, it doesn't require a button to be pressed first. * `Pointer.motionFactor` is a new property that controls how much smoothing to apply to the Pointer positions each frame. This value is passed to the Smooth Step Interpolation that is used to calculate the velocity, angle and distance of the Pointer. It's applied every frame, until the midPoint reaches the current position of the Pointer. The default value is 0.2. * The Input Plugin was emitting a `preUpdate` event, with the capital U, instead of `preupdate`. This has now been corrected. Fix #4185 (thanks @gadelan) +* `Pointer.updateMotion` is a new method that is called automatically, each step, by the Input Manager. It's responsible for calculating the Pointer velocity, angle and distance properties. ### New Features From b437efa64234ac88879f947832b349b52f01dd6f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 26 Nov 2018 11:29:13 +0000 Subject: [PATCH 088/221] Removed un-used function --- src/input/Pointer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/input/Pointer.js b/src/input/Pointer.js index a24afdac0..4b8bcf218 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -6,7 +6,6 @@ var Class = require('../utils/Class'); var Distance = require('../math/distance/DistanceBetween'); -var Linear = require('../math/Linear'); var FuzzyEqual = require('../math/fuzzy/Equal'); var SmoothStepInterpolation = require('../math/interpolation/SmoothStepInterpolation'); var Vector2 = require('../math/Vector2'); From d2cb4a40069ee8a8204e20c3f03654e9956c5c5b Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 26 Nov 2018 13:10:54 +0000 Subject: [PATCH 089/221] Pass the time to Pointer.reset --- src/input/InputManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/InputManager.js b/src/input/InputManager.js index 7b7cacdf6..fad6f03f5 100644 --- a/src/input/InputManager.js +++ b/src/input/InputManager.js @@ -445,7 +445,7 @@ var InputManager = new Class({ for (i = 0; i < this.pointersTotal; i++) { - pointers[i].reset(); + pointers[i].reset(time); } if (!this.enabled || len === 0) From 41e64b9f5371b0ca2e6022134741026697d8fe78 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 26 Nov 2018 13:11:24 +0000 Subject: [PATCH 090/221] Added time property, getDistance, getDuration and getAngle. --- src/input/Pointer.js | 86 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/src/input/Pointer.js b/src/input/Pointer.js index 4b8bcf218..7591c1c3f 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -4,6 +4,7 @@ * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ +var Angle = require('../math/angle/Between'); var Class = require('../utils/Class'); var Distance = require('../math/distance/DistanceBetween'); var FuzzyEqual = require('../math/fuzzy/Equal'); @@ -449,7 +450,14 @@ var Pointer = new Class({ */ this.active = (id === 0) ? true : false; - this.history = []; + /** + * Time when this Pointer was most recently updated by the Game step. + * + * @name Phaser.Input.Pointer#time + * @type {number} + * @since 3.16.0 + */ + this.time = 0; }, /** @@ -477,7 +485,7 @@ var Pointer = new Class({ * @private * @since 3.0.0 */ - reset: function () + reset: function (time) { this.dirty = false; @@ -485,6 +493,8 @@ var Pointer = new Class({ this.justUp = false; this.justMoved = false; + this.time = time; + this.movementX = 0; this.movementY = 0; }, @@ -863,17 +873,81 @@ var Pointer = new Class({ }, /** - * Returns the distance between the Pointer's current position and where it was - * first pressed down (the `downX` and `downY` properties) + * If the Pointer has a button pressed down at the time this method is called, it will return the + * distance between the Pointer's `downX` and `downY` values and the current position. + * + * If no button is held down, it will return the last recorded distance, based on where + * the Pointer was when the button was released. + * + * If you wish to get the distance being travelled currently, based on the velocity of the Pointer, + * then see the `Pointer.distance` property. * * @method Phaser.Input.Pointer#getDistance * @since 3.13.0 * - * @return {number} The distance the Pointer has moved since being pressed down. + * @return {number} The distance the Pointer moved. */ getDistance: function () { - return Distance(this.downX, this.downY, this.x, this.y); + if (this.isDown) + { + return Distance(this.downX, this.downY, this.x, this.y); + } + else + { + return Distance(this.downX, this.downY, this.upX, this.upY); + } + }, + + /** + * If the Pointer has a button pressed down at the time this method is called, it will return the + * duration since the Pointer's was pressed down. + * + * If no button is held down, it will return the last recorded duration, based on the time + * the Pointer button was released. + * + * @method Phaser.Input.Pointer#getDuration + * @since 3.16.0 + * + * @return {number} The duration the Pointer was held down for in milliseconds. + */ + getDuration: function () + { + if (this.isDown) + { + return (this.time - this.downTime); + } + else + { + return (this.upTime - this.downTime); + } + }, + + /** + * If the Pointer has a button pressed down at the time this method is called, it will return the + * angle between the Pointer's `downX` and `downY` values and the current position. + * + * If no button is held down, it will return the last recorded angle, based on where + * the Pointer was when the button was released. + * + * If you wish to get the current angle, based on the velocity of the Pointer, then + * see the `Pointer.angle` property. + * + * @method Phaser.Input.Pointer#getAngle + * @since 3.16.0 + * + * @return {number} The angle between the Pointer's 'up' and 'down' coordinates. + */ + getAngle: function () + { + if (this.isDown) + { + return Angle(this.x, this.y, this.downX, this.downY); + } + else + { + return Angle(this.upX, this.upY, this.downX, this.downY); + } }, /** From a74616b0906d9a90118330b9ec56a680443ce3bf Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 26 Nov 2018 15:35:18 +0000 Subject: [PATCH 091/221] Added getDistanceX and getDistanceY --- CHANGELOG.md | 6 ++++++ src/input/Pointer.js | 50 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fd58de9d..831b54d78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,12 @@ * `Pointer.motionFactor` is a new property that controls how much smoothing to apply to the Pointer positions each frame. This value is passed to the Smooth Step Interpolation that is used to calculate the velocity, angle and distance of the Pointer. It's applied every frame, until the midPoint reaches the current position of the Pointer. The default value is 0.2. * The Input Plugin was emitting a `preUpdate` event, with the capital U, instead of `preupdate`. This has now been corrected. Fix #4185 (thanks @gadelan) * `Pointer.updateMotion` is a new method that is called automatically, each step, by the Input Manager. It's responsible for calculating the Pointer velocity, angle and distance properties. +* `Pointer.time` is a new property that holds the time the Pointer was last updated by the Game step. +* `Pointer.getDistance` has been updated. If called while a button is being held down, it will return the distance between the Pointer's current position and it's down position. If called when a Pointer doesn't have a button down, it will return the historic distance between the up and down positions. +* `Pointer.getDistanceX` is a new method that will return the horizontal distance between the Pointer's previous and current coordinates. If called while a button is being held down, it will return the distance between the Pointer's current position and it's down position. If called when a Pointer doesn't have a button down, it will return the historic distance between the up and down positions. +* `Pointer.getDistanceY` is a new method that will return the horizontal distance between the Pointer's previous and current coordinates. If called while a button is being held down, it will return the distance between the Pointer's current position and it's down position. If called when a Pointer doesn't have a button down, it will return the historic distance between the up and down positions. +* `Pointer.getDuration` is a new method that will return the duration the Pointer was held down for. If the Pointer has a button pressed down at the time this method is called, it will return the duration since the Pointer's was pressed down. If no button is held down, it will return the last recorded duration, based on the time the Pointer button was released. +* `Pointer.getAngle` is a new method that will return the angle between the Pointer coordinates. If the Pointer has a button pressed down at the time this method is called, it will return the angle between the Pointer's `downX` and `downY` values and the current position. If no button is held down, it will return the last recorded angle, based on where the Pointer was when the button was released. ### New Features diff --git a/src/input/Pointer.js b/src/input/Pointer.js index 7591c1c3f..6ceb10929 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -899,6 +899,54 @@ var Pointer = new Class({ } }, + /** + * If the Pointer has a button pressed down at the time this method is called, it will return the + * horizontal distance between the Pointer's `downX` and `downY` values and the current position. + * + * If no button is held down, it will return the last recorded horizontal distance, based on where + * the Pointer was when the button was released. + * + * @method Phaser.Input.Pointer#getDistanceX + * @since 3.16.0 + * + * @return {number} The horizontal distance the Pointer moved. + */ + getDistanceX: function () + { + if (this.isDown) + { + return Math.abs(this.downX - this.x); + } + else + { + return Math.abs(this.downX - this.upX); + } + }, + + /** + * If the Pointer has a button pressed down at the time this method is called, it will return the + * vertical distance between the Pointer's `downX` and `downY` values and the current position. + * + * If no button is held down, it will return the last recorded vertical distance, based on where + * the Pointer was when the button was released. + * + * @method Phaser.Input.Pointer#getDistanceY + * @since 3.16.0 + * + * @return {number} The vertical distance the Pointer moved. + */ + getDistanceY: function () + { + if (this.isDown) + { + return Math.abs(this.downY - this.y); + } + else + { + return Math.abs(this.downY - this.upY); + } + }, + /** * If the Pointer has a button pressed down at the time this method is called, it will return the * duration since the Pointer's was pressed down. @@ -936,7 +984,7 @@ var Pointer = new Class({ * @method Phaser.Input.Pointer#getAngle * @since 3.16.0 * - * @return {number} The angle between the Pointer's 'up' and 'down' coordinates. + * @return {number} The angle between the Pointer's coordinates in radians. */ getAngle: function () { From 524892f095bc0769e49540e20e39e4ecaab70412 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 26 Nov 2018 15:42:53 +0000 Subject: [PATCH 092/221] Fixed angle value and facing direction --- src/input/Pointer.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/input/Pointer.js b/src/input/Pointer.js index 6ceb10929..8d1c30858 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -151,6 +151,8 @@ var Pointer = new Class({ /** * The current angle the Pointer is moving, in radians, based on its previous and current position. * + * The angle is based on the old position facing to the current position. + * * This property is updated whenever the Pointer moves, regardless of any button states. In other words, * it changes based on movement alone - a button doesn't have to be pressed first. * @@ -159,7 +161,7 @@ var Pointer = new Class({ * @readonly * @since 3.16.0 */ - this.angle = new Vector2(); + this.angle = 0; /** * The distance the Pointer has moved, based on its previous and current position. @@ -542,7 +544,7 @@ var Pointer = new Class({ this.velocity.set(dx, dy); - this.angle = Math.atan2(dy, dx); + this.angle = Angle(vx, vy, cx, cy); this.distance = Math.sqrt(dx * dx + dy * dy); }, @@ -978,6 +980,8 @@ var Pointer = new Class({ * If no button is held down, it will return the last recorded angle, based on where * the Pointer was when the button was released. * + * The angle is based on the old position facing to the current position. + * * If you wish to get the current angle, based on the velocity of the Pointer, then * see the `Pointer.angle` property. * @@ -990,11 +994,11 @@ var Pointer = new Class({ { if (this.isDown) { - return Angle(this.x, this.y, this.downX, this.downY); + return Angle(this.downX, this.downY, this.x, this.y); } else { - return Angle(this.upX, this.upY, this.downX, this.downY); + return Angle(this.downX, this.downY, this.upX, this.upY); } }, From 2c78c22112eca2ab7d1b0009d8ab520d61ff2c78 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 26 Nov 2018 23:28:07 +0000 Subject: [PATCH 093/221] `Geom.Intersects.PointToLine` has a new optional argument `lineThickness` (which defaults to 1). This allows you to determine if the point intersects a line of a given thickness, where the line-ends are circular (not square) --- CHANGELOG.md | 1 + src/geom/intersects/PointToLine.js | 49 +++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 831b54d78..478e3f35a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ * There is a new boolean Game Config property called `customEnvironment`. If set to `true` it will skip the internal Feature checks when working out which type of renderer to create, allowing you to run Phaser under non-native web environments. If using this value, you _must_ set an explicit `renderType` of either CANVAS or WEBGL. It cannot be left as AUTO. Fix #4166 (thanks @jcyuan) * `Animation.nextFrame` will advance an animation to the next frame in the sequence instantly, regardless of the animation time or state. You can call this on a Sprite: `sprite.anims.nextFrame()` (thanks rgk25) * `Animation.previousFrame` will set an animation to the previous frame in the sequence instantly, regardless of the animation time or state. You can call this on a Sprite: `sprite.anims.previousFrame()` (thanks rgk25) +* `Geom.Intersects.PointToLine` has a new optional argument `lineThickness` (which defaults to 1). This allows you to determine if the point intersects a line of a given thickness, where the line-ends are circular (not square). ### Updates diff --git a/src/geom/intersects/PointToLine.js b/src/geom/intersects/PointToLine.js index e1bd7b471..395f01cbc 100644 --- a/src/geom/intersects/PointToLine.js +++ b/src/geom/intersects/PointToLine.js @@ -1,23 +1,64 @@ /** * @author Richard Davey + * @author Florian Mertens * @copyright 2018 Photon Storm Ltd. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ /** - * Checks if the given point falls between the two end-points of the line segment. + * Checks if the a Point falls between the two end-points of a Line, based on the given line thickness. + * + * Assumes that the line end points are circular, not square. * * @function Phaser.Geom.Intersects.PointToLine * @since 3.0.0 * * @param {(Phaser.Geom.Point|any)} point - The point, or point-like object to check. * @param {Phaser.Geom.Line} line - The line segment to test for intersection on. + * @param {number} [lineThickness=1] - The line thickness. Assumes that the line end points are circular. * - * @return {boolean} `true` if the two objects intersect, otherwise `false`. + * @return {boolean} `true` if the Point falls on the Line, otherwise `false`. */ -var PointToLine = function (point, line) +var PointToLine = function (point, line, lineThickness) { - return ((point.x - line.x1) * (line.y2 - line.y1) === (line.x2 - line.x1) * (point.y - line.y1)); + if (lineThickness === undefined) { lineThickness = 1; } + + var x1 = line.x1; + var y1 = line.y1; + + var x2 = line.x2; + var y2 = line.y2; + + var px = point.x; + var py = point.y; + + var L2 = (((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))); + + if (L2 === 0) + { + return false; + } + + var r = (((px - x1) * (x2 - x1)) + ((py - y1) * (y2 - y1))) / L2; + + // Assume line thickness is circular + if (r < 0) + { + // Outside line1 + return (Math.sqrt(((x1 - px) * (x1 - px) ) + ( (y1 - py) * (y1 - py))) <= lineThickness); + } + else if ((r >= 0) && (r <= 1)) + { + // On the line segment + var s = (((y1 - py) * (x2 - x1)) - ((x1 - px) * (y2 - y1))) / L2; + + return (Math.abs(s) * Math.sqrt(L2) <= lineThickness); + } + else + { + // Outside line2 + return (Math.sqrt(((x2 - px) * (x2 - px)) + ((y2 - py) * (y2 - py))) <= lineThickness); + } }; module.exports = PointToLine; From 91e4a91c5a636f114fedb2bcee86c3b4a9733eb8 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 27 Nov 2018 00:42:37 +0000 Subject: [PATCH 094/221] Added GetNearestPoint and GetShortestDistance methods --- CHANGELOG.md | 2 ++ src/geom/line/GetNearestPoint.js | 49 ++++++++++++++++++++++++++++ src/geom/line/GetShortestDistance.js | 41 +++++++++++++++++++++++ src/geom/line/index.js | 2 ++ 4 files changed, 94 insertions(+) create mode 100644 src/geom/line/GetNearestPoint.js create mode 100644 src/geom/line/GetShortestDistance.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 478e3f35a..e03cc85d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,8 @@ * `Animation.nextFrame` will advance an animation to the next frame in the sequence instantly, regardless of the animation time or state. You can call this on a Sprite: `sprite.anims.nextFrame()` (thanks rgk25) * `Animation.previousFrame` will set an animation to the previous frame in the sequence instantly, regardless of the animation time or state. You can call this on a Sprite: `sprite.anims.previousFrame()` (thanks rgk25) * `Geom.Intersects.PointToLine` has a new optional argument `lineThickness` (which defaults to 1). This allows you to determine if the point intersects a line of a given thickness, where the line-ends are circular (not square). +* `Geom.Line.GetNearestPoint` is a new static method that will return the nearest point on a line to the given point. +* `Geom.Line.GetShortestDistance` is a new static method that will return the shortest distance from a line to the given point. ### Updates diff --git a/src/geom/line/GetNearestPoint.js b/src/geom/line/GetNearestPoint.js new file mode 100644 index 000000000..a42c48048 --- /dev/null +++ b/src/geom/line/GetNearestPoint.js @@ -0,0 +1,49 @@ +/** + * @author Richard Davey + * @author Florian Mertens + * @copyright 2018 Photon Storm Ltd. + * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} + */ + +var Point = require('../point/Point'); + +/** + * Get the nearest point on a line perpendicular to the given point. + * + * @function Phaser.Geom.Line.GetNearestPoint + * @since 3.16.0 + * + * @generic {Phaser.Geom.Point} O - [out,$return] + * + * @param {Phaser.Geom.Line} line - The line to get the nearest point on. + * @param {(Phaser.Geom.Point|object)} point - The point to get the nearest point to. + * @param {(Phaser.Geom.Point|object)} [out] - An optional point, or point-like object, to store the coordinates of the nearest point on the line. + * + * @return {(Phaser.Geom.Point|object)} The nearest point on the line. + */ +var GetNearestPoint = function (line, point, out) +{ + if (out === undefined) { out = new Point(); } + + var x1 = line.x1; + var y1 = line.y1; + + var x2 = line.x2; + var y2 = line.y2; + + var L2 = (((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))); + + if (L2 === 0) + { + return out; + } + + var r = (((point.x - x1) * (x2 - x1)) + ((point.y - y1) * (y2 - y1))) / L2; + + out.x = x1 + (r * (x2 - x1)); + out.y = y1 + (r * (y2 - y1)); + + return out; +}; + +module.exports = GetNearestPoint; diff --git a/src/geom/line/GetShortestDistance.js b/src/geom/line/GetShortestDistance.js new file mode 100644 index 000000000..74b9c2adf --- /dev/null +++ b/src/geom/line/GetShortestDistance.js @@ -0,0 +1,41 @@ +/** + * @author Richard Davey + * @author Florian Mertens + * @copyright 2018 Photon Storm Ltd. + * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} + */ + +/** + * Get the shortest distance from a Line to the given Point. + * + * @function Phaser.Geom.Line.GetShortestDistance + * @since 3.16.0 + * + * @generic {Phaser.Geom.Point} O - [out,$return] + * + * @param {Phaser.Geom.Line} line - The line to get the distance from. + * @param {(Phaser.Geom.Point|object)} point - The point to get the shortest distance to. + * + * @return {number} The shortest distance from the line to the point. + */ +var GetShortestDistance = function (line, point) +{ + var x1 = line.x1; + var y1 = line.y1; + + var x2 = line.x2; + var y2 = line.y2; + + var L2 = (((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))); + + if (L2 === 0) + { + return false; + } + + var s = (((y1 - point.y) * (x2 - x1)) - ((x1 - point.x) * (y2 - y1))) / L2; + + return Math.abs(s) * Math.sqrt(L2); +}; + +module.exports = GetShortestDistance; diff --git a/src/geom/line/index.js b/src/geom/line/index.js index d0b34c470..9097da263 100644 --- a/src/geom/line/index.js +++ b/src/geom/line/index.js @@ -13,9 +13,11 @@ Line.Clone = require('./Clone'); Line.CopyFrom = require('./CopyFrom'); Line.Equals = require('./Equals'); Line.GetMidPoint = require('./GetMidPoint'); +Line.GetNearestPoint = require('./GetNearestPoint'); Line.GetNormal = require('./GetNormal'); Line.GetPoint = require('./GetPoint'); Line.GetPoints = require('./GetPoints'); +Line.GetShortestDistance = require('./GetShortestDistance'); Line.Height = require('./Height'); Line.Length = require('./Length'); Line.NormalAngle = require('./NormalAngle'); From b0df6892b57258f94bdf09824467d53f54f4f99a Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 27 Nov 2018 13:54:59 +0000 Subject: [PATCH 095/221] The Canvas `SetTransform` method would save the context state, but it wasn't restored at the end in the following Game Objects: Dynamic Bitmap Text, Graphics, Arc, Curve, Ellipse, Grid, IsoBox, IsoTriangle, Line, Polygon, Rectangle, Star and Triangle. These now all restore the context, meaning if you're using non-canvas sized cameras in Canvas mode, it will now render beyond just the first custom camera. --- CHANGELOG.md | 1 + .../DynamicBitmapTextCanvasRenderer.js | 7 +------ .../graphics/GraphicsCanvasRenderer.js | 3 +-- .../shape/arc/ArcCanvasRenderer.js | 3 +++ .../shape/curve/CurveCanvasRenderer.js | 3 +++ .../shape/ellipse/EllipseCanvasRenderer.js | 3 +++ .../shape/grid/GridCanvasRenderer.js | 3 +++ .../shape/isobox/IsoBoxCanvasRenderer.js | 3 +++ .../isotriangle/IsoTriangleCanvasRenderer.js | 3 +++ .../shape/line/LineCanvasRenderer.js | 3 +++ .../shape/polygon/PolygonCanvasRenderer.js | 3 +++ .../rectangle/RectangleCanvasRenderer.js | 3 +++ .../shape/star/StarCanvasRenderer.js | 3 +++ .../shape/triangle/TriangleCanvasRenderer.js | 3 +++ src/renderer/canvas/CanvasRenderer.js | 20 +++++++++---------- 15 files changed, 46 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e03cc85d9..796d5c42a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -116,6 +116,7 @@ * `Particle.index` has been removed, as it's no longer required. Particles don't need to keep track of their index any more. * The Particle Emitter no longer needs to call the StableSort.inplace during its preUpdate, saving cpu. * `Particle.resetPosition` is a new method that is called when a particle dies, preparing it ready for firing again in the future. +* The Canvas `SetTransform` method would save the context state, but it wasn't restored at the end in the following Game Objects: Dynamic Bitmap Text, Graphics, Arc, Curve, Ellipse, Grid, IsoBox, IsoTriangle, Line, Polygon, Rectangle, Star and Triangle. These now all restore the context, meaning if you're using non-canvas sized cameras in Canvas mode, it will now render beyond just the first custom camera. ### Examples and TypeScript diff --git a/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextCanvasRenderer.js b/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextCanvasRenderer.js index ae2f4d3cc..2eacb724a 100644 --- a/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextCanvasRenderer.js +++ b/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextCanvasRenderer.js @@ -72,7 +72,6 @@ var DynamicBitmapTextCanvasRenderer = function (renderer, src, interpolationPerc if (src.cropWidth > 0 && src.cropHeight > 0) { - ctx.save(); ctx.beginPath(); ctx.rect(0, 0, src.cropWidth, src.cropHeight); ctx.clip(); @@ -167,11 +166,7 @@ var DynamicBitmapTextCanvasRenderer = function (renderer, src, interpolationPerc lastCharCode = charCode; } - if (src.cropWidth > 0 && src.cropHeight > 0) - { - ctx.restore(); - } - + // Restore the context saved in SetTransform ctx.restore(); }; diff --git a/src/gameobjects/graphics/GraphicsCanvasRenderer.js b/src/gameobjects/graphics/GraphicsCanvasRenderer.js index 432d50591..40f438790 100644 --- a/src/gameobjects/graphics/GraphicsCanvasRenderer.js +++ b/src/gameobjects/graphics/GraphicsCanvasRenderer.js @@ -45,8 +45,6 @@ var GraphicsCanvasRenderer = function (renderer, src, interpolationPercentage, c var green = 0; var blue = 0; - ctx.save(); - // Reset any currently active paths ctx.beginPath(); @@ -239,6 +237,7 @@ var GraphicsCanvasRenderer = function (renderer, src, interpolationPercentage, c } } + // Restore the context saved in SetTransform ctx.restore(); }; diff --git a/src/gameobjects/shape/arc/ArcCanvasRenderer.js b/src/gameobjects/shape/arc/ArcCanvasRenderer.js index d38d329d8..188410c0b 100644 --- a/src/gameobjects/shape/arc/ArcCanvasRenderer.js +++ b/src/gameobjects/shape/arc/ArcCanvasRenderer.js @@ -61,6 +61,9 @@ var ArcCanvasRenderer = function (renderer, src, interpolationPercentage, camera ctx.stroke(); } + + // Restore the context saved in SetTransform + ctx.restore(); } }; diff --git a/src/gameobjects/shape/curve/CurveCanvasRenderer.js b/src/gameobjects/shape/curve/CurveCanvasRenderer.js index 8aec847ea..05a2e4a65 100644 --- a/src/gameobjects/shape/curve/CurveCanvasRenderer.js +++ b/src/gameobjects/shape/curve/CurveCanvasRenderer.js @@ -73,6 +73,9 @@ var CurveCanvasRenderer = function (renderer, src, interpolationPercentage, came ctx.stroke(); } + + // Restore the context saved in SetTransform + ctx.restore(); } }; diff --git a/src/gameobjects/shape/ellipse/EllipseCanvasRenderer.js b/src/gameobjects/shape/ellipse/EllipseCanvasRenderer.js index 7120f8df1..5336a0518 100644 --- a/src/gameobjects/shape/ellipse/EllipseCanvasRenderer.js +++ b/src/gameobjects/shape/ellipse/EllipseCanvasRenderer.js @@ -70,6 +70,9 @@ var EllipseCanvasRenderer = function (renderer, src, interpolationPercentage, ca ctx.stroke(); } + + // Restore the context saved in SetTransform + ctx.restore(); } }; diff --git a/src/gameobjects/shape/grid/GridCanvasRenderer.js b/src/gameobjects/shape/grid/GridCanvasRenderer.js index 973cc88c9..3f4ceeb7a 100644 --- a/src/gameobjects/shape/grid/GridCanvasRenderer.js +++ b/src/gameobjects/shape/grid/GridCanvasRenderer.js @@ -59,6 +59,9 @@ var RectangleCanvasRenderer = function (renderer, src, interpolationPercentage, ctx.stroke(); } + + // Restore the context saved in SetTransform + ctx.restore(); } }; diff --git a/src/gameobjects/shape/isobox/IsoBoxCanvasRenderer.js b/src/gameobjects/shape/isobox/IsoBoxCanvasRenderer.js index 94b828b2e..f94dc0d80 100644 --- a/src/gameobjects/shape/isobox/IsoBoxCanvasRenderer.js +++ b/src/gameobjects/shape/isobox/IsoBoxCanvasRenderer.js @@ -86,6 +86,9 @@ var IsoBoxCanvasRenderer = function (renderer, src, interpolationPercentage, cam ctx.fill(); } + + // Restore the context saved in SetTransform + ctx.restore(); } }; diff --git a/src/gameobjects/shape/isotriangle/IsoTriangleCanvasRenderer.js b/src/gameobjects/shape/isotriangle/IsoTriangleCanvasRenderer.js index 5410b0398..cbd1a64e5 100644 --- a/src/gameobjects/shape/isotriangle/IsoTriangleCanvasRenderer.js +++ b/src/gameobjects/shape/isotriangle/IsoTriangleCanvasRenderer.js @@ -99,6 +99,9 @@ var IsoTriangleCanvasRenderer = function (renderer, src, interpolationPercentage ctx.fill(); } + + // Restore the context saved in SetTransform + ctx.restore(); } }; diff --git a/src/gameobjects/shape/line/LineCanvasRenderer.js b/src/gameobjects/shape/line/LineCanvasRenderer.js index e3fbe3d04..231d4d0dc 100644 --- a/src/gameobjects/shape/line/LineCanvasRenderer.js +++ b/src/gameobjects/shape/line/LineCanvasRenderer.js @@ -42,6 +42,9 @@ var LineCanvasRenderer = function (renderer, src, interpolationPercentage, camer ctx.stroke(); } + + // Restore the context saved in SetTransform + ctx.restore(); } }; diff --git a/src/gameobjects/shape/polygon/PolygonCanvasRenderer.js b/src/gameobjects/shape/polygon/PolygonCanvasRenderer.js index b01abd1f4..bf447b96e 100644 --- a/src/gameobjects/shape/polygon/PolygonCanvasRenderer.js +++ b/src/gameobjects/shape/polygon/PolygonCanvasRenderer.js @@ -70,6 +70,9 @@ var PolygonCanvasRenderer = function (renderer, src, interpolationPercentage, ca ctx.stroke(); } + + // Restore the context saved in SetTransform + ctx.restore(); } }; diff --git a/src/gameobjects/shape/rectangle/RectangleCanvasRenderer.js b/src/gameobjects/shape/rectangle/RectangleCanvasRenderer.js index 973cc88c9..3f4ceeb7a 100644 --- a/src/gameobjects/shape/rectangle/RectangleCanvasRenderer.js +++ b/src/gameobjects/shape/rectangle/RectangleCanvasRenderer.js @@ -59,6 +59,9 @@ var RectangleCanvasRenderer = function (renderer, src, interpolationPercentage, ctx.stroke(); } + + // Restore the context saved in SetTransform + ctx.restore(); } }; diff --git a/src/gameobjects/shape/star/StarCanvasRenderer.js b/src/gameobjects/shape/star/StarCanvasRenderer.js index ab70adbd0..287976bc6 100644 --- a/src/gameobjects/shape/star/StarCanvasRenderer.js +++ b/src/gameobjects/shape/star/StarCanvasRenderer.js @@ -70,6 +70,9 @@ var StarCanvasRenderer = function (renderer, src, interpolationPercentage, camer ctx.stroke(); } + + // Restore the context saved in SetTransform + ctx.restore(); } }; diff --git a/src/gameobjects/shape/triangle/TriangleCanvasRenderer.js b/src/gameobjects/shape/triangle/TriangleCanvasRenderer.js index 1214eebe2..25bc48a67 100644 --- a/src/gameobjects/shape/triangle/TriangleCanvasRenderer.js +++ b/src/gameobjects/shape/triangle/TriangleCanvasRenderer.js @@ -60,6 +60,9 @@ var TriangleCanvasRenderer = function (renderer, src, interpolationPercentage, c ctx.stroke(); } + + // Restore the context saved in SetTransform + ctx.restore(); } }; diff --git a/src/renderer/canvas/CanvasRenderer.js b/src/renderer/canvas/CanvasRenderer.js index 1d9b37ea0..fc5a39537 100644 --- a/src/renderer/canvas/CanvasRenderer.js +++ b/src/renderer/canvas/CanvasRenderer.js @@ -410,7 +410,15 @@ var CanvasRenderer = new Class({ var ctx = (camera.renderToTexture) ? camera.context : scene.sys.context; - var scissor = (cx !== 0 || cy !== 0 || cw !== ctx.canvas.width || ch !== ctx.canvas.height); + // Save context pre-clip + ctx.save(); + + if (this.game.scene.customViewports) + { + ctx.beginPath(); + ctx.rect(cx, cy, cw, ch); + ctx.clip(); + } this.currentContext = ctx; @@ -426,15 +434,6 @@ var CanvasRenderer = new Class({ this.drawCount += list.length; - ctx.save(); - - if (scissor) - { - ctx.beginPath(); - ctx.rect(cx, cy, cw, ch); - ctx.clip(); - } - if (camera.renderToTexture) { camera.emit('prerender', camera); @@ -473,6 +472,7 @@ var CanvasRenderer = new Class({ camera.dirty = false; + // Restore pre-clip context ctx.restore(); if (camera.renderToTexture) From 052da6e40c1bede105ff926bd02fbfdad8b2fcc1 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 27 Nov 2018 14:04:19 +0000 Subject: [PATCH 096/221] lint fix --- src/geom/intersects/PointToLine.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/geom/intersects/PointToLine.js b/src/geom/intersects/PointToLine.js index 395f01cbc..c29a6ed11 100644 --- a/src/geom/intersects/PointToLine.js +++ b/src/geom/intersects/PointToLine.js @@ -45,7 +45,7 @@ var PointToLine = function (point, line, lineThickness) if (r < 0) { // Outside line1 - return (Math.sqrt(((x1 - px) * (x1 - px) ) + ( (y1 - py) * (y1 - py))) <= lineThickness); + return (Math.sqrt(((x1 - px) * (x1 - px)) + ((y1 - py) * (y1 - py))) <= lineThickness); } else if ((r >= 0) && (r <= 1)) { From 30972f4528dc4ea3c9dc74c666dd699dba2a4f41 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 27 Nov 2018 17:16:03 +0000 Subject: [PATCH 097/221] `Camera.getBounds` is a new method that will return a rectangle containing the bounds of the camera. --- CHANGELOG.md | 1 + src/cameras/2d/BaseCamera.js | 29 ++++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 796d5c42a..dc9c2b69f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ * `Geom.Intersects.PointToLine` has a new optional argument `lineThickness` (which defaults to 1). This allows you to determine if the point intersects a line of a given thickness, where the line-ends are circular (not square). * `Geom.Line.GetNearestPoint` is a new static method that will return the nearest point on a line to the given point. * `Geom.Line.GetShortestDistance` is a new static method that will return the shortest distance from a line to the given point. +* `Camera.getBounds` is a new method that will return a rectangle containing the bounds of the camera. ### Updates diff --git a/src/cameras/2d/BaseCamera.js b/src/cameras/2d/BaseCamera.js index 78ba5f84f..d73e07869 100644 --- a/src/cameras/2d/BaseCamera.js +++ b/src/cameras/2d/BaseCamera.js @@ -1079,12 +1079,14 @@ var BaseCamera = new Class({ * @param {integer} y - The top-left y coordinate of the bounds. * @param {integer} width - The width of the bounds, in pixels. * @param {integer} height - The height of the bounds, in pixels. - * @param {boolean} [centerOn] - If `true` the Camera will automatically be centered on the new bounds. + * @param {boolean} [centerOn=false] - If `true` the Camera will automatically be centered on the new bounds. * * @return {Phaser.Cameras.Scene2D.BaseCamera} This Camera instance. */ setBounds: function (x, y, width, height, centerOn) { + if (centerOn === undefined) { centerOn = false; } + this._bounds.setTo(x, y, width, height); this.dirty = true; @@ -1103,6 +1105,31 @@ var BaseCamera = new Class({ return this; }, + /** + * Returns a rectangle containing the bounds of the Camera. + * + * If the Camera does not have any bounds the rectangle will be empty. + * + * The rectangle is a copy of the bounds, so is safe to modify. + * + * @method Phaser.Cameras.Scene2D.BaseCamera#getBounds + * @since 3.16.0 + * + * @param {Phaser.Geom.Rectangle} [out] - An optional Rectangle to store the bounds in. If not given, a new Rectangle will be created. + * + * @return {Phaser.Geom.Rectangle} A rectangle containing the bounds of this Camera. + */ + getBounds: function (out) + { + if (out === undefined) { out = new Rectangle(); } + + var source = this._bounds; + + out.setTo(source.x, source.y, source.width, source.height); + + return out; + }, + /** * Sets the name of this Camera. * This value is for your own use and isn't used internally. From 74798cf206b321b637ea6d32a394ceff15061e87 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 08:41:03 +0000 Subject: [PATCH 098/221] Typo --- src/cameras/2d/BaseCamera.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cameras/2d/BaseCamera.js b/src/cameras/2d/BaseCamera.js index d73e07869..b0033e775 100644 --- a/src/cameras/2d/BaseCamera.js +++ b/src/cameras/2d/BaseCamera.js @@ -568,7 +568,7 @@ var BaseCamera = new Class({ * @param {number} y - The vertical coordinate to center on. * @param {Phaser.Math.Vector2} [out] - A Vec2 to store the values in. If not given a new Vec2 is created. * - * @return {Phaser.Math.Vector2} The scroll coordinates stored in the `x` abd `y` properties. + * @return {Phaser.Math.Vector2} The scroll coordinates stored in the `x` and `y` properties. */ getScroll: function (x, y, out) { From 09bd56bd8e38b5c2a34a71722420629e472f95b4 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 13:09:48 +0000 Subject: [PATCH 099/221] Removed Game.isOver property --- src/boot/Game.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/boot/Game.js b/src/boot/Game.js index 12e953bf2..a286c8d65 100644 --- a/src/boot/Game.js +++ b/src/boot/Game.js @@ -329,17 +329,6 @@ var Game = new Class({ */ this.hasFocus = false; - /** - * Is the mouse pointer currently over the game canvas or not? - * This is modified by the VisibilityHandler. - * - * @name Phaser.Game#isOver - * @type {boolean} - * @readonly - * @since 3.10.0 - */ - this.isOver = true; - // Wait for the DOM Ready event, then call boot. DOMContentLoaded(this.boot.bind(this)); }, From 5b6920c577e03b6c5bcc1e7c4a3a5ab358e25057 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 13:10:05 +0000 Subject: [PATCH 100/221] Vis handler no longer responsible for focus or isOver events. --- src/boot/VisibilityHandler.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/boot/VisibilityHandler.js b/src/boot/VisibilityHandler.js index 189eeaede..35413c259 100644 --- a/src/boot/VisibilityHandler.js +++ b/src/boot/VisibilityHandler.js @@ -109,26 +109,6 @@ var VisibilityHandler = function (game) if (window.focus && game.config.autoFocus) { window.focus(); - - game.canvas.addEventListener('mousedown', function () - { - window.focus(); - }, { passive: true }); - } - - if (game.canvas) - { - game.canvas.onmouseout = function () - { - game.isOver = false; - eventEmitter.emit('mouseout'); - }; - - game.canvas.onmouseover = function () - { - game.isOver = true; - eventEmitter.emit('mouseover'); - }; } }; From 0d2197d9f7c126f024648faab3e1c7036160b5bf Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 13:10:25 +0000 Subject: [PATCH 101/221] Added new isOver property and method handlers. --- src/input/InputManager.js | 56 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/input/InputManager.js b/src/input/InputManager.js index fad6f03f5..b40d0073b 100644 --- a/src/input/InputManager.js +++ b/src/input/InputManager.js @@ -110,6 +110,27 @@ var InputManager = new Class({ */ this.domCallbacks = { up: [], down: [], move: [], upOnce: [], downOnce: [], moveOnce: [] }; + /** + * Are any mouse or touch pointers currently over the game canvas? + * This is updated automatically by the canvas over and out handlers. + * + * @name Phaser.Input.InputManager#isOver + * @type {boolean} + * @readonly + * @since 3.16.0 + */ + this.isOver = true; + + /** + * isOver state change property. + * + * @name Phaser.Input.InputManager#_emitIsOverEvent + * @type {boolean} + * @private + * @since 3.16.0 + */ + this._emitIsOverEvent = false; + /** * Are there any up callbacks defined? * @@ -418,6 +439,38 @@ var InputManager = new Class({ */ }, + /** + * Internal canvas state change, called automatically by the Mouse Manager. + * + * @method Phaser.Input.InputManager#setCanvasOver + * @private + * @since 3.16.0 + * + * @param {number} event - The DOM Event. + */ + setCanvasOver: function (event) + { + this.isOver = true; + + this._emitIsOverEvent = event; + }, + + /** + * Internal canvas state change, called automatically by the Mouse Manager. + * + * @method Phaser.Input.InputManager#setCanvasOut + * @private + * @since 3.16.0 + * + * @param {number} event - The DOM Event. + */ + setCanvasOut: function (event) + { + this.isOver = false; + + this._emitIsOverEvent = event; + }, + /** * Internal update loop, called automatically by the Game Step. * @@ -535,6 +588,9 @@ var InputManager = new Class({ { this.canvas.style.cursor = this.defaultCursor; } + + // Reset the isOver event + this._emitIsOverEvent = null; }, /** From 4a312f16dbc67dc2eb4cd2b9a56e99a6f6ad2fd5 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 13:10:54 +0000 Subject: [PATCH 102/221] Input Plugin will now emit a `gameover` or `gameout` event and has an `isOver` property. --- src/input/InputPlugin.js | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/input/InputPlugin.js b/src/input/InputPlugin.js index f73b7cc5a..7dbdb7291 100644 --- a/src/input/InputPlugin.js +++ b/src/input/InputPlugin.js @@ -476,16 +476,23 @@ var InputPlugin = new Class({ return; } - this.pluginEvents.emit('update', time, delta); - var manager = this.manager; + this.pluginEvents.emit('update', time, delta); + // Another Scene above this one has already consumed the input events, or we're in transition if (manager.globalTopOnly && manager.ignoreEvents) { return; } + if (manager._emitIsOverEvent) + { + var event = (manager.isOver) ? 'gameover' : 'gameout'; + + this.emit(event, time, manager._emitIsOverEvent); + } + var runUpdate = (manager.dirty || this.pollRate === 0); if (this.pollRate > -1) @@ -2297,6 +2304,23 @@ var InputPlugin = new Class({ }, + /** + * Are any mouse or touch pointers currently over the game canvas? + * + * @name Phaser.Input.InputPlugin#isOver + * @type {boolean} + * @readonly + * @since 3.16.0 + */ + isOver: { + + get: function () + { + return this.manager.isOver; + } + + }, + /** * The mouse has its own unique Pointer object, which you can reference directly if making a _desktop specific game_. * If you are supporting both desktop and touch devices then do not use this property, instead use `activePointer` From 4b50065dfd22cf1e7740310dad3293b1ca483759 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 13:11:13 +0000 Subject: [PATCH 103/221] Touch Manager will track over and out canvas states. --- src/input/touch/TouchManager.js | 69 +++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/src/input/touch/TouchManager.js b/src/input/touch/TouchManager.js index 4cdb99d4b..c3ee25e04 100644 --- a/src/input/touch/TouchManager.js +++ b/src/input/touch/TouchManager.js @@ -112,6 +112,26 @@ var TouchManager = new Class({ */ this.onTouchCancel = NOOP; + /** + * The Touch Over event handler function. + * Initially empty and bound in the `startListeners` method. + * + * @name Phaser.Input.Touch.TouchManager#onTouchOver + * @type {function} + * @since 3.16.0 + */ + this.onTouchOver = NOOP; + + /** + * The Touch Out event handler function. + * Initially empty and bound in the `startListeners` method. + * + * @name Phaser.Input.Touch.TouchManager#onTouchOut + * @type {function} + * @since 3.16.0 + */ + this.onTouchOut = NOOP; + inputManager.events.once('boot', this.boot, this); }, @@ -219,6 +239,28 @@ var TouchManager = new Class({ } }; + this.onTouchOver = function (event) + { + if (event.defaultPrevented || !_this.enabled || !_this.manager) + { + // Do nothing if event already handled + return; + } + + _this.manager.setCanvasOver(event); + }; + + this.onTouchOut = function (event) + { + if (event.defaultPrevented || !_this.enabled || !_this.manager) + { + // Do nothing if event already handled + return; + } + + _this.manager.setCanvasOut(event); + }; + var target = this.target; if (!target) @@ -229,18 +271,16 @@ var TouchManager = new Class({ var passive = { passive: true }; var nonPassive = { passive: false }; - if (this.capture) + target.addEventListener('touchstart', this.onTouchStart, (this.capture) ? nonPassive : passive); + target.addEventListener('touchmove', this.onTouchMove, (this.capture) ? nonPassive : passive); + target.addEventListener('touchend', this.onTouchEnd, (this.capture) ? nonPassive : passive); + target.addEventListener('touchcancel', this.onTouchCancel, (this.capture) ? nonPassive : passive); + target.addEventListener('touchover', this.onTouchOver, (this.capture) ? nonPassive : passive); + target.addEventListener('touchout', this.onTouchOut, (this.capture) ? nonPassive : passive); + + if (window) { - target.addEventListener('touchstart', this.onTouchStart, nonPassive); - target.addEventListener('touchmove', this.onTouchMove, nonPassive); - target.addEventListener('touchend', this.onTouchEnd, nonPassive); - target.addEventListener('touchcancel', this.onTouchCancel, nonPassive); - } - else - { - target.addEventListener('touchstart', this.onTouchStart, passive); - target.addEventListener('touchmove', this.onTouchMove, passive); - target.addEventListener('touchend', this.onTouchEnd, passive); + window.addEventListener('touchend', this.onTouchEnd, nonPassive); } this.enabled = true; @@ -261,6 +301,13 @@ var TouchManager = new Class({ target.removeEventListener('touchmove', this.onTouchMove); target.removeEventListener('touchend', this.onTouchEnd); target.removeEventListener('touchcancel', this.onTouchCancel); + target.removeEventListener('touchover', this.onTouchOver); + target.removeEventListener('touchout', this.onTouchOut); + + if (window) + { + window.removeEventListener('touchend', this.onTouchEnd); + } }, /** From 5623515c4128c6bcf735b81541131744757f141e Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 13:13:25 +0000 Subject: [PATCH 104/221] Mouse Manager will track over and out states and auto focus. --- src/input/mouse/MouseManager.js | 79 +++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 14 deletions(-) diff --git a/src/input/mouse/MouseManager.js b/src/input/mouse/MouseManager.js index 4b2e105be..b19f03024 100644 --- a/src/input/mouse/MouseManager.js +++ b/src/input/mouse/MouseManager.js @@ -116,6 +116,28 @@ var MouseManager = new Class({ */ this.onMouseUp = NOOP; + /** + * The Mouse Over Event handler. + * This function is sent the native DOM MouseEvent. + * Initially empty and bound in the `startListeners` method. + * + * @name Phaser.Input.Mouse.MouseManager#onMouseOver + * @type {function} + * @since 3.16.0 + */ + this.onMouseOver = NOOP; + + /** + * The Mouse Out Event handler. + * This function is sent the native DOM MouseEvent. + * Initially empty and bound in the `startListeners` method. + * + * @name Phaser.Input.Mouse.MouseManager#onMouseOut + * @type {function} + * @since 3.16.0 + */ + this.onMouseOut = NOOP; + /** * Internal pointerLockChange handler. * This function is sent the native DOM MouseEvent. @@ -127,10 +149,6 @@ var MouseManager = new Class({ */ this.pointerLockChange = NOOP; - // Testing ... - this.prevPosition = new Vector2(); - this.position = new Vector2(); - inputManager.events.once('boot', this.boot, this); }, @@ -243,6 +261,7 @@ var MouseManager = new Class({ startListeners: function () { var _this = this; + var autoFocus = (window && window.focus && this.manager.game.config.autoFocus); this.onMouseMove = function (event) { @@ -262,6 +281,11 @@ var MouseManager = new Class({ this.onMouseDown = function (event) { + if (autoFocus) + { + window.focus(); + } + if (event.defaultPrevented || !_this.enabled || !_this.manager) { // Do nothing if event already handled @@ -292,6 +316,28 @@ var MouseManager = new Class({ } }; + this.onMouseOver = function (event) + { + if (event.defaultPrevented || !_this.enabled || !_this.manager) + { + // Do nothing if event already handled + return; + } + + _this.manager.setCanvasOver(event); + }; + + this.onMouseOut = function (event) + { + if (event.defaultPrevented || !_this.enabled || !_this.manager) + { + // Do nothing if event already handled + return; + } + + _this.manager.setCanvasOut(event); + }; + var target = this.target; if (!target) @@ -302,17 +348,15 @@ var MouseManager = new Class({ var passive = { passive: true }; var nonPassive = { passive: false }; - if (this.capture) + target.addEventListener('mousemove', this.onMouseMove, (this.capture) ? nonPassive : passive); + target.addEventListener('mousedown', this.onMouseDown, (this.capture) ? nonPassive : passive); + target.addEventListener('mouseup', this.onMouseUp, (this.capture) ? nonPassive : passive); + target.addEventListener('mouseover', this.onMouseOver, (this.capture) ? nonPassive : passive); + target.addEventListener('mouseout', this.onMouseOut, (this.capture) ? nonPassive : passive); + + if (window) { - target.addEventListener('mousemove', this.onMouseMove, nonPassive); - target.addEventListener('mousedown', this.onMouseDown, nonPassive); - target.addEventListener('mouseup', this.onMouseUp, nonPassive); - } - else - { - target.addEventListener('mousemove', this.onMouseMove, passive); - target.addEventListener('mousedown', this.onMouseDown, passive); - target.addEventListener('mouseup', this.onMouseUp, passive); + window.addEventListener('mouseup', this.onMouseUp, nonPassive); } if (Features.pointerLock) @@ -348,6 +392,13 @@ var MouseManager = new Class({ target.removeEventListener('mousemove', this.onMouseMove); target.removeEventListener('mousedown', this.onMouseDown); target.removeEventListener('mouseup', this.onMouseUp); + target.removeEventListener('mouseover', this.onMouseOver); + target.removeEventListener('mouseout', this.onMouseOut); + + if (window) + { + window.removeEventListener('mouseup', this.onMouseUp); + } if (Features.pointerLock) { From f2de618b244e072b3856186fe20278bf5fd2b19d Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 13:13:44 +0000 Subject: [PATCH 105/221] Touch Manager will now handle focus events as well. --- src/input/touch/TouchManager.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/input/touch/TouchManager.js b/src/input/touch/TouchManager.js index c3ee25e04..2320b685b 100644 --- a/src/input/touch/TouchManager.js +++ b/src/input/touch/TouchManager.js @@ -174,9 +174,15 @@ var TouchManager = new Class({ startListeners: function () { var _this = this; + var autoFocus = (window && window.focus && this.manager.game.config.autoFocus); this.onTouchStart = function (event) { + if (autoFocus) + { + window.focus(); + } + if (event.defaultPrevented || !_this.enabled || !_this.manager) { // Do nothing if event already handled From f8cd23766e582ed3a38b7cd15de1c8c69516a210 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 13:13:46 +0000 Subject: [PATCH 106/221] Update CHANGELOG.md --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc9c2b69f..8f24b4f32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,16 @@ * `Pointer.getDistanceY` is a new method that will return the horizontal distance between the Pointer's previous and current coordinates. If called while a button is being held down, it will return the distance between the Pointer's current position and it's down position. If called when a Pointer doesn't have a button down, it will return the historic distance between the up and down positions. * `Pointer.getDuration` is a new method that will return the duration the Pointer was held down for. If the Pointer has a button pressed down at the time this method is called, it will return the duration since the Pointer's was pressed down. If no button is held down, it will return the last recorded duration, based on the time the Pointer button was released. * `Pointer.getAngle` is a new method that will return the angle between the Pointer coordinates. If the Pointer has a button pressed down at the time this method is called, it will return the angle between the Pointer's `downX` and `downY` values and the current position. If no button is held down, it will return the last recorded angle, based on where the Pointer was when the button was released. +* In previous versions, the VisibilityHandler would create a `mousedown` listener for the game canvas and then call `window.focus` when detected (assuming the game config `autoFocus` property was `true`). Responsibility for this has now been handled to the Mouse Manager `onMouseDown` handler. +* In previous versions, the VisibilityHandler would create a `mouseout` listener for the game canvas and then set `game.isOver` when detected. Responsibility for this has now been handled to the Mouse Manager, which sets the new Input Manager `isOver` property directly. +* In previous versions, the VisibilityHandler would create a `mouseover` listener for the game canvas and then set `game.isOver` when detected. Responsibility for this has now been handled to the Mouse Manager, which sets the new Input Manager `isOver` property directly. +* The `Phaser.Game.isOver` property has been moved. You can now find it in the Input Manager and it's also accessible via the Input Plugin, which means you can do `this.input.isOver` from within a Scene. This makes more sense as it's input related and not a game level property. +* The Input Plugin has a new event you can listen to: `gameover`, which is triggered whenever the mouse or a pointer is moved over the Game canvas. Listen to it with `this.input.on('gameover')` from within a Scene. +* The Input Plugin has a new event you can listen to: `gameout`, which is triggered whenever the mouse or a pointer leaves the Game canvas. Listen to it with `this.input.on('gameout')` from within a Scene. +* The Game used to emit a `mouseover` event when the mouse entered the game canvas. This is no longer emitted by the Game itself and can instead be listened for using the new Input Plugin event `gameover`. +* The Game used to emit a `mouseout` event when the mouse left the game canvas. This is no longer emitted by the Game itself and can instead be listened for using the new Input Plugin event `gameout`. +* If the `window` object exists (which it will in normal browser environments) new `mouseup` and `touchend` event listeners are bound to it and trigger the normal `mouseup` or `touchend` events within the internal input system. This means if you will now get a `pointerup` event from the Input Plugin even if the pointer is released outside of the game canvas. Pointers will also no longer think they are still 'down' if released outside the canvas and then moved inside again in their new state. +* The window will now have focus called on it by the Touch Manager, as well as the Mouse Manager, is the `autoFocus` game config property is enabled. ### New Features From 171191e1d846b99612016fe5c4d1a412c70f93de Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 13:24:29 +0000 Subject: [PATCH 107/221] Added Camera centerOnX and centerOnY methods. --- CHANGELOG.md | 2 ++ src/cameras/2d/BaseCamera.js | 69 +++++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f24b4f32..9ee290ef2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,8 @@ * `Geom.Line.GetNearestPoint` is a new static method that will return the nearest point on a line to the given point. * `Geom.Line.GetShortestDistance` is a new static method that will return the shortest distance from a line to the given point. * `Camera.getBounds` is a new method that will return a rectangle containing the bounds of the camera. +* `Camera.centerOnX` will move the camera horizontally to be centered on the given coordinate, without changing its vertical placement. +* `Camera.centerOnY` will move the camera vertically to be centered on the given coordinate, without changing its horizontally placement. ### Updates diff --git a/src/cameras/2d/BaseCamera.js b/src/cameras/2d/BaseCamera.js index b0033e775..a72025e33 100644 --- a/src/cameras/2d/BaseCamera.js +++ b/src/cameras/2d/BaseCamera.js @@ -589,6 +589,60 @@ var BaseCamera = new Class({ return out; }, + /** + * Moves the Camera horizontally so that it is centered on the given x coordinate, bounds allowing. + * Calling this does not change the scrollY value. + * + * @method Phaser.Cameras.Scene2D.BaseCamera#centerOnX + * @since 3.16.0 + * + * @param {number} x - The horizontal coordinate to center on. + * + * @return {Phaser.Cameras.Scene2D.BaseCamera} This Camera instance. + */ + centerOnX: function (x) + { + var originX = this.width * 0.5; + + this.midPoint.x = x; + + this.scrollX = x - originX; + + if (this.useBounds) + { + this.scrollX = this.clampX(this.scrollX); + } + + return this; + }, + + /** + * Moves the Camera vertically so that it is centered on the given y coordinate, bounds allowing. + * Calling this does not change the scrollX value. + * + * @method Phaser.Cameras.Scene2D.BaseCamera#centerOnY + * @since 3.16.0 + * + * @param {number} y - The vertical coordinate to center on. + * + * @return {Phaser.Cameras.Scene2D.BaseCamera} This Camera instance. + */ + centerOnY: function (y) + { + var originY = this.height * 0.5; + + this.midPoint.y = y; + + this.scrollY = y - originY; + + if (this.useBounds) + { + this.scrollY = this.clampY(this.scrollY); + } + + return this; + }, + /** * Moves the Camera so that it is centered on the given coordinates, bounds allowing. * @@ -602,19 +656,8 @@ var BaseCamera = new Class({ */ centerOn: function (x, y) { - var originX = this.width * 0.5; - var originY = this.height * 0.5; - - this.midPoint.set(x, y); - - this.scrollX = x - originX; - this.scrollY = y - originY; - - if (this.useBounds) - { - this.scrollX = this.clampX(this.scrollX); - this.scrollY = this.clampY(this.scrollY); - } + this.centerOnX(x); + this.centerOnY(y); return this; }, From 299a3d108c17fbfbd7c95152a98f1a0c977da7d5 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 15:47:06 +0000 Subject: [PATCH 108/221] Fixed custom environment logic --- src/boot/CreateRenderer.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/boot/CreateRenderer.js b/src/boot/CreateRenderer.js index 4aeb1aa3d..562ffc33e 100644 --- a/src/boot/CreateRenderer.js +++ b/src/boot/CreateRenderer.js @@ -23,10 +23,13 @@ var CreateRenderer = function (game) { var config = game.config; - // Game either requested Canvas, - // or requested AUTO or WEBGL but the browser doesn't support it, so fall back to Canvas + if ((config.customEnvironment || config.canvas) && config.renderType === CONST.AUTO) + { + throw new Error('Must set explicit renderType in custom environment'); + } - if ((config.customEnvironment || config.canvas) && config.renderType !== CONST.HEADLESS) + // Not a custom environment, didn't provide their own canvas and not headless, so determine the renderer: + if (!config.customEnvironment && !config.canvas && config.renderType !== CONST.HEADLESS) { if (config.renderType === CONST.CANVAS || (config.renderType !== CONST.CANVAS && !Features.webGL)) { @@ -47,11 +50,6 @@ var CreateRenderer = function (game) } } - if (config.customEnvironment && config.renderType === CONST.AUTO) - { - throw new Error('Must set renderType in custom environment'); - } - // Pixel Art mode? if (!config.antialias) { From fafc597b4c64776bbcd91e16c5c883fe56293faf Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 15:49:24 +0000 Subject: [PATCH 109/221] Added fillRect back in for non-transparent canvas --- src/renderer/canvas/CanvasRenderer.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/renderer/canvas/CanvasRenderer.js b/src/renderer/canvas/CanvasRenderer.js index fc5a39537..881280abc 100644 --- a/src/renderer/canvas/CanvasRenderer.js +++ b/src/renderer/canvas/CanvasRenderer.js @@ -382,6 +382,12 @@ var CanvasRenderer = new Class({ ctx.clearRect(0, 0, width, height); } + if (!config.transparent) + { + ctx.fillStyle = config.backgroundColor.rgba; + ctx.fillRect(0, 0, width, height); + } + ctx.save(); this.drawCount = 0; From f3488b0d7c0c75291c484c845c70a3a15e660806 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 28 Nov 2018 15:51:31 +0000 Subject: [PATCH 110/221] Undid CSS background style --- CHANGELOG.md | 1 - src/boot/CreateRenderer.js | 6 ------ 2 files changed, 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ee290ef2..3656a295e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,7 +78,6 @@ ### Updates -* The `backgroundColor` property of the Game Config is now used to set the CSS backgroundColor property of the game Canvas element. This avoids a `fillRect` call in Canvas mode and allows for 'punch through' effects to be created. If `transparent` is true, the CSS property is not set and no background color is drawn in either WebGL or Canvas, allowing the canvas to be fully transparent. * You can now modify `this.physics.world.debugGraphic.defaultStrokeWidth` to set the stroke width of any debug drawn body, previously it was always 1 (thanks @samme) * `TextStyle.setFont` has a new optional argument `updateText` which will sets if the text should be automatically updated or not (thanks @DotTheGreat) * `ProcessQueue.destroy` now sets the internal `toProcess` counter to zero. diff --git a/src/boot/CreateRenderer.js b/src/boot/CreateRenderer.js index 562ffc33e..76c37eb82 100644 --- a/src/boot/CreateRenderer.js +++ b/src/boot/CreateRenderer.js @@ -75,12 +75,6 @@ var CreateRenderer = function (game) game.canvas.style = config.canvasStyle; } - // Background color - if (!config.transparent) - { - game.canvas.style.backgroundColor = config.backgroundColor.rgba; - } - // Pixel Art mode? if (!config.antialias) { From b8f7ecb3176ad60ab95e7cafa06fd70ad229c895 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 29 Nov 2018 13:42:26 +0000 Subject: [PATCH 111/221] Removed Vec2 and added global handlers with capture tests. --- src/input/mouse/MouseManager.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/input/mouse/MouseManager.js b/src/input/mouse/MouseManager.js index b19f03024..882f39a9a 100644 --- a/src/input/mouse/MouseManager.js +++ b/src/input/mouse/MouseManager.js @@ -7,7 +7,6 @@ var Class = require('../../utils/Class'); var Features = require('../../device/Features'); var NOOP = require('../../utils/Class'); -var Vector2 = require('../../math/Vector2'); // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md @@ -261,6 +260,7 @@ var MouseManager = new Class({ startListeners: function () { var _this = this; + var canvas = this.manager.canvas; var autoFocus = (window && window.focus && this.manager.game.config.autoFocus); this.onMouseMove = function (event) @@ -294,7 +294,7 @@ var MouseManager = new Class({ _this.manager.queueMouseDown(event); - if (_this.capture) + if (_this.capture && event.target === canvas) { event.preventDefault(); } @@ -310,7 +310,7 @@ var MouseManager = new Class({ _this.manager.queueMouseUp(event); - if (_this.capture) + if (_this.capture && event.target === canvas) { event.preventDefault(); } @@ -356,6 +356,7 @@ var MouseManager = new Class({ if (window) { + window.addEventListener('mousedown', this.onMouseDown, nonPassive); window.addEventListener('mouseup', this.onMouseUp, nonPassive); } @@ -397,6 +398,7 @@ var MouseManager = new Class({ if (window) { + window.removeEventListener('mousedown', this.onMouseDown); window.removeEventListener('mouseup', this.onMouseUp); } From a065bf1b4613ebee368246329d8aa40dde7029f6 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 29 Nov 2018 13:42:40 +0000 Subject: [PATCH 112/221] Added global touchstart handler. --- src/input/touch/TouchManager.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/input/touch/TouchManager.js b/src/input/touch/TouchManager.js index 2320b685b..eb5d8761a 100644 --- a/src/input/touch/TouchManager.js +++ b/src/input/touch/TouchManager.js @@ -174,6 +174,7 @@ var TouchManager = new Class({ startListeners: function () { var _this = this; + var canvas = this.manager.canvas; var autoFocus = (window && window.focus && this.manager.game.config.autoFocus); this.onTouchStart = function (event) @@ -191,7 +192,7 @@ var TouchManager = new Class({ _this.manager.queueTouchStart(event); - if (_this.capture) + if (_this.capture && event.target === canvas) { event.preventDefault(); } @@ -223,7 +224,7 @@ var TouchManager = new Class({ _this.manager.queueTouchEnd(event); - if (_this.capture) + if (_this.capture && event.target === canvas) { event.preventDefault(); } @@ -286,6 +287,7 @@ var TouchManager = new Class({ if (window) { + window.addEventListener('touchstart', this.onTouchStart, nonPassive); window.addEventListener('touchend', this.onTouchEnd, nonPassive); } @@ -312,6 +314,7 @@ var TouchManager = new Class({ if (window) { + window.removeEventListener('touchstart', this.onTouchStart); window.removeEventListener('touchend', this.onTouchEnd); } }, From 068124b73967c306537bba28398e0d0766ef1b03 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 29 Nov 2018 13:43:44 +0000 Subject: [PATCH 113/221] Added sceneManager property. --- src/loader/LoaderPlugin.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/loader/LoaderPlugin.js b/src/loader/LoaderPlugin.js index 46ae0c70d..51315b9a3 100644 --- a/src/loader/LoaderPlugin.js +++ b/src/loader/LoaderPlugin.js @@ -100,6 +100,16 @@ var LoaderPlugin = new Class({ */ this.textureManager = scene.sys.textures; + /** + * A reference to the global Scene Manager. + * + * @name Phaser.Loader.LoaderPlugin#sceneManager + * @type {Phaser.Scenes.SceneManager} + * @protected + * @since 3.16.0 + */ + this.sceneManager = scene.sys.game.scene; + // Inject the available filetypes into the Loader FileTypesManager.install(this); @@ -1089,6 +1099,7 @@ var LoaderPlugin = new Class({ this.systems = null; this.textureManager = null; this.cacheManager = null; + this.sceneManager = null; } }); From 5b5b83d2693dc9c271297511c6ad3d3efa094a53 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 29 Nov 2018 13:44:18 +0000 Subject: [PATCH 114/221] Added downElement and upElement properties --- src/input/Pointer.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/input/Pointer.js b/src/input/Pointer.js index 8d1c30858..020135c81 100644 --- a/src/input/Pointer.js +++ b/src/input/Pointer.js @@ -68,6 +68,26 @@ var Pointer = new Class({ */ this.event; + /** + * The DOM element the Pointer was pressed down on, taken from the DOM event. + * + * @name Phaser.Input.Pointer#downElement + * @type {any} + * @readonly + * @since 3.16.0 + */ + this.downElement; + + /** + * The DOM element the Pointer was released on, taken from the DOM event. + * + * @name Phaser.Input.Pointer#upElement + * @type {any} + * @readonly + * @since 3.16.0 + */ + this.upElement; + /** * The camera the Pointer interacted with during its last update. * @@ -568,6 +588,8 @@ var Pointer = new Class({ this.event = event; + this.upElement = event.target; + // Sets the local x/y properties this.manager.transformPointer(this, event.pageX, event.pageY, false); @@ -607,6 +629,8 @@ var Pointer = new Class({ this.event = event; + this.downElement = event.target; + // Sets the local x/y properties this.manager.transformPointer(this, event.pageX, event.pageY, false); @@ -690,6 +714,8 @@ var Pointer = new Class({ this.event = event; + this.downElement = event.target; + // Sets the local x/y properties this.manager.transformPointer(this, event.pageX, event.pageY, false); @@ -749,6 +775,8 @@ var Pointer = new Class({ this.event = event; + this.upElement = event.target; + // Sets the local x/y properties this.manager.transformPointer(this, event.pageX, event.pageY, false); From 1b280805759d99b1579ad7c75e81c661530e866f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 29 Nov 2018 13:44:42 +0000 Subject: [PATCH 115/221] Added `pointerupoutside` and `pointerdownoutside` events. --- src/input/InputPlugin.js | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/input/InputPlugin.js b/src/input/InputPlugin.js index 7dbdb7291..46c698604 100644 --- a/src/input/InputPlugin.js +++ b/src/input/InputPlugin.js @@ -758,6 +758,7 @@ var InputPlugin = new Class({ * @fires Phaser.GameObjects.GameObject#pointerdownEvent * @fires Phaser.Input.InputPlugin#gameobjectdownEvent * @fires Phaser.Input.InputPlugin#pointerdownEvent + * @fires Phaser.Input.InputPlugin#pointerdownoutsideEvent * @since 3.0.0 * * @param {Phaser.Input.Pointer} pointer - The Pointer being tested. @@ -805,10 +806,13 @@ var InputPlugin = new Class({ } } - // Contains ALL Game Objects currently over in the array + // If they released outside the canvas, but pressed down inside it, we'll still dispatch the event. if (!aborted) { - this.emit('pointerdown', pointer, currentlyOver); + var type = (pointer.downElement === this.manager.game.canvas) ? 'pointerdown' : 'pointerdownoutside'; + + // Contains ALL Game Objects currently up in the array + this.emit(type, pointer, currentlyOver); } return total; @@ -1344,6 +1348,7 @@ var InputPlugin = new Class({ * @private * @fires Phaser.GameObjects.GameObject#pointerupEvent * @fires Phaser.Input.InputPlugin#gameobjectupEvent + * @fires Phaser.Input.InputPlugin#gameobjectupoutsideEvent * @since 3.0.0 * * @param {Phaser.Input.Pointer} pointer - The pointer to check for events against. @@ -1371,8 +1376,6 @@ var InputPlugin = new Class({ continue; } - // pointerupoutside - gameObject.emit('pointerup', pointer, gameObject.input.localX, gameObject.input.localY, _eventContainer); if (_eventData.cancelled) @@ -1390,10 +1393,13 @@ var InputPlugin = new Class({ } } + // If they released outside the canvas, but pressed down inside it, we'll still dispatch the event. if (!aborted) { + var type = (pointer.upElement === this.manager.game.canvas) ? 'pointerup' : 'pointerupoutside'; + // Contains ALL Game Objects currently up in the array - this.emit('pointerup', pointer, currentlyOver); + this.emit(type, pointer, currentlyOver); } return currentlyOver.length; @@ -2699,4 +2705,14 @@ module.exports = InputPlugin; * @event Phaser.Input.InputPlugin#pointerupEvent * @param {Phaser.Input.Pointer} pointer - The Pointer. * @param {Phaser.GameObjects.GameObject[]} currentlyOver - All the Game Objects currently under the Pointer. + * + * A Pointer was pressed down outside of the game canvas. + * @event Phaser.Input.InputPlugin#pointerdownoutsideEvent + * @param {Phaser.Input.Pointer} pointer - The Pointer. + * @param {Phaser.GameObjects.GameObject[]} currentlyOver - All the Game Objects currently under the Pointer. + * + * A Pointer was released outside of the game canvas. + * @event Phaser.Input.InputPlugin#pointerupoutsideEvent + * @param {Phaser.Input.Pointer} pointer - The Pointer. + * @param {Phaser.GameObjects.GameObject[]} currentlyOver - All the Game Objects currently under the Pointer. */ From 2eb5fb67945ba299a3e13e29fbe64738b03467f5 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 29 Nov 2018 13:44:51 +0000 Subject: [PATCH 116/221] You can now load external Scene files using the new `load.sceneFile` method. This allows you to dynamically load a Scene into the Scene Manager of your game, and swap to it at will. --- src/loader/filetypes/SceneFile.js | 221 ++++++++++++++++++++++++++++++ src/loader/filetypes/index.js | 1 + 2 files changed, 222 insertions(+) create mode 100644 src/loader/filetypes/SceneFile.js diff --git a/src/loader/filetypes/SceneFile.js b/src/loader/filetypes/SceneFile.js new file mode 100644 index 000000000..c33f79e1d --- /dev/null +++ b/src/loader/filetypes/SceneFile.js @@ -0,0 +1,221 @@ +/** + * @author Richard Davey + * @copyright 2018 Photon Storm Ltd. + * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} + */ + +var Class = require('../../utils/Class'); +var CONST = require('../const'); +var File = require('../File'); +var FileTypesManager = require('../FileTypesManager'); +var GetFastValue = require('../../utils/object/GetFastValue'); +var IsPlainObject = require('../../utils/object/IsPlainObject'); + +/** + * @typedef {object} Phaser.Loader.FileTypes.SceneFileConfig + * + * @property {string} key - The key of the file. Must be unique within both the Loader and the Text Cache. + * @property {string} [url] - The absolute or relative URL to load the file from. + * @property {string} [extension='txt'] - The default file extension to use if no url is provided. + * @property {XHRSettingsObject} [xhrSettings] - Extra XHR Settings specifically for this file. + */ + +/** + * @classdesc + * An external Scene JavaScript File suitable for loading by the Loader. + * + * These are created when you use the Phaser.Loader.LoaderPlugin#sceneFile method and are not typically created directly. + * + * For documentation about what all the arguments and configuration options mean please see Phaser.Loader.LoaderPlugin#sceneFile. + * + * @class SceneFile + * @extends Phaser.Loader.File + * @memberof Phaser.Loader.FileTypes + * @constructor + * @since 3.16.0 + * + * @param {Phaser.Loader.LoaderPlugin} loader - A reference to the Loader that is responsible for this file. + * @param {(string|Phaser.Loader.FileTypes.SceneFileConfig)} key - The key to use for this file, or a file configuration object. + * @param {string} [url] - The absolute or relative URL to load this file from. If undefined or `null` it will be set to `.js`, i.e. if `key` was "alien" then the URL will be "alien.js". + * @param {XHRSettingsObject} [xhrSettings] - Extra XHR Settings specifically for this file. + */ +var SceneFile = new Class({ + + Extends: File, + + initialize: + + function SceneFile (loader, key, url, xhrSettings) + { + var extension = 'js'; + + if (IsPlainObject(key)) + { + var config = key; + + key = GetFastValue(config, 'key'); + url = GetFastValue(config, 'url'); + xhrSettings = GetFastValue(config, 'xhrSettings'); + extension = GetFastValue(config, 'extension', extension); + } + + var fileConfig = { + type: 'text', + cache: loader.cacheManager.text, + extension: extension, + responseType: 'text', + key: key, + url: url, + xhrSettings: xhrSettings + }; + + File.call(this, loader, fileConfig); + }, + + /** + * Called automatically by Loader.nextFile. + * This method controls what extra work this File does with its loaded data. + * + * @method Phaser.Loader.FileTypes.SceneFile#onProcess + * @since 3.16.0 + */ + onProcess: function () + { + this.state = CONST.FILE_PROCESSING; + + this.data = this.xhrLoader.responseText; + + this.onProcessComplete(); + }, + + /** + * Adds this file to its target cache upon successful loading and processing. + * + * @method Phaser.Loader.FileTypes.SceneFile#addToCache + * @since 3.16.0 + */ + addToCache: function () + { + var code = this.data.concat('(function(){\n' + 'return new ' + this.key + '();\n' + '}).call(this);'); + + this.loader.sceneManager.add(this.key, eval(code)); + + this.complete = true; + } + +}); + +/** + * Adds an external Scene file, or array of Scene files, to the current load queue. + * + * You can call this method from within your Scene's `preload`, along with any other files you wish to load: + * + * ```javascript + * function preload () + * { + * this.load.sceneFile('Level1', 'src/Level1.js'); + * } + * ``` + * + * The file is **not** loaded right away. It is added to a queue ready to be loaded either when the loader starts, + * or if it's already running, when the next free load slot becomes available. This happens automatically if you + * are calling this from within the Scene's `preload` method, or a related callback. Because the file is queued + * it means you cannot use the file immediately after calling this method, but must wait for the file to complete. + * The typical flow for a Phaser Scene is that you load assets in the Scene's `preload` method and then when the + * Scene's `create` method is called you are guaranteed that all of those assets are ready for use and have been + * loaded. + * + * The key must be a unique String. It is used to add the file to the global Scene Manager upon a successful load. + * + * For a Scene File it's vitally important that the key matches the class name in the JavaScript file. + * + * For example here is the source file: + * + * ```javascript + * class ExternalScene extends Phaser.Scene { + * + * constructor () + * { + * super('myScene'); + * } + * + * } + * ``` + * + * Because the class is called `ExternalScene` that is the exact same key you must use when loading it: + * + * ```javascript + * function preload () + * { + * this.load.sceneFile('ExternalScene', 'src/yourScene.js'); + * } + * ``` + * + * The key that is used within the Scene Manager can either be set to the same, or you can override it in the Scene + * constructor, as we've done in the example above, where the Scene key was changed to `myScene`. + * + * The key should be unique both in terms of files being loaded and Scenes already present in the Scene Manager. + * Loading a file using a key that is already taken will result in a warning. If you wish to replace an existing file + * then remove it from the Scene Manager first, before loading a new one. + * + * Instead of passing arguments you can pass a configuration object, such as: + * + * ```javascript + * this.load.sceneFile({ + * key: 'Level1', + * url: 'src/Level1.js' + * }); + * ``` + * + * See the documentation for `Phaser.Loader.FileTypes.SceneFileConfig` for more details. + * + * Once the file has finished loading it will be added to the Scene Manager. + * + * ```javascript + * this.load.sceneFile('Level1', 'src/Level1.js'); + * // and later in your game ... + * this.scene.start('Level1'); + * ``` + * + * If you have specified a prefix in the loader, via `Loader.setPrefix` then this value will be prepended to this files + * key. For example, if the prefix was `WORLD1.` and the key was `Story` the final key will be `WORLD1.Story` and + * this is what you would use to retrieve the text from the Scene Manager. + * + * The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it. + * + * If the URL isn't specified the Loader will take the key and create a filename from that. For example if the key is "story" + * and no URL is given then the Loader will set the URL to be "story.js". It will always add `.js` as the extension, although + * this can be overridden if using an object instead of method arguments. If you do not desire this action then provide a URL. + * + * Note: The ability to load this type of file will only be available if the Scene File type has been built into Phaser. + * It is available in the default build but can be excluded from custom builds. + * + * @method Phaser.Loader.LoaderPlugin#sceneFile + * @fires Phaser.Loader.LoaderPlugin#addFileEvent + * @since 3.16.0 + * + * @param {(string|Phaser.Loader.FileTypes.SceneFileConfig|Phaser.Loader.FileTypes.SceneFileConfig[])} key - The key to use for this file, or a file configuration object, or array of them. + * @param {string} [url] - The absolute or relative URL to load this file from. If undefined or `null` it will be set to `.js`, i.e. if `key` was "alien" then the URL will be "alien.js". + * @param {XHRSettingsObject} [xhrSettings] - An XHR Settings configuration object. Used in replacement of the Loaders default XHR Settings. + * + * @return {Phaser.Loader.LoaderPlugin} The Loader instance. + */ +FileTypesManager.register('sceneFile', function (key, url, xhrSettings) +{ + if (Array.isArray(key)) + { + for (var i = 0; i < key.length; i++) + { + // If it's an array it has to be an array of Objects, so we get everything out of the 'key' object + this.addFile(new SceneFile(this, key[i])); + } + } + else + { + this.addFile(new SceneFile(this, key, url, xhrSettings)); + } + + return this; +}); + +module.exports = SceneFile; diff --git a/src/loader/filetypes/index.js b/src/loader/filetypes/index.js index 4c8a38d88..c804a5db3 100644 --- a/src/loader/filetypes/index.js +++ b/src/loader/filetypes/index.js @@ -26,6 +26,7 @@ module.exports = { MultiAtlasFile: require('./MultiAtlasFile'), PackFile: require('./PackFile'), PluginFile: require('./PluginFile'), + SceneFile: require('./SceneFile'), ScenePluginFile: require('./ScenePluginFile'), ScriptFile: require('./ScriptFile'), SpriteSheetFile: require('./SpriteSheetFile'), From 52cfd5b4d671043daf4c6434b933b1e8ca0188fc Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 29 Nov 2018 13:44:53 +0000 Subject: [PATCH 117/221] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3656a295e..0a15312d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,9 +46,14 @@ * The Game used to emit a `mouseout` event when the mouse left the game canvas. This is no longer emitted by the Game itself and can instead be listened for using the new Input Plugin event `gameout`. * If the `window` object exists (which it will in normal browser environments) new `mouseup` and `touchend` event listeners are bound to it and trigger the normal `mouseup` or `touchend` events within the internal input system. This means if you will now get a `pointerup` event from the Input Plugin even if the pointer is released outside of the game canvas. Pointers will also no longer think they are still 'down' if released outside the canvas and then moved inside again in their new state. * The window will now have focus called on it by the Touch Manager, as well as the Mouse Manager, is the `autoFocus` game config property is enabled. +* The Input Plugin has a new event you can listen to: `pointerdownoutside`, which is triggered whenever the mouse or a pointer is pressed down while outside of the Game canvas. Listen to it with `this.input.on('pointerdownoutside')` from within a Scene. +* The Input Plugin has a new event you can listen to: `pointerupoutside`, which is triggered whenever the mouse or a pointer is released while outside of the Game canvas. Listen to it with `this.input.on('pointerupoutside')` from within a Scene. +* `Pointer.downElement` is a new property that holds the target of the DOM Event that triggered when the Pointer was pressed down. If this is within the game, this will be the game canvas element. +* `Pointer.upElement` is a new property that holds the target of the DOM Event that triggered when the Pointer was released. If this is within the game, this will be the game canvas element. ### New Features +* You can now load external Scene files using the new `load.sceneFile` method. This allows you to dynamically load a Scene into the Scene Manager of your game, and swap to it at will. Please see the documentation and examples for further details. * The data object being sent to the Dynamic Bitmap Text callback now has a new property `parent`, which is a reference to the Bitmap Text instance that owns the data object (thanks ornyth) * The WebGL Renderer has a new method `clearPipeline`, which will clear down the current pipeline and reset the blend mode, ready for the context to be passed to a 3rd party library. * The WebGL Renderer has a new method `rebindPipeline`, which will rebind the given pipeline instance, reset the blank texture and reset the blend mode. Which is useful for recovering from 3rd party libs that have modified the gl context. @@ -96,6 +101,7 @@ * When using `ScenePlugin.add`, to add a new Scene to the Scene Manager, it didn't allow you to include the optional Scene data object. You can now pass this in the call (thanks @kainage) * `Graphics.stroke` is a new alias for the `strokePath` method, to keep the calls consistent with the Canvas Rendering Context API. * `Graphics.fill` is a new alias for the `fillPath` method, to keep the calls consistent with the Canvas Rendering Context API. +* `LoaderPlugin.sceneManager` is a new property that is a reference to the global Scene Manager, useful for Plugins. ### Bug Fixes From 146745057aee13268f3992de013a2c15601c2e6a Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 29 Nov 2018 23:33:54 +0000 Subject: [PATCH 118/221] `Utils.Array.MoveUp` wouldn't let you move an array element to the top-most index in the array. This also impacted `Container.moveUp`. --- CHANGELOG.md | 1 + src/utils/array/MoveUp.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a15312d9..9609e4c31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -135,6 +135,7 @@ * The Particle Emitter no longer needs to call the StableSort.inplace during its preUpdate, saving cpu. * `Particle.resetPosition` is a new method that is called when a particle dies, preparing it ready for firing again in the future. * The Canvas `SetTransform` method would save the context state, but it wasn't restored at the end in the following Game Objects: Dynamic Bitmap Text, Graphics, Arc, Curve, Ellipse, Grid, IsoBox, IsoTriangle, Line, Polygon, Rectangle, Star and Triangle. These now all restore the context, meaning if you're using non-canvas sized cameras in Canvas mode, it will now render beyond just the first custom camera. +* `Utils.Array.MoveUp` wouldn't let you move an array element to the top-most index in the array. This also impacted `Container.moveUp`. ### Examples and TypeScript diff --git a/src/utils/array/MoveUp.js b/src/utils/array/MoveUp.js index 7b61e7440..a66668014 100644 --- a/src/utils/array/MoveUp.js +++ b/src/utils/array/MoveUp.js @@ -20,10 +20,10 @@ var MoveUp = function (array, item) { var currentIndex = array.indexOf(item); - if (currentIndex !== -1 && currentIndex < array.length - 2) + if (currentIndex !== -1 && currentIndex < array.length - 1) { + // The element one above `item` in the array var item2 = array[currentIndex + 1]; - var index2 = array.indexOf(item2); array[currentIndex] = item2; From 6f8759c186cded1b3cff8ec0aa88db8f9315ed2f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 30 Nov 2018 10:27:25 +0000 Subject: [PATCH 119/221] Whenever `Camera.roundPixels` was enabled it would use a bitwise operation to truncate the float (`x |= 0`) - this has been replaced across all files that used it, with a call to `Math.round` instead. This gives far better results when zooming cameras both in and out of a Scene, stopping thin gaps appearing between closely packed Game Objects. --- CHANGELOG.md | 1 + src/cameras/2d/effects/Shake.js | 4 +-- .../DynamicBitmapTextCanvasRenderer.js | 4 +-- .../dynamic/DynamicBitmapTextWebGLRenderer.js | 16 +++++----- .../static/BitmapTextCanvasRenderer.js | 4 +-- .../static/BitmapTextWebGLRenderer.js | 16 +++++----- .../blitter/BlitterCanvasRenderer.js | 4 +-- .../blitter/BlitterWebGLRenderer.js | 8 ++--- src/gameobjects/mesh/MeshWebGLRenderer.js | 4 +-- .../ParticleManagerCanvasRenderer.js | 4 +-- .../particles/ParticleManagerWebGLRenderer.js | 22 ++++++------- .../pipelines/ForwardDiffuseLightPipeline.js | 16 +++++----- .../webgl/pipelines/TextureTintPipeline.js | 32 +++++++++---------- .../staticlayer/StaticTilemapLayer.js | 16 +++++----- 14 files changed, 76 insertions(+), 75 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9609e4c31..bcb9f17fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -102,6 +102,7 @@ * `Graphics.stroke` is a new alias for the `strokePath` method, to keep the calls consistent with the Canvas Rendering Context API. * `Graphics.fill` is a new alias for the `fillPath` method, to keep the calls consistent with the Canvas Rendering Context API. * `LoaderPlugin.sceneManager` is a new property that is a reference to the global Scene Manager, useful for Plugins. +* Whenever `Camera.roundPixels` was enabled it would use a bitwise operation to truncate the float (`x |= 0`) - this has been replaced across all files that used it, with a call to `Math.round` instead. This gives far better results when zooming cameras both in and out of a Scene, stopping thin gaps appearing between closely packed Game Objects. ### Bug Fixes diff --git a/src/cameras/2d/effects/Shake.js b/src/cameras/2d/effects/Shake.js index 4669c79cb..009064a47 100644 --- a/src/cameras/2d/effects/Shake.js +++ b/src/cameras/2d/effects/Shake.js @@ -270,8 +270,8 @@ var Shake = new Class({ if (this.camera.roundPixels) { - this._offsetX |= 0; - this._offsetY |= 0; + this._offsetX = Math.round(this._offsetX); + this._offsetY = Math.round(this._offsetY); } } else diff --git a/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextCanvasRenderer.js b/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextCanvasRenderer.js index 2eacb724a..e1a053256 100644 --- a/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextCanvasRenderer.js +++ b/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextCanvasRenderer.js @@ -144,8 +144,8 @@ var DynamicBitmapTextCanvasRenderer = function (renderer, src, interpolationPerc if (camera.roundPixels) { - x |= 0; - y |= 0; + x = Math.round(x); + y = Math.round(y); } ctx.save(); diff --git a/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextWebGLRenderer.js b/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextWebGLRenderer.js index 06c380850..42d98ec95 100644 --- a/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextWebGLRenderer.js +++ b/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextWebGLRenderer.js @@ -273,17 +273,17 @@ var DynamicBitmapTextWebGLRenderer = function (renderer, src, interpolationPerce if (roundPixels) { - tx0 |= 0; - ty0 |= 0; + tx0 = Math.round(tx0); + ty0 = Math.round(ty0); - tx1 |= 0; - ty1 |= 0; + tx1 = Math.round(tx1); + ty1 = Math.round(ty1); - tx2 |= 0; - ty2 |= 0; + tx2 = Math.round(tx2); + ty2 = Math.round(ty2); - tx3 |= 0; - ty3 |= 0; + tx3 = Math.round(tx3); + ty3 = Math.round(ty3); } pipeline.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect); diff --git a/src/gameobjects/bitmaptext/static/BitmapTextCanvasRenderer.js b/src/gameobjects/bitmaptext/static/BitmapTextCanvasRenderer.js index 0030f7775..366da02b5 100644 --- a/src/gameobjects/bitmaptext/static/BitmapTextCanvasRenderer.js +++ b/src/gameobjects/bitmaptext/static/BitmapTextCanvasRenderer.js @@ -148,8 +148,8 @@ var BitmapTextCanvasRenderer = function (renderer, src, interpolationPercentage, if (roundPixels) { - x |= 0; - y |= 0; + x = Math.round(x); + y = Math.round(y); } ctx.save(); diff --git a/src/gameobjects/bitmaptext/static/BitmapTextWebGLRenderer.js b/src/gameobjects/bitmaptext/static/BitmapTextWebGLRenderer.js index c9b851b32..446dd30a2 100644 --- a/src/gameobjects/bitmaptext/static/BitmapTextWebGLRenderer.js +++ b/src/gameobjects/bitmaptext/static/BitmapTextWebGLRenderer.js @@ -203,17 +203,17 @@ var BitmapTextWebGLRenderer = function (renderer, src, interpolationPercentage, if (roundPixels) { - tx0 |= 0; - ty0 |= 0; + tx0 = Math.round(tx0); + ty0 = Math.round(ty0); - tx1 |= 0; - ty1 |= 0; + tx1 = Math.round(tx1); + ty1 = Math.round(ty1); - tx2 |= 0; - ty2 |= 0; + tx2 = Math.round(tx2); + ty2 = Math.round(ty2); - tx3 |= 0; - ty3 |= 0; + tx3 = Math.round(tx3); + ty3 = Math.round(ty3); } pipeline.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect); diff --git a/src/gameobjects/blitter/BlitterCanvasRenderer.js b/src/gameobjects/blitter/BlitterCanvasRenderer.js index cef0e9859..09ee942a0 100644 --- a/src/gameobjects/blitter/BlitterCanvasRenderer.js +++ b/src/gameobjects/blitter/BlitterCanvasRenderer.js @@ -78,8 +78,8 @@ var BlitterCanvasRenderer = function (renderer, src, interpolationPercentage, ca { if (roundPixels) { - dx |= 0; - dy |= 0; + dx = Math.round(dx); + dy = Math.round(dy); } ctx.drawImage( diff --git a/src/gameobjects/blitter/BlitterWebGLRenderer.js b/src/gameobjects/blitter/BlitterWebGLRenderer.js index 8c2752eff..ce98e5708 100644 --- a/src/gameobjects/blitter/BlitterWebGLRenderer.js +++ b/src/gameobjects/blitter/BlitterWebGLRenderer.js @@ -106,11 +106,11 @@ var BlitterWebGLRenderer = function (renderer, src, interpolationPercentage, cam if (roundPixels) { - tx0 |= 0; - ty0 |= 0; + tx0 = Math.round(tx0); + ty0 = Math.round(ty0); - tx1 |= 0; - ty1 |= 0; + tx1 = Math.round(tx1); + ty1 = Math.round(ty1); } // TL x/y, BL x/y, BR x/y, TR x/y diff --git a/src/gameobjects/mesh/MeshWebGLRenderer.js b/src/gameobjects/mesh/MeshWebGLRenderer.js index 834c86c50..bc8dbfe3c 100644 --- a/src/gameobjects/mesh/MeshWebGLRenderer.js +++ b/src/gameobjects/mesh/MeshWebGLRenderer.js @@ -92,8 +92,8 @@ var MeshWebGLRenderer = function (renderer, src, interpolationPercentage, camera if (camera.roundPixels) { - tx |= 0; - ty |= 0; + tx = Math.round(tx); + ty = Math.round(ty); } vertexViewF32[++vertexOffset] = tx; diff --git a/src/gameobjects/particles/ParticleManagerCanvasRenderer.js b/src/gameobjects/particles/ParticleManagerCanvasRenderer.js index d09a1a563..0772e03dd 100644 --- a/src/gameobjects/particles/ParticleManagerCanvasRenderer.js +++ b/src/gameobjects/particles/ParticleManagerCanvasRenderer.js @@ -99,8 +99,8 @@ var ParticleManagerCanvasRenderer = function (renderer, emitterManager, interpol if (roundPixels) { - x |= 0; - y |= 0; + x = Math.round(x); + y = Math.round(y); } ctx.drawImage(frame.source.image, cd.x, cd.y, cd.width, cd.height, x, y, cd.width, cd.height); diff --git a/src/gameobjects/particles/ParticleManagerWebGLRenderer.js b/src/gameobjects/particles/ParticleManagerWebGLRenderer.js index 416f8ad8d..1c549ece4 100644 --- a/src/gameobjects/particles/ParticleManagerWebGLRenderer.js +++ b/src/gameobjects/particles/ParticleManagerWebGLRenderer.js @@ -118,17 +118,17 @@ var ParticleManagerWebGLRenderer = function (renderer, emitterManager, interpola if (roundPixels) { - tx0 |= 0; - ty0 |= 0; - - tx1 |= 0; - ty1 |= 0; - - tx2 |= 0; - ty2 |= 0; - - tx3 |= 0; - ty3 |= 0; + tx0 = Math.round(tx0); + ty0 = Math.round(ty0); + + tx1 = Math.round(tx1); + ty1 = Math.round(ty1); + + tx2 = Math.round(tx2); + ty2 = Math.round(ty2); + + tx3 = Math.round(tx3); + ty3 = Math.round(ty3); } var tint = getTint(particle.tint, alpha); diff --git a/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js b/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js index 1545eea0e..198d7632b 100644 --- a/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js +++ b/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js @@ -362,17 +362,17 @@ var ForwardDiffuseLightPipeline = new Class({ if (camera.roundPixels) { - tx0 |= 0; - ty0 |= 0; + tx0 = Math.round(tx0); + ty0 = Math.round(ty0); - tx1 |= 0; - ty1 |= 0; + tx1 = Math.round(tx1); + ty1 = Math.round(ty1); - tx2 |= 0; - ty2 |= 0; + tx2 = Math.round(tx2); + ty2 = Math.round(ty2); - tx3 |= 0; - ty3 |= 0; + tx3 = Math.round(tx3); + ty3 = Math.round(ty3); } this.setTexture2D(texture, 0); diff --git a/src/renderer/webgl/pipelines/TextureTintPipeline.js b/src/renderer/webgl/pipelines/TextureTintPipeline.js index a42b9ad12..86cf3341f 100644 --- a/src/renderer/webgl/pipelines/TextureTintPipeline.js +++ b/src/renderer/webgl/pipelines/TextureTintPipeline.js @@ -606,17 +606,17 @@ var TextureTintPipeline = new Class({ if (camera.roundPixels) { - tx0 |= 0; - ty0 |= 0; + tx0 = Math.round(tx0); + ty0 = Math.round(ty0); - tx1 |= 0; - ty1 |= 0; + tx1 = Math.round(tx1); + ty1 = Math.round(ty1); - tx2 |= 0; - ty2 |= 0; + tx2 = Math.round(tx2); + ty2 = Math.round(ty2); - tx3 |= 0; - ty3 |= 0; + tx3 = Math.round(tx3); + ty3 = Math.round(ty3); } this.setTexture2D(texture, 0); @@ -971,17 +971,17 @@ var TextureTintPipeline = new Class({ if (camera.roundPixels) { - tx0 |= 0; - ty0 |= 0; + tx0 = Math.round(tx0); + ty0 = Math.round(ty0); - tx1 |= 0; - ty1 |= 0; + tx1 = Math.round(tx1); + ty1 = Math.round(ty1); - tx2 |= 0; - ty2 |= 0; + tx2 = Math.round(tx2); + ty2 = Math.round(ty2); - tx3 |= 0; - ty3 |= 0; + tx3 = Math.round(tx3); + ty3 = Math.round(ty3); } this.setTexture2D(texture, 0); diff --git a/src/tilemaps/staticlayer/StaticTilemapLayer.js b/src/tilemaps/staticlayer/StaticTilemapLayer.js index d771d2948..88014c391 100644 --- a/src/tilemaps/staticlayer/StaticTilemapLayer.js +++ b/src/tilemaps/staticlayer/StaticTilemapLayer.js @@ -661,17 +661,17 @@ var StaticTilemapLayer = new Class({ if (camera.roundPixels) { - tx0 |= 0; - ty0 |= 0; + tx0 = Math.round(tx0); + ty0 = Math.round(ty0); - tx1 |= 0; - ty1 |= 0; + tx1 = Math.round(tx1); + ty1 = Math.round(ty1); - tx2 |= 0; - ty2 |= 0; + tx2 = Math.round(tx2); + ty2 = Math.round(ty2); - tx3 |= 0; - ty3 |= 0; + tx3 = Math.round(tx3); + ty3 = Math.round(ty3); } var vertexViewF32 = this.vertexViewF32[tilesetIndex]; From bd5f2b3bf52f0f63602816cd4a12ffe1494fec1d Mon Sep 17 00:00:00 2001 From: Thomas Felix Date: Sat, 1 Dec 2018 20:40:17 +0100 Subject: [PATCH 120/221] fixes the typedef for the layer parameter The layer parameter is used to call getLayer() so the parameter type for the parent function should match the on of getLayer(). --- src/tilemaps/Tilemap.js | 106 ++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 52 deletions(-) diff --git a/src/tilemaps/Tilemap.js b/src/tilemaps/Tilemap.js index bc189c2d0..8b335cbf7 100644 --- a/src/tilemaps/Tilemap.js +++ b/src/tilemaps/Tilemap.js @@ -124,14 +124,14 @@ var Tilemap = new Class({ /** * The render (draw) order of the map data (as specified in Tiled), usually 'right-down'. - * + * * The draw orders are: - * + * * right-down * left-down * right-up * left-up - * + * * This can be changed via the `setRenderOrder` method. * * @name Phaser.Tilemaps.Tilemap#renderOrder @@ -241,22 +241,22 @@ var Tilemap = new Class({ /** * Sets the rendering (draw) order of the tiles in this map. - * + * * The default is 'right-down', meaning it will order the tiles starting from the top-left, * drawing to the right and then moving down to the next row. - * + * * The draw orders are: - * + * * 0 = right-down * 1 = left-down * 2 = right-up * 3 = left-up - * + * * Setting the render order does not change the tiles or how they are stored in the layer, * it purely impacts the order in which they are rendered. - * + * * You can provide either an integer (0 to 3), or the string version of the order. - * + * * Calling this method _after_ creating Static or Dynamic Tilemap Layers will **not** automatically * update them to use the new render order. If you call this method after creating layers, use their * own `setRenderOrder` methods to change them as needed. @@ -408,12 +408,12 @@ var Tilemap = new Class({ * Copies the tiles in the source rectangular area to a new destination (all specified in tile * coordinates) within the layer. This copies all tile properties & recalculates collision * information in the destination region. - * + * * If no layer specified, the map's current layer is used. This cannot be applied to StaticTilemapLayers. * * @method Phaser.Tilemaps.Tilemap#copy * @since 3.0.0 - * + * * @param {integer} srcTileX - The x coordinate of the area to copy from, in tiles, not pixels. * @param {integer} srcTileY - The y coordinate of the area to copy from, in tiles, not pixels. * @param {integer} width - The width of the area to copy, in tiles, not pixels. @@ -421,7 +421,7 @@ var Tilemap = new Class({ * @param {integer} destTileX - The x coordinate of the area to copy to, in tiles, not pixels. * @param {integer} destTileY - The y coordinate of the area to copy to, in tiles, not pixels. * @param {boolean} [recalculateFaces=true] - `true` if the faces data should be recalculated. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Returns this, or null if the layer given was invalid. */ @@ -458,7 +458,7 @@ var Tilemap = new Class({ * @param {integer} [height] - The height of the layer in tiles. If not specified, it will default to the map's height. * @param {integer} [tileWidth] - The width of the tiles the layer uses for calculations. If not specified, it will default to the map's tileWidth. * @param {integer} [tileHeight] - The height of the tiles the layer uses for calculations. If not specified, it will default to the map's tileHeight. - * + * * @return {?Phaser.Tilemaps.DynamicTilemapLayer} Returns the new layer was created, or null if it failed. */ createBlankDynamicLayer: function (name, tileset, x, y, width, height, tileWidth, tileHeight) @@ -688,7 +688,7 @@ var Tilemap = new Class({ * @param {SpriteConfig} spriteConfig - The config object to pass into the Sprite creator (i.e. scene.make.sprite). * @param {Phaser.Scene} [scene=scene the map is within] - The Scene to create the Sprites within. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.GameObjects.Sprite[]} Returns an array of Tiles, or null if the layer given was invalid. */ @@ -788,7 +788,7 @@ var Tilemap = new Class({ * @param {integer} [width=max width based on tileX] - How many tiles wide from the `tileX` index the area will be. * @param {integer} [height=max height based on tileY] - How many tiles tall from the `tileY` index the area will be. * @param {boolean} [recalculateFaces=true] - `true` if the faces data should be recalculated. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Returns this, or null if the layer given was invalid. */ @@ -859,7 +859,7 @@ var Tilemap = new Class({ * @param {boolean} [filteringOptions.isNotEmpty=false] - If true, only return tiles that don't have -1 for an index. * @param {boolean} [filteringOptions.isColliding=false] - If true, only return tiles that collide on at least one side. * @param {boolean} [filteringOptions.hasInterestingFace=false] - If true, only return tiles that have at least one interesting face. - * @param {Phaser.Tilemaps.LayerData} [layer] - The Tile layer to apply the filter on. If not provided will use the current layer. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tile[]} Returns an array of Tiles, or null if the layer given was invalid. */ @@ -886,7 +886,7 @@ var Tilemap = new Class({ * @param {integer} index - The tile index value to search for. * @param {integer} [skip=0] - The number of times to skip a matching tile before returning. * @param {boolean} [reverse=false] - If true it will scan the layer in reverse, starting at the bottom-right. Otherwise it scans from the top-left. - * @param {Phaser.Tilemaps.LayerData} [layer] - The Tile layer to run the search on. If not provided will use the current layer. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tile} Returns a Tiles, or null if the layer given was invalid. */ @@ -950,7 +950,7 @@ var Tilemap = new Class({ * @param {boolean} [filteringOptions.isNotEmpty=false] - If true, only return tiles that don't have -1 for an index. * @param {boolean} [filteringOptions.isColliding=false] - If true, only return tiles that collide on at least one side. * @param {boolean} [filteringOptions.hasInterestingFace=false] - If true, only return tiles that have at least one interesting face. - * @param {Phaser.Tilemaps.LayerData} [layer] - The Tile layer to run the search on. If not provided will use the current layer. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The Tile layer to run the search on. If not provided will use the current layer. * * @return {?Phaser.Tilemaps.Tile} Returns a Tiles, or null if the layer given was invalid. */ @@ -982,7 +982,7 @@ var Tilemap = new Class({ * @param {boolean} [filteringOptions.isNotEmpty=false] - If true, only return tiles that don't have -1 for an index. * @param {boolean} [filteringOptions.isColliding=false] - If true, only return tiles that collide on at least one side. * @param {boolean} [filteringOptions.hasInterestingFace=false] - If true, only return tiles that have at least one interesting face. - * @param {Phaser.Tilemaps.LayerData} [layer] - The Tile layer to run the search on. If not provided will use the current layer. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The Tile layer to run the search on. If not provided will use the current layer. * * @return {?Phaser.Tilemaps.Tilemap} Returns this, or null if the layer given was invalid. */ @@ -1139,7 +1139,7 @@ var Tilemap = new Class({ * @param {integer} tileX - X position to get the tile from (given in tile units, not pixels). * @param {integer} tileY - Y position to get the tile from (given in tile units, not pixels). * @param {boolean} [nonNull=false] - If true getTile won't return null for empty tiles, but a Tile object with an index of -1. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tile} Returns a Tile, or null if the layer given was invalid. */ @@ -1163,7 +1163,7 @@ var Tilemap = new Class({ * @param {number} worldY - Y position to get the tile from (given in pixels) * @param {boolean} [nonNull=false] - If true, function won't return null for empty tiles, but a Tile object with an index of -1. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tile} Returns a Tile, or null if the layer given was invalid. */ @@ -1196,7 +1196,7 @@ var Tilemap = new Class({ * @param {boolean} [filteringOptions.isNotEmpty=false] - If true, only return tiles that don't have -1 for an index. * @param {boolean} [filteringOptions.isColliding=false] - If true, only return tiles that collide on at least one side. * @param {boolean} [filteringOptions.hasInterestingFace=false] - If true, only return tiles that have at least one interesting face. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tile[]} Returns an array of Tiles, or null if the layer given was invalid. */ @@ -1223,7 +1223,7 @@ var Tilemap = new Class({ * @param {boolean} [filteringOptions.isColliding=false] - If true, only return tiles that collide on at least one side. * @param {boolean} [filteringOptions.hasInterestingFace=false] - If true, only return tiles that have at least one interesting face. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when factoring in which tiles to return. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to search. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tile[]} Returns an array of Tiles, or null if the layer given was invalid. */ @@ -1252,7 +1252,7 @@ var Tilemap = new Class({ * @param {boolean} [filteringOptions.isColliding=false] - If true, only return tiles that collide on at least one side. * @param {boolean} [filteringOptions.hasInterestingFace=false] - If true, only return tiles that have at least one interesting face. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when factoring in which tiles to return. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to search. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tile[]} Returns an array of Tiles, or null if the layer given was invalid. */ @@ -1309,7 +1309,7 @@ var Tilemap = new Class({ * * @param {integer} tileX - The x coordinate, in tiles, not pixels. * @param {integer} tileY - The y coordinate, in tiles, not pixels. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to search. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?boolean} Returns a boolean, or null if the layer given was invalid. */ @@ -1334,7 +1334,7 @@ var Tilemap = new Class({ * @param {number} worldX - The x coordinate, in pixels. * @param {number} worldY - The y coordinate, in pixels. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when factoring in which tiles to return. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to search. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?boolean} Returns a boolean, or null if the layer given was invalid. */ @@ -1384,7 +1384,7 @@ var Tilemap = new Class({ * @param {integer} tileX - The x coordinate, in tiles, not pixels. * @param {integer} tileY - The y coordinate, in tiles, not pixels. * @param {boolean} [recalculateFaces=true] - `true` if the faces data should be recalculated. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tile} Returns a Tile, or null if the layer given was invalid or the coordinates were out of bounds. */ @@ -1416,7 +1416,7 @@ var Tilemap = new Class({ * @param {number} worldY - The y coordinate, in pixels. * @param {boolean} [recalculateFaces=true] - `true` if the faces data should be recalculated. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tile} Returns a Tile, or null if the layer given was invalid. */ @@ -1448,7 +1448,7 @@ var Tilemap = new Class({ * @param {integer} tileX - The x coordinate, in tiles, not pixels. * @param {integer} tileY - The y coordinate, in tiles, not pixels. * @param {boolean} [recalculateFaces=true] - `true` if the faces data should be recalculated. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Returns this, or null if the layer given was invalid. */ @@ -1484,7 +1484,7 @@ var Tilemap = new Class({ * @param {integer} [width=max width based on tileX] - How many tiles wide from the `tileX` index the area will be. * @param {integer} [height=max height based on tileY] - How many tiles tall from the `tileY` index the area will be. * @param {integer[]} [indexes] - An array of indexes to randomly draw from during randomization. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Returns this, or null if the layer given was invalid. */ @@ -1514,7 +1514,7 @@ var Tilemap = new Class({ * * @param {integer} tileX - The x coordinate, in tiles, not pixels. * @param {integer} tileY - The y coordinate, in tiles, not pixels. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Returns this, or null if the layer given was invalid. */ @@ -1543,7 +1543,7 @@ var Tilemap = new Class({ * @param {integer} [tileY=0] - The top most tile index (in tile coordinates) to use as the origin of the area. * @param {integer} [width=max width based on tileX] - How many tiles wide from the `tileX` index the area will be. * @param {integer} [height=max height based on tileY] - How many tiles tall from the `tileY` index the area will be. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Returns this, or null if the layer given was invalid. */ @@ -1598,7 +1598,7 @@ var Tilemap = new Class({ * @param {integer} tileY - The y coordinate, in tiles, not pixels. * @param {boolean} [replaceWithNull=true] - If true, this will replace the tile at the specified location with null instead of a Tile with an index of -1. * @param {boolean} [recalculateFaces=true] - `true` if the faces data should be recalculated. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to search. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tile} Returns a Tile, or null if the layer given was invalid. */ @@ -1628,7 +1628,7 @@ var Tilemap = new Class({ * @param {boolean} [replaceWithNull=true] - If true, this will replace the tile at the specified location with null instead of a Tile with an index of -1. * @param {boolean} [recalculateFaces=true] - `true` if the faces data should be recalculated. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tile} Returns a Tile, or null if the layer given was invalid. */ @@ -1659,7 +1659,7 @@ var Tilemap = new Class({ * @param {?Color} [styleConfig.tileColor=blue] - Color to use for drawing a filled rectangle at non-colliding tile locations. If set to null, non-colliding tiles will not be drawn. * @param {?Color} [styleConfig.collidingTileColor=orange] - Color to use for drawing a filled rectangle at colliding tile locations. If set to null, colliding tiles will not be drawn. * @param {?Color} [styleConfig.faceColor=grey] - Color to use for drawing a line at interesting tile faces. If set to null, interesting tile faces will not be drawn. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to search. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid. */ @@ -1691,7 +1691,7 @@ var Tilemap = new Class({ * @param {integer} [tileY=0] - The top most tile index (in tile coordinates) to use as the origin of the area. * @param {integer} [width=max width based on tileX] - How many tiles wide from the `tileX` index the area will be. * @param {integer} [height=max height based on tileY] - How many tiles tall from the `tileY` index the area will be. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid. */ @@ -1722,7 +1722,7 @@ var Tilemap = new Class({ * @param {(integer|array)} indexes - Either a single tile index, or an array of tile indexes. * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision. * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the update. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid. */ @@ -1752,7 +1752,7 @@ var Tilemap = new Class({ * @param {integer} stop - The last index of the tile to be set for collision. * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision. * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the update. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid. */ @@ -1784,7 +1784,7 @@ var Tilemap = new Class({ * @param {object} properties - An object with tile properties and corresponding values that should be checked. * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision. * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the update. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid. */ @@ -1812,7 +1812,7 @@ var Tilemap = new Class({ * @param {integer[]} indexes - An array of the tile indexes to not be counted for collision. * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision. * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the update. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid. */ @@ -1840,7 +1840,7 @@ var Tilemap = new Class({ * * @param {boolean} [collides=true] - If true it will enable collision. If false it will clear collision. * @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the update. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid. */ @@ -1869,7 +1869,7 @@ var Tilemap = new Class({ * @param {(integer|array)} indexes - Either a single tile index, or an array of tile indexes to have a collision callback set for. * @param {function} callback - The callback that will be invoked when the tile is collided with. * @param {object} callbackContext - The context under which the callback is called. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid. */ @@ -1900,7 +1900,7 @@ var Tilemap = new Class({ * @param {integer} height - How many tiles tall from the `tileY` index the area will be. * @param {function} callback - The callback that will be invoked when the tile is collided with. * @param {object} [callbackContext] - The context under which the callback is called. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid. */ @@ -2043,7 +2043,7 @@ var Tilemap = new Class({ * @param {integer} [tileY=0] - The top most tile index (in tile coordinates) to use as the origin of the area. * @param {integer} [width=max width based on tileX] - How many tiles wide from the `tileX` index the area will be. * @param {integer} [height=max height based on tileY] - How many tiles tall from the `tileY` index the area will be. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid. */ @@ -2078,7 +2078,7 @@ var Tilemap = new Class({ * @param {integer} [tileY=0] - The top most tile index (in tile coordinates) to use as the origin of the area. * @param {integer} [width=max width based on tileX] - How many tiles wide from the `tileX` index the area will be. * @param {integer} [height=max height based on tileY] - How many tiles tall from the `tileY` index the area will be. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid. */ @@ -2107,7 +2107,7 @@ var Tilemap = new Class({ * * @param {integer} tileX - The x coordinate, in tiles, not pixels. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?number} Returns a number, or null if the layer given was invalid. */ @@ -2131,7 +2131,8 @@ var Tilemap = new Class({ * * @param {integer} tileY - The y coordinate, in tiles, not pixels. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer + * to use. If not given the current layer is used. * * @return {?number} Returns a number, or null if the layer given was invalid. */ @@ -2158,7 +2159,7 @@ var Tilemap = new Class({ * @param {integer} tileY - The y coordinate, in tiles, not pixels. * @param {Phaser.Math.Vector2} [point] - A Vector2 to store the coordinates in. If not given a new Vector2 is created. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Math.Vector2} Returns a point, or null if the layer given was invalid. */ @@ -2199,7 +2200,7 @@ var Tilemap = new Class({ * @param {object[]} [weightedIndexes] - An array of objects to randomly draw from during * randomization. They should be in the form: { index: 0, weight: 4 } or * { index: [0, 1], weight: 4 } if you wish to draw from multiple tile indexes. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid. */ @@ -2229,7 +2230,8 @@ var Tilemap = new Class({ * @param {number} worldX - The x coordinate to be converted, in pixels, not tiles. * @param {boolean} [snapToFloor=true] - Whether or not to round the tile coordinate down to the nearest integer. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer + * to use. If not given the current layer is used. * * @return {?number} Returns a number, or null if the layer given was invalid. */ @@ -2254,7 +2256,7 @@ var Tilemap = new Class({ * @param {number} worldY - The y coordinate to be converted, in pixels, not tiles. * @param {boolean} [snapToFloor=true] - Whether or not to round the tile coordinate down to the nearest integer. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?number} Returns a number, or null if the layer given was invalid. */ @@ -2282,7 +2284,7 @@ var Tilemap = new Class({ * @param {boolean} [snapToFloor=true] - Whether or not to round the tile coordinate down to the nearest integer. * @param {Phaser.Math.Vector2} [point] - A Vector2 to store the coordinates in. If not given a new Vector2 is created. * @param {Phaser.Cameras.Scene2D.Camera} [camera=main camera] - The Camera to use when calculating the tile index from the world values. - * @param {Phaser.Tilemaps.LayerData} [layer] - The tile layer to use. If not given the current layer is used. + * @param {(string|integer|Phaser.Tilemaps.DynamicTilemapLayer|Phaser.Tilemaps.StaticTilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used. * * @return {?Phaser.Math.Vector2} Returns a point, or null if the layer given was invalid. */ From 2780babe106dff006029afdfb0c9698d500b5371 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 3 Dec 2018 15:16:23 +0000 Subject: [PATCH 121/221] Final Doc Jam merge --- CHANGELOG.md | 6 +-- src/animations/AnimationManager.js | 7 ++-- src/curves/path/MoveTo.js | 22 +++++----- src/geom/line/NormalY.js | 7 ++-- src/geom/point/GetCentroid.js | 3 +- src/geom/point/SetMagnitude.js | 8 ++-- src/geom/polygon/Clone.js | 6 +-- src/geom/polygon/Polygon.js | 18 +++++++-- src/geom/polygon/Reverse.js | 6 +-- src/geom/rectangle/Area.js | 6 +-- src/geom/rectangle/Floor.js | 6 +-- src/geom/rectangle/GetPoints.js | 4 +- src/geom/rectangle/Overlaps.js | 8 ++-- src/geom/triangle/CircumCircle.js | 8 ++-- src/geom/triangle/InCenter.js | 8 ++-- src/geom/triangle/Offset.js | 10 ++--- src/math/RotateAroundDistance.js | 4 +- src/physics/impact/Body.js | 12 +++--- src/physics/impact/World.js | 2 +- src/physics/matter-js/Factory.js | 18 ++++----- src/physics/matter-js/World.js | 12 +++--- src/physics/matter-js/components/Bounce.js | 6 +-- src/physics/matter-js/components/Collision.js | 8 ++-- src/physics/matter-js/components/Friction.js | 18 ++++----- src/physics/matter-js/components/Mass.js | 8 ++-- src/physics/matter-js/components/SetBody.js | 24 +++++------ src/renderer/canvas/utils/GetBlendModes.js | 6 ++- src/renderer/webgl/WebGLRenderer.js | 18 ++++----- src/tilemaps/mapdata/MapData.js | 23 ++++++----- src/tilemaps/parsers/tiled/ParseObject.js | 10 ++--- src/tweens/Timeline.js | 40 +++++++++---------- src/tweens/builders/GetTweens.js | 2 +- src/tweens/builders/TimelineBuilder.js | 37 +++++++++++++++-- src/tweens/builders/TweenBuilder.js | 28 ++++++++++++- src/tweens/tween/Tween.js | 12 +++--- 35 files changed, 248 insertions(+), 173 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcb9f17fd..0ef06f5a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -146,11 +146,9 @@ Thanks to the following for helping with the Phaser 3 Examples and TypeScript de ### Phaser Doc Jam -The [Phaser Doc Jam](http://docjam.phaser.io) is an on-going effort to ensure that the Phaser 3 API has 100% documentation coverage. Thanks to the monumental effort of myself and the following people we're now really close to that goal! My thanks to: +The Phaser Doc Jam was a community-backed effort to try and get the Phaser 3 API documentation to 100% coverage. The Doc Jam is now over and I offer my thanks to the following who helped with docs in this release: -16patsle - @icbat - @gurungrahul2 - @samme - @telinc1 - anandu pavanan - blackhawx - candelibas - Diego Romero - Elliott Wallace - eric - Georges Gabereau - Haobo Zhang - henriacle - madclaws - marc136 - Mihail Ilinov - naum303 - NicolasRoehm - rejacobson - Robert Kowalski - rootasjey - scottwestover - stetso - therealsamf - Tigran - willblackmore - zenwaichi - -If you'd like to help finish off the last parts of documentation then take a look at the [Doc Jam site](http://docjam.phaser.io). +16patsle - @gurungrahul2 - @icbat - @samme - @telinc1 - anandu pavanan - blackhawx - candelibas - Diego Romero - doronlinder - Elliott Wallace - eric - Georges Gabereau - Haobo Zhang - henriacle - jak6jak - Jake Jensen - James Van Roose - JamesSkemp - joelahoover - Joey - madclaws - marc136 - Mihail Ilinov - naum303 - NicolasRoehm - nuane - rejacobson - Robert Kowalski - rodri042 - rootasjey - sawamara - scottwestover - sir13tommy - stetso - therealsamf - Tigran - willblackmore - zenwaichi ## Version 3.15.1 - Batou - 16th October 2018 diff --git a/src/animations/AnimationManager.js b/src/animations/AnimationManager.js index fdfdca20b..20ce067ca 100644 --- a/src/animations/AnimationManager.js +++ b/src/animations/AnimationManager.js @@ -421,7 +421,7 @@ var AnimationManager = new Class({ * @param {string} key - The key of the animation to load. * @param {(string|integer)} [startFrame] - The name of a start frame to set on the loaded animation. * - * @return {Phaser.GameObjects.GameObject} [description] + * @return {Phaser.GameObjects.GameObject} The Game Object with the animation loaded into it. */ load: function (child, key, startFrame) { @@ -576,7 +576,7 @@ var AnimationManager = new Class({ }, /** - * [description] + * Get the animation data as javascript object by giving key, or get the data of all animations as array of objects, if key wasn't provided. * * @method Phaser.Animations.AnimationManager#toJSON * @since 3.0.0 @@ -608,7 +608,8 @@ var AnimationManager = new Class({ }, /** - * [description] + * Destroy this Animation Manager and clean up animation definitions and references to other objects. + * This method should not be called directly. It will be called automatically as a response to a `destroy` event from the Phaser.Game instance. * * @method Phaser.Animations.AnimationManager#destroy * @since 3.0.0 diff --git a/src/curves/path/MoveTo.js b/src/curves/path/MoveTo.js index fd970dc06..635868efb 100644 --- a/src/curves/path/MoveTo.js +++ b/src/curves/path/MoveTo.js @@ -9,15 +9,15 @@ var Vector2 = require('../../math/Vector2'); /** * @classdesc - * [description] + * A MoveTo Curve is a very simple curve consisting of only a single point. Its intended use is to move the ending point in a Path. * * @class MoveTo * @memberof Phaser.Curves * @constructor * @since 3.0.0 * - * @param {number} [x] - [description] - * @param {number} [y] - [description] + * @param {number} [x] - `x` pixel coordinate. + * @param {number} [y] - `y` pixel coordinate. */ var MoveTo = new Class({ @@ -28,7 +28,7 @@ var MoveTo = new Class({ // Skip length calcs in paths /** - * [description] + * Denotes that this Curve does not influence the bounds, points, and drawing of its parent Path. Must be `false` or some methods in the parent Path will throw errors. * * @name Phaser.Curves.MoveTo#active * @type {boolean} @@ -38,7 +38,7 @@ var MoveTo = new Class({ this.active = false; /** - * [description] + * The lone point which this curve consists of. * * @name Phaser.Curves.MoveTo#p0 * @type {Phaser.Math.Vector2} @@ -68,17 +68,17 @@ var MoveTo = new Class({ }, /** - * [description] + * Retrieves the point at given position in the curve. This will always return this curve's only point. * * @method Phaser.Curves.MoveTo#getPointAt * @since 3.0.0 * * @generic {Phaser.Math.Vector2} O - [out,$return] * - * @param {number} u - [description] - * @param {Phaser.Math.Vector2} [out] - [description] + * @param {number} u - The position in the path to retrieve, between 0 and 1. Not used. + * @param {Phaser.Math.Vector2} [out] - An optional vector in which to store the point. * - * @return {Phaser.Math.Vector2} [description] + * @return {Phaser.Math.Vector2} The modified `out` vector, or a new `Vector2` if none was provided. */ getPointAt: function (u, out) { @@ -112,12 +112,12 @@ var MoveTo = new Class({ }, /** - * [description] + * Converts this curve into a JSON-serializable object. * * @method Phaser.Curves.MoveTo#toJSON * @since 3.0.0 * - * @return {JSONCurve} [description] + * @return {JSONCurve} A primitive object with the curve's type and only point. */ toJSON: function () { diff --git a/src/geom/line/NormalY.js b/src/geom/line/NormalY.js index 80a173750..ae7960ce5 100644 --- a/src/geom/line/NormalY.js +++ b/src/geom/line/NormalY.js @@ -8,14 +8,15 @@ var MATH_CONST = require('../../math/const'); var Angle = require('./Angle'); /** - * [description] + * The Y value of the normal of the given line. + * The normal of a line is a vector that points perpendicular from it. * * @function Phaser.Geom.Line.NormalY * @since 3.0.0 * - * @param {Phaser.Geom.Line} line - [description] + * @param {Phaser.Geom.Line} line - The line to calculate the normal of. * - * @return {number} [description] + * @return {number} The Y value of the normal of the Line. */ var NormalY = function (line) { diff --git a/src/geom/point/GetCentroid.js b/src/geom/point/GetCentroid.js index aa395579e..6c7c3e1eb 100644 --- a/src/geom/point/GetCentroid.js +++ b/src/geom/point/GetCentroid.js @@ -7,7 +7,8 @@ var Point = require('./Point'); /** - * [description] + * Get the centroid or geometric center of a plane figure (the arithmetic mean position of all the points in the figure). + * Informally, it is the point at which a cutout of the shape could be perfectly balanced on the tip of a pin. * * @function Phaser.Geom.Point.GetCentroid * @since 3.0.0 diff --git a/src/geom/point/SetMagnitude.js b/src/geom/point/SetMagnitude.js index 622236eb6..8b0332536 100644 --- a/src/geom/point/SetMagnitude.js +++ b/src/geom/point/SetMagnitude.js @@ -7,17 +7,17 @@ var GetMagnitude = require('./GetMagnitude'); /** - * [description] + * Changes the magnitude (length) of a two-dimensional vector without changing its direction. * * @function Phaser.Geom.Point.SetMagnitude * @since 3.0.0 * * @generic {Phaser.Geom.Point} O - [point,$return] * - * @param {Phaser.Geom.Point} point - [description] - * @param {number} magnitude - [description] + * @param {Phaser.Geom.Point} point - The Point to treat as the end point of the vector. + * @param {number} magnitude - The new magnitude of the vector. * - * @return {Phaser.Geom.Point} [description] + * @return {Phaser.Geom.Point} The modified Point. */ var SetMagnitude = function (point, magnitude) { diff --git a/src/geom/polygon/Clone.js b/src/geom/polygon/Clone.js index 101b98547..4519c5d23 100644 --- a/src/geom/polygon/Clone.js +++ b/src/geom/polygon/Clone.js @@ -7,14 +7,14 @@ var Polygon = require('./Polygon'); /** - * [description] + * Create a new polygon which is a copy of the specified polygon * * @function Phaser.Geom.Polygon.Clone * @since 3.0.0 * - * @param {Phaser.Geom.Polygon} polygon - [description] + * @param {Phaser.Geom.Polygon} polygon - The polygon to create a clone of * - * @return {Phaser.Geom.Polygon} [description] + * @return {Phaser.Geom.Polygon} A new separate Polygon cloned from the specified polygon, based on the same points. */ var Clone = function (polygon) { diff --git a/src/geom/polygon/Polygon.js b/src/geom/polygon/Polygon.js index 3e2c63696..48a59072a 100644 --- a/src/geom/polygon/Polygon.js +++ b/src/geom/polygon/Polygon.js @@ -10,14 +10,26 @@ var GetPoints = require('./GetPoints'); /** * @classdesc - * [description] + * A Polygon object + * + + * The polygon is a closed shape consists of a series of connected straight lines defined by list of ordered points. + * Several formats are supported to define the list of points, check the setTo method for details. + * This is a geometry object allowing you to define and inspect the shape. + * It is not a Game Object, in that you cannot add it to the display list, and it has no texture. + * To render a Polygon you should look at the capabilities of the Graphics class. * * @class Polygon * @memberof Phaser.Geom * @constructor * @since 3.0.0 * - * @param {Phaser.Geom.Point[]} [points] - [description] + * @param {Phaser.Geom.Point[]} [points] - List of points defining the perimeter of this Polygon. Several formats are supported: + * - A string containing paired x y values separated by a single space: `'40 0 40 20 100 20 100 80 40 80 40 100 0 50'` + * - An array of Point objects: `[new Phaser.Point(x1, y1), ...]` + * - An array of objects with public x y properties: `[obj1, obj2, ...]` + * - An array of paired numbers that represent point coordinates: `[x1,y1, x2,y2, ...]` + * - An array of arrays with two elements representing x/y coordinates: `[[x1, y1], [x2, y2], ...]` */ var Polygon = new Class({ @@ -82,7 +94,7 @@ var Polygon = new Class({ * @method Phaser.Geom.Polygon#setTo * @since 3.0.0 * - * @param {array} points - [description] + * @param {array} points - Points defining the perimeter of this polygon. Please check function description above for the different supported formats. * * @return {Phaser.Geom.Polygon} This Polygon object. */ diff --git a/src/geom/polygon/Reverse.js b/src/geom/polygon/Reverse.js index 5b5e26aec..8cbee3ba5 100644 --- a/src/geom/polygon/Reverse.js +++ b/src/geom/polygon/Reverse.js @@ -5,16 +5,16 @@ */ /** - * [description] + * Reverses the order of the points of a Polygon. * * @function Phaser.Geom.Polygon.Reverse * @since 3.0.0 * * @generic {Phaser.Geom.Polygon} O - [polygon,$return] * - * @param {Phaser.Geom.Polygon} polygon - [description] + * @param {Phaser.Geom.Polygon} polygon - The Polygon to modify. * - * @return {Phaser.Geom.Polygon} [description] + * @return {Phaser.Geom.Polygon} The modified Polygon. */ var Reverse = function (polygon) { diff --git a/src/geom/rectangle/Area.js b/src/geom/rectangle/Area.js index 80909723f..e90f8d7a1 100644 --- a/src/geom/rectangle/Area.js +++ b/src/geom/rectangle/Area.js @@ -5,14 +5,14 @@ */ /** - * [description] + * Calculates the area of the given Rectangle object. * * @function Phaser.Geom.Rectangle.Area * @since 3.0.0 * - * @param {Phaser.Geom.Rectangle} rect - [description] + * @param {Phaser.Geom.Rectangle} rect - The rectangle to calculate the area of. * - * @return {number} [description] + * @return {number} The area of the Rectangle object. */ var Area = function (rect) { diff --git a/src/geom/rectangle/Floor.js b/src/geom/rectangle/Floor.js index 0cf4f2aee..24bfa9a39 100644 --- a/src/geom/rectangle/Floor.js +++ b/src/geom/rectangle/Floor.js @@ -5,16 +5,16 @@ */ /** - * [description] + * Rounds down (floors) the top left X and Y co-ordinates of the given Rectangle to the largest integer less than or equal to them * * @function Phaser.Geom.Rectangle.Floor * @since 3.0.0 * * @generic {Phaser.Geom.Rectangle} O - [rect,$return] * - * @param {Phaser.Geom.Rectangle} rect - [description] + * @param {Phaser.Geom.Rectangle} rect - The rectangle to floor the top left X and Y co-ordinates of * - * @return {Phaser.Geom.Rectangle} [description] + * @return {Phaser.Geom.Rectangle} The rectangle that was passed to this function with its co-ordinates floored. */ var Floor = function (rect) { diff --git a/src/geom/rectangle/GetPoints.js b/src/geom/rectangle/GetPoints.js index cb6a720f8..a4b4c63f1 100644 --- a/src/geom/rectangle/GetPoints.js +++ b/src/geom/rectangle/GetPoints.js @@ -19,8 +19,8 @@ var Perimeter = require('./Perimeter'); * @generic {Phaser.Geom.Point[]} O - [out,$return] * * @param {Phaser.Geom.Rectangle} rectangle - The Rectangle object to get the points from. - * @param {number} step - [description] - * @param {integer} quantity - [description] + * @param {number} step - Step between points. Used to calculate the number of points to return when quantity is falsy. Ignored if quantity is positive. + * @param {integer} quantity - The number of evenly spaced points from the rectangles perimeter to return. If falsy, step param will be used to calculate the number of points. * @param {(array|Phaser.Geom.Point[])} [out] - An optional array to store the points in. * * @return {(array|Phaser.Geom.Point[])} An array of Points from the perimeter of the rectangle. diff --git a/src/geom/rectangle/Overlaps.js b/src/geom/rectangle/Overlaps.js index 1fbb93116..cae6a6eaa 100644 --- a/src/geom/rectangle/Overlaps.js +++ b/src/geom/rectangle/Overlaps.js @@ -5,15 +5,15 @@ */ /** - * [description] + * Checks if two Rectangles overlap. If a Rectangle is within another Rectangle, the two will be considered overlapping. Thus, the Rectangles are treated as "solid". * * @function Phaser.Geom.Rectangle.Overlaps * @since 3.0.0 * - * @param {Phaser.Geom.Rectangle} rectA - [description] - * @param {Phaser.Geom.Rectangle} rectB - [description] + * @param {Phaser.Geom.Rectangle} rectA - The first Rectangle to check. + * @param {Phaser.Geom.Rectangle} rectB - The second Rectangle to check. * - * @return {boolean} [description] + * @return {boolean} `true` if the two Rectangles overlap, `false` otherwise. */ var Overlaps = function (rectA, rectB) { diff --git a/src/geom/triangle/CircumCircle.js b/src/geom/triangle/CircumCircle.js index b1c04225f..ce7e8e28d 100644 --- a/src/geom/triangle/CircumCircle.js +++ b/src/geom/triangle/CircumCircle.js @@ -9,17 +9,17 @@ var Circle = require('../circle/Circle'); // Adapted from https://gist.github.com/mutoo/5617691 /** - * [description] + * Finds the circumscribed circle (circumcircle) of a Triangle object. The circumcircle is the circle which touches all of the triangle's vertices. * * @function Phaser.Geom.Triangle.CircumCircle * @since 3.0.0 * * @generic {Phaser.Geom.Circle} O - [out,$return] * - * @param {Phaser.Geom.Triangle} triangle - [description] - * @param {Phaser.Geom.Circle} [out] - [description] + * @param {Phaser.Geom.Triangle} triangle - The Triangle to use as input. + * @param {Phaser.Geom.Circle} [out] - An optional Circle to store the result in. * - * @return {Phaser.Geom.Circle} [description] + * @return {Phaser.Geom.Circle} The updated `out` Circle, or a new Circle if none was provided. */ var CircumCircle = function (triangle, out) { diff --git a/src/geom/triangle/InCenter.js b/src/geom/triangle/InCenter.js index dd32726dc..9032d7db2 100644 --- a/src/geom/triangle/InCenter.js +++ b/src/geom/triangle/InCenter.js @@ -19,17 +19,17 @@ function getLength (x1, y1, x2, y2) } /** - * [description] + * Calculates the position of the incenter of a Triangle object. This is the point where its three angle bisectors meet and it's also the center of the incircle, which is the circle inscribed in the triangle. * * @function Phaser.Geom.Triangle.InCenter * @since 3.0.0 * * @generic {Phaser.Geom.Point} O - [out,$return] * - * @param {Phaser.Geom.Triangle} triangle - [description] - * @param {Phaser.Geom.Point} [out] - [description] + * @param {Phaser.Geom.Triangle} triangle - The Triangle to find the incenter of. + * @param {Phaser.Geom.Point} [out] - An optional Point in which to store the coordinates. * - * @return {Phaser.Geom.Point} [description] + * @return {Phaser.Geom.Point} Point (x, y) of the center pixel of the triangle. */ var InCenter = function (triangle, out) { diff --git a/src/geom/triangle/Offset.js b/src/geom/triangle/Offset.js index 78150f552..59a2b1a2a 100644 --- a/src/geom/triangle/Offset.js +++ b/src/geom/triangle/Offset.js @@ -5,18 +5,18 @@ */ /** - * [description] + * Moves each point (vertex) of a Triangle by a given offset, thus moving the entire Triangle by that offset. * * @function Phaser.Geom.Triangle.Offset * @since 3.0.0 * * @generic {Phaser.Geom.Triangle} O - [triangle,$return] * - * @param {Phaser.Geom.Triangle} triangle - [description] - * @param {number} x - [description] - * @param {number} y - [description] + * @param {Phaser.Geom.Triangle} triangle - The Triangle to move. + * @param {number} x - The horizontal offset (distance) by which to move each point. Can be positive or negative. + * @param {number} y - The vertical offset (distance) by which to move each point. Can be positive or negative. * - * @return {Phaser.Geom.Triangle} [description] + * @return {Phaser.Geom.Triangle} The modified Triangle. */ var Offset = function (triangle, x, y) { diff --git a/src/math/RotateAroundDistance.js b/src/math/RotateAroundDistance.js index 02b582645..4eaf00791 100644 --- a/src/math/RotateAroundDistance.js +++ b/src/math/RotateAroundDistance.js @@ -5,7 +5,7 @@ */ /** - * [description] + * Rotate a `point` around `x` and `y` by the given `angle` and `distance`. * * @function Phaser.Math.RotateAroundDistance * @since 3.0.0 @@ -14,7 +14,7 @@ * @param {number} x - The horizontal coordinate to rotate around. * @param {number} y - The vertical coordinate to rotate around. * @param {number} angle - The angle of rotation in radians. - * @param {number} distance - [description] + * @param {number} distance - The distance from (x, y) to place the point at. * * @return {Phaser.Geom.Point} The given point. */ diff --git a/src/physics/impact/Body.js b/src/physics/impact/Body.js index 3be6e09c9..ee7affcd7 100644 --- a/src/physics/impact/Body.js +++ b/src/physics/impact/Body.js @@ -22,11 +22,11 @@ var UpdateMotion = require('./UpdateMotion'); * * @property {string} name - [description] * @property {object} size - [description] - * @property {object} pos - [description] - * @property {object} vel - [description] - * @property {object} accel - [description] - * @property {object} friction - [description] - * @property {object} maxVel - [description] + * @property {object} pos - The entity's position in the game world. + * @property {object} vel - Current velocity in pixels per second. + * @property {object} accel - Current acceleration to be added to the entity's velocity per second. E.g. an entity with a `vel.x` of 0 and `accel.x` of 10 will have a `vel.x` of 100 ten seconds later. + * @property {object} friction - Deceleration to be subtracted from the entity's velocity per second. Only applies if `accel` is 0. + * @property {object} maxVel - The maximum velocity a body can move. * @property {number} gravityFactor - [description] * @property {number} bounciness - [description] * @property {number} minBounceVelocity - [description] @@ -461,7 +461,7 @@ var Body = new Class({ }, /** - * [description] + * Determines whether the body collides with the `other` one or not. * * @method Phaser.Physics.Impact.Body#touches * @since 3.0.0 diff --git a/src/physics/impact/World.js b/src/physics/impact/World.js index e70cd3297..ac44a53cd 100644 --- a/src/physics/impact/World.js +++ b/src/physics/impact/World.js @@ -81,7 +81,7 @@ var TYPE = require('./TYPE'); * @constructor * @since 3.0.0 * - * @param {Phaser.Scene} scene - [description] + * @param {Phaser.Scene} scene - The Scene to which this Impact World instance belongs. * @param {Phaser.Physics.Impact.WorldConfig} config - [description] */ var World = new Class({ diff --git a/src/physics/matter-js/Factory.js b/src/physics/matter-js/Factory.js index e2d8a19ea..aae35f3bb 100644 --- a/src/physics/matter-js/Factory.js +++ b/src/physics/matter-js/Factory.js @@ -163,9 +163,9 @@ var Factory = new Class({ * @param {number} y - The Y coordinate of the center of the Body. * @param {array} vertexSets - [description] * @param {object} options - [description] - * @param {boolean} flagInternal - [description] - * @param {boolean} removeCollinear - [description] - * @param {number} minimumArea - [description] + * @param {boolean} flagInternal - Flag internal edges (coincident part edges) + * @param {boolean} removeCollinear - Whether Matter.js will discard collinear edges (to improve performance). + * @param {number} minimumArea - During decomposition discard parts that have an area less than this * * @return {MatterJS.Body} A Matter JS Body. */ @@ -261,7 +261,7 @@ var Factory = new Class({ * @param {number} rows - The number of rows in the pyramid. * @param {number} columnGap - The distance between each column. * @param {number} rowGap - The distance between each row. - * @param {function} callback - [description] + * @param {function} callback - The callback function to be invoked. * * @return {MatterJS.Composite} A Matter JS Composite pyramid. */ @@ -372,7 +372,7 @@ var Factory = new Class({ * @param {number} columnGap - The distance between each column. * @param {number} rowGap - The distance between each row. * @param {boolean} crossBrace - [description] - * @param {number} particleRadius - [description] + * @param {number} particleRadius - The radius of this circlular composite. * @param {object} particleOptions - [description] * @param {object} constraintOptions - [description] * @@ -412,10 +412,10 @@ var Factory = new Class({ * @method Phaser.Physics.Matter.Factory#spring * @since 3.0.0 * - * @param {MatterJS.Body} bodyA - [description] - * @param {MatterJS.Body} bodyB - [description] - * @param {number} length - [description] - * @param {number} [stiffness=1] - [description] + * @param {MatterJS.Body} bodyA - The first possible `Body` that this constraint is attached to. + * @param {MatterJS.Body} bodyB - The second possible `Body` that this constraint is attached to. + * @param {number} length - A Number that specifies the target resting length of the constraint. It is calculated automatically in `Constraint.create` from initial positions of the `constraint.bodyA` and `constraint.bodyB` + * @param {number} [stiffness=1] - A Number that specifies the stiffness of the constraint, i.e. the rate at which it returns to its resting `constraint.length`. A value of `1` means the constraint should be very stiff. A value of `0.2` means the constraint acts as a soft spring. * @param {object} [options={}] - [description] * * @return {MatterJS.Constraint} A Matter JS Constraint. diff --git a/src/physics/matter-js/World.js b/src/physics/matter-js/World.js index 5f8dcc5c5..0a8fda1e5 100644 --- a/src/physics/matter-js/World.js +++ b/src/physics/matter-js/World.js @@ -399,7 +399,7 @@ var World = new Class({ }, /** - * [description] + * Sets the world's gravity and gravity scale to 0. * * @method Phaser.Physics.Matter.World#disableGravity * @since 3.0.0 @@ -416,13 +416,13 @@ var World = new Class({ }, /** - * [description] + * Sets the world's gravity * * @method Phaser.Physics.Matter.World#setGravity * @since 3.0.0 * - * @param {number} [x=0] - [description] - * @param {number} [y=1] - [description] + * @param {number} [x=0] - The world gravity x component. + * @param {number} [y=1] - The world gravity y component. * @param {number} [scale] - [description] * * @return {Phaser.Physics.Matter.World} This Matter World object. @@ -467,7 +467,7 @@ var World = new Class({ }, /** - * [description] + * Adds an object to the world. * * @method Phaser.Physics.Matter.World#add * @since 3.0.0 @@ -592,7 +592,7 @@ var World = new Class({ * @method Phaser.Physics.Matter.World#nextCategory * @since 3.0.0 * - * @return {number} [description] + * @return {number} Returns the next unique category bitfield. */ nextCategory: function () { diff --git a/src/physics/matter-js/components/Bounce.js b/src/physics/matter-js/components/Bounce.js index 9ada1efaf..634ca6514 100644 --- a/src/physics/matter-js/components/Bounce.js +++ b/src/physics/matter-js/components/Bounce.js @@ -5,7 +5,7 @@ */ /** - * [description] + * A component to set restitution on objects. * * @name Phaser.Physics.Matter.Components.Bounce * @since 3.0.0 @@ -13,12 +13,12 @@ var Bounce = { /** - * [description] + * Sets the restitution on the physics object. * * @method Phaser.Physics.Matter.Components.Bounce#setBounce * @since 3.0.0 * - * @param {number} value - [description] + * @param {number} value - A Number that defines the restitution (elasticity) of the body. The value is always positive and is in the range (0, 1). A value of 0 means collisions may be perfectly inelastic and no bouncing may occur. A value of 0.8 means the body may bounce back with approximately 80% of its kinetic energy. Note that collision response is based on pairs of bodies, and that restitution values are combined with the following formula: `Math.max(bodyA.restitution, bodyB.restitution)` * * @return {Phaser.GameObjects.GameObject} This Game Object. */ diff --git a/src/physics/matter-js/components/Collision.js b/src/physics/matter-js/components/Collision.js index 5843eda57..1d43f0fb4 100644 --- a/src/physics/matter-js/components/Collision.js +++ b/src/physics/matter-js/components/Collision.js @@ -5,7 +5,7 @@ */ /** - * [description] + * Contains methods for changing the collision filter of a Matter Body. Should be used as a mixin and not called directly. * * @name Phaser.Physics.Matter.Components.Collision * @since 3.0.0 @@ -13,7 +13,7 @@ var Collision = { /** - * [description] + * Sets the collision category of this Game Object's Matter Body. This number must be a power of two between 2^0 (= 1) and 2^31. Two bodies with different collision groups (see {@link #setCollisionGroup}) will only collide if their collision categories are included in their collision masks (see {@link #setCollidesWith}). * * @method Phaser.Physics.Matter.Components.Collision#setCollisionCategory * @since 3.0.0 @@ -30,7 +30,7 @@ var Collision = { }, /** - * [description] + * Sets the collision group of this Game Object's Matter Body. If this is zero or two Matter Bodies have different values, they will collide according to the usual rules (see {@link #setCollisionCategory} and {@link #setCollisionGroup}). If two Matter Bodies have the same positive value, they will always collide; if they have the same negative value, they will never collide. * * @method Phaser.Physics.Matter.Components.Collision#setCollisionGroup * @since 3.0.0 @@ -47,7 +47,7 @@ var Collision = { }, /** - * [description] + * Sets the collision mask for this Game Object's Matter Body. Two Matter Bodies with different collision groups will only collide if each one includes the other's category in its mask based on a bitwise AND, i.e. `(categoryA & maskB) !== 0` and `(categoryB & maskA) !== 0` are both true. * * @method Phaser.Physics.Matter.Components.Collision#setCollidesWith * @since 3.0.0 diff --git a/src/physics/matter-js/components/Friction.js b/src/physics/matter-js/components/Friction.js index 41bb33ab2..1a778ed67 100644 --- a/src/physics/matter-js/components/Friction.js +++ b/src/physics/matter-js/components/Friction.js @@ -5,7 +5,7 @@ */ /** - * [description] + * Contains methods for changing the friction of a Game Object's Matter Body. Should be used a mixin, not called directly. * * @name Phaser.Physics.Matter.Components.Friction * @since 3.0.0 @@ -13,14 +13,14 @@ var Friction = { /** - * [description] + * Sets new friction values for this Game Object's Matter Body. * * @method Phaser.Physics.Matter.Components.Friction#setFriction * @since 3.0.0 * - * @param {number} value - [description] - * @param {number} [air] - [description] - * @param {number} [fstatic] - [description] + * @param {number} value - The new friction of the body, between 0 and 1, where 0 allows the Body to slide indefinitely, while 1 allows it to stop almost immediately after a force is applied. + * @param {number} [air] - If provided, the new air resistance of the Body. The higher the value, the faster the Body will slow as it moves through space. 0 means the body has no air resistance. + * @param {number} [fstatic] - If provided, the new static friction of the Body. The higher the value (e.g. 10), the more force it will take to initially get the Body moving when it is nearly stationary. 0 means the body will never "stick" when it is nearly stationary. * * @return {Phaser.GameObjects.GameObject} This Game Object. */ @@ -42,12 +42,12 @@ var Friction = { }, /** - * [description] + * Sets a new air resistance for this Game Object's Matter Body. A value of 0 means the Body will never slow as it moves through space. The higher the value, the faster a Body slows when moving through space. * * @method Phaser.Physics.Matter.Components.Friction#setFrictionAir * @since 3.0.0 * - * @param {number} value - [description] + * @param {number} value - The new air resistance for the Body. * * @return {Phaser.GameObjects.GameObject} This Game Object. */ @@ -59,12 +59,12 @@ var Friction = { }, /** - * [description] + * Sets a new static friction for this Game Object's Matter Body. A value of 0 means the Body will never "stick" when it is nearly stationary. The higher the value (e.g. 10), the more force it will take to initially get the Body moving when it is nearly stationary. * * @method Phaser.Physics.Matter.Components.Friction#setFrictionStatic * @since 3.0.0 * - * @param {number} value - [description] + * @param {number} value - The new static friction for the Body. * * @return {Phaser.GameObjects.GameObject} This Game Object. */ diff --git a/src/physics/matter-js/components/Mass.js b/src/physics/matter-js/components/Mass.js index 4e7a5d8e9..f6d461864 100644 --- a/src/physics/matter-js/components/Mass.js +++ b/src/physics/matter-js/components/Mass.js @@ -8,7 +8,7 @@ var Body = require('../lib/body/Body'); var Vector2 = require('../../../math/Vector2'); /** - * [description] + * Allows accessing the mass, density, and center of mass of a Matter-enabled Game Object. Should be used as a mixin and not directly. * * @name Phaser.Physics.Matter.Components.Mass * @since 3.0.0 @@ -16,12 +16,12 @@ var Vector2 = require('../../../math/Vector2'); var Mass = { /** - * [description] + * Sets the mass of the Game Object's Matter Body. * * @method Phaser.Physics.Matter.Components.Mass#setMass * @since 3.0.0 * - * @param {number} value - [description] + * @param {number} value - The new mass of the body. * * @return {Phaser.GameObjects.GameObject} This Game Object. */ @@ -38,7 +38,7 @@ var Mass = { * @method Phaser.Physics.Matter.Components.Mass#setDensity * @since 3.0.0 * - * @param {number} value - [description] + * @param {number} value - The new density of the body. * * @return {Phaser.GameObjects.GameObject} This Game Object. */ diff --git a/src/physics/matter-js/components/SetBody.js b/src/physics/matter-js/components/SetBody.js index 8277c0922..c9ff710ba 100644 --- a/src/physics/matter-js/components/SetBody.js +++ b/src/physics/matter-js/components/SetBody.js @@ -21,13 +21,13 @@ var SetBody = { // Calling any of these methods resets previous properties you may have set on the body, including plugins, mass, etc /** - * [description] + * Set the body on a Game Object to a rectangle. * * @method Phaser.Physics.Matter.Components.SetBody#setRectangle * @since 3.0.0 * - * @param {number} width - [description] - * @param {number} height - [description] + * @param {number} width - Width of the rectangle. + * @param {number} height - Height of the rectangle. * @param {object} options - [description] * * @return {Phaser.GameObjects.GameObject} This Game Object. @@ -54,14 +54,14 @@ var SetBody = { }, /** - * [description] + * Set the body on the Game Object to a polygon shape. * * @method Phaser.Physics.Matter.Components.SetBody#setPolygon * @since 3.0.0 * - * @param {number} radius - [description] - * @param {number} sides - [description] - * @param {object} options - [description] + * @param {number} radius - The radius of the polygon. + * @param {number} sides - The amount of sides creating the polygon. + * @param {object} options - A matterjs config object. * * @return {Phaser.GameObjects.GameObject} This Game Object. */ @@ -71,15 +71,15 @@ var SetBody = { }, /** - * [description] + * Creates a new matterjs trapezoid body. * * @method Phaser.Physics.Matter.Components.SetBody#setTrapezoid * @since 3.0.0 * - * @param {number} width - [description] - * @param {number} height - [description] - * @param {number} slope - [description] - * @param {object} options - [description] + * @param {number} width - The width of the trapezoid. + * @param {number} height - The height of the trapezoid. + * @param {number} slope - The angle of slope for the trapezoid. + * @param {object} options - A matterjs config object for the body. * * @return {Phaser.GameObjects.GameObject} This Game Object. */ diff --git a/src/renderer/canvas/utils/GetBlendModes.js b/src/renderer/canvas/utils/GetBlendModes.js index 4670f58d4..b3b1e1eed 100644 --- a/src/renderer/canvas/utils/GetBlendModes.js +++ b/src/renderer/canvas/utils/GetBlendModes.js @@ -8,12 +8,14 @@ var modes = require('../../BlendModes'); var CanvasFeatures = require('../../../device/CanvasFeatures'); /** - * [description] + * Returns an array which maps the default blend modes to supported Canvas blend modes. + * + * If the browser doesn't support a blend mode, it will default to the normal `source-over` blend mode. * * @function Phaser.Renderer.Canvas.GetBlendModes * @since 3.0.0 * - * @return {array} [description] + * @return {array} Which Canvas blend mode corresponds to which default Phaser blend mode. */ var GetBlendModes = function () { diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index 2575c1daa..e01b7a274 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -2187,8 +2187,8 @@ var WebGLRenderer = new Class({ * * @param {WebGLProgram} program - The target WebGLProgram from which the uniform location will be looked-up. * @param {string} name - The name of the uniform to look-up and modify. - * @param {integer} x - [description] - * @param {integer} y - [description] + * @param {integer} x - The new X component + * @param {integer} y - The new Y component * * @return {this} This WebGL Renderer instance. */ @@ -2209,9 +2209,9 @@ var WebGLRenderer = new Class({ * * @param {WebGLProgram} program - The target WebGLProgram from which the uniform location will be looked-up. * @param {string} name - The name of the uniform to look-up and modify. - * @param {integer} x - [description] - * @param {integer} y - [description] - * @param {integer} z - [description] + * @param {integer} x - The new X component + * @param {integer} y - The new Y component + * @param {integer} z - The new Z component * * @return {this} This WebGL Renderer instance. */ @@ -2249,15 +2249,15 @@ var WebGLRenderer = new Class({ }, /** - * [description] + * Sets the value of a 2x2 matrix uniform variable in the given WebGLProgram. * * @method Phaser.Renderer.WebGL.WebGLRenderer#setMatrix2 * @since 3.0.0 * * @param {WebGLProgram} program - The target WebGLProgram from which the uniform location will be looked-up. * @param {string} name - The name of the uniform to look-up and modify. - * @param {boolean} transpose - [description] - * @param {Float32Array} matrix - [description] + * @param {boolean} transpose - The value indicating whether to transpose the matrix. Must be false. + * @param {Float32Array} matrix - The new matrix value. * * @return {this} This WebGL Renderer instance. */ @@ -2343,7 +2343,7 @@ var WebGLRenderer = new Class({ }, /** - * [description] + * Destroy this WebGLRenderer, cleaning up all related resources such as pipelines, native textures, etc. * * @method Phaser.Renderer.WebGL.WebGLRenderer#destroy * @since 3.0.0 diff --git a/src/tilemaps/mapdata/MapData.js b/src/tilemaps/mapdata/MapData.js index e5ffe9430..28dc8422f 100644 --- a/src/tilemaps/mapdata/MapData.js +++ b/src/tilemaps/mapdata/MapData.js @@ -110,7 +110,7 @@ var MapData = new Class({ this.orientation = GetFastValue(config, 'orientation', 'orthogonal'); /** - * [description] + * The orientation of the map data (i.e. orthogonal, isometric, hexagonal), default 'orthogonal'. * * @name Phaser.Tilemaps.MapData#renderOrder * @type {string} @@ -119,7 +119,12 @@ var MapData = new Class({ this.renderOrder = GetFastValue(config, 'renderOrder', 'right-down'); /** - * [description] + * Determines the draw order of tilemap. Default is right-down + * + * 0, or 'right-down' + * 1, or 'left-down' + * 2, or 'right-up' + * 3, or 'left-up' * * @name Phaser.Tilemaps.MapData#version * @type {string} @@ -128,7 +133,7 @@ var MapData = new Class({ this.version = GetFastValue(config, 'version', '1'); /** - * [description] + * The version of the map data (as specified in Tiled). * * @name Phaser.Tilemaps.MapData#properties * @type {object} @@ -137,7 +142,7 @@ var MapData = new Class({ this.properties = GetFastValue(config, 'properties', {}); /** - * [description] + * Map specific properties (can be specified in Tiled) * * @name Phaser.Tilemaps.MapData#layers * @type {array} @@ -146,7 +151,7 @@ var MapData = new Class({ this.layers = GetFastValue(config, 'layers', []); /** - * [description] + * An array with all the layers configured to the MapData * * @name Phaser.Tilemaps.MapData#images * @type {array} @@ -155,7 +160,7 @@ var MapData = new Class({ this.images = GetFastValue(config, 'images', []); /** - * [description] + * An array of Tiled Image Layers * * @name Phaser.Tilemaps.MapData#objects * @type {object} @@ -164,7 +169,7 @@ var MapData = new Class({ this.objects = GetFastValue(config, 'objects', {}); /** - * [description] + * An object of Tiled Object Layers * * @name Phaser.Tilemaps.MapData#collision * @type {object} @@ -173,7 +178,7 @@ var MapData = new Class({ this.collision = GetFastValue(config, 'collision', {}); /** - * [description] + * An object of collision data. Must be created as physics object or will return undefined * * @name Phaser.Tilemaps.MapData#tilesets * @type {array} @@ -182,7 +187,7 @@ var MapData = new Class({ this.tilesets = GetFastValue(config, 'tilesets', []); /** - * [description] + * An array of Tilesets * * @name Phaser.Tilemaps.MapData#imageCollections * @type {array} diff --git a/src/tilemaps/parsers/tiled/ParseObject.js b/src/tilemaps/parsers/tiled/ParseObject.js index f56fb9b4c..d54d0abc5 100644 --- a/src/tilemaps/parsers/tiled/ParseObject.js +++ b/src/tilemaps/parsers/tiled/ParseObject.js @@ -12,16 +12,16 @@ var copyPoints = function (p) { return { x: p.x, y: p.y }; }; var commonObjectProps = [ 'id', 'name', 'type', 'rotation', 'properties', 'visible', 'x', 'y', 'width', 'height' ]; /** - * [description] + * Convert a Tiled object to an internal parsed object normalising and copying properties over, while applying optional x and y offsets. The parsed object will always have the properties `id`, `name`, `type`, `rotation`, `properties`, `visible`, `x`, `y`, `width` and `height`. Other properties will be added according to the object type (such as text, polyline, gid etc.) * * @function Phaser.Tilemaps.Parsers.Tiled.ParseObject * @since 3.0.0 * - * @param {object} tiledObject - [description] - * @param {number} [offsetX=0] - [description] - * @param {number} [offsetY=0] - [description] + * @param {object} tiledObject - Tiled object to convert to an internal parsed object normalising and copying properties over. + * @param {number} [offsetX=0] - Optional additional offset to apply to the object's x property. Defaults to 0. + * @param {number} [offsetY=0] - Optional additional offset to apply to the object's y property. Defaults to 0. * - * @return {object} [description] + * @return {object} The parsed object containing properties read from the Tiled object according to it's type with x and y values updated according to the given offsets. */ var ParseObject = function (tiledObject, offsetX, offsetY) { diff --git a/src/tweens/Timeline.js b/src/tweens/Timeline.js index 40a844cbf..8ab481664 100644 --- a/src/tweens/Timeline.js +++ b/src/tweens/Timeline.js @@ -344,14 +344,14 @@ var Timeline = new Class({ }, /** - * [description] + * Checks whether the offset value is a number or a directive that is relative to previous tweens. * * @method Phaser.Tweens.Timeline#isOffsetAbsolute * @since 3.0.0 * - * @param {number} value - [description] + * @param {number} value - The offset value to be evaluated * - * @return {boolean} [description] + * @return {boolean} True if the result is a number, false if it is a directive like " -= 1000" */ isOffsetAbsolute: function (value) { @@ -359,14 +359,14 @@ var Timeline = new Class({ }, /** - * [description] + * Checks if the offset is a relative value rather than an absolute one. If the value is just a number, this returns false. * * @method Phaser.Tweens.Timeline#isOffsetRelative * @since 3.0.0 * - * @param {string} value - [description] + * @param {string} value - The offset value to be evaluated * - * @return {boolean} [description] + * @return {boolean} Returns true if the value is relative, i.e " -= 1000". If false, the offset is absolute. */ isOffsetRelative: function (value) { @@ -386,15 +386,15 @@ var Timeline = new Class({ }, /** - * [description] + * Parses the relative offset value, returning a positive or negative number. * * @method Phaser.Tweens.Timeline#getRelativeOffset * @since 3.0.0 * - * @param {string} value - [description] + * @param {string} value - The relative offset, in the format of '-=500', for example. The first character determines whether it will be a positive or negative number. Spacing matters here. * @param {number} base - The value to use as the offset. * - * @return {number} [description] + * @return {number} The returned number value. */ getRelativeOffset: function (value, base) { @@ -418,7 +418,7 @@ var Timeline = new Class({ }, /** - * [description] + * Calculates the total duration of the timeline. Computes all tween's durations and returns the full duration of the timeline. The resulting number is stored in the timeline, not as a return value. * * @method Phaser.Tweens.Timeline#calcDuration * @since 3.0.0 @@ -481,12 +481,12 @@ var Timeline = new Class({ }, /** - * [description] + * Initializes the timeline, which means all Tweens get their init() called, and the total duration will be computed. Returns a boolean indicating whether the timeline is auto-started or not. * * @method Phaser.Tweens.Timeline#init * @since 3.0.0 * - * @return {boolean} [description] + * @return {boolean} Returns true if the timeline is started. False if it is paused. */ init: function () { @@ -508,12 +508,12 @@ var Timeline = new Class({ }, /** - * [description] + * Resets all of the timeline's tweens back to their initial states. The boolean parameter indicates whether tweens that are looping should reset as well, or not. * * @method Phaser.Tweens.Timeline#resetTweens * @since 3.0.0 * - * @param {boolean} resetFromLoop - [description] + * @param {boolean} resetFromLoop - If true, resets all looping tweens to their initial values. */ resetTweens: function (resetFromLoop) { @@ -564,7 +564,7 @@ var Timeline = new Class({ }, /** - * [description] + * Starts playing the timeline. * * @method Phaser.Tweens.Timeline#play * @since 3.0.0 @@ -775,7 +775,7 @@ var Timeline = new Class({ }, /** - * [description] + * Pauses the timeline, retaining its internal state. * * @method Phaser.Tweens.Timeline#pause * @since 3.0.0 @@ -801,7 +801,7 @@ var Timeline = new Class({ }, /** - * [description] + * Resumes the timeline from where it was when it was paused. * * @method Phaser.Tweens.Timeline#resume * @since 3.0.0 @@ -823,14 +823,14 @@ var Timeline = new Class({ }, /** - * [description] + * Checks if any of the tweens has the target as the object they are operating on. Retuns false if no tweens operate on the target object. * * @method Phaser.Tweens.Timeline#hasTarget * @since 3.0.0 * - * @param {object} target - [description] + * @param {object} target - The target to check all tweens against. * - * @return {boolean} [description] + * @return {boolean} True if there at least a single tween that operates on the target object. False otherwise. */ hasTarget: function (target) { diff --git a/src/tweens/builders/GetTweens.js b/src/tweens/builders/GetTweens.js index f42a33655..0ffcdac6c 100644 --- a/src/tweens/builders/GetTweens.js +++ b/src/tweens/builders/GetTweens.js @@ -7,7 +7,7 @@ var GetValue = require('../../utils/object/GetValue'); /** - * [description] + * Returns an array of all tweens in the given config * * @function Phaser.Tweens.Builders.GetTweens * @since 3.0.0 diff --git a/src/tweens/builders/TimelineBuilder.js b/src/tweens/builders/TimelineBuilder.js index 2a6ff9079..a282527b6 100644 --- a/src/tweens/builders/TimelineBuilder.js +++ b/src/tweens/builders/TimelineBuilder.js @@ -17,15 +17,44 @@ var Timeline = require('../Timeline'); var TweenBuilder = require('./TweenBuilder'); /** - * [description] + * Builds a Timeline of Tweens based on a configuration object. + * + * The configuration object (`config`) can have the following properties: + * + * `tweens` - an array of tween configuration objects to create and add into the new Timeline, as described by `TweenBuilder`. If this doesn't exist or is empty, the Timeline will start off paused and none of the other configuration settings will be read. If it's a function, it will be called and its return value will be used as the array. + * `targets` - an array (or function which returns one) of default targets to which to apply the Timeline. Each individual Tween configuration can override this value. + * `totalDuration` - if specified, each Tween in the Timeline will get an equal portion of this duration, usually in milliseconds, by default. Each individual Tween configuration can override the Tween's duration. + * `duration` - if `totalDuration` is not specified, the default duration, usually in milliseconds, of each Tween which will be created. Each individual Tween configuration can override the Tween's duration. + * `delay`, `easeParams`, `ease`, `hold`, `repeat`, `repeatDelay`, `yoyo`, `flipX`, `flipY` - the default settings for each Tween which will be created, as specified by `TweenBuilder`. Each individual Tween configuration can override any of these values. + * `completeDelay` - if specified, the time to wait, usually in milliseconds, before the Timeline completes. + * `loop` - how many times the Timeline should loop, or -1 to loop indefinitely. + * `loopDelay` - the time, usually in milliseconds, between each loop + * `paused` - if `true`, the Timeline will start paused + * `useFrames` - if `true`, all duration in the Timeline will be in frames instead of milliseconds + * `callbackScope` - the default scope (`this` value) to use for each callback registered by the Timeline Builder. If not specified, the Timeline itself will be used. + * `onStart` - if specified, the `onStart` callback for the Timeline, called every time it starts playing + * `onStartScope` - the scope (`this` value) to use for the `onStart` callback. If not specified, the `callbackScope` will be used. + * `onStartParams` - additional arguments to pass to the `onStart` callback. The Timeline will always be the first argument. + * `onUpdate` - if specified, the `onUpdate` callback for the Timeline, called every frame it's active, regardless of its Tweens + * `onUpdateScope` - the scope (`this` value) to use for the `onUpdate` callback. If not specified, the `callbackScope` will be used. + * `onUpdateParams` - additional arguments to pass to the `onUpdate` callback. The Timeline will always be the first argument. + * `onLoop` - if specified, the `onLoop` callback for the Timeline, called every time it loops + * `onLoopScope` - the scope (`this` value) to use for the `onLoop` callback. If not specified, the `callbackScope` will be used. + * `onLoopParams` - additional arguments to pass to the `onLoop` callback. The Timeline will always be the first argument. + * `onYoyo` - if specified, the `onYoyo` callback for the Timeline, called every time it yoyos + * `onYoyoScope` - the scope (`this` value) to use for the `onYoyo` callback. If not specified, the `callbackScope` will be used. + * `onYoyoParams` - additional arguments to pass to the `onYoyo` callback. The first argument will always be `null`, while the Timeline will always be the second argument. + * `onComplete` - if specified, the `onComplete` callback for the Timeline, called after it completes + * `onCompleteScope` - the scope (`this` value) to use for the `onComplete` callback. If not specified, the `callbackScope` will be used. + * `onCompleteParams` - additional arguments to pass to the `onComplete` callback. The Timeline will always be the first argument. * * @function Phaser.Tweens.Builders.TimelineBuilder * @since 3.0.0 * - * @param {Phaser.Tweens.TweenManager} manager - [description] - * @param {object} config - [description] + * @param {Phaser.Tweens.TweenManager} manager - The Tween Manager to which the Timeline will belong. + * @param {object} config - The configuration object for the Timeline, as described above. * - * @return {Phaser.Tweens.Timeline} [description] + * @return {Phaser.Tweens.Timeline} The created Timeline. */ var TimelineBuilder = function (manager, config) { diff --git a/src/tweens/builders/TweenBuilder.js b/src/tweens/builders/TweenBuilder.js index 8d1d92af9..c9102f926 100644 --- a/src/tweens/builders/TweenBuilder.js +++ b/src/tweens/builders/TweenBuilder.js @@ -24,7 +24,33 @@ var TweenData = require('../tween/TweenData'); * * @param {(Phaser.Tweens.TweenManager|Phaser.Tweens.Timeline)} parent - [description] * @param {object} config - [description] - * @param {Phaser.Tweens.TweenConfigDefaults} defaults - [description] + * @param {Phaser.Tweens.TweenConfigDefaults} defaults - Tween configuration defaults. +` + * @property {(object|object[])} targets - The object, or an array of objects, to run the tween on. + * @property {number} [delay=0] - The number of milliseconds to delay before the tween will start. + * @property {number} [duration=1000] - The duration of the tween in milliseconds. + * @property {string} [ease='Power0'] - The easing equation to use for the tween. + * @property {array} [easeParams] - Optional easing parameters. + * @property {number} [hold=0] - The number of milliseconds to hold the tween for before yoyo'ing. + * @property {number} [repeat=0] - The number of times to repeat the tween. + * @property {number} [repeatDelay=0] - The number of milliseconds to pause before a tween will repeat. + * @property {boolean} [yoyo=false] - Should the tween complete, then reverse the values incrementally to get back to the starting tween values? The reverse tweening will also take `duration` milliseconds to complete. + * @property {boolean} [flipX=false] - Horizontally flip the target of the Tween when it completes (before it yoyos, if set to do so). Only works for targets that support the `flipX` property. + * @property {boolean} [flipY=false] - Vertically flip the target of the Tween when it completes (before it yoyos, if set to do so). Only works for targets that support the `flipY` property. +` +{ + targets: null, + delay: 0, + duration: 1000, + ease: 'Power0', + easeParams: null, + hold: 0, + repeat: 0, + repeatDelay: 0, + yoyo: false, + flipX: false, + flipY: false +}; * * @return {Phaser.Tweens.Tween} [description] */ diff --git a/src/tweens/tween/Tween.js b/src/tweens/tween/Tween.js index 23b36650f..66624c25b 100644 --- a/src/tweens/tween/Tween.js +++ b/src/tweens/tween/Tween.js @@ -297,12 +297,12 @@ var Tween = new Class({ }, /** - * [description] + * Set the scale the time applied to this Tween. A value of 1 runs in real-time. A value of 0.5 runs 50% slower, and so on. * * @method Phaser.Tweens.Tween#setTimeScale * @since 3.0.0 * - * @param {number} value - [description] + * @param {number} value - The scale factor for timescale. * * @return {Phaser.Tweens.Tween} This Tween object. */ @@ -314,12 +314,12 @@ var Tween = new Class({ }, /** - * [description] + * Returns the scale of the time applied to this Tween. * * @method Phaser.Tweens.Tween#getTimeScale * @since 3.0.0 * - * @return {number} [description] + * @return {number} The timescale of this tween (between 0 and 1) */ getTimeScale: function () { @@ -353,7 +353,7 @@ var Tween = new Class({ }, /** - * [description] + * See if this Tween is currently acting upon the given target. * * @method Phaser.Tweens.Tween#hasTarget * @since 3.0.0 @@ -915,7 +915,7 @@ var Tween = new Class({ * @method Phaser.Tweens.Tween#update * @since 3.0.0 * - * @param {number} timestamp - [description] + * @param {number} timestamp - The current time. Either a High Resolution Timer value if it comes from Request Animation Frame, or Date.now if using SetTimeout. * @param {number} delta - The delta time in ms since the last frame. This is a smoothed and capped value based on the FPS rate. * * @return {boolean} Returns `true` if this Tween has finished and should be removed from the Tween Manager, otherwise returns `false`. From 87be97aaf077662f5a6a0de1a58444a1a6b477d3 Mon Sep 17 00:00:00 2001 From: Mato Date: Wed, 5 Dec 2018 16:29:18 +0700 Subject: [PATCH 122/221] Add link to bitmaptext --- src/gameobjects/bitmaptext/static/BitmapText.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gameobjects/bitmaptext/static/BitmapText.js b/src/gameobjects/bitmaptext/static/BitmapText.js index 4a718e428..93cb0c7ba 100644 --- a/src/gameobjects/bitmaptext/static/BitmapText.js +++ b/src/gameobjects/bitmaptext/static/BitmapText.js @@ -68,12 +68,12 @@ var Render = require('./BitmapTextRender'); * * To create a BitmapText data files you need a 3rd party app such as: * - * BMFont (Windows, free): http://www.angelcode.com/products/bmfont/ - * Glyph Designer (OS X, commercial): http://www.71squared.com/en/glyphdesigner - * Littera (Web-based, free): http://kvazars.com/littera/ + * BMFont (Windows, free): {@link http://www.angelcode.com/products/bmfont/|http://www.angelcode.com/products/bmfont/} + * Glyph Designer (OS X, commercial): {@link http://www.71squared.com/en/glyphdesigner|http://www.71squared.com/en/glyphdesigner} + * Littera (Web-based, free): {@link http://kvazars.com/littera/|http://kvazars.com/littera/} * * For most use cases it is recommended to use XML. If you wish to use JSON, the formatting should be equal to the result of - * converting a valid XML file through the popular X2JS library. An online tool for conversion can be found here: http://codebeautify.org/xmltojson + * converting a valid XML file through the popular X2JS library. An online tool for conversion can be found here: {@link http://codebeautify.org/xmltojson|http://codebeautify.org/xmltojson} * * @class BitmapText * @extends Phaser.GameObjects.GameObject From 606a3832c1d0f1e41d2abaf82da19094f5232842 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 5 Dec 2018 11:16:45 +0000 Subject: [PATCH 123/221] Moving to a global keyboard manager for the DOM events. --- src/input/InputManager.js | 15 ++ src/input/keyboard/KeyboardManager.js | 227 ++++++++++++++++++++++++++ src/input/keyboard/KeyboardPlugin.js | 2 +- src/input/keyboard/index.js | 1 + 4 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 src/input/keyboard/KeyboardManager.js diff --git a/src/input/InputManager.js b/src/input/InputManager.js index b40d0073b..c13f38a12 100644 --- a/src/input/InputManager.js +++ b/src/input/InputManager.js @@ -7,6 +7,7 @@ var Class = require('../utils/Class'); var CONST = require('./const'); var EventEmitter = require('eventemitter3'); +var Keyboard = require('./mouse/KeyboardManager'); var Mouse = require('./mouse/MouseManager'); var Pointer = require('./Pointer'); var Rectangle = require('../geom/rectangle/Rectangle'); @@ -196,6 +197,15 @@ var InputManager = new Class({ */ this.defaultCursor = ''; + /** + * A reference to the Keyboard Manager class, if enabled via the `input.keyboard` Game Config property. + * + * @name Phaser.Input.InputManager#keyboard + * @type {?Phaser.Input.Keyboard.KeyboardManager} + * @since 3.16.0 + */ + this.keyboard = (config.inputKeyboard) ? new Keyboard(this) : null; + /** * A reference to the Mouse Manager class, if enabled via the `input.mouse` Game Config property. * @@ -1507,6 +1517,11 @@ var InputManager = new Class({ { this.events.removeAllListeners(); + if (this.keyboard) + { + this.keyboard.destroy(); + } + if (this.mouse) { this.mouse.destroy(); diff --git a/src/input/keyboard/KeyboardManager.js b/src/input/keyboard/KeyboardManager.js new file mode 100644 index 000000000..c7f9a8c04 --- /dev/null +++ b/src/input/keyboard/KeyboardManager.js @@ -0,0 +1,227 @@ +/** + * @author Richard Davey + * @copyright 2018 Photon Storm Ltd. + * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} + */ + +var Class = require('../../utils/Class'); +var Features = require('../../device/Features'); +var NOOP = require('../../utils/Class'); + +/** + * @classdesc + * The Keyboard Manager is a helper class that belongs to the Input Manager. + * + * Its role is to listen for native DOM Keyboard Events and then pass them onto the Input Manager for further processing. + * + * You do not need to create this class directly, the Input Manager will create an instance of it automatically. + * + * @class KeyboardManager + * @memberof Phaser.Input.Keyboard + * @constructor + * @since 3.16.0 + * + * @param {Phaser.Input.InputManager} inputManager - A reference to the Input Manager. + */ +var KeyboardManager = new Class({ + + initialize: + + function KeyboardManager (inputManager) + { + /** + * A reference to the Input Manager. + * + * @name Phaser.Input.Keyboard.KeyboardManager#manager + * @type {Phaser.Input.InputManager} + * @since 3.16.0 + */ + this.manager = inputManager; + + /** + * If true the DOM keyboard events will have event.preventDefault applied to them, if false they will propagate fully. + * + * @name Phaser.Input.Keyboard.KeyboardManager#capture + * @type {boolean} + * @default true + * @since 3.16.0 + */ + this.capture = true; + + /** + * A boolean that controls if the Keyboard Manager is enabled or not. + * Can be toggled on the fly. + * + * @name Phaser.Input.Keyboard.KeyboardManager#enabled + * @type {boolean} + * @default false + * @since 3.16.0 + */ + this.enabled = false; + + /** + * The Keyboard Event target, as defined in the Game Config. + * Typically the canvas to which the game is rendering, but can be any interactive DOM element. + * + * @name Phaser.Input.Keyboard.KeyboardManager#target + * @type {any} + * @since 3.16.0 + */ + this.target; + + /** + * The Key Down Event handler. + * This function is sent the native DOM KeyEvent. + * Initially empty and bound in the `startListeners` method. + * + * @name Phaser.Input.Keyboard.KeyboardManager#onKeyDown + * @type {function} + * @since 3.16.00 + */ + this.onKeyDown = NOOP; + + /** + * The Key Up Event handler. + * This function is sent the native DOM KeyEvent. + * Initially empty and bound in the `startListeners` method. + * + * @name Phaser.Input.Keyboard.KeyboardManager#onKeyUp + * @type {function} + * @since 3.16.00 + */ + this.onKeyUp = NOOP; + + inputManager.events.once('boot', this.boot, this); + }, + + /** + * The Keyboard Manager boot process. + * + * @method Phaser.Input.Keyboard.KeyboardManager#boot + * @private + * @since 3.16.0 + */ + boot: function () + { + var config = this.manager.config; + + // this.enabled = config.inputMouse; + // this.target = config.inputMouseEventTarget; + // this.capture = config.inputMouseCapture; + + if (!this.target) + { + this.target = this.manager.game.canvas; + } + + if (this.enabled && this.target) + { + this.startListeners(); + } + }, + + /** + * Starts the Mouse Event listeners running. + * This is called automatically and does not need to be manually invoked. + * + * @method Phaser.Input.Keyboard.KeyboardManager#startListeners + * @since 3.16.0 + */ + startListeners: function () + { + var _this = this; + var canvas = this.manager.canvas; + + this.onMouseDown = function (event) + { + if (event.defaultPrevented || !_this.enabled || !_this.manager) + { + // Do nothing if event already handled + return; + } + + _this.manager.queueMouseDown(event); + + if (_this.capture && event.target === canvas) + { + event.preventDefault(); + } + }; + + this.onMouseUp = function (event) + { + if (event.defaultPrevented || !_this.enabled || !_this.manager) + { + // Do nothing if event already handled + return; + } + + _this.manager.queueMouseUp(event); + + if (_this.capture && event.target === canvas) + { + event.preventDefault(); + } + }; + + var target = this.target; + + if (!target) + { + return; + } + + var passive = { passive: true }; + var nonPassive = { passive: false }; + + target.addEventListener('mousedown', this.onMouseDown, (this.capture) ? nonPassive : passive); + target.addEventListener('mouseup', this.onMouseUp, (this.capture) ? nonPassive : passive); + + if (window) + { + window.addEventListener('mousedown', this.onMouseDown, nonPassive); + window.addEventListener('mouseup', this.onMouseUp, nonPassive); + } + + this.enabled = true; + }, + + /** + * Stops the Mouse Event listeners. + * This is called automatically and does not need to be manually invoked. + * + * @method Phaser.Input.Keyboard.KeyboardManager#stopListeners + * @since 3.16.0 + */ + stopListeners: function () + { + var target = this.target; + + target.removeEventListener('mousedown', this.onMouseDown); + target.removeEventListener('mouseup', this.onMouseUp); + + if (window) + { + window.removeEventListener('mousedown', this.onMouseDown); + window.removeEventListener('mouseup', this.onMouseUp); + } + }, + + /** + * Destroys this Mouse Manager instance. + * + * @method Phaser.Input.Keyboard.KeyboardManager#destroy + * @since 3.16.0 + */ + destroy: function () + { + this.stopListeners(); + + this.target = null; + this.enabled = false; + this.manager = null; + } + +}); + +module.exports = KeyboardManager; diff --git a/src/input/keyboard/KeyboardPlugin.js b/src/input/keyboard/KeyboardPlugin.js index 59f136f91..2be6b40d7 100644 --- a/src/input/keyboard/KeyboardPlugin.js +++ b/src/input/keyboard/KeyboardPlugin.js @@ -577,7 +577,7 @@ var KeyboardPlugin = new Class({ }, /** - * Internal update handler called by the Input Manager, which is in turn invoked by the Game step. + * Internal update handler called by the Input Plugin, which is in turn invoked by the Game step. * * @method Phaser.Input.Keyboard.KeyboardPlugin#update * @private diff --git a/src/input/keyboard/index.js b/src/input/keyboard/index.js index e41a27b20..2aad578fd 100644 --- a/src/input/keyboard/index.js +++ b/src/input/keyboard/index.js @@ -10,6 +10,7 @@ module.exports = { + KeyboardManager: require('./KeyboardManager'), KeyboardPlugin: require('./KeyboardPlugin'), Key: require('./keys/Key'), From dd051ddc0398b3b57480f9fed29955d7f6525b2f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 5 Dec 2018 15:58:44 +0000 Subject: [PATCH 124/221] Added event handlers and event emitter. --- src/input/keyboard/keys/Key.js | 136 ++++++++++++++++++++++++++++++--- 1 file changed, 125 insertions(+), 11 deletions(-) diff --git a/src/input/keyboard/keys/Key.js b/src/input/keyboard/keys/Key.js index 0ca137a43..da337a0fe 100644 --- a/src/input/keyboard/keys/Key.js +++ b/src/input/keyboard/keys/Key.js @@ -5,6 +5,7 @@ */ var Class = require('../../../utils/Class'); +var EventEmitter = require('eventemitter3'); /** * @classdesc @@ -12,6 +13,7 @@ var Class = require('../../../utils/Class'); * keycode must be an integer * * @class Key + * @extends Phaser.Events.EventEmitter * @memberof Phaser.Input.Keyboard * @constructor * @since 3.0.0 @@ -20,10 +22,14 @@ var Class = require('../../../utils/Class'); */ var Key = new Class({ + Extends: EventEmitter, + initialize: function Key (keyCode) { + EventEmitter.call(this); + /** * The keycode of this key. * @@ -42,16 +48,6 @@ var Key = new Class({ */ this.originalEvent = undefined; - /** - * Should this Key prevent event propagation? - * - * @name Phaser.Input.Keyboard.Key#preventDefault - * @type {boolean} - * @default true - * @since 3.0.0 - */ - this.preventDefault = true; - /** * Can this Key be processed? * @@ -163,6 +159,19 @@ var Key = new Class({ */ this.timeUp = 0; + /** + * When a key is held down should it continuously fire the `down` event each time it repeats? + * + * By default it will emit the `down` event just once, but if you wish to receive the event + * for each repeat as well, enable this property. + * + * @name Phaser.Input.Keyboard.Key#emitOnRepeat + * @type {boolean} + * @default false + * @since 3.16.0 + */ + this.emitOnRepeat = false; + /** * If a key is held down this holds down the number of times the key has 'repeated'. * @@ -206,10 +215,102 @@ var Key = new Class({ this._tick = -1; }, + /** + * Controls if this Key will continuously emit a `down` event while being held down (true), + * or emit the event just once, on first press, and then skip future events (false). + * + * @method Phaser.Input.Keyboard.Key#setEmitOnRepeat + * @since 3.16.0 + * + * @param {boolean} value - Emit `down` events on repeated key down actions, or just once? + * + * @return {Phaser.Input.Keyboard.Key} This Key instance. + */ + setEmitOnRepeat: function (value) + { + this.emitOnRepeat = value; + + return this; + }, + + /** + * Processes the Key Down action for this Key. + * Called automatically by the Keyboard Plugin. + * + * @method Phaser.Input.Keyboard.Key#onDown + * @since 3.16.0 + * + * @param {KeyboardEvent} event - The native DOM Keyboard event. + */ + onDown: function (event) + { + this.originalEvent = event; + + if (!this.enabled) + { + return; + } + + this.altKey = event.altKey; + this.ctrlKey = event.ctrlKey; + this.shiftKey = event.shiftKey; + this.metaKey = event.metaKey; + this.location = event.location; + + this.repeats++; + + if (!this.isDown) + { + this.isDown = true; + this.isUp = false; + this.timeDown = event.timeStamp; + this.duration = 0; + this._justDown = true; + this._justUp = false; + + this.emit('down', this, event); + } + else if (this.emitOnRepeat) + { + this.emit('down', this, event); + } + }, + + /** + * Processes the Key Up action for this Key. + * Called automatically by the Keyboard Plugin. + * + * @method Phaser.Input.Keyboard.Key#onUp + * @since 3.16.0 + * + * @param {KeyboardEvent} event - The native DOM Keyboard event. + */ + onUp: function (event) + { + this.originalEvent = event; + + if (!this.enabled) + { + return; + } + + this.isDown = false; + this.isUp = true; + this.timeUp = event.timeStamp; + this.duration = this.timeUp - this.timeDown; + this.repeats = 0; + + this._justDown = false; + this._justUp = true; + this._tick = -1; + + this.emit('up', this, event); + }, + /** * Resets this Key object back to its default un-pressed state. * - * @method Phaser.Input.Keyboard.Key.reset + * @method Phaser.Input.Keyboard.Key#reset * @since 3.6.0 * * @return {Phaser.Input.Keyboard.Key} This Key instance. @@ -233,6 +334,19 @@ var Key = new Class({ this._tick = -1; return this; + }, + + /** + * Removes any bound event handlers and removes local references. + * + * @method Phaser.Input.Keyboard.Key#destroy + * @since 3.16.0 + */ + destroy: function () + { + this.removeAllListeners(); + + this.originalEvent = null; } }); From 7431f0a621178b105ebbd0e9707335d94cf83f2b Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 5 Dec 2018 15:58:53 +0000 Subject: [PATCH 125/221] No longer required. --- src/input/keyboard/keys/ProcessKeyDown.js | 49 ----------------------- src/input/keyboard/keys/ProcessKeyUp.js | 41 ------------------- 2 files changed, 90 deletions(-) delete mode 100644 src/input/keyboard/keys/ProcessKeyDown.js delete mode 100644 src/input/keyboard/keys/ProcessKeyUp.js diff --git a/src/input/keyboard/keys/ProcessKeyDown.js b/src/input/keyboard/keys/ProcessKeyDown.js deleted file mode 100644 index 5a98f9661..000000000 --- a/src/input/keyboard/keys/ProcessKeyDown.js +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @author Richard Davey - * @copyright 2018 Photon Storm Ltd. - * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} - */ - -/** - * Used internally by the Keyboard Plugin. - * - * @function Phaser.Input.Keyboard.ProcessKeyDown - * @private - * @since 3.0.0 - * - * @param {Phaser.Input.Keyboard.Key} key - The Key to process the event for. - * @param {KeyboardEvent} event - The native Keyboard event. - * - * @return {Phaser.Input.Keyboard.Key} The Key that was processed. - */ -var ProcessKeyDown = function (key, event) -{ - key.originalEvent = event; - - if (!key.enabled) - { - return; - } - - key.altKey = event.altKey; - key.ctrlKey = event.ctrlKey; - key.shiftKey = event.shiftKey; - key.metaKey = event.metaKey; - key.location = event.location; - - if (key.isDown === false) - { - key.isDown = true; - key.isUp = false; - key.timeDown = event.timeStamp; - key.duration = 0; - key._justDown = true; - key._justUp = false; - } - - key.repeats++; - - return key; -}; - -module.exports = ProcessKeyDown; diff --git a/src/input/keyboard/keys/ProcessKeyUp.js b/src/input/keyboard/keys/ProcessKeyUp.js deleted file mode 100644 index af834261e..000000000 --- a/src/input/keyboard/keys/ProcessKeyUp.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @author Richard Davey - * @copyright 2018 Photon Storm Ltd. - * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} - */ - -/** - * Used internally by the Keyboard Plugin. - * - * @function Phaser.Input.Keyboard.ProcessKeyUp - * @private - * @since 3.0.0 - * - * @param {Phaser.Input.Keyboard.Key} key - The Key to process the event for. - * @param {KeyboardEvent} event - The native Keyboard event. - * - * @return {Phaser.Input.Keyboard.Key} The Key that was processed. - */ -var ProcessKeyUp = function (key, event) -{ - key.originalEvent = event; - - if (!key.enabled) - { - return; - } - - key.isDown = false; - key.isUp = true; - key.timeUp = event.timeStamp; - key.duration = key.timeUp - key.timeDown; - key.repeats = 0; - - key._justDown = false; - key._justUp = true; - key._tick = -1; - - return key; -}; - -module.exports = ProcessKeyUp; From 97805afab0533a7c75a9324cf5b7bd711ab3b23f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 5 Dec 2018 16:01:39 +0000 Subject: [PATCH 126/221] Input Manager now creates Keyboard Manager. --- src/input/InputManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/InputManager.js b/src/input/InputManager.js index c13f38a12..8f5aa8b54 100644 --- a/src/input/InputManager.js +++ b/src/input/InputManager.js @@ -7,7 +7,7 @@ var Class = require('../utils/Class'); var CONST = require('./const'); var EventEmitter = require('eventemitter3'); -var Keyboard = require('./mouse/KeyboardManager'); +var Keyboard = require('./keyboard/KeyboardManager'); var Mouse = require('./mouse/MouseManager'); var Pointer = require('./Pointer'); var Rectangle = require('../geom/rectangle/Rectangle'); From a7fba605ada56c6f069059aeba7fd5dfae2e38ad Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 5 Dec 2018 16:02:09 +0000 Subject: [PATCH 127/221] By default, no key captures. --- src/boot/Config.js | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/boot/Config.js b/src/boot/Config.js index 3f92d8d07..9d28741f3 100644 --- a/src/boot/Config.js +++ b/src/boot/Config.js @@ -11,7 +11,6 @@ var GetFastValue = require('../utils/object/GetFastValue'); var GetValue = require('../utils/object/GetValue'); var IsPlainObject = require('../utils/object/IsPlainObject'); var MATH = require('../math/const'); -var NumberArray = require('../utils/array/NumberArray'); var RND = require('../math/random-data-generator/RandomDataGenerator'); var NOOP = require('../utils/NOOP'); var DefaultPlugins = require('../plugins/DefaultPlugins'); @@ -65,7 +64,7 @@ var ValueToColor = require('../display/color/ValueToColor'); * @typedef {object} KeyboardInputConfig * * @property {*} [target=window] - Where the Keyboard Manager listens for keyboard input events. - * @property {(boolean|integer[])} [capture] - `preventDefault` will be called on every non-modified key which has a key code in this array. By default, it's set to all the space key, cursors and all alphanumeric keys. Or, set to 'false' to disable. + * @property {?integer} [capture] - `preventDefault` will be called on every non-modified key which has a key code in this array. By default it is empty. */ /** @@ -422,21 +421,9 @@ var Config = new Class({ this.inputKeyboardEventTarget = GetValue(config, 'input.keyboard.target', window); /** - * @const {(boolean|integer[])} Phaser.Boot.Config#inputKeyboardCapture - `preventDefault` will be called on every non-modified key which has a key code in this array. By default, it's set to all alphanumeric keys. Or, set to 'false' to disable. + * @const {?integer[]} Phaser.Boot.Config#inputKeyboardCapture - `preventDefault` will be called on every non-modified key which has a key code in this array. By default, it is empty. */ - var defaultCaptures = [ 32, 38, 39, 40, 42 ]; - - defaultCaptures = defaultCaptures.concat(NumberArray(48, 57)); - defaultCaptures = defaultCaptures.concat(NumberArray(65, 90)); - - var keyboardCapture = GetValue(config, 'input.keyboard.capture', defaultCaptures); - - if (!Array.isArray(keyboardCapture)) - { - keyboardCapture = []; - } - - this.inputKeyboardCapture = keyboardCapture; + this.inputKeyboardCapture = GetValue(config, 'input.keyboard.capture', []); /** * @const {(boolean|object)} Phaser.Boot.Config#inputMouse - Enable the Mouse Plugin. This can be disabled in games that don't need mouse input. From 114d61cf59cded07602f3f04d7a09909664d6efb Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 5 Dec 2018 16:02:29 +0000 Subject: [PATCH 128/221] Added capture handling and event queue. --- src/input/keyboard/KeyboardManager.js | 303 +++++++++++++++++++++----- 1 file changed, 254 insertions(+), 49 deletions(-) diff --git a/src/input/keyboard/KeyboardManager.js b/src/input/keyboard/KeyboardManager.js index c7f9a8c04..9e658ee67 100644 --- a/src/input/keyboard/KeyboardManager.js +++ b/src/input/keyboard/KeyboardManager.js @@ -4,17 +4,19 @@ * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ +var ArrayRemove = require('../../utils/array/Remove'); var Class = require('../../utils/Class'); -var Features = require('../../device/Features'); +var KeyCodes = require('../../input/keyboard/keys/KeyCodes'); var NOOP = require('../../utils/Class'); /** * @classdesc - * The Keyboard Manager is a helper class that belongs to the Input Manager. + * The Keyboard Manager is a helper class that belongs to the global Input Manager. * - * Its role is to listen for native DOM Keyboard Events and then pass them onto the Input Manager for further processing. + * Its role is to listen for native DOM Keyboard Events and then store them for further processing by the Keyboard Plugin. * - * You do not need to create this class directly, the Input Manager will create an instance of it automatically. + * You do not need to create this class directly, the Input Manager will create an instance of it automatically if keyboard + * input has been enabled in the Game Config. * * @class KeyboardManager * @memberof Phaser.Input.Keyboard @@ -39,14 +41,59 @@ var KeyboardManager = new Class({ this.manager = inputManager; /** - * If true the DOM keyboard events will have event.preventDefault applied to them, if false they will propagate fully. + * An internal event queue. * - * @name Phaser.Input.Keyboard.KeyboardManager#capture - * @type {boolean} - * @default true + * @name Phaser.Input.Keyboard.KeyboardManager#queue + * @type {KeyboardEvent[]} + * @private * @since 3.16.0 */ - this.capture = true; + this.queue = []; + + /** + * A flag that controls if the non-modified keys, matching those stored in the `captures` array, + * have `preventDefault` called on them or not. + * + * A non-modified key is one that doesn't have a modifier key held down with it. The modifier keys are + * shift, control, alt and the meta key (Command on a Mac, the Windows Key on Windows). + * Therefore, if the user presses shift + r, it won't prevent this combination, because of the modifier. + * However, if the user presses just the r key on its own, it will have its event prevented. + * + * If you wish to stop capturing the keys, for example switching out to a DOM based element, then + * you can toggle this property at run-time. + * + * @name Phaser.Input.Keyboard.KeyboardManager#preventDefault + * @type {boolean} + * @since 3.16.0 + */ + this.preventDefault = true; + + /** + * An array of Key Code values that will automatically have `preventDefault` called on them, + * as long as the `KeyboardManager.preventDefault` boolean is set to `true`. + * + * By default the array contains: The Space Key, the Cursor Keys, 0 to 9 and A to Z. + * + * The key must be non-modified when pressed in order to be captured. + * + * A non-modified key is one that doesn't have a modifier key held down with it. The modifier keys are + * shift, control, alt and the meta key (Command on a Mac, the Windows Key on Windows). + * Therefore, if the user presses shift + r, it won't prevent this combination, because of the modifier. + * However, if the user presses just the r key on its own, it will have its event prevented. + * + * If you wish to stop capturing the keys, for example switching out to a DOM based element, then + * you can toggle the `KeyboardManager.preventDefault` boolean at run-time. + * + * If you need more specific control, you can create Key objects and set the flag on each of those instead. + * + * This array can be populated via the Game Config by setting the `input.keyboard.capture` array, or you + * can call the `addCapture` method. See also `removeCapture` and `clearCaptures`. + * + * @name Phaser.Input.Keyboard.KeyboardManager#captures + * @type {integer[]} + * @since 3.16.0 + */ + this.captures = []; /** * A boolean that controls if the Keyboard Manager is enabled or not. @@ -61,7 +108,7 @@ var KeyboardManager = new Class({ /** * The Keyboard Event target, as defined in the Game Config. - * Typically the canvas to which the game is rendering, but can be any interactive DOM element. + * Typically the window in which the game is rendering, but can be any interactive DOM element. * * @name Phaser.Input.Keyboard.KeyboardManager#target * @type {any} @@ -105,23 +152,26 @@ var KeyboardManager = new Class({ { var config = this.manager.config; - // this.enabled = config.inputMouse; - // this.target = config.inputMouseEventTarget; - // this.capture = config.inputMouseCapture; + this.enabled = config.inputKeyboard; + this.target = config.inputKeyboardEventTarget; - if (!this.target) + this.addCapture(config.inputKeyboardCapture); + + if (!this.target && window) { - this.target = this.manager.game.canvas; + this.target = window; } if (this.enabled && this.target) { this.startListeners(); } + + this.manager.game.events.on('poststep', this.postUpdate, this); }, /** - * Starts the Mouse Event listeners running. + * Starts the Keyboard Event listeners running. * This is called automatically and does not need to be manually invoked. * * @method Phaser.Input.Keyboard.KeyboardManager#startListeners @@ -130,25 +180,26 @@ var KeyboardManager = new Class({ startListeners: function () { var _this = this; - var canvas = this.manager.canvas; - this.onMouseDown = function (event) + this.onKeyDown = function (event) { if (event.defaultPrevented || !_this.enabled || !_this.manager) { // Do nothing if event already handled return; } + + _this.queue.push(event); - _this.manager.queueMouseDown(event); - - if (_this.capture && event.target === canvas) + var modified = (event.altKey || event.ctrlKey || event.shiftKey || event.metaKey); + + if (_this.preventDefault && !modified && _this.captures.indexOf(event.keyCode) > -1) { event.preventDefault(); } }; - this.onMouseUp = function (event) + this.onKeyUp = function (event) { if (event.defaultPrevented || !_this.enabled || !_this.manager) { @@ -156,9 +207,11 @@ var KeyboardManager = new Class({ return; } - _this.manager.queueMouseUp(event); + _this.queue.push(event); - if (_this.capture && event.target === canvas) + var modified = (event.altKey || event.ctrlKey || event.shiftKey || event.metaKey); + + if (_this.preventDefault && !modified && _this.captures.indexOf(event.keyCode) > -1) { event.preventDefault(); } @@ -166,28 +219,17 @@ var KeyboardManager = new Class({ var target = this.target; - if (!target) + if (target) { - return; + target.addEventListener('keydown', this.onKeyDown, false); + target.addEventListener('keyup', this.onKeyUp, false); + + this.enabled = true; } - - var passive = { passive: true }; - var nonPassive = { passive: false }; - - target.addEventListener('mousedown', this.onMouseDown, (this.capture) ? nonPassive : passive); - target.addEventListener('mouseup', this.onMouseUp, (this.capture) ? nonPassive : passive); - - if (window) - { - window.addEventListener('mousedown', this.onMouseDown, nonPassive); - window.addEventListener('mouseup', this.onMouseUp, nonPassive); - } - - this.enabled = true; }, /** - * Stops the Mouse Event listeners. + * Stops the Key Event listeners. * This is called automatically and does not need to be manually invoked. * * @method Phaser.Input.Keyboard.KeyboardManager#stopListeners @@ -197,18 +239,175 @@ var KeyboardManager = new Class({ { var target = this.target; - target.removeEventListener('mousedown', this.onMouseDown); - target.removeEventListener('mouseup', this.onMouseUp); + target.removeEventListener('keydown', this.onKeyDown, false); + target.removeEventListener('keyup', this.onKeyUp, false); - if (window) - { - window.removeEventListener('mousedown', this.onMouseDown); - window.removeEventListener('mouseup', this.onMouseUp); - } + this.enabled = false; }, /** - * Destroys this Mouse Manager instance. + * Clears the event queue. + * Called automatically by the Input Manager. + * + * @method Phaser.Input.Keyboard.KeyboardManager#postUpdate + * @private + * @since 3.16.0 + */ + postUpdate: function () + { + this.queue = []; + }, + + /** + * By default when a key is pressed Phaser will not stop the event from propagating up to the browser. + * There are some keys this can be annoying for, like the arrow keys or space bar, which make the browser window scroll. + * + * This `addCapture` method enables consuming keyboard event for specific keys so it doesn't bubble up to the the browser + * and cause the default browser behavior. + * + * Please note that keyboard captures are global. This means that if you call this method from within a Scene, to say prevent + * the SPACE BAR from triggering a page scroll, then it will prevent it for any Scene in your game, not just the calling one. + * + * You can pass in a single key code value, or an array of key codes, or a string: + * + * ```javascript + * this.input.keyboard.addCapture(62); + * ``` + * + * An array of key codes: + * + * ```javascript + * this.input.keyboard.addCapture([ 62, 63, 64 ]); + * ``` + * + * Or a string: + * + * ```javascript + * this.input.keyboard.addCapture('W,S,A,D'); + * ``` + * + * To use non-alpha numeric keys, use a string, such as 'UP', 'SPACE' or 'LEFT'. + * + * You can also provide an array mixing both strings and key code integers. + * + * If there are active captures after calling this method, the `preventDefault` property is set to `true`. + * + * @method Phaser.Input.Keyboard.KeyboardManager#addCapture + * @since 3.16.0 + * + * @param {(string|integer|integer[]|any[])} keycode - The Key Codes to enable capture for, preventing them reaching the browser. + */ + addCapture: function (keycode) + { + if (typeof keycode === 'string') + { + keycode = keycode.split(','); + } + + if (!Array.isArray(keycode)) + { + keycode = [ keycode ]; + } + + var captures = this.captures; + + for (var i = 0; i < keycode.length; i++) + { + var code = keycode[i]; + + if (typeof code === 'string') + { + code = KeyCodes[code.toUpperCase()]; + } + + if (captures.indexOf(code) === -1) + { + captures.push(code); + } + } + + this.preventDefault = captures.length > 0; + }, + + /** + * Removes an existing key capture. + * + * Please note that keyboard captures are global. This means that if you call this method from within a Scene, to remove + * the capture of a key, then it will remove it for any Scene in your game, not just the calling one. + * + * You can pass in a single key code value, or an array of key codes, or a string: + * + * ```javascript + * this.input.keyboard.removeCapture(62); + * ``` + * + * An array of key codes: + * + * ```javascript + * this.input.keyboard.removeCapture([ 62, 63, 64 ]); + * ``` + * + * Or a string: + * + * ```javascript + * this.input.keyboard.removeCapture('W,S,A,D'); + * ``` + * + * To use non-alpha numeric keys, use a string, such as 'UP', 'SPACE' or 'LEFT'. + * + * You can also provide an array mixing both strings and key code integers. + * + * If there are no captures left after calling this method, the `preventDefault` property is set to `false`. + * + * @method Phaser.Input.Keyboard.KeyboardManager#removeCapture + * @since 3.16.0 + * + * @param {(string|integer|integer[]|any[])} keycode - The Key Codes to disable capture for, allowing them reaching the browser again. + */ + removeCapture: function (keycode) + { + if (typeof keycode === 'string') + { + keycode = keycode.split(','); + } + + if (!Array.isArray(keycode)) + { + keycode = [ keycode ]; + } + + var captures = this.captures; + + for (var i = 0; i < keycode.length; i++) + { + var code = keycode[i]; + + if (typeof code === 'string') + { + code = KeyCodes[code.toUpperCase()]; + } + + ArrayRemove(captures, code); + } + + this.preventDefault = captures.length > 0; + }, + + /** + * Removes all keyboard captures and sets the `preventDefault` property to `false`. + * + * @method Phaser.Input.Keyboard.KeyboardManager#clearCaptures + * @since 3.16.0 + */ + clearCaptures: function () + { + this.captures = []; + + this.preventDefault = false; + }, + + /** + * Destroys this Keyboard Manager instance. * * @method Phaser.Input.Keyboard.KeyboardManager#destroy * @since 3.16.0 @@ -217,6 +416,12 @@ var KeyboardManager = new Class({ { this.stopListeners(); + this.clearCaptures(); + + this.queue = []; + + this.manager.game.events.off('poststep', this.postUpdate, this); + this.target = null; this.enabled = false; this.manager = null; From 715e6d3c15d2bba80087aa63ddc4da965b5a905e Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 5 Dec 2018 16:07:47 +0000 Subject: [PATCH 129/221] Added key capturing methods. --- src/input/keyboard/KeyboardPlugin.js | 387 +++++++++++++++++---------- 1 file changed, 244 insertions(+), 143 deletions(-) diff --git a/src/input/keyboard/KeyboardPlugin.js b/src/input/keyboard/KeyboardPlugin.js index 2be6b40d7..409d1d9f2 100644 --- a/src/input/keyboard/KeyboardPlugin.js +++ b/src/input/keyboard/KeyboardPlugin.js @@ -12,8 +12,6 @@ var Key = require('./keys/Key'); var KeyCodes = require('./keys/KeyCodes'); var KeyCombo = require('./combo/KeyCombo'); var KeyMap = require('./keys/KeyMap'); -var ProcessKeyDown = require('./keys/ProcessKeyDown'); -var ProcessKeyUp = require('./keys/ProcessKeyUp'); var SnapFloor = require('../../math/snap/SnapFloor'); /** @@ -99,7 +97,16 @@ var KeyboardPlugin = new Class({ this.sceneInputPlugin = sceneInputPlugin; /** - * A boolean that controls if the Keyboard Plugin is enabled or not. + * A reference to the global Keyboard Manager. + * + * @name Phaser.Input.Keyboard.KeyboardPlugin#manager + * @type {Phaser.Input.InputPlugin} + * @since 3.16.0 + */ + this.manager = sceneInputPlugin.manager.keyboard; + + /** + * A boolean that controls if this Keyboard Plugin is enabled or not. * Can be toggled on the fly. * * @name Phaser.Input.Keyboard.KeyboardPlugin#enabled @@ -109,16 +116,6 @@ var KeyboardPlugin = new Class({ */ this.enabled = true; - /** - * The Keyboard Event target, as defined in the Scene or Game Config. - * Typically the browser window, but can be any interactive DOM element. - * - * @name Phaser.Input.Keyboard.KeyboardPlugin#target - * @type {any} - * @since 3.10.0 - */ - this.target; - /** * An array of Key objects to process. * @@ -137,26 +134,6 @@ var KeyboardPlugin = new Class({ */ this.combos = []; - /** - * An internal event queue. - * - * @name Phaser.Input.Keyboard.KeyboardPlugin#queue - * @type {KeyboardEvent[]} - * @private - * @since 3.10.0 - */ - this.queue = []; - - /** - * Internal event handler. - * - * @name Phaser.Input.Keyboard.KeyboardPlugin#onKeyHandler - * @type {function} - * @private - * @since 3.10.0 - */ - this.onKeyHandler; - /** * Internal time value. * @@ -167,54 +144,6 @@ var KeyboardPlugin = new Class({ */ this.time = 0; - /** - * A flag that controls if the non-modified keys, matching those stored in the `captures` array, - * have `preventDefault` called on them or not. By default this is `true`. - * - * A non-modified key is one that doesn't have a modifier key held down with it. The modifier keys are - * shift, control, alt and the meta key (Command on a Mac, the Windows Key on Windows). - * Therefore, if the user presses shift + r, it won't prevent this combination, because of the modifier. - * However, if the user presses just the r key on its own, it will have its event prevented. - * - * You can set this flag to stop any capture key from triggering the default browser action, or if you need - * more specific control, you can create Key objects and set the flag on each of those instead. - * - * This flag can be set in the Game Config by setting the `input.keyboard.capture` to a `false` boolean, or you - * can set it in the Scene Config, in which case the Scene Config setting overrides the Game Config one. - * - * @name Phaser.Input.Keyboard.KeyboardPlugin#preventDefault - * @type {boolean} - * @since 3.16.0 - */ - this.preventDefault = true; - - /** - * An array of Key Code values that will automatically have `preventDefault` called on them, - * as long as the `KeyboardPlugin.preventDefault` boolean is set to `true`. - * - * By default the array contains: The Space Key, the Cursor Keys, 0 to 9 and A to Z. - * - * The key must be non-modified when pressed in order to be captured. - * - * A non-modified key is one that doesn't have a modifier key held down with it. The modifier keys are - * shift, control, alt and the meta key (Command on a Mac, the Windows Key on Windows). - * Therefore, if the user presses shift + r, it won't prevent this combination, because of the modifier. - * However, if the user presses just the r key on its own, it will have its event prevented. - * - * If you wish to stop capturing the keys, for example switching out to a DOM based element, then - * you can toggle the `KeyboardPlugin.preventDefault` boolean at run-time. - * - * If you need more specific control, you can create Key objects and set the flag on each of those instead. - * - * This array can be populated via the Game Config by setting the `input.keyboard.capture` array, or you - * can set it in the Scene Config, in which case the Scene Config array overrides the Game Config one. - * - * @name Phaser.Input.Keyboard.KeyboardPlugin#captures - * @type {integer[]} - * @since 3.16.0 - */ - this.captures = []; - sceneInputPlugin.pluginEvents.once('boot', this.boot, this); sceneInputPlugin.pluginEvents.on('start', this.start, this); }, @@ -230,12 +159,15 @@ var KeyboardPlugin = new Class({ boot: function () { var settings = this.settings.input; - var config = this.scene.sys.game.config; - this.enabled = GetValue(settings, 'keyboard', config.inputKeyboard); - this.target = GetValue(settings, 'keyboard.target', config.inputKeyboardEventTarget); - this.captures = GetValue(settings, 'keyboard.capture', config.inputKeyboardCapture); - this.preventDefault = this.captures.length > 0; + this.enabled = GetValue(settings, 'keyboard', true); + + var captures = GetValue(settings, 'keyboard.capture', null); + + if (captures) + { + this.addCaptures(captures); + } this.sceneInputPlugin.pluginEvents.once('destroy', this.destroy, this); }, @@ -251,10 +183,7 @@ var KeyboardPlugin = new Class({ */ start: function () { - if (this.enabled) - { - this.startListeners(); - } + this.startListeners(); this.sceneInputPlugin.pluginEvents.once('shutdown', this.shutdown, this); }, @@ -282,34 +211,6 @@ var KeyboardPlugin = new Class({ */ startListeners: function () { - var _this = this; - - var handler = function (event) - { - if (event.defaultPrevented || !_this.isActive()) - { - // Do nothing if event already handled - return; - } - - _this.queue.push(event); - - var key = _this.keys[event.keyCode]; - - var modified = (event.altKey || event.ctrlKey || event.shiftKey || event.metaKey); - - if ((_this.preventDefault && !modified && _this.captures.indexOf(event.keyCode) > -1) || (key && key.preventDefault)) - { - event.preventDefault(); - } - }; - - this.onKeyHandler = handler; - - this.target.addEventListener('keydown', handler, false); - this.target.addEventListener('keyup', handler, false); - - // Finally, listen for an update event from the Input Plugin this.sceneInputPlugin.pluginEvents.on('update', this.update, this); }, @@ -323,12 +224,159 @@ var KeyboardPlugin = new Class({ */ stopListeners: function () { - this.target.removeEventListener('keydown', this.onKeyHandler); - this.target.removeEventListener('keyup', this.onKeyHandler); - this.sceneInputPlugin.pluginEvents.off('update', this.update); }, + /** + * By default when a key is pressed Phaser will not stop the event from propagating up to the browser. + * There are some keys this can be annoying for, like the arrow keys or space bar, which make the browser window scroll. + * + * This `addCapture` method enables consuming keyboard events for specific keys, so they don't bubble up the browser + * and cause the default behaviors. + * + * Please note that keyboard captures are global. This means that if you call this method from within a Scene, to say prevent + * the SPACE BAR from triggering a page scroll, then it will prevent it for any Scene in your game, not just the calling one. + * + * You can pass a single key code value: + * + * ```javascript + * this.input.keyboard.addCapture(62); + * ``` + * + * An array of key codes: + * + * ```javascript + * this.input.keyboard.addCapture([ 62, 63, 64 ]); + * ``` + * + * Or, a comma-delimited string: + * + * ```javascript + * this.input.keyboard.addCapture('W,S,A,D'); + * ``` + * + * To use non-alpha numeric keys, use a string, such as 'UP', 'SPACE' or 'LEFT'. + * + * You can also provide an array mixing both strings and key code integers. + * + * @method Phaser.Input.Keyboard.KeyboardPlugin#addCapture + * @since 3.16.0 + * + * @param {(string|integer|integer[]|any[])} keycode - The Key Codes to enable event capture for. + * + * @return {Phaser.Input.Keyboard.KeyboardPlugin} This KeyboardPlugin object. + */ + addCapture: function (keycode) + { + this.manager.addCapture(keycode); + + return this; + }, + + /** + * Removes an existing key capture. + * + * Please note that keyboard captures are global. This means that if you call this method from within a Scene, to remove + * the capture of a key, then it will remove it for any Scene in your game, not just the calling one. + * + * You can pass a single key code value: + * + * ```javascript + * this.input.keyboard.removeCapture(62); + * ``` + * + * An array of key codes: + * + * ```javascript + * this.input.keyboard.removeCapture([ 62, 63, 64 ]); + * ``` + * + * Or, a comma-delimited string: + * + * ```javascript + * this.input.keyboard.removeCapture('W,S,A,D'); + * ``` + * + * To use non-alpha numeric keys, use a string, such as 'UP', 'SPACE' or 'LEFT'. + * + * You can also provide an array mixing both strings and key code integers. + * + * @method Phaser.Input.Keyboard.KeyboardPlugin#removeCapture + * @since 3.16.0 + * + * @param {(string|integer|integer[]|any[])} keycode - The Key Codes to disable event capture for. + * + * @return {Phaser.Input.Keyboard.KeyboardPlugin} This KeyboardPlugin object. + */ + removeCapture: function (keycode) + { + this.manager.removeCapture(keycode); + + return this; + }, + + /** + * Returns an array that contains all of the keyboard captures currently enabled. + * + * @method Phaser.Input.Keyboard.KeyboardPlugin#getCaptures + * @since 3.16.0 + * + * @return {integer[]} An array of all the currently capturing key codes. + */ + getCaptures: function () + { + return this.manager.captures; + }, + + /** + * Allows Phaser to prevent any key captures you may have defined from bubbling up the browser. + * You can use this to re-enable event capturing if you had paused it via `disableGlobalCapture`. + * + * @method Phaser.Input.Keyboard.KeyboardPlugin#enableGlobalCapture + * @since 3.16.0 + * + * @return {Phaser.Input.Keyboard.KeyboardPlugin} This KeyboardPlugin object. + */ + enableGlobalCapture: function () + { + this.manager.preventDefault = true; + + return this; + }, + + /** + * Disables Phaser from preventing any key captures you may have defined, without actually removing them. + * You can use this to temporarily disable event capturing if, for example, you swap to a DOM element. + * + * @method Phaser.Input.Keyboard.KeyboardPlugin#disableGlobalCapture + * @since 3.16.0 + * + * @return {Phaser.Input.Keyboard.KeyboardPlugin} This KeyboardPlugin object. + */ + disableGlobalCapture: function () + { + this.manager.preventDefault = false; + + return this; + }, + + /** + * Removes all keyboard captures. + * + * Note that this is a global change. It will clear all event captures across your game, not just for this specific Scene. + * + * @method Phaser.Input.Keyboard.KeyboardPlugin#clearCaptures + * @since 3.16.0 + * + * @return {Phaser.Input.Keyboard.KeyboardPlugin} This KeyboardPlugin object. + */ + clearCaptures: function () + { + this.manager.clearCaptures(); + + return this; + }, + /** * @typedef {object} CursorKeys * @memberof Phaser.Input.Keyboard @@ -386,11 +434,14 @@ var KeyboardPlugin = new Class({ * @since 3.10.0 * * @param {(object|string)} keys - An object containing Key Codes, or a comma-separated string. + * @param {boolean} [enableCapture=true] - Automatically call `preventDefault` on the native DOM browser event for the key codes being added. * * @return {object} An object containing Key objects mapped to the input properties. */ - addKeys: function (keys) + addKeys: function (keys, enableCapture) { + if (enableCapture === undefined) { enableCapture = true; } + var output = {}; if (typeof keys === 'string') @@ -429,11 +480,14 @@ var KeyboardPlugin = new Class({ * @since 3.10.0 * * @param {(Phaser.Input.Keyboard.Key|string|integer)} key - Either a Key object, a string, such as `A` or `SPACE`, or a key code value. + * @param {boolean} [enableCapture=true] - Automatically call `preventDefault` on the native DOM browser event for the key codes being added. * * @return {Phaser.Input.Keyboard.Key} The newly created Key object, or a reference to it if it already existed in the keys array. */ - addKey: function (key) + addKey: function (key, enableCapture) { + if (enableCapture === undefined) { enableCapture = true; } + var keys = this.keys; if (key instanceof Key) @@ -449,6 +503,11 @@ var KeyboardPlugin = new Class({ keys[key.keyCode] = key; } + if (enableCapture) + { + this.addCapture(key.keyCode); + } + return key; } @@ -460,6 +519,11 @@ var KeyboardPlugin = new Class({ if (!keys[key]) { keys[key] = new Key(key); + + if (enableCapture) + { + this.addCapture(key); + } } return keys[key]; @@ -474,6 +538,8 @@ var KeyboardPlugin = new Class({ * @since 3.10.0 * * @param {(Phaser.Input.Keyboard.Key|string|integer)} key - Either a Key object, a string, such as `A` or `SPACE`, or a key code value. + * + * @return {Phaser.Input.Keyboard.KeyboardPlugin} This KeyboardPlugin object. */ removeKey: function (key) { @@ -497,6 +563,8 @@ var KeyboardPlugin = new Class({ { keys[key] = undefined; } + + return this; }, /** @@ -589,17 +657,14 @@ var KeyboardPlugin = new Class({ { this.time = time; - var len = this.queue.length; + var queue = this.manager.queue; + var len = queue.length; - if (!this.enabled || len === 0) + if (!this.isActive() || len === 0) { return; } - // Clears the queue array, and also means we don't work on array data that could potentially - // be modified during the processing phase - var queue = this.queue.splice(0, len); - var keys = this.keys; // Process the event queue, dispatching all of the events that have stored up @@ -607,32 +672,55 @@ var KeyboardPlugin = new Class({ { var event = queue[i]; var code = event.keyCode; + var key = keys[code]; + var repeat = false; + + // Override the default function (it's too late for the browser to use it anyway, so we may as well) + event.stopPropagation = function () + { + event.cancelled = true; + }; if (event.type === 'keydown') { - if (KeyMap[code] && (keys[code] === undefined || keys[code].isDown === false)) + // Key specific callback first + if (key) { - // Will emit a keyboard or keyup event - this.emit(event.type, event); + repeat = key.isDown; - this.emit('keydown_' + KeyMap[code], event); + key.onDown(event); } - if (keys[code]) + if (!event.cancelled && KeyMap[code] && (!key || !repeat)) { - ProcessKeyDown(keys[code], event); + // keydown_code event + this.emit('keydown_' + KeyMap[code], event); + + if (!event.cancelled) + { + // keydown event + this.emit(event.type, event); + } } } else { - // Will emit a keyboard or keyup event - this.emit(event.type, event); - - this.emit('keyup_' + KeyMap[code], event); - - if (keys[code]) + // Key specific callback first + if (key) { - ProcessKeyUp(keys[code], event); + key.onUp(event); + } + + if (!event.cancelled && KeyMap[code]) + { + // keyup_code event + this.emit('keyup_' + KeyMap[code], event); + + if (!event.cancelled) + { + // keyup event + this.emit(event.type, event); + } } } } @@ -648,6 +736,8 @@ var KeyboardPlugin = new Class({ * * @method Phaser.Input.Keyboard.KeyboardPlugin#resetKeys * @since 3.15.0 + * + * @return {Phaser.Input.Keyboard.KeyboardPlugin} This KeyboardPlugin object. */ resetKeys: function () { @@ -698,6 +788,17 @@ var KeyboardPlugin = new Class({ { this.shutdown(); + var keys = this.keys; + + for (var i = 0; i < keys.length; i++) + { + // Because it's a sparsely populated array + if (keys[i]) + { + keys[i].destroy(); + } + } + this.keys = []; this.combos = []; this.queue = []; @@ -705,7 +806,7 @@ var KeyboardPlugin = new Class({ this.scene = null; this.settings = null; this.sceneInputPlugin = null; - this.target = null; + this.manager = null; } }); From 4174626b844550ae8bd8c30b96b1ac93643d87cd Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 5 Dec 2018 16:07:51 +0000 Subject: [PATCH 130/221] Update CHANGELOG.md --- CHANGELOG.md | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ef06f5a2..9c5503a59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,13 +11,42 @@ * If the `setScore` or `getPlayerScore` calls fail, it will return `null` as the score instance, instead of causing a run-time error. * You can now pass an object or a string to `setScore` and objects will be automatically stringified. -### Input - New Features, Updates and Fixes +### Keyboard Input - New Features, Updates and Fixes + +The specificity of the Keyboard events has been changed to allow you more control over event handling. Previously, the Keyboard Plugin would emit the global `keydown_CODE` event first (where CODE was a keycode string, like `keydown_A`), then it would emit the global `keydown` event. In previous versions, `Key` objects, created via `this.input.keyboard.addKey()`, didn't emit events. + +The `Key` class now extends EventEmitter and emits two new events directly: `down` and `up`. This means you can listen for an event from a Key you've created, i.e.: `yourKey.on('up', handler)`. + +The order has also now changed. If it exists, the Key object will dispatch its `down` event first. Then the Keyboard Plugin will dispatch `keydown_CODE` and finally the less specific of them all, `keydown` will be dispatched. + +You also now have the ability to cancel this at any stage. All events handlers are sent an event object which you can call `event.stopPropagation()` on. This will immediately stop any further listeners from being invoked. Therefore, if you call `stopPropagation()` after `Key.on`, then the Keyboard Plugin will not emit either the `keydown_CODE` or `keydown` global events. You can also call `stopPropagation()` during the `keydown_CODE` handler, to stop it getting to the global `keydown` event. As `keydown` is last, calling it has no effect there. This also works for `keyup` events. + +* There is a new class called `KeyboardManager`. This class is created by the global Input Manager, if keyboard access has been enabled in the Game config. It's responsible for handling all browser keyboard events. Previously, the `KeyboardPlugin` did this. Which meant that every Scene that had its own Keyboard Plugin was binding more native keyboard events. This was causing problems with parallel Scenes when needing to capture keys. the `KeyboardPlugin` class still exists, and is still the main point of interface when you call `this.input.keyboard` in a Scene, but DOM event handling responsibility has been taken away from it. This means there's no only +one set of bindings ever created, which makes things a lot cleaner. +* There is a new Game and Scene Config setting `input.keyboard.capture` which is an array of KeyCodes that the Keyboard Plugin will capture all non-modified key events on. By default it is empty. You can populate it in the config, or use the new capture methods. +* The Keyboard Manager will now call `preventDefault` only on non-modified key presses, stopping the keyboard event from hitting the browser. Previously, capturing the R key, for example, would block a CTRL+R page reload, but it now ignores it because of the key modifier. +* `Key.emitOnRepeat` is a new boolean property that controls if the Key will continuously emit a `down` event while being held down (true), or emit the event just once, on first press, and then skip future events (false). +* `Key.setEmitOnRepeat` is a new chainable method for setting the `emitOnRepeat` property. +* The keyboard event flow has changed. +* The `Key` class now extends EventEmitter and emits two events directly: `down` and `up`. This means you can listen for an event from a Key you've created, i.e.: `yourKey.on('up', handler)`. +* `Key.onDown` is a new method that handles the Key being pressed down, including down repeats. +* `Key.onUp` is a new method that handles the Key being released. +* `Key.destroy` is a new method that handles Key instance destruction. It is called automatically in `KeyboardPlugin.destroy`. +* The `Key.preventDefault` property has been removed. This is now handled by the global keyboard capture methods. +* `Key.metaKey` is a new boolean property which indicates if the Meta Key was held down when the Key was pressed. On a Mac the Meta Key is Command. On a Windows keyboard, it's the Windows key. +* `InputManager.keyboard` is a new property that instantiates the global Keyboard Manager, if enabled in the game config. +* The `KeyboardPlugin.addKey` method has a new boolean property `enableCapture` which automatically prevents default on the Key being created. +* The `KeyboardPlugin.addKeys` method has a new boolean property `enableCapture` which automatically prevents default on Keys being created. +* `Phaser.Input.Keyboard.ProcessKeyDown` has been removed as it's no longer required, `Key.onDown` handles it instead. +* `Phaser.Input.Keyboard.ProcessKeyUp` has been removed as it's no longer required, `Key.onUp` handles it instead. +* The Keyboard Manager has a property called `captures` which is an array of keycodes, as populated by the Game Config. Any key code in the array will have `preventDefault` called on it if pressed. +* `KeyboardPlugin.manager` is a new property that references the Keyboard Manager and is used internally. +* `KeyboardPlugin.target` has been removed as it's no longer used by the class. +* `KeyboardPlugin.queue` has been removed as it's no longer used by the class. +* `KeyboardPlugin.onKeyHandler` has been removed as it's no longer used by the class. + +### Mouse and Touch Input - New Features, Updates and Fixes -* The Keyboard Plugin will now call `preventDefault` on all non-modified alphanumeric key presses by default, stopping the keyboard event from hitting the browser. Previously, you had to create `Key` objects to enable this. You can control this at runtime by toggling the `KeyboardPlugin.preventDefault` boolean, or the `keyboard.capture` config setting. -* There is a new Game and Scene Config setting `input.keyboard.capture` which is an array of KeyCodes that the Keyboard Plugin will capture all non-modified key events on. By default it is populated with the space key, cursors, 0 - 9 and A - Z. You can also set this in a Scene Config, in which case it will override the Game Config value. -* If you have multiple parallel Scenes, each trying to get keyboard input, be sure to disable capture on them to stop them from stealing input from another Scene in the list. You can do this with `this.input.keyboard.enabled = false` within the Scene to stop all input, or `this.input.keyboard.preventDefault = false` to stop a Scene halting input on another Scene. -* The Keyboard Plugin has a new property called `captures` which is an array of keycodes, as populated by the Game Config. Any key code in the array will have `preventDefault` called on it if pressed. Modify this by changing the game config, or altering the array contents at run-time. -* The Key object has a new boolean `metaKey` which indicates if the Meta Key was held down when the Key was pressed. On a Mac the Meta Key is Command. On a Windows keyboard, it's the Windows key. * The Mouse Manager class has been updated to remove some commented out code and refine the `startListeners` method. * The following Key Codes have been added, which include some missing alphabet letters in Persian and Arabic: `SEMICOLON_FIREFOX`, `COLON`, `COMMA_FIREFOX_WINDOWS`, `COMMA_FIREFOX`, `BRACKET_RIGHT_FIREFOX` and `BRACKET_LEFT_FIREFOX` (thanks @wmateam) * When enabling a Game Object for input it will now use the `width` and `height` properties of the Game Object first, falling back to the frame size if not found. This stops a bug when enabling BitmapText objects for input and it using the font texture as the hit area size, rather than the text itself. From df9365cae60ea6e8c6350c8165f654de03d8eed4 Mon Sep 17 00:00:00 2001 From: Bill Reed Date: Wed, 5 Dec 2018 11:32:47 -0500 Subject: [PATCH 131/221] update type param for group factory and creator methods --- src/gameobjects/group/GroupCreator.js | 2 +- src/gameobjects/group/GroupFactory.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gameobjects/group/GroupCreator.js b/src/gameobjects/group/GroupCreator.js index de5ba9816..0569852ea 100644 --- a/src/gameobjects/group/GroupCreator.js +++ b/src/gameobjects/group/GroupCreator.js @@ -15,7 +15,7 @@ var Group = require('./Group'); * @method Phaser.GameObjects.GameObjectCreator#group * @since 3.0.0 * - * @param {GroupConfig} config - The configuration object this Game Object will use to create itself. + * @param {GroupConfig|GroupCreateConfig} config - The configuration object this Game Object will use to create itself. * * @return {Phaser.GameObjects.Group} The Game Object that was created. */ diff --git a/src/gameobjects/group/GroupFactory.js b/src/gameobjects/group/GroupFactory.js index dbe160312..3367ba1e7 100644 --- a/src/gameobjects/group/GroupFactory.js +++ b/src/gameobjects/group/GroupFactory.js @@ -16,7 +16,7 @@ var GameObjectFactory = require('../GameObjectFactory'); * @since 3.0.0 * * @param {(Phaser.GameObjects.GameObject[]|GroupConfig|GroupConfig[])} [children] - Game Objects to add to this Group; or the `config` argument. - * @param {GroupConfig} [config] - A Group Configuration object. + * @param {GroupConfig|GroupCreateConfig} [config] - A Group Configuration object. * * @return {Phaser.GameObjects.Group} The Game Object that was created. */ From 1df20f9070b1190e1ba6c93c0706d7b46948b82c Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 11:35:16 +0000 Subject: [PATCH 132/221] Keyboard events can now be blocked on a local or global level. --- src/input/keyboard/KeyboardPlugin.js | 33 ++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/input/keyboard/KeyboardPlugin.js b/src/input/keyboard/KeyboardPlugin.js index 409d1d9f2..8cca87588 100644 --- a/src/input/keyboard/KeyboardPlugin.js +++ b/src/input/keyboard/KeyboardPlugin.js @@ -675,11 +675,30 @@ var KeyboardPlugin = new Class({ var key = keys[code]; var repeat = false; - // Override the default function (it's too late for the browser to use it anyway, so we may as well) - event.stopPropagation = function () + // Override the default functions (it's too late for the browser to use them anyway, so we may as well) + if (event.cancelled === undefined) { - event.cancelled = true; - }; + // Event allowed to flow across all handlers in this Scene, and any other Scene in the Scene list + event.cancelled = 0; + + // Won't reach any more local (Scene level) handlers + event.stopImmediatePropagation = function () + { + event.cancelled = 1; + }; + + // Won't reach any more handlers in any Scene further down the Scene list + event.stopPropagation = function () + { + event.cancelled = -1; + }; + } + + if (event.cancelled === -1) + { + // This event has been stopped from broadcasting to any other Scene, so abort. + continue; + } if (event.type === 'keydown') { @@ -723,6 +742,12 @@ var KeyboardPlugin = new Class({ } } } + + // Reset the cancel state for other Scenes to use + if (event.cancelled === 1) + { + event.cancelled = 0; + } } }, From bca8d9b0c9c4e8b5fd311dfddd25cce23622ecc5 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 11:55:14 +0000 Subject: [PATCH 133/221] Add Key capture information --- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c5503a59..ab49311d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,15 +11,42 @@ * If the `setScore` or `getPlayerScore` calls fail, it will return `null` as the score instance, instead of causing a run-time error. * You can now pass an object or a string to `setScore` and objects will be automatically stringified. -### Keyboard Input - New Features, Updates and Fixes +### Keyboard Input - New Features The specificity of the Keyboard events has been changed to allow you more control over event handling. Previously, the Keyboard Plugin would emit the global `keydown_CODE` event first (where CODE was a keycode string, like `keydown_A`), then it would emit the global `keydown` event. In previous versions, `Key` objects, created via `this.input.keyboard.addKey()`, didn't emit events. The `Key` class now extends EventEmitter and emits two new events directly: `down` and `up`. This means you can listen for an event from a Key you've created, i.e.: `yourKey.on('up', handler)`. -The order has also now changed. If it exists, the Key object will dispatch its `down` event first. Then the Keyboard Plugin will dispatch `keydown_CODE` and finally the less specific of them all, `keydown` will be dispatched. +The order has also now changed. If it exists, the Key object will dispatch its `down` event first. Then the Keyboard Plugin will dispatch `keydown_CODE` and finally the least specific of them all, `keydown` will be dispatched. -You also now have the ability to cancel this at any stage. All events handlers are sent an event object which you can call `event.stopPropagation()` on. This will immediately stop any further listeners from being invoked. Therefore, if you call `stopPropagation()` after `Key.on`, then the Keyboard Plugin will not emit either the `keydown_CODE` or `keydown` global events. You can also call `stopPropagation()` during the `keydown_CODE` handler, to stop it getting to the global `keydown` event. As `keydown` is last, calling it has no effect there. This also works for `keyup` events. +You also now have the ability to cancel this at any stage either on a local or global level. All events handlers are sent an event object which you can call `event.stopImmediatePropagation()` on. This will immediately stop any further listeners from being invoked in the current Scene. Therefore, if you call `stopImmediatePropagation()` in the `Key.on` handler, then the Keyboard Plugin will not emit either the `keydown_CODE` or `keydown` global events. You can also call `stopImmediatePropagation()` during the `keydown_CODE` handler, to stop it reaching the global `keydown` handler. As `keydown` is last, calling it there has no effect. + +There is also the `stopPropagation()` function. This works in the same way as `stopImmediatePropagation` but instead of being local, it works across all of the Scenes in your game. For example, if you had 3 active Scenes (A, B and C, with A at the top of the Scene list), all listening for the same key, calling `stopPropagation()` in Scene A would stop the event from reaching any handlers in Scenes B or C. Remember that events flow down the Scene list from top to bottom. So, the top-most rendering Scene in the Scene list has priority over any Scene below it. + +All the above also works for `keyup` events. + +#### Keyboard Captures + +Key capturing is the way in which you stop a keyboard DOM event from activating anything else in the browser by calling `preventDefault` on it. For example, in tall web pages, pressing the SPACE BAR causes the page to scroll down. Obviously, if this is also the fire or jump button in your game, you don't want this to happen. So the key needs to be 'captured' to prevent it. Equally, you may wish to also capture the arrow keys, for similar reasons. Key capturing is done on a global level. If you set-up the capture of a key in one Scene, it will be captured globally across the whole game. + +In 3.16 you now do this using the new `KeyboardPlugin.addCapture` method. This takes keycodes as its argument. You can either pass in a single key code (i.e. 32 for the Space Bar), an array of key codes, or a comma-delimited string - in which case the string is parsed and each code it can work out is captured. + +To remove a capture you can use the `KeyboardPlugin.removeCapture` method, which takes the same style arguments as adding captures. To clear all captures call `KeyboardPlugin.clearCaptures`. Again, remember that these actions are global. + +You can also temporarily enable and disable capturing using `KeyboardPlugin.enableGlobalCapture` and `KeyboardPlugin.disableGlobalCapture`. This means if you set-up a bunch of key captures, but then need to disable them all for a while (perhaps you swap focus to a DOM text field), you can call `disableGlobalCapture` to do this, and when finished in the DOM you can enable captures again with `enableGlobalCapture`, without having to clear and re-create them all. + +Default captures can be defined in the Game Config in the `input.keyboard.captures` object. The captures are actually stored in the `KeyboardManager` class. The `KeyboardPlugin` is just a proxy to methods in the Keyboard Manager, but is how you should interface with it. + +* `KeyboardPlugin.addCapture` is a new method that allows you to define a set of keycodes to have the default browser behaviors disabled on. +* `KeyboardPlugin.removeCapture` is a new method that removes specific previously set key captures. +* `KeyboardPlugin.clearCaptures` is a new method that removes all key captures. +* `KeyboardPlugin.getCaptures` is a new method that returns an array of all current key captures. +* `KeyboardPlugin.enableGlobalCapture` is a new method that enables any key captures that have been created. +* `KeyboardPlugin.disableGlobalCapture` is a new method that disables any key captures that have been created, without removing them from the captures list. +* `KeyboardPlugin.addKey` has a new boolean argument `enableCapture`, which is true by default, that will add a key capture for the Key being created. +* `KeyboardPlugin.addKeys` has a new boolean argument `enableCapture`, which is true by default, that will add a key capture for any Key created by the method. + +#### Other Keyboard Updates and Fixes * There is a new class called `KeyboardManager`. This class is created by the global Input Manager, if keyboard access has been enabled in the Game config. It's responsible for handling all browser keyboard events. Previously, the `KeyboardPlugin` did this. Which meant that every Scene that had its own Keyboard Plugin was binding more native keyboard events. This was causing problems with parallel Scenes when needing to capture keys. the `KeyboardPlugin` class still exists, and is still the main point of interface when you call `this.input.keyboard` in a Scene, but DOM event handling responsibility has been taken away from it. This means there's no only one set of bindings ever created, which makes things a lot cleaner. @@ -29,6 +56,7 @@ one set of bindings ever created, which makes things a lot cleaner. * `Key.setEmitOnRepeat` is a new chainable method for setting the `emitOnRepeat` property. * The keyboard event flow has changed. * The `Key` class now extends EventEmitter and emits two events directly: `down` and `up`. This means you can listen for an event from a Key you've created, i.e.: `yourKey.on('up', handler)`. +* The following Key Codes have been added, which include some missing alphabet letters in Persian and Arabic: `SEMICOLON_FIREFOX`, `COLON`, `COMMA_FIREFOX_WINDOWS`, `COMMA_FIREFOX`, `BRACKET_RIGHT_FIREFOX` and `BRACKET_LEFT_FIREFOX` (thanks @wmateam) * `Key.onDown` is a new method that handles the Key being pressed down, including down repeats. * `Key.onUp` is a new method that handles the Key being released. * `Key.destroy` is a new method that handles Key instance destruction. It is called automatically in `KeyboardPlugin.destroy`. @@ -48,7 +76,6 @@ one set of bindings ever created, which makes things a lot cleaner. ### Mouse and Touch Input - New Features, Updates and Fixes * The Mouse Manager class has been updated to remove some commented out code and refine the `startListeners` method. -* The following Key Codes have been added, which include some missing alphabet letters in Persian and Arabic: `SEMICOLON_FIREFOX`, `COLON`, `COMMA_FIREFOX_WINDOWS`, `COMMA_FIREFOX`, `BRACKET_RIGHT_FIREFOX` and `BRACKET_LEFT_FIREFOX` (thanks @wmateam) * When enabling a Game Object for input it will now use the `width` and `height` properties of the Game Object first, falling back to the frame size if not found. This stops a bug when enabling BitmapText objects for input and it using the font texture as the hit area size, rather than the text itself. * `Pointer.smoothFactor` is a float-value that allows you to automatically apply smoothing to the Pointer position as it moves. This is ideal when you want something smoothly tracking a pointer in a game, or are need a smooth drawing motion for an art package. The default value is zero, meaning disabled. Set to a small number, such as 0.2, to enable. * `Config.inputSmoothFactor` is a new property that allows you to set the smoothing factor for all Pointers the game creators. The default value is zero, which is disabled. Set in the game config as `input: { smoothFactor: value }`. From 1a407bc4f585e9bff0a7f52af9c2419fc76a53f2 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 14:47:06 +0000 Subject: [PATCH 134/221] `ArcadePhysics.Body.destroy` will now only add itself to the World `pendingDestroy` list if the world property exists. This prevents `Cannot read property 'pendingDestroy' of undefined` errors if you try to delete a physics body in a callback and then immediately change Scene (which tells the physics work to also delete all bodies) --- src/physics/arcade/Body.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/physics/arcade/Body.js b/src/physics/arcade/Body.js index b2ccf4810..524c23dde 100644 --- a/src/physics/arcade/Body.js +++ b/src/physics/arcade/Body.js @@ -1397,7 +1397,10 @@ var Body = new Class({ { this.enable = false; - this.world.pendingDestroy.set(this); + if (this.world) + { + this.world.pendingDestroy.set(this); + } }, /** From 20ea562d23d57a70089daf1ea22daaaa8d333bd8 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 14:47:26 +0000 Subject: [PATCH 135/221] `create` no longer throws a warning, returns existing animation. Also added `exists` method. --- src/animations/AnimationManager.js | 51 ++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/animations/AnimationManager.js b/src/animations/AnimationManager.js index 20ce067ca..3f7d4055f 100644 --- a/src/animations/AnimationManager.js +++ b/src/animations/AnimationManager.js @@ -154,8 +154,35 @@ var AnimationManager = new Class({ return this; }, + /** + * Checks to see if the given key is already in use within the Animation Manager or not. + * + * Animations are global. Keys created in one scene can be used from any other Scene in your game. They are not Scene specific. + * + * @method Phaser.Animations.AnimationManager#exists + * @since 3.16.0 + * + * @param {string} key - The key of the Animation to check. + * + * @return {boolean} `true` if the Animation already exists in the Animation Manager, or `false` if the key is available. + */ + exists: function (key) + { + return this.anims.has(key); + }, + /** * Creates a new Animation and adds it to the Animation Manager. + * + * Animations are global. Once created, you can use them in any Scene in your game. They are not Scene specific. + * + * If an invalid key is given this method will return `false`. + * + * If you pass the key of an animation that already exists in the Animation Manager, that animation will be returned. + * + * A brand new animation is only created if the key is valid and not already in use. + * + * If you wish to re-use an existing key, call `AnimationManager.remove` first, then this method. * * @method Phaser.Animations.AnimationManager#create * @fires AddAnimationEvent @@ -163,24 +190,28 @@ var AnimationManager = new Class({ * * @param {AnimationConfig} config - The configuration settings for the Animation. * - * @return {Phaser.Animations.Animation} The Animation that was created. + * @return {(Phaser.Animations.Animation|false)} The Animation that was created, or `false` is the key is already in use. */ create: function (config) { var key = config.key; - if (!key || this.anims.has(key)) + var anim = false; + + if (key) { - console.warn('Invalid Animation Key, or Key already in use: ' + key); - return; + anim = this.get(key); + + if (!anim) + { + anim = new Animation(this, key, config); + + this.anims.set(key, anim); + + this.emit('add', key, anim); + } } - var anim = new Animation(this, key, config); - - this.anims.set(key, anim); - - this.emit('add', key, anim); - return anim; }, From 8955c50ab5def69c8d92a87f9e6c8ed9e870d2b9 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 14:47:29 +0000 Subject: [PATCH 136/221] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab49311d3..98874545c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -136,6 +136,7 @@ one set of bindings ever created, which makes things a lot cleaner. * `Camera.getBounds` is a new method that will return a rectangle containing the bounds of the camera. * `Camera.centerOnX` will move the camera horizontally to be centered on the given coordinate, without changing its vertical placement. * `Camera.centerOnY` will move the camera vertically to be centered on the given coordinate, without changing its horizontally placement. +* `AnimationManager.exists` is a new method that will check to see if an Animation using the given key already exists or not and returns a boolean. ### Updates @@ -159,6 +160,9 @@ one set of bindings ever created, which makes things a lot cleaner. * `Graphics.fill` is a new alias for the `fillPath` method, to keep the calls consistent with the Canvas Rendering Context API. * `LoaderPlugin.sceneManager` is a new property that is a reference to the global Scene Manager, useful for Plugins. * Whenever `Camera.roundPixels` was enabled it would use a bitwise operation to truncate the float (`x |= 0`) - this has been replaced across all files that used it, with a call to `Math.round` instead. This gives far better results when zooming cameras both in and out of a Scene, stopping thin gaps appearing between closely packed Game Objects. +* `AnimationManager.create` will now return a boolean `false` is the given key is invalid (i.e. undefined or falsey). +* `AnimationManager.create` will no longer raise a console warning if the animation key is already in use. Instead, it will return the animation belonging to that key. A brand new animation will only be created if the key isn't already in use. When this happens, the `add` event is emitted by the Animation Manager. If no event is emitted, the animation already existed. +* `ArcadePhysics.Body.destroy` will now only add itself to the World `pendingDestroy` list if the world property exists. This prevents `Cannot read property 'pendingDestroy' of undefined` errors if you try to delete a physics body in a callback and then immediately change Scene (which tells the physics work to also delete all bodies) ### Bug Fixes From 9e78553a4800a6a61b61b39e0768fb05a514438a Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 15:28:32 +0000 Subject: [PATCH 137/221] `reverse` no longer needs the argument. `play` and `playReverse` can now take an Animation instance as an argument, not just a key. --- src/gameobjects/components/Animation.js | 87 ++++++++++++++++++++----- 1 file changed, 69 insertions(+), 18 deletions(-) diff --git a/src/gameobjects/components/Animation.js b/src/gameobjects/components/Animation.js index 160f4f4a9..348df0c05 100644 --- a/src/gameobjects/components/Animation.js +++ b/src/gameobjects/components/Animation.js @@ -4,12 +4,16 @@ * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ +var BaseAnimation = require('../../animations/Animation'); var Class = require('../../utils/Class'); /** * This event is dispatched when an animation starts playing. * * Listen for it on the Game Object: `sprite.on('animationstart', listener)` + * + * You can also listen for a specific animation by appending a hyphen and its key to the event name. For example, + * if you have an animation called `explode`, you can listen for `sprite.on('animationstart-explode', listener)`. * * @event Phaser.GameObjects.Components.Animation#onStartEvent * @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation. @@ -21,6 +25,9 @@ var Class = require('../../utils/Class'); * This event is dispatched when an animation restarts. * * Listen for it on the Game Object: `sprite.on('animationrestart', listener)` + * + * You can also listen for a specific animation by appending a hyphen and its key to the event name. For example, + * if you have an animation called `explode`, you can listen for `sprite.on('animationrestart-explode', listener)`. * * @event Phaser.GameObjects.Components.Animation#onRestartEvent * @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation. @@ -32,6 +39,9 @@ var Class = require('../../utils/Class'); * This event is dispatched when an animation repeats. * * Listen for it on the Game Object: `sprite.on('animationrepeat', listener)` + * + * You can also listen for a specific animation by appending a hyphen and its key to the event name. For example, + * if you have an animation called `explode`, you can listen for `sprite.on('animationrepeat-explode', listener)`. * * @event Phaser.GameObjects.Components.Animation#onRepeatEvent * @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation. @@ -45,6 +55,9 @@ var Class = require('../../utils/Class'); * based on the animation frame rate and other factors like timeScale and delay. * * Listen for it on the Game Object: `sprite.on('animationupdate', listener)` + * + * You can also listen for a specific animation by appending a hyphen and its key to the event name. For example, + * if you have an animation called `explode`, you can listen for `sprite.on('animationupdate-explode', listener)`. * * @event Phaser.GameObjects.Components.Animation#onUpdateEvent * @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation. @@ -56,6 +69,9 @@ var Class = require('../../utils/Class'); * This event is dispatched when an animation completes playing, either naturally or via Animation.stop. * * Listen for it on the Game Object: `sprite.on('animationcomplete', listener)` + * + * You can also listen for a specific animation by appending a hyphen and its key to the event name. For example, + * if you have an animation called `explode`, you can listen for `sprite.on('animationcomplete-explode', listener)`. * * @event Phaser.GameObjects.Components.Animation#onCompleteEvent * @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation. @@ -508,13 +524,15 @@ var Animation = new Class({ }, /** - * Plays an Animation on the Game Object that owns this Animation Component. + * Plays an Animation on a Game Object that has the Animation component, such as a Sprite. + * + * Animations are stored in the global Animation Manager and are referenced by a unique string-based key. * * @method Phaser.GameObjects.Components.Animation#play * @fires Phaser.GameObjects.Components.Animation#onStartEvent * @since 3.0.0 * - * @param {string} key - The string-based key of the animation to play, as defined previously in the Animation Manager. + * @param {(string|Phaser.Animations.Animation)} key - The string-based key of the animation to play, as defined previously in the Animation Manager. Or an Animation instance. * @param {boolean} [ignoreIfPlaying=false] - If an animation is already playing then ignore this call. * @param {integer} [startFrame=0] - Optionally start the animation playing from this frame index. * @@ -525,6 +543,11 @@ var Animation = new Class({ if (ignoreIfPlaying === undefined) { ignoreIfPlaying = false; } if (startFrame === undefined) { startFrame = 0; } + if (key instanceof BaseAnimation) + { + key = key.key; + } + if (ignoreIfPlaying && this.isPlaying && this.currentAnim.key === key) { return this.parent; @@ -543,7 +566,7 @@ var Animation = new Class({ * @fires Phaser.GameObjects.Components.Animation#onStartEvent * @since 3.12.0 * - * @param {string} key - The string-based key of the animation to play, as defined previously in the Animation Manager. + * @param {(string|Phaser.Animations.Animation)} key - The string-based key of the animation to play, as defined previously in the Animation Manager. Or an Animation instance. * @param {boolean} [ignoreIfPlaying=false] - If an animation is already playing then ignore this call. * @param {integer} [startFrame=0] - Optionally start the animation playing from this frame index. * @@ -554,6 +577,11 @@ var Animation = new Class({ if (ignoreIfPlaying === undefined) { ignoreIfPlaying = false; } if (startFrame === undefined) { startFrame = 0; } + if (key instanceof BaseAnimation) + { + key = key.key; + } + if (ignoreIfPlaying && this.isPlaying && this.currentAnim.key === key) { return this.parent; @@ -566,8 +594,7 @@ var Animation = new Class({ }, /** - * Load an Animation and fires 'onStartEvent' event, - * extracted from 'play' method + * Load an Animation and fires 'onStartEvent' event, extracted from 'play' method. * * @method Phaser.GameObjects.Components.Animation#_startAnimation * @fires Phaser.GameObjects.Components.Animation#onStartEvent @@ -598,26 +625,33 @@ var Animation = new Class({ gameObject.visible = true; } - gameObject.emit('animationstart', this.currentAnim, this.currentFrame, gameObject); + var frame = this.currentFrame; + + anim.emit('start', anim, frame); + + gameObject.emit('animationstart-' + key, anim, frame, gameObject); + + gameObject.emit('animationstart', anim, frame, gameObject); return gameObject; }, /** - * Reverse an Animation that is already playing on the Game Object. + * Reverse the Animation that is already playing on the Game Object. * * @method Phaser.GameObjects.Components.Animation#reverse * @since 3.12.0 * - * @param {string} key - The string-based key of the animation to play, as defined previously in the Animation Manager. - * * @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component. */ - reverse: function (key) + reverse: function () { - if (!this.isPlaying || this.currentAnim.key !== key) { return this.parent; } - this._reverse = !this._reverse; - this.forward = !this.forward; + if (this.isPlaying) + { + this._reverse = !this._reverse; + + this.forward = !this.forward; + } return this.parent; }, @@ -774,7 +808,9 @@ var Animation = new Class({ { if (includeDelay === undefined) { includeDelay = false; } - this.currentAnim.getFirstTick(this, includeDelay); + var anim = this.currentAnim; + + anim.getFirstTick(this, includeDelay); this.forward = true; this.isPlaying = true; @@ -782,11 +818,16 @@ var Animation = new Class({ this._paused = false; // Set frame - this.updateFrame(this.currentAnim.frames[0]); + this.updateFrame(anim.frames[0]); var gameObject = this.parent; + var frame = this.currentFrame; - gameObject.emit('animationrestart', this.currentAnim, this.currentFrame, gameObject); + anim.emit('restart', anim, frame); + + gameObject.emit('animationrestart-' + anim.key, anim, frame, gameObject); + + gameObject.emit('animationrestart', anim, frame, gameObject); return this.parent; }, @@ -807,8 +848,14 @@ var Animation = new Class({ this.isPlaying = false; var gameObject = this.parent; + var anim = this.currentAnim; + var frame = this.currentFrame; - gameObject.emit('animationcomplete', this.currentAnim, this.currentFrame, gameObject); + anim.on('complete', anim, frame); + + gameObject.emit('animationcomplete-' + anim.key, anim, frame, gameObject); + + gameObject.emit('animationcomplete', anim, frame, gameObject); return gameObject; }, @@ -856,7 +903,7 @@ var Animation = new Class({ * @fires Phaser.GameObjects.Components.Animation#onCompleteEvent * @since 3.4.0 * - * @param {Phaser.Animations.AnimationFrame} delay - The frame to check before stopping this animation. + * @param {Phaser.Animations.AnimationFrame} frame - The frame to check before stopping this animation. * * @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component. */ @@ -1010,6 +1057,10 @@ var Animation = new Class({ var anim = this.currentAnim; + anim.emit('update', anim, animationFrame); + + gameObject.emit('animationupdate-' + anim.key, anim, animationFrame, gameObject); + gameObject.emit('animationupdate', anim, animationFrame, gameObject); if (this._pendingStop === 3 && this._pendingStopValue === animationFrame) From eda6e648fc2dc953a4c08ee8e4682ad6c1f1cf31 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 15:28:48 +0000 Subject: [PATCH 138/221] Animation now extends the EventEmitter. --- src/animations/Animation.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/animations/Animation.js b/src/animations/Animation.js index 4ec58fa7f..8f089c121 100644 --- a/src/animations/Animation.js +++ b/src/animations/Animation.js @@ -6,6 +6,7 @@ var Clamp = require('../math/Clamp'); var Class = require('../utils/Class'); +var EventEmitter = require('eventemitter3'); var FindClosestInSorted = require('../utils/array/FindClosestInSorted'); var Frame = require('./AnimationFrame'); var GetValue = require('../utils/object/GetValue'); @@ -65,6 +66,7 @@ var GetValue = require('../utils/object/GetValue'); * * @class Animation * @memberof Phaser.Animations + * @extends Phaser.Events.EventEmitter * @constructor * @since 3.0.0 * @@ -74,10 +76,14 @@ var GetValue = require('../utils/object/GetValue'); */ var Animation = new Class({ + Extends: EventEmitter, + initialize: function Animation (manager, key, config) { + EventEmitter.call(this); + /** * A reference to the global Animation Manager * @@ -797,6 +803,8 @@ var Animation = new Class({ component.pendingRepeat = false; + component.parent.emit('animationrepeat-' + component.currentAnim.key, this, component.currentFrame, component.repeatCounter, component.parent); + component.parent.emit('animationrepeat', this, component.currentFrame, component.repeatCounter, component.parent); } } @@ -939,6 +947,8 @@ var Animation = new Class({ */ destroy: function () { + this.removeAllListeners(); + this.manager.off('pauseall', this.pause, this); this.manager.off('resumeall', this.resume, this); From 8fe2e306358c5b2b3d2629f01dca32cb2ffb18f3 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 15:34:15 +0000 Subject: [PATCH 139/221] Removed update event --- src/gameobjects/components/Animation.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/gameobjects/components/Animation.js b/src/gameobjects/components/Animation.js index 348df0c05..20dfac5d5 100644 --- a/src/gameobjects/components/Animation.js +++ b/src/gameobjects/components/Animation.js @@ -1057,8 +1057,6 @@ var Animation = new Class({ var anim = this.currentAnim; - anim.emit('update', anim, animationFrame); - gameObject.emit('animationupdate-' + anim.key, anim, animationFrame, gameObject); gameObject.emit('animationupdate', anim, animationFrame, gameObject); From 3d362156235813e548da9215de4ac24d7602c0f6 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 15:39:47 +0000 Subject: [PATCH 140/221] Added repeat event. --- src/animations/Animation.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/animations/Animation.js b/src/animations/Animation.js index 8f089c121..1465d64e2 100644 --- a/src/animations/Animation.js +++ b/src/animations/Animation.js @@ -803,9 +803,14 @@ var Animation = new Class({ component.pendingRepeat = false; - component.parent.emit('animationrepeat-' + component.currentAnim.key, this, component.currentFrame, component.repeatCounter, component.parent); + var frame = component.currentFrame; + var parent = component.parent; - component.parent.emit('animationrepeat', this, component.currentFrame, component.repeatCounter, component.parent); + this.emit('repeat', this, frame); + + parent.emit('animationrepeat-' + this.key, this, frame, component.repeatCounter, parent); + + parent.emit('animationrepeat', this, frame, component.repeatCounter, parent); } } }, From cd80b27ea6877a1c2afa610d517b51f5cf206c97 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 15:39:57 +0000 Subject: [PATCH 141/221] Updated jsdocs --- src/gameobjects/components/Animation.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gameobjects/components/Animation.js b/src/gameobjects/components/Animation.js index 20dfac5d5..4315cd671 100644 --- a/src/gameobjects/components/Animation.js +++ b/src/gameobjects/components/Animation.js @@ -14,6 +14,8 @@ var Class = require('../../utils/Class'); * * You can also listen for a specific animation by appending a hyphen and its key to the event name. For example, * if you have an animation called `explode`, you can listen for `sprite.on('animationstart-explode', listener)`. + * + * You can also listen for the `start` event from the Animation itself: `animation.on('start', listener)`. * * @event Phaser.GameObjects.Components.Animation#onStartEvent * @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation. @@ -28,6 +30,8 @@ var Class = require('../../utils/Class'); * * You can also listen for a specific animation by appending a hyphen and its key to the event name. For example, * if you have an animation called `explode`, you can listen for `sprite.on('animationrestart-explode', listener)`. + * + * You can also listen for the `restart` event from the Animation itself: `animation.on('restart', listener)`. * * @event Phaser.GameObjects.Components.Animation#onRestartEvent * @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation. @@ -42,6 +46,8 @@ var Class = require('../../utils/Class'); * * You can also listen for a specific animation by appending a hyphen and its key to the event name. For example, * if you have an animation called `explode`, you can listen for `sprite.on('animationrepeat-explode', listener)`. + * + * You can also listen for the `repeat` event from the Animation itself: `animation.on('repeat', listener)`. * * @event Phaser.GameObjects.Components.Animation#onRepeatEvent * @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation. @@ -72,6 +78,8 @@ var Class = require('../../utils/Class'); * * You can also listen for a specific animation by appending a hyphen and its key to the event name. For example, * if you have an animation called `explode`, you can listen for `sprite.on('animationcomplete-explode', listener)`. + * + * You can also listen for the `complete` event from the Animation itself: `animation.on('complete', listener)`. * * @event Phaser.GameObjects.Components.Animation#onCompleteEvent * @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation. From 96fab45ced8f7e6c8341981eb54cb2e71f609fdc Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 15:40:00 +0000 Subject: [PATCH 142/221] Update CHANGELOG.md --- CHANGELOG.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98874545c..503369fab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -137,6 +137,14 @@ one set of bindings ever created, which makes things a lot cleaner. * `Camera.centerOnX` will move the camera horizontally to be centered on the given coordinate, without changing its vertical placement. * `Camera.centerOnY` will move the camera vertically to be centered on the given coordinate, without changing its horizontally placement. * `AnimationManager.exists` is a new method that will check to see if an Animation using the given key already exists or not and returns a boolean. +* `animationstart-key` is a new Animation key specific event emitted by a Game Object. For example, if you had an animation with a key of 'explode' you can now listen for `animationstart-explode`. +* `animationrestart-key` is a new Animation key specific event emitted by a Game Object. For example, if you had an animation with a key of 'explode' you can now listen for `animationrestart-explode`. +* `animationcomplete-key` is a new Animation key specific event emitted by a Game Object. For example, if you had an animation with a key of 'explode' you can now listen for `animationcomplete-explode`. +* `animationupdate-key` is a new Animation key specific event emitted by a Game Object. For example, if you had an animation with a key of 'explode' you can now listen for `animationupdate-explode`. +* The Animation class now extends the Event Emitter and dispatches events itself. This allows you to listen for events from a specific Animation, rather than via a Game Object. This is handy, for example, if you had an explosion animation that you wanted to trigger a sound effect when it started. You can now listen for the events from the Animation object directly. +* The Animation class now emits the `start` event when played (either forward, or in reverse) by any Game Object. +* The Animation class now emits the `restart` event when it restarts playing on any Game Object. +* The Animation class now emits the `complete` event when it finishes playing on any Game Object. ### Updates @@ -160,9 +168,11 @@ one set of bindings ever created, which makes things a lot cleaner. * `Graphics.fill` is a new alias for the `fillPath` method, to keep the calls consistent with the Canvas Rendering Context API. * `LoaderPlugin.sceneManager` is a new property that is a reference to the global Scene Manager, useful for Plugins. * Whenever `Camera.roundPixels` was enabled it would use a bitwise operation to truncate the float (`x |= 0`) - this has been replaced across all files that used it, with a call to `Math.round` instead. This gives far better results when zooming cameras both in and out of a Scene, stopping thin gaps appearing between closely packed Game Objects. -* `AnimationManager.create` will now return a boolean `false` is the given key is invalid (i.e. undefined or falsey). +* `AnimationManager.create` will now return a boolean `false` if the given key is invalid (i.e. undefined or falsey). * `AnimationManager.create` will no longer raise a console warning if the animation key is already in use. Instead, it will return the animation belonging to that key. A brand new animation will only be created if the key isn't already in use. When this happens, the `add` event is emitted by the Animation Manager. If no event is emitted, the animation already existed. * `ArcadePhysics.Body.destroy` will now only add itself to the World `pendingDestroy` list if the world property exists. This prevents `Cannot read property 'pendingDestroy' of undefined` errors if you try to delete a physics body in a callback and then immediately change Scene (which tells the physics work to also delete all bodies) +* The Animation Component `restart` method has had is sole `key` argument removed. Previously, you had to pass in the key of the animation you wished to reverse, but now you can just call the method directly, and as long as there is an animation playing, it will automatically start playing in reverse, without the nee for a key (the way it should have been originally) +* `Animation.play` and `playReverse` will now accept either a string-based key of the animation to play (like before), or you can pass in an Animation instance, and it will play that animation. ### Bug Fixes From e6f5d0144eba25b9a475fa8d839448bc8ff557a4 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 15:57:52 +0000 Subject: [PATCH 143/221] Added Animation.chain method to queue an animation to start when the current one ends. --- CHANGELOG.md | 1 + src/gameobjects/components/Animation.js | 49 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 503369fab..eda65fb32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -145,6 +145,7 @@ one set of bindings ever created, which makes things a lot cleaner. * The Animation class now emits the `start` event when played (either forward, or in reverse) by any Game Object. * The Animation class now emits the `restart` event when it restarts playing on any Game Object. * The Animation class now emits the `complete` event when it finishes playing on any Game Object. +* The Animation Component has a new method called `chain` which allows you to line-up another animation to start playing as soon as the current one stops, no matter how it stops (either by reaching its natural end, or directly by having stop called on it). You can chain a new animation at any point, including before the current one starts playing, during it, or when it ends (via its `animationcomplete` callback). Chained animations are specific to a Game Object, meaning different Game Objects can have different chained animations without impacting the global animation they're playing. ### Updates diff --git a/src/gameobjects/components/Animation.js b/src/gameobjects/components/Animation.js index 4315cd671..1990af54e 100644 --- a/src/gameobjects/components/Animation.js +++ b/src/gameobjects/components/Animation.js @@ -156,6 +156,16 @@ var Animation = new Class({ */ this.currentFrame = null; + /** + * The key of the next Animation to be loaded into this Animation Controller when the current animation completes. + * + * @name Phaser.GameObjects.Components.Animation#nextAnim + * @type {?string} + * @default null + * @since 3.16.0 + */ + this.nextAnim = null; + /** * Time scale factor. * @@ -363,6 +373,34 @@ var Animation = new Class({ this._pendingStopValue; }, + /** + * Sets an animation to be played immediately after the current one completes. + * + * The current animation must enter a 'completed' state for this to happen, i.e. finish all of its repeats, delays, etc. + * + * An animation set to repeat forever will never enter a completed state. + * + * Call this method with no arguments to reset the chained animation. + * + * @method Phaser.GameObjects.Components.Animation#chain + * @since 3.16.0 + * + * @param {(string|Phaser.Animations.Animation)} [key] - The string-based key of the animation to play next, as defined previously in the Animation Manager. Or an Animation instance. + * + * @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component. + */ + chain: function (key) + { + if (key instanceof BaseAnimation) + { + key = key.key; + } + + this.nextAnim = key; + + return this.parent; + }, + /** * Sets the amount of time, in milliseconds, that the animation will be delayed before starting playback. * @@ -842,6 +880,8 @@ var Animation = new Class({ /** * Immediately stops the current animation from playing and dispatches the `animationcomplete` event. + * + * If there is another animation queued (via the `chain` method) then it will start playing immediately. * * @method Phaser.GameObjects.Components.Animation#stop * @fires Phaser.GameObjects.Components.Animation#onCompleteEvent @@ -865,6 +905,15 @@ var Animation = new Class({ gameObject.emit('animationcomplete', anim, frame, gameObject); + if (this.nextAnim) + { + var key = this.nextAnim; + + this.nextAnim = null; + + this.play(key); + } + return gameObject; }, From 2fe4d536a9d4e71553c6d2596c21e90787b410ae Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 15:59:22 +0000 Subject: [PATCH 144/221] Updated docs --- src/gameobjects/components/Animation.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gameobjects/components/Animation.js b/src/gameobjects/components/Animation.js index 1990af54e..d5e96e1f6 100644 --- a/src/gameobjects/components/Animation.js +++ b/src/gameobjects/components/Animation.js @@ -376,10 +376,13 @@ var Animation = new Class({ /** * Sets an animation to be played immediately after the current one completes. * - * The current animation must enter a 'completed' state for this to happen, i.e. finish all of its repeats, delays, etc. + * The current animation must enter a 'completed' state for this to happen, i.e. finish all of its repeats, delays, etc, or have the `stop` method called directly on it. * * An animation set to repeat forever will never enter a completed state. * + * You can chain a new animation at any point, including before the current one starts playing, during it, or when it ends (via its `animationcomplete` callback). + * Chained animations are specific to a Game Object, meaning different Game Objects can have different chained animations without impacting the global animation they're playing. + * * Call this method with no arguments to reset the chained animation. * * @method Phaser.GameObjects.Components.Animation#chain From da0d9802de3e6108735b1115b4f3accaba3f1e7e Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 6 Dec 2018 16:59:53 +0000 Subject: [PATCH 145/221] Fixed typo --- src/gameobjects/components/Animation.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gameobjects/components/Animation.js b/src/gameobjects/components/Animation.js index d5e96e1f6..7f81941a5 100644 --- a/src/gameobjects/components/Animation.js +++ b/src/gameobjects/components/Animation.js @@ -46,8 +46,6 @@ var Class = require('../../utils/Class'); * * You can also listen for a specific animation by appending a hyphen and its key to the event name. For example, * if you have an animation called `explode`, you can listen for `sprite.on('animationrepeat-explode', listener)`. - * - * You can also listen for the `repeat` event from the Animation itself: `animation.on('repeat', listener)`. * * @event Phaser.GameObjects.Components.Animation#onRepeatEvent * @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation. @@ -902,7 +900,7 @@ var Animation = new Class({ var anim = this.currentAnim; var frame = this.currentFrame; - anim.on('complete', anim, frame); + anim.emit('complete', anim, frame); gameObject.emit('animationcomplete-' + anim.key, anim, frame, gameObject); From e672592aef13fc29111857b249aad15c37ec91e0 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 7 Dec 2018 01:39:30 +0000 Subject: [PATCH 146/221] Modified how ad placement loading works. --- CHANGELOG.md | 2 ++ plugins/fbinstant/src/AdInstance.js | 4 +-- .../src/FacebookInstantGamesPlugin.js | 34 +++++++++++-------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eda65fb32..daecf0a17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ * `Leaderboard.getPlayerScore` now only populates the `playerScore` property if the entry isn't `null`. * If the `setScore` or `getPlayerScore` calls fail, it will return `null` as the score instance, instead of causing a run-time error. * You can now pass an object or a string to `setScore` and objects will be automatically stringified. +* The `preloadAds` method will now only create an AdInstance object if the interstitial `loadSync` promise resolves. +* The `preloadVideoAds` method will now only create an AdInstance object if the interstitial `loadSync` promise resolves. ### Keyboard Input - New Features diff --git a/plugins/fbinstant/src/AdInstance.js b/plugins/fbinstant/src/AdInstance.js index b8d714c7c..fd26da692 100644 --- a/plugins/fbinstant/src/AdInstance.js +++ b/plugins/fbinstant/src/AdInstance.js @@ -13,11 +13,11 @@ * @property {boolean} video - Is this a video ad? */ -var AdInstance = function (instance, video) +var AdInstance = function (placementID, instance, video) { return { instance: instance, - placementID: instance.getPlacementID(), + placementID: placementID, shown: false, video: video }; diff --git a/plugins/fbinstant/src/FacebookInstantGamesPlugin.js b/plugins/fbinstant/src/FacebookInstantGamesPlugin.js index 41778ed8c..77d156822 100644 --- a/plugins/fbinstant/src/FacebookInstantGamesPlugin.js +++ b/plugins/fbinstant/src/FacebookInstantGamesPlugin.js @@ -1912,15 +1912,18 @@ var FacebookInstantGamesPlugin = new Class({ for (i = 0; i < placementID.length; i++) { var id = placementID[i]; + var data; - FBInstant.getInterstitialAdAsync(id).then(function (data) + FBInstant.getInterstitialAdAsync(id).then(function (interstitial) { - var ad = AdInstance(data, true); - - _this.ads.push(ad); - - return ad.loadAsync(); - + data = interstitial; + + return interstitial.loadAsync(); + + }).then(function () + { + _this.ads.push(AdInstance(id, data, false)); + }).catch(function (e) { console.warn(e); @@ -1976,15 +1979,18 @@ var FacebookInstantGamesPlugin = new Class({ for (i = 0; i < placementID.length; i++) { var id = placementID[i]; + var data; - FBInstant.getRewardedVideoAsync(id).then(function (data) + FBInstant.getRewardedVideoAsync(id).then(function (reward) { - var ad = AdInstance(data, true); - - _this.ads.push(ad); - - return ad.loadAsync(); - + data = reward; + + return reward.loadAsync(); + + }).then(function () + { + _this.ads.push(AdInstance(id, data, true)); + }).catch(function (e) { console.warn(e); From 2ed6c649a3fb9b66d1808cfe9b9665a9f72b8fed Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 7 Dec 2018 01:49:01 +0000 Subject: [PATCH 147/221] Swapped ad events placement. --- CHANGELOG.md | 4 ++ .../src/FacebookInstantGamesPlugin.js | 42 +++++++++++++++---- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index daecf0a17..6a29b54ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ * You can now pass an object or a string to `setScore` and objects will be automatically stringified. * The `preloadAds` method will now only create an AdInstance object if the interstitial `loadSync` promise resolves. * The `preloadVideoAds` method will now only create an AdInstance object if the interstitial `loadSync` promise resolves. +* The `preloadAds` method will now emit the `adsnofill` event, if there are no ads in the inventory to load. +* The `preloadVideoAds` method will now emit the `adsnofill` event, if there are no ads in the inventory to load. +* The `showAd` method will now emit the `adsnotloaded` event, if there are no ads loaded matching the given Placement ID. +* The `showVideo` method will now emit the `adsnotloaded` event, if there are no ads loaded matching the given Placement ID. ### Keyboard Input - New Features diff --git a/plugins/fbinstant/src/FacebookInstantGamesPlugin.js b/plugins/fbinstant/src/FacebookInstantGamesPlugin.js index 77d156822..fb132988a 100644 --- a/plugins/fbinstant/src/FacebookInstantGamesPlugin.js +++ b/plugins/fbinstant/src/FacebookInstantGamesPlugin.js @@ -1870,6 +1870,8 @@ var FacebookInstantGamesPlugin = new Class({ * Attempt to create an instance of an interstitial ad. * * If the instance is created successfully then the ad is preloaded ready for display in-game via the method `showAd()`. + * + * If the ad cannot be displayed because there was no inventory to fill it, it will emit the `adsnofill` event. * * @method Phaser.FacebookInstantGamesPlugin#preloadAds * @since 3.13.0 @@ -1926,7 +1928,18 @@ var FacebookInstantGamesPlugin = new Class({ }).catch(function (e) { - console.warn(e); + if (e.code === 'ADS_NO_FILL') + { + _this.emit('adsnofill'); + } + else if (e.code === 'ADS_FREQUENT_LOAD') + { + _this.emit('adsfrequentload'); + } + else + { + console.warn(e); + } }); } @@ -1937,6 +1950,8 @@ var FacebookInstantGamesPlugin = new Class({ * Attempt to create an instance of an interstitial video ad. * * If the instance is created successfully then the ad is preloaded ready for display in-game via the method `showVideo()`. + * + * If the ad cannot be displayed because there was no inventory to fill it, it will emit the `adsnofill` event. * * @method Phaser.FacebookInstantGamesPlugin#preloadVideoAds * @since 3.13.0 @@ -1993,7 +2008,18 @@ var FacebookInstantGamesPlugin = new Class({ }).catch(function (e) { - console.warn(e); + if (e.code === 'ADS_NO_FILL') + { + _this.emit('adsnofill'); + } + else if (e.code === 'ADS_FREQUENT_LOAD') + { + _this.emit('adsfrequentload'); + } + else + { + console.warn(e); + } }); } @@ -2005,7 +2031,7 @@ var FacebookInstantGamesPlugin = new Class({ * * If the ad is successfully displayed this plugin will emit the `showad` event, with the AdInstance object as its parameter. * - * If the ad cannot be displayed because there was no inventory to fill it, it will emit the `adsnofill` event. + * If the ad cannot be displayed, it will emit the `adsnotloaded` event. * * @method Phaser.FacebookInstantGamesPlugin#showAd * @since 3.13.0 @@ -2032,9 +2058,9 @@ var FacebookInstantGamesPlugin = new Class({ }).catch(function (e) { - if (e.code === 'ADS_NO_FILL') + if (e.code === 'ADS_NOT_LOADED') { - _this.emit('adsnofill'); + _this.emit('adsnotloaded'); } else { @@ -2052,7 +2078,7 @@ var FacebookInstantGamesPlugin = new Class({ * * If the ad is successfully displayed this plugin will emit the `showad` event, with the AdInstance object as its parameter. * - * If the ad cannot be displayed because there was no inventory to fill it, it will emit the `adsnofill` event. + * If the ad cannot be displayed, it will emit the `adsnotloaded` event. * * @method Phaser.FacebookInstantGamesPlugin#showVideo * @since 3.13.0 @@ -2079,9 +2105,9 @@ var FacebookInstantGamesPlugin = new Class({ }).catch(function (e) { - if (e.code === 'ADS_NO_FILL') + if (e.code === 'ADS_NOT_LOADED') { - _this.emit('adsnofill'); + _this.emit('adsnotloaded'); } else { From 06c6b280e79cba98006de7a7a4ddddcc3a3cf450 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 7 Dec 2018 04:29:18 +0000 Subject: [PATCH 148/221] New global adshowerror handler and better event flow. --- CHANGELOG.md | 1 + .../src/FacebookInstantGamesPlugin.js | 50 ++++++++++++------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a29b54ac..89af38797 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * The `preloadVideoAds` method will now emit the `adsnofill` event, if there are no ads in the inventory to load. * The `showAd` method will now emit the `adsnotloaded` event, if there are no ads loaded matching the given Placement ID. * The `showVideo` method will now emit the `adsnotloaded` event, if there are no ads loaded matching the given Placement ID. +* Showing an ad will emit the `adfinished` event when the ad is closed, previously this event was called `showad` but the new name better reflects what has happened. ### Keyboard Input - New Features diff --git a/plugins/fbinstant/src/FacebookInstantGamesPlugin.js b/plugins/fbinstant/src/FacebookInstantGamesPlugin.js index fb132988a..21ce8c54d 100644 --- a/plugins/fbinstant/src/FacebookInstantGamesPlugin.js +++ b/plugins/fbinstant/src/FacebookInstantGamesPlugin.js @@ -1871,6 +1871,8 @@ var FacebookInstantGamesPlugin = new Class({ * * If the instance is created successfully then the ad is preloaded ready for display in-game via the method `showAd()`. * + * If the ad loads it will emit the `adloaded` event, passing the AdInstance as the only parameter. + * * If the ad cannot be displayed because there was no inventory to fill it, it will emit the `adsnofill` event. * * @method Phaser.FacebookInstantGamesPlugin#preloadAds @@ -1924,17 +1926,21 @@ var FacebookInstantGamesPlugin = new Class({ }).then(function () { - _this.ads.push(AdInstance(id, data, false)); + var ad = AdInstance(id, data, false); + + _this.ads.push(ad); + + _this.emit('adloaded', ad); }).catch(function (e) { if (e.code === 'ADS_NO_FILL') { - _this.emit('adsnofill'); + _this.emit('adsnofill', id); } else if (e.code === 'ADS_FREQUENT_LOAD') { - _this.emit('adsfrequentload'); + _this.emit('adsfrequentload', id); } else { @@ -1947,10 +1953,12 @@ var FacebookInstantGamesPlugin = new Class({ }, /** - * Attempt to create an instance of an interstitial video ad. + * Attempt to create an instance of an rewarded video ad. * * If the instance is created successfully then the ad is preloaded ready for display in-game via the method `showVideo()`. * + * If the ad loads it will emit the `adloaded` event, passing the AdInstance as the only parameter. + * * If the ad cannot be displayed because there was no inventory to fill it, it will emit the `adsnofill` event. * * @method Phaser.FacebookInstantGamesPlugin#preloadVideoAds @@ -2004,17 +2012,21 @@ var FacebookInstantGamesPlugin = new Class({ }).then(function () { - _this.ads.push(AdInstance(id, data, true)); + var ad = AdInstance(id, data, true); + + _this.ads.push(ad); + + _this.emit('adloaded', ad); }).catch(function (e) { if (e.code === 'ADS_NO_FILL') { - _this.emit('adsnofill'); + _this.emit('adsnofill', id); } else if (e.code === 'ADS_FREQUENT_LOAD') { - _this.emit('adsfrequentload'); + _this.emit('adsfrequentload', id); } else { @@ -2029,7 +2041,7 @@ var FacebookInstantGamesPlugin = new Class({ /** * Displays a previously loaded interstitial ad. * - * If the ad is successfully displayed this plugin will emit the `showad` event, with the AdInstance object as its parameter. + * If the ad is successfully displayed this plugin will emit the `adfinished` event, with the AdInstance object as its parameter. * * If the ad cannot be displayed, it will emit the `adsnotloaded` event. * @@ -2054,18 +2066,20 @@ var FacebookInstantGamesPlugin = new Class({ { ad.shown = true; - _this.emit('showad', ad); + _this.emit('adfinished', ad); }).catch(function (e) { if (e.code === 'ADS_NOT_LOADED') { - _this.emit('adsnotloaded'); + _this.emit('adsnotloaded', ad); } - else + else if (e.code === 'RATE_LIMITED') { - console.warn(e); + _this.emit('adratelimited', ad); } + + _this.emit('adshowerror', e, ad); }); } } @@ -2076,7 +2090,7 @@ var FacebookInstantGamesPlugin = new Class({ /** * Displays a previously loaded interstitial video ad. * - * If the ad is successfully displayed this plugin will emit the `showad` event, with the AdInstance object as its parameter. + * If the ad is successfully displayed this plugin will emit the `adfinished` event, with the AdInstance object as its parameter. * * If the ad cannot be displayed, it will emit the `adsnotloaded` event. * @@ -2101,18 +2115,20 @@ var FacebookInstantGamesPlugin = new Class({ { ad.shown = true; - _this.emit('showad', ad); + _this.emit('adfinished', ad); }).catch(function (e) { if (e.code === 'ADS_NOT_LOADED') { - _this.emit('adsnotloaded'); + _this.emit('adsnotloaded', ad); } - else + else if (e.code === 'RATE_LIMITED') { - console.warn(e); + _this.emit('adratelimited', ad); } + + _this.emit('adshowerror', e, ad); }); } } From 50502cfb63cb72335c8e1905e8e96d5e0302946a Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 7 Dec 2018 19:28:25 +0000 Subject: [PATCH 149/221] Added emitOnRepeat boolean --- src/input/keyboard/KeyboardPlugin.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/input/keyboard/KeyboardPlugin.js b/src/input/keyboard/KeyboardPlugin.js index 8cca87588..fca90d85a 100644 --- a/src/input/keyboard/KeyboardPlugin.js +++ b/src/input/keyboard/KeyboardPlugin.js @@ -435,12 +435,14 @@ var KeyboardPlugin = new Class({ * * @param {(object|string)} keys - An object containing Key Codes, or a comma-separated string. * @param {boolean} [enableCapture=true] - Automatically call `preventDefault` on the native DOM browser event for the key codes being added. + * @param {boolean} [emitOnRepeat=false] - Controls if the Key will continuously emit a 'down' event while being held down (true), or emit the event just once (false, the default). * * @return {object} An object containing Key objects mapped to the input properties. */ - addKeys: function (keys, enableCapture) + addKeys: function (keys, enableCapture, emitOnRepeat) { if (enableCapture === undefined) { enableCapture = true; } + if (emitOnRepeat === undefined) { emitOnRepeat = false; } var output = {}; @@ -454,7 +456,7 @@ var KeyboardPlugin = new Class({ if (currentKey) { - output[currentKey] = this.addKey(currentKey); + output[currentKey] = this.addKey(currentKey, enableCapture, emitOnRepeat); } } } @@ -462,7 +464,7 @@ var KeyboardPlugin = new Class({ { for (var key in keys) { - output[key] = this.addKey(keys[key]); + output[key] = this.addKey(keys[key], enableCapture, emitOnRepeat); } } @@ -481,12 +483,14 @@ var KeyboardPlugin = new Class({ * * @param {(Phaser.Input.Keyboard.Key|string|integer)} key - Either a Key object, a string, such as `A` or `SPACE`, or a key code value. * @param {boolean} [enableCapture=true] - Automatically call `preventDefault` on the native DOM browser event for the key codes being added. + * @param {boolean} [emitOnRepeat=false] - Controls if the Key will continuously emit a 'down' event while being held down (true), or emit the event just once (false, the default). * * @return {Phaser.Input.Keyboard.Key} The newly created Key object, or a reference to it if it already existed in the keys array. */ - addKey: function (key, enableCapture) + addKey: function (key, enableCapture, emitOnRepeat) { if (enableCapture === undefined) { enableCapture = true; } + if (emitOnRepeat === undefined) { emitOnRepeat = false; } var keys = this.keys; @@ -508,6 +512,8 @@ var KeyboardPlugin = new Class({ this.addCapture(key.keyCode); } + key.setEmitOnRepeat(emitOnRepeat); + return key; } @@ -524,6 +530,8 @@ var KeyboardPlugin = new Class({ { this.addCapture(key); } + + keys[key].setEmitOnRepeat(emitOnRepeat); } return keys[key]; From 7d34db27530d6fbc26ef93642415cf9b604ed974 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 7 Dec 2018 19:28:38 +0000 Subject: [PATCH 150/221] Added clear region arguments --- src/textures/CanvasTexture.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/textures/CanvasTexture.js b/src/textures/CanvasTexture.js index 3f2104393..a96d4f476 100644 --- a/src/textures/CanvasTexture.js +++ b/src/textures/CanvasTexture.js @@ -301,16 +301,27 @@ var CanvasTexture = new Class({ }, /** - * Clears this Canvas Texture, resetting it back to transparent. + * Clears the given region of this Canvas Texture, resetting it back to transparent. + * If no region is given, the whole Canvas Texture is cleared. * * @method Phaser.Textures.CanvasTexture#clear * @since 3.7.0 + * + * @param {integer} [x=0] - The x coordinate of the top-left of the region to clear. + * @param {integer} [y=0] - The y coordinate of the top-left of the region to clear. + * @param {integer} [width] - The width of the region. + * @param {integer} [height] - The height of the region. * * @return {Phaser.Textures.CanvasTexture} The Canvas Texture. */ - clear: function () + clear: function (x, y, width, height) { - this.context.clearRect(0, 0, this.width, this.height); + if (x === undefined) { x = 0; } + if (y === undefined) { y = 0; } + if (width === undefined) { width = this.width; } + if (height === undefined) { height = this.height; } + + this.context.clearRect(x, y, width, height); return this.update(); }, From f1113358b844e213870cbfa2b75a4e940d51351a Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 7 Dec 2018 19:28:43 +0000 Subject: [PATCH 151/221] Update CHANGELOG.md --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eda65fb32..6891c08ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,7 +54,8 @@ one set of bindings ever created, which makes things a lot cleaner. * The Keyboard Manager will now call `preventDefault` only on non-modified key presses, stopping the keyboard event from hitting the browser. Previously, capturing the R key, for example, would block a CTRL+R page reload, but it now ignores it because of the key modifier. * `Key.emitOnRepeat` is a new boolean property that controls if the Key will continuously emit a `down` event while being held down (true), or emit the event just once, on first press, and then skip future events (false). * `Key.setEmitOnRepeat` is a new chainable method for setting the `emitOnRepeat` property. -* The keyboard event flow has changed. +* The `KeyboardPlugin.addKeys` method has a new optional boolean `emitOnRepeat` which sets that property on all Key objects it creates as part of the call. It defaults to `false`. +* The `KeyboardPlugin.addKey` method has a new optional boolean `emitOnRepeat` which sets that property on the Key object it creates. It defaults to `false`. * The `Key` class now extends EventEmitter and emits two events directly: `down` and `up`. This means you can listen for an event from a Key you've created, i.e.: `yourKey.on('up', handler)`. * The following Key Codes have been added, which include some missing alphabet letters in Persian and Arabic: `SEMICOLON_FIREFOX`, `COLON`, `COMMA_FIREFOX_WINDOWS`, `COMMA_FIREFOX`, `BRACKET_RIGHT_FIREFOX` and `BRACKET_LEFT_FIREFOX` (thanks @wmateam) * `Key.onDown` is a new method that handles the Key being pressed down, including down repeats. @@ -174,6 +175,7 @@ one set of bindings ever created, which makes things a lot cleaner. * `ArcadePhysics.Body.destroy` will now only add itself to the World `pendingDestroy` list if the world property exists. This prevents `Cannot read property 'pendingDestroy' of undefined` errors if you try to delete a physics body in a callback and then immediately change Scene (which tells the physics work to also delete all bodies) * The Animation Component `restart` method has had is sole `key` argument removed. Previously, you had to pass in the key of the animation you wished to reverse, but now you can just call the method directly, and as long as there is an animation playing, it will automatically start playing in reverse, without the nee for a key (the way it should have been originally) * `Animation.play` and `playReverse` will now accept either a string-based key of the animation to play (like before), or you can pass in an Animation instance, and it will play that animation. +* `CanvasTexture.clear` now has 4 new optional arguments: `x, y, width, height` which allow you to define the region of the texture to be cleared. If not provided it will clear the whole texture, which is the same behavior as before. ### Bug Fixes From 8e495da71d7ce7ec7a71992fb1ac7036e7c1a852 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Sat, 8 Dec 2018 11:37:26 +0000 Subject: [PATCH 152/221] Fixed currentScissor assignment order of operation --- src/renderer/webgl/WebGLRenderer.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index e01b7a274..12b4d7efc 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -839,10 +839,10 @@ var WebGLRenderer = new Class({ scissorStack.push(scissor); - this.setScissor(x, y, width, height); - this.currentScissor = scissor; + this.setScissor(x, y, width, height); + return scissor; }, @@ -877,7 +877,6 @@ var WebGLRenderer = new Class({ if (width > 0 && height > 0) { gl.scissor(x, (this.drawingBufferHeight - y - height), width, height); - } } }, From c3524b345fc6f8fa6f90854d11436feed8aca0ee Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Sat, 8 Dec 2018 13:10:55 +0000 Subject: [PATCH 153/221] Added CanvasTexture.drawFrame method. --- CHANGELOG.md | 1 + src/textures/CanvasTexture.js | 39 +++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3f839035..1a3e76998 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -154,6 +154,7 @@ one set of bindings ever created, which makes things a lot cleaner. * The Animation class now emits the `restart` event when it restarts playing on any Game Object. * The Animation class now emits the `complete` event when it finishes playing on any Game Object. * The Animation Component has a new method called `chain` which allows you to line-up another animation to start playing as soon as the current one stops, no matter how it stops (either by reaching its natural end, or directly by having stop called on it). You can chain a new animation at any point, including before the current one starts playing, during it, or when it ends (via its `animationcomplete` callback). Chained animations are specific to a Game Object, meaning different Game Objects can have different chained animations without impacting the global animation they're playing. +* `CanvasTexture.drawFrame` is a new method that allows you to draw a texture frame to the CanvasTexture based on the texture key and frame given. ### Updates diff --git a/src/textures/CanvasTexture.js b/src/textures/CanvasTexture.js index a96d4f476..96ea82df0 100644 --- a/src/textures/CanvasTexture.js +++ b/src/textures/CanvasTexture.js @@ -223,6 +223,45 @@ var CanvasTexture = new Class({ return this.update(); }, + /** + * Draws the given texture frame to this CanvasTexture, then updates the internal + * ImageData buffer and arrays. + * + * @method Phaser.Textures.CanvasTexture#drawFrame + * @since 3.16.0 + * + * @param {string} key - The unique string-based key of the Texture. + * @param {(string|integer)} [frame] - The string-based name, or integer based index, of the Frame to get from the Texture. + * @param {integer} [x=0] - The x coordinate to draw the source at. + * @param {integer} [y=0] - The y coordinate to draw the source at. + * + * @return {Phaser.Textures.CanvasTexture} This CanvasTexture. + */ + drawFrame: function (key, frame, x, y) + { + if (x === undefined) { x = 0; } + if (y === undefined) { y = 0; } + + var frame = this.manager.getFrame(key, frame); + + if (frame) + { + var cd = frame.canvasData; + + var frameWidth = frame.cutWidth; + var frameHeight = frame.cutHeight; + var res = frame.source.resolution; + + this.context.drawImage(frame.source.image, cd.x, cd.y, frameWidth, frameHeight, x, y, frameWidth / res, frameHeight / res); + + return this.update(); + } + else + { + return this; + } + }, + /** * Get the color of a specific pixel from this texture and store it in a Color object. * From 84bf2e5e9392f2a14a8481000b810f062c72834a Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Sat, 8 Dec 2018 14:59:07 +0000 Subject: [PATCH 154/221] lint fix --- src/textures/CanvasTexture.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/textures/CanvasTexture.js b/src/textures/CanvasTexture.js index 96ea82df0..8272a61c5 100644 --- a/src/textures/CanvasTexture.js +++ b/src/textures/CanvasTexture.js @@ -242,17 +242,25 @@ var CanvasTexture = new Class({ if (x === undefined) { x = 0; } if (y === undefined) { y = 0; } - var frame = this.manager.getFrame(key, frame); + var textureFrame = this.manager.getFrame(key, frame); - if (frame) + if (textureFrame) { - var cd = frame.canvasData; + var cd = textureFrame.canvasData; - var frameWidth = frame.cutWidth; - var frameHeight = frame.cutHeight; - var res = frame.source.resolution; + var width = textureFrame.cutWidth; + var height = textureFrame.cutHeight; + var res = textureFrame.source.resolution; - this.context.drawImage(frame.source.image, cd.x, cd.y, frameWidth, frameHeight, x, y, frameWidth / res, frameHeight / res); + this.context.drawImage( + textureFrame.source.image, + cd.x, cd.y, + width, + height, + x, y, + width / res, + height / res + ); return this.update(); } From a62f01e97c57b0d679cb8c7cd1725d08958faed3 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Sat, 8 Dec 2018 15:02:52 +0000 Subject: [PATCH 155/221] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a3e76998..a2ab79e52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -223,7 +223,7 @@ one set of bindings ever created, which makes things a lot cleaner. Thanks to the following for helping with the Phaser 3 Examples and TypeScript definitions, either by reporting errors, or even better, fixing them: -@guilhermehto @samvieten @darkwebdev @RoryO +@guilhermehto @samvieten @darkwebdev @RoryO @snowbillr @slothyrulez ### Phaser Doc Jam From dc2f6153b4e7b9527107d7edb0c80bf7407102e2 Mon Sep 17 00:00:00 2001 From: Bryan Date: Mon, 10 Dec 2018 14:24:22 +1000 Subject: [PATCH 156/221] Change JSDoc @type from any to Phaser.FacebookInstantGamesPlugin This matches the definition in Phaser.Game --- src/scene/Systems.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scene/Systems.js b/src/scene/Systems.js index ad51edd1c..ef07b5cd7 100644 --- a/src/scene/Systems.js +++ b/src/scene/Systems.js @@ -58,7 +58,7 @@ var Systems = new Class({ * The Facebook Instant Games Plugin. * * @name Phaser.Scenes.Systems#facebook - * @type {any} + * @type {Phaser.FacebookInstantGamesPlugin} * @since 3.12.0 */ this.facebook; From d35e30dc6be8cd7f628bc799da9494bd45d0961c Mon Sep 17 00:00:00 2001 From: Bryan Date: Mon, 10 Dec 2018 15:21:34 +1000 Subject: [PATCH 157/221] Add facebook plugin to Phaser.Scene for JSDoc --- src/scene/Scene.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/scene/Scene.js b/src/scene/Scene.js index a4b9efd41..aad2c600a 100644 --- a/src/scene/Scene.js +++ b/src/scene/Scene.js @@ -242,6 +242,18 @@ var Scene = new Class({ * @since 3.0.0 */ this.matter; + + if(typeof PLUGIN_FBINSTANT){ + /** + * A scene level Facebook Instant Games Plugin. + * This property will only be available if defined in the Scene Injection Map, the plugin is installed and configured. + * + * @name Phaser.Scene#facebook + * @type {Phaser.FacebookInstantGamesPlugin} + * @since 3.12.0 + */ + this.facebook; + } }, /** From 24ffe623cd026a3a559b008b8d859dee9daaf5c2 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 10 Dec 2018 15:57:50 +0000 Subject: [PATCH 158/221] Update README.md --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2c6125750..ae2391003 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ Also, please subscribe to the [Phaser World](https://phaser.io/community/newslet ### Facebook Instant Games -Phaser 3.13 introduced the new [Facebook Instant Games](https://developers.facebook.com/docs/games/instant-games) Plugin. The plugin provides a seamless bridge between Phaser and version 6.2 of the Facebook Instant Games SDK. Every single SDK function is available via the plugin and we will keep track of the official SDK to make sure they stay in sync. +Phaser 3.13 introduced the new [Facebook Instant Games](http://phaser.io/news/2018/10/facebook-instant-games-phaser-tutorial) Plugin. The plugin provides a seamless bridge between Phaser and version 6.2 of the Facebook Instant Games SDK. Every single SDK function is available via the plugin and we will keep track of the official SDK to make sure they stay in sync. The plugin offers the following features: @@ -177,6 +177,12 @@ The plugin offers the following features: * Easily preload a set of interstitial ads, in both banner and video form, then display the ad at any point in your game, with in-built tracking of ads displayed and inventory available. * Plus other features, such as logging to FB Analytics, creating short cuts, switching games, etc. +We've 3 tutorials related to Facebook Instant Games and Phaser: + +* [Getting Started with Facebook Instant Games](http://phaser.io/news/2018/10/facebook-instant-games-phaser-tutorial) +* [Facebook Instant Games Leaderboards Tutorial](http://phaser.io/news/2018/11/facebook-instant-games-leaderboards-tutorial) +* [Displaying Ads in your Instant Games](http://phaser.io/news/2018/12/facebook-instant-games-ads-tutorial) + A special build of Phaser with the Facebook Instant Games Plugin ready-enabled is [available on jsDelivr](https://www.jsdelivr.com/projects/phaser). Include the following in your html: ```html @@ -382,8 +388,8 @@ All rights reserved. "Above all, video games are meant to be just one thing: fun. Fun for everyone." - Satoru Iwata -[get-js]: https://github.com/photonstorm/phaser/releases/download/v3.11/phaser.js -[get-minjs]: https://github.com/photonstorm/phaser/releases/download/v3.11/phaser.min.js +[get-js]: https://github.com/photonstorm/phaser/releases/download/v3.15.1/phaser.js +[get-minjs]: https://github.com/photonstorm/phaser/releases/download/v3.15.1/phaser.min.js [clone-http]: https://github.com/photonstorm/phaser.git [clone-ssh]: git@github.com:photonstorm/phaser.git [clone-ghwin]: github-windows://openRepo/https://github.com/photonstorm/phaser @@ -392,4 +398,4 @@ All rights reserved. [issues]: https://github.com/photonstorm/phaser/issues [examples]: https://github.com/photonstorm/phaser3-examples [contribute]: https://github.com/photonstorm/phaser/blob/master/.github/CONTRIBUTING.md -[forum]: http://www.html5gamedevs.com/forum/33-phaser-3/ +[forum]: https://phaser.discourse.group/ From 27c1426856a545ac25b2b6189ce904efcfc854f5 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 10 Dec 2018 16:35:11 +0000 Subject: [PATCH 159/221] Updated earcut from 2.1.1 to 2.1.4. --- CHANGELOG.md | 1 + src/geom/polygon/Earcut.js | 122 +++++++++++++++++++------------------ 2 files changed, 65 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2ab79e52..417e7752a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -184,6 +184,7 @@ one set of bindings ever created, which makes things a lot cleaner. * The Animation Component `restart` method has had is sole `key` argument removed. Previously, you had to pass in the key of the animation you wished to reverse, but now you can just call the method directly, and as long as there is an animation playing, it will automatically start playing in reverse, without the nee for a key (the way it should have been originally) * `Animation.play` and `playReverse` will now accept either a string-based key of the animation to play (like before), or you can pass in an Animation instance, and it will play that animation. * `CanvasTexture.clear` now has 4 new optional arguments: `x, y, width, height` which allow you to define the region of the texture to be cleared. If not provided it will clear the whole texture, which is the same behavior as before. +* EarCut, the polygon triangulation library used by the Graphics and WebGL classes, has been upgraded from 2.1.1 to 2.1.4. 2.1.2 fixed a few race conditions where bad input would cause an error. 2.1.3 improved performance for bigger inputs (5-12%) and 2.1.4 fixed a race condition that could lead to a freeze on degenerate input. ### Bug Fixes diff --git a/src/geom/polygon/Earcut.js b/src/geom/polygon/Earcut.js index 31f1f8b96..9a190b56c 100644 --- a/src/geom/polygon/Earcut.js +++ b/src/geom/polygon/Earcut.js @@ -4,37 +4,30 @@ * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ -// 2.1.1 (Mar 17, 2016) +// Earcut 2.1.4 (December 4th 2018) /* -ISC License - -Copyright (c) 2016, Mapbox - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. + * ISC License + * + * Copyright (c) 2016, Mapbox + * + * Permission to use, copy, modify, and/or distribute this software for any purpose + * with or without fee is hereby granted, provided that the above copyright notice + * and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + * THIS SOFTWARE. */ 'use strict'; module.exports = earcut; -/* -vertices is a flat array of vertice coordinates like [x0,y0, x1,y1, x2,y2, ...]. -holes is an array of hole indices if any (e.g. [5, 8] for a 12-vertice input would mean one hole with vertices 5–7 and another with 8–11). -dimensions is the number of coordinates per vertice in the input array (2 by default). -Each group of three vertice indices in the resulting array forms a triangle. - */ - function earcut(data, holeIndices, dim) { dim = dim || 2; @@ -44,9 +37,9 @@ function earcut(data, holeIndices, dim) { outerNode = linkedList(data, 0, outerLen, dim, true), triangles = []; - if (!outerNode) return triangles; + if (!outerNode || outerNode.next === outerNode.prev) return triangles; - var minX, minY, maxX, maxY, x, y, size; + var minX, minY, maxX, maxY, x, y, invSize; if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim); @@ -64,11 +57,12 @@ function earcut(data, holeIndices, dim) { if (y > maxY) maxY = y; } - // minX, minY and size are later used to transform coords into integers for z-order calculation - size = Math.max(maxX - minX, maxY - minY); + // minX, minY and invSize are later used to transform coords into integers for z-order calculation + invSize = Math.max(maxX - minX, maxY - minY); + invSize = invSize !== 0 ? 1 / invSize : 0; } - earcutLinked(outerNode, triangles, dim, minX, minY, size); + earcutLinked(outerNode, triangles, dim, minX, minY, invSize); return triangles; } @@ -104,7 +98,7 @@ function filterPoints(start, end) { if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) { removeNode(p); p = end = p.prev; - if (p === p.next) return null; + if (p === p.next) break; again = true; } else { @@ -116,11 +110,11 @@ function filterPoints(start, end) { } // main ear slicing loop which triangulates a polygon (given as a linked list) -function earcutLinked(ear, triangles, dim, minX, minY, size, pass) { +function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) { if (!ear) return; // interlink polygon nodes in z-order - if (!pass && size) indexCurve(ear, minX, minY, size); + if (!pass && invSize) indexCurve(ear, minX, minY, invSize); var stop = ear, prev, next; @@ -130,7 +124,7 @@ function earcutLinked(ear, triangles, dim, minX, minY, size, pass) { prev = ear.prev; next = ear.next; - if (size ? isEarHashed(ear, minX, minY, size) : isEar(ear)) { + if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) { // cut off the triangle triangles.push(prev.i / dim); triangles.push(ear.i / dim); @@ -138,7 +132,7 @@ function earcutLinked(ear, triangles, dim, minX, minY, size, pass) { removeNode(ear); - // skipping the next vertice leads to less sliver triangles + // skipping the next vertex leads to less sliver triangles ear = next.next; stop = next.next; @@ -151,16 +145,16 @@ function earcutLinked(ear, triangles, dim, minX, minY, size, pass) { if (ear === stop) { // try filtering points and slicing again if (!pass) { - earcutLinked(filterPoints(ear), triangles, dim, minX, minY, size, 1); + earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1); // if this didn't work, try curing all small self-intersections locally } else if (pass === 1) { ear = cureLocalIntersections(ear, triangles, dim); - earcutLinked(ear, triangles, dim, minX, minY, size, 2); + earcutLinked(ear, triangles, dim, minX, minY, invSize, 2); // as a last resort, try splitting the remaining polygon into two } else if (pass === 2) { - splitEarcut(ear, triangles, dim, minX, minY, size); + splitEarcut(ear, triangles, dim, minX, minY, invSize); } break; @@ -188,7 +182,7 @@ function isEar(ear) { return true; } -function isEarHashed(ear, minX, minY, size) { +function isEarHashed(ear, minX, minY, invSize) { var a = ear.prev, b = ear, c = ear.next; @@ -202,22 +196,26 @@ function isEarHashed(ear, minX, minY, size) { maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y); // z-order range for the current triangle bbox; - var minZ = zOrder(minTX, minTY, minX, minY, size), - maxZ = zOrder(maxTX, maxTY, minX, minY, size); + var minZ = zOrder(minTX, minTY, minX, minY, invSize), + maxZ = zOrder(maxTX, maxTY, minX, minY, invSize); - // first look for points inside the triangle in increasing z-order - var p = ear.nextZ; + var p = ear.prevZ, + n = ear.nextZ; - while (p && p.z <= maxZ) { + // look for points inside the triangle in both directions + while (p && p.z >= minZ && n && n.z <= maxZ) { if (p !== ear.prev && p !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false; - p = p.nextZ; + p = p.prevZ; + + if (n !== ear.prev && n !== ear.next && + pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) && + area(n.prev, n, n.next) >= 0) return false; + n = n.nextZ; } - // then look for points in decreasing z-order - p = ear.prevZ; - + // look for remaining points in decreasing z-order while (p && p.z >= minZ) { if (p !== ear.prev && p !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && @@ -225,6 +223,14 @@ function isEarHashed(ear, minX, minY, size) { p = p.prevZ; } + // look for remaining points in increasing z-order + while (n && n.z <= maxZ) { + if (n !== ear.prev && n !== ear.next && + pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) && + area(n.prev, n, n.next) >= 0) return false; + n = n.nextZ; + } + return true; } @@ -254,7 +260,7 @@ function cureLocalIntersections(start, triangles, dim) { } // try splitting polygon into two and triangulate them independently -function splitEarcut(start, triangles, dim, minX, minY, size) { +function splitEarcut(start, triangles, dim, minX, minY, invSize) { // look for a valid diagonal that divides the polygon into two var a = start; do { @@ -269,8 +275,8 @@ function splitEarcut(start, triangles, dim, minX, minY, size) { c = filterPoints(c, c.next); // run earcut on each half - earcutLinked(a, triangles, dim, minX, minY, size); - earcutLinked(c, triangles, dim, minX, minY, size); + earcutLinked(a, triangles, dim, minX, minY, invSize); + earcutLinked(c, triangles, dim, minX, minY, invSize); return; } b = b.next; @@ -376,10 +382,10 @@ function findHoleBridge(hole, outerNode) { } // interlink polygon nodes in z-order -function indexCurve(start, minX, minY, size) { +function indexCurve(start, minX, minY, invSize) { var p = start; do { - if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, size); + if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, invSize); p.prevZ = p.prev; p.nextZ = p.next; p = p.next; @@ -444,11 +450,11 @@ function sortLinked(list) { return list; } -// z-order of a point given coords and size of the data bounding box -function zOrder(x, y, minX, minY, size) { +// z-order of a point given coords and inverse of the longer side of data bbox +function zOrder(x, y, minX, minY, invSize) { // coords are transformed into non-negative 15-bit integer range - x = 32767 * (x - minX) / size; - y = 32767 * (y - minY) / size; + x = 32767 * (x - minX) * invSize; + y = 32767 * (y - minY) * invSize; x = (x | (x << 8)) & 0x00FF00FF; x = (x | (x << 4)) & 0x0F0F0F0F; @@ -590,14 +596,14 @@ function removeNode(p) { } function Node(i, x, y) { - // vertice index in coordinates array + // vertex index in coordinates array this.i = i; // vertex coordinates this.x = x; this.y = y; - // previous and next vertice nodes in a polygon ring + // previous and next vertex nodes in a polygon ring this.prev = null; this.next = null; @@ -666,4 +672,4 @@ earcut.flatten = function (data) { } } return result; -}; \ No newline at end of file +}; From c239700528d8d260764f2755d2c75d245f1803fd Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 11 Dec 2018 02:37:00 +0000 Subject: [PATCH 160/221] Added getIndex and getPixels methods. --- src/textures/CanvasTexture.js | 109 ++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 10 deletions(-) diff --git a/src/textures/CanvasTexture.js b/src/textures/CanvasTexture.js index 8272a61c5..e548870af 100644 --- a/src/textures/CanvasTexture.js +++ b/src/textures/CanvasTexture.js @@ -5,6 +5,7 @@ */ var Class = require('../utils/Class'); +var Clamp = require('../math/Clamp'); var Color = require('../display/color/Color'); var IsSizePowerOfTwo = require('../math/pow2/IsSizePowerOfTwo'); var Texture = require('./Texture'); @@ -279,9 +280,9 @@ var CanvasTexture = new Class({ * @method Phaser.Textures.CanvasTexture#getPixel * @since 3.13.0 * - * @param {integer} x - The x coordinate of the pixel to be set. Must lay within the dimensions of this CanvasTexture and be an integer. - * @param {integer} y - The y coordinate of the pixel to be set. Must lay within the dimensions of this CanvasTexture and be an integer. - * @param {Phaser.Display.Color} [out] - An object into which 4 properties will be set: r, g, b and a. If not provided a Color object will be created. + * @param {integer} x - The x coordinate of the pixel to get. Must lay within the dimensions of this CanvasTexture and be an integer. + * @param {integer} y - The y coordinate of the pixel to get. Must lay within the dimensions of this CanvasTexture and be an integer. + * @param {Phaser.Display.Color} [out] - A Color object to store the pixel values in. If not provided a new Color object will be created. * * @return {Phaser.Display.Color} An object with the red, green, blue and alpha values set in the r, g, b and a properties. */ @@ -292,16 +293,104 @@ var CanvasTexture = new Class({ out = new Color(); } - var index = ~~(x + (y * this.width)); + var index = this.getIndex(x, y); - index *= 4; + if (index > -1) + { + var data = this.data; - var r = this.data[index]; - var g = this.data[++index]; - var b = this.data[++index]; - var a = this.data[++index]; + var r = data[index + 0]; + var g = data[index + 1]; + var b = data[index + 2]; + var a = data[index + 3]; - return out.setTo(r, g, b, a); + out.setTo(r, g, b, a); + } + + return out; + }, + + /** + * Returns an array containing all of the pixels in the given region. + * + * If the requested region extends outside the bounds of this CanvasTexture, + * the region is truncated to fit. + * + * If you have drawn anything to this CanvasTexture since it was created you must call `CanvasTexture.update` to refresh the array buffer, + * otherwise this may return out of date color values, or worse - throw a run-time error as it tries to access an array element that doesn't exist. + * + * @method Phaser.Textures.CanvasTexture#getPixels + * @since 3.16.0 + * + * @param {integer} x - The x coordinate of the top-left of the region. Must lay within the dimensions of this CanvasTexture and be an integer. + * @param {integer} y - The y coordinate of the top-left of the region. Must lay within the dimensions of this CanvasTexture and be an integer. + * @param {integer} width - The width of the region to get. Must be an integer. + * @param {integer} [height] - The height of the region to get. Must be an integer. If not given will be set to the `width`. + * + * @return {any[]} An array of Pixel objects. + */ + getPixels: function (x, y, width, height) + { + if (height === undefined) { height = width; } + + x = Math.abs(Math.round(x)); + y = Math.abs(Math.round(y)); + + var left = Clamp(x, 0, this.width); + var right = Clamp(x + width, 0, this.width); + var top = Clamp(y, 0, this.height); + var bottom = Clamp(y + height, 0, this.height); + + var pixel = new Color(); + + var out = []; + + for (var py = top; py < bottom; py++) + { + var row = []; + + for (var px = left; px < right; px++) + { + var pixel = this.getPixel(px, py, pixel); + + row.push({ x: px, y: py, color: pixel.color, alpha: pixel.alpha }); + } + + out.push(row); + } + + return out; + }, + + /** + * Returns the Image Data index for the given pixel in this CanvasTexture. + * + * The index can be used to read directly from the `this.data` array. + * + * The index points to the red value in the array. The subsequent 3 indexes + * point to green, blue and alpha respectively. + * + * @method Phaser.Textures.CanvasTexture#getIndex + * @since 3.16.0 + * + * @param {integer} x - The x coordinate of the pixel to get. Must lay within the dimensions of this CanvasTexture and be an integer. + * @param {integer} y - The y coordinate of the pixel to get. Must lay within the dimensions of this CanvasTexture and be an integer. + * + * @return {integer} + */ + getIndex: function (x, y) + { + x = Math.abs(Math.round(x)); + y = Math.abs(Math.round(y)); + + if (x < this.width && y < this.height) + { + return (x + y * this.width) * 4; + } + else + { + return -1; + } }, /** From d9f89fbde1d2d507d8b17fe7d3a61f8f7fff4b2e Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 11 Dec 2018 09:31:56 +0000 Subject: [PATCH 161/221] Fixed lint error, added docs. --- CHANGELOG.md | 2 ++ src/textures/CanvasTexture.js | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 417e7752a..49862d4c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -155,6 +155,8 @@ one set of bindings ever created, which makes things a lot cleaner. * The Animation class now emits the `complete` event when it finishes playing on any Game Object. * The Animation Component has a new method called `chain` which allows you to line-up another animation to start playing as soon as the current one stops, no matter how it stops (either by reaching its natural end, or directly by having stop called on it). You can chain a new animation at any point, including before the current one starts playing, during it, or when it ends (via its `animationcomplete` callback). Chained animations are specific to a Game Object, meaning different Game Objects can have different chained animations without impacting the global animation they're playing. * `CanvasTexture.drawFrame` is a new method that allows you to draw a texture frame to the CanvasTexture based on the texture key and frame given. +* `CanvasTexture.getIndex` is a new method that will take an x/y coordinate and return the Image Data index offset used to retrieve the pixel values. +* `CanvasTexture.getPixels` is a new method that will take a region as an x/y and width/height and return all of the pixels in that region from the CanvasTexture. ### Updates diff --git a/src/textures/CanvasTexture.js b/src/textures/CanvasTexture.js index e548870af..1a6d3f7dc 100644 --- a/src/textures/CanvasTexture.js +++ b/src/textures/CanvasTexture.js @@ -310,6 +310,17 @@ var CanvasTexture = new Class({ return out; }, + /** + * An object containing the position and color data for a single pixel in a CanvasTexture. + * + * @typedef {object} Phaser.Textures.CanvasTexture.PixelConfig + * + * @property {integer} x - The x-coordinate of the pixel. + * @property {integer} y - The y-coordinate of the pixel. + * @property {integer} color - The color of the pixel, not including the alpha channel. + * @property {float} alpha - The alpha of the pixel, between 0 and 1. + */ + /** * Returns an array containing all of the pixels in the given region. * @@ -327,7 +338,7 @@ var CanvasTexture = new Class({ * @param {integer} width - The width of the region to get. Must be an integer. * @param {integer} [height] - The height of the region to get. Must be an integer. If not given will be set to the `width`. * - * @return {any[]} An array of Pixel objects. + * @return {Phaser.Textures.CanvasTexture.PixelConfig[]} An array of Pixel objects. */ getPixels: function (x, y, width, height) { @@ -351,9 +362,9 @@ var CanvasTexture = new Class({ for (var px = left; px < right; px++) { - var pixel = this.getPixel(px, py, pixel); + pixel = this.getPixel(px, py, pixel); - row.push({ x: px, y: py, color: pixel.color, alpha: pixel.alpha }); + row.push({ x: px, y: py, color: pixel.color, alpha: pixel.alphaGL }); } out.push(row); From 56837132533f4e890ee69a732b7f616fb4af6e5b Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 11 Dec 2018 14:59:50 +0000 Subject: [PATCH 162/221] Added flush argument --- src/renderer/webgl/WebGLRenderer.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index 12b4d7efc..472f76d99 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -1140,13 +1140,18 @@ var WebGLRenderer = new Class({ * * @return {this} This WebGLRenderer instance. */ - setTexture2D: function (texture, textureUnit) + setTexture2D: function (texture, textureUnit, flush) { + if (flush === undefined) { flush = true; } + var gl = this.gl; if (texture !== this.currentTextures[textureUnit]) { - this.flush(); + if (flush) + { + this.flush(); + } if (this.currentActiveTextureUnit !== textureUnit) { From bacff65177600b94c6f6a25a202cf5649049d658 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 11 Dec 2018 15:00:12 +0000 Subject: [PATCH 163/221] Refactoring texture batch creation --- .../webgl/pipelines/TextureTintPipeline.js | 126 ++++++++++-------- 1 file changed, 71 insertions(+), 55 deletions(-) diff --git a/src/renderer/webgl/pipelines/TextureTintPipeline.js b/src/renderer/webgl/pipelines/TextureTintPipeline.js index 86cf3341f..8737c3cce 100644 --- a/src/renderer/webgl/pipelines/TextureTintPipeline.js +++ b/src/renderer/webgl/pipelines/TextureTintPipeline.js @@ -278,11 +278,6 @@ var TextureTintPipeline = new Class({ this.mvpUpdate(); - if (this.batches.length === 0) - { - this.pushBatch(); - } - return this; }, @@ -308,58 +303,56 @@ var TextureTintPipeline = new Class({ }, /** - * Assigns a texture to the current batch. If a texture is already set it creates - * a new batch object. + * Assigns a texture to the current batch. If a different texture is already set it creates a new batch object. * * @method Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline#setTexture2D * @since 3.1.0 * - * @param {WebGLTexture} texture - WebGLTexture that will be assigned to the current batch. - * @param {integer} textureUnit - Texture unit to which the texture needs to be bound. + * @param {WebGLTexture} [texture] - WebGLTexture that will be assigned to the current batch. If not given uses blankTexture. + * @param {integer} [unit=0] - Texture unit to which the texture needs to be bound. * * @return {Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline} This pipeline instance. */ setTexture2D: function (texture, unit) { - if (!texture) + if (texture === undefined) { texture = this.renderer.blankTexture.glTexture; } + if (unit === undefined) { unit = 0; } + + if (this.requireTextureBatch(texture, unit)) { - texture = this.renderer.blankTexture.glTexture; - unit = 0; - } - - var batches = this.batches; - - if (batches.length === 0) - { - this.pushBatch(); - } - - var batch = batches[batches.length - 1]; - - if (unit > 0) - { - if (batch.textures[unit - 1] && - batch.textures[unit - 1] !== texture) - { - this.pushBatch(); - } - - batches[batches.length - 1].textures[unit - 1] = texture; - } - else - { - if (batch.texture !== null && - batch.texture !== texture) - { - this.pushBatch(); - } - - batches[batches.length - 1].texture = texture; + this.pushBatch(texture, unit); } return this; }, + /** + * Checks if the current batch has the same texture and texture unit, or if we need to create a new batch. + * + * @method Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline#requireTextureBatch + * @since 3.16.0 + * + * @param {WebGLTexture} texture - WebGLTexture that will be assigned to the current batch. If not given uses blankTexture. + * @param {integer} unit - Texture unit to which the texture needs to be bound. + * + * @return {boolean} `true` if the pipeline needs to create a new batch, otherwise `false`. + */ + requireTextureBatch: function (texture, unit) + { + var batches = this.batches; + var batchLength = batches.length; + + if (batchLength > 0) + { + // If Texture Unit specified, we get the texture from the textures array, otherwise we use the texture property + var currentTexture = (unit > 0) ? batches[batchLength - 1].textures[unit - 1] : batches[batchLength - 1].texture; + + return !(currentTexture === texture); + } + + return true; + }, + /** * Creates a new batch object and pushes it to a batch array. * The batch object contains information relevant to the current @@ -368,16 +361,32 @@ var TextureTintPipeline = new Class({ * * @method Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline#pushBatch * @since 3.1.0 + * + * @param {WebGLTexture} texture - Optional WebGLTexture that will be assigned to the created batch. + * @param {integer} unit - Texture unit to which the texture needs to be bound. */ - pushBatch: function () + pushBatch: function (texture, unit) { - var batch = { - first: this.vertexCount, - texture: null, - textures: [] - }; + if (unit === 0) + { + this.batches.push({ + first: this.vertexCount, + texture: texture, + textures: [] + }); + } + else + { + var textures = []; - this.batches.push(batch); + textures[unit - 1] = texture; + + this.batches.push({ + first: this.vertexCount, + texture: null, + textures: textures + }); + } }, /** @@ -420,11 +429,14 @@ var TextureTintPipeline = new Class({ gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.bytes.subarray(0, vertexCount * vertexSize)); + // Process the TEXTURE BATCHES + for (var index = 0; index < batchCount - 1; index++) { batch = batches[index]; batchNext = batches[index + 1]; + // Multi-texture check (for non-zero texture units) if (batch.textures.length > 0) { for (textureIndex = 0; textureIndex < batch.textures.length; ++textureIndex) @@ -433,7 +445,7 @@ var TextureTintPipeline = new Class({ if (nTexture) { - renderer.setTexture2D(nTexture, 1 + textureIndex); + renderer.setTexture2D(nTexture, 1 + textureIndex, false); } } @@ -442,12 +454,13 @@ var TextureTintPipeline = new Class({ batchVertexCount = batchNext.first - batch.first; + // Bail out if texture property is null (i.e. if a texture unit > 0) if (batch.texture === null || batchVertexCount <= 0) { continue; } - renderer.setTexture2D(batch.texture, 0); + renderer.setTexture2D(batch.texture, 0, false); gl.drawArrays(topology, batch.first, batchVertexCount); } @@ -455,6 +468,8 @@ var TextureTintPipeline = new Class({ // Left over data batch = batches[batchCount - 1]; + // Multi-texture check (for non-zero texture units) + if (batch.textures.length > 0) { for (textureIndex = 0; textureIndex < batch.textures.length; ++textureIndex) @@ -463,7 +478,7 @@ var TextureTintPipeline = new Class({ if (nTexture) { - renderer.setTexture2D(nTexture, 1 + textureIndex); + renderer.setTexture2D(nTexture, 1 + textureIndex, false); } } @@ -474,7 +489,7 @@ var TextureTintPipeline = new Class({ if (batch.texture && batchVertexCount > 0) { - renderer.setTexture2D(batch.texture, 0); + renderer.setTexture2D(batch.texture, 0, false); gl.drawArrays(topology, batch.first, batchVertexCount); } @@ -483,8 +498,6 @@ var TextureTintPipeline = new Class({ batches.length = 0; - this.pushBatch(); - this.flushLocked = false; return this; @@ -502,6 +515,7 @@ var TextureTintPipeline = new Class({ */ batchSprite: function (sprite, camera, parentTransformMatrix) { + // Will cause a flush if there are batchSize entries already this.renderer.setPipeline(this); var camMatrix = this._tempMatrix1; @@ -619,10 +633,12 @@ var TextureTintPipeline = new Class({ ty3 = Math.round(ty3); } + // Adds texture to batch (if not present) this.setTexture2D(texture, 0); var tintEffect = (sprite._isTinted && sprite.tintFill); + // Flushes batch if full, which can take the texture batch with it this.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect); }, From 69e6643800252ea7c8ddaacdb5c0f9adb59fde74 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 11 Dec 2018 23:22:00 +0000 Subject: [PATCH 164/221] Added setPixel method. --- src/textures/CanvasTexture.js | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/textures/CanvasTexture.js b/src/textures/CanvasTexture.js index e548870af..8e531d273 100644 --- a/src/textures/CanvasTexture.js +++ b/src/textures/CanvasTexture.js @@ -271,6 +271,47 @@ var CanvasTexture = new Class({ } }, + /** + * Sets a pixel in the CanvasTexture to the given color and alpha values. + * + * This is an expensive operation to run in large quantities, so use sparingly. + * + * @method Phaser.Textures.CanvasTexture#setPixel + * @since 3.16.0 + * + * @param {integer} x - The x coordinate of the pixel to get. Must lay within the dimensions of this CanvasTexture and be an integer. + * @param {integer} y - The y coordinate of the pixel to get. Must lay within the dimensions of this CanvasTexture and be an integer. + * @param {integer} red - The red color value. A number between 0 and 255. + * @param {integer} green - The green color value. A number between 0 and 255. + * @param {integer} blue - The blue color value. A number between 0 and 255. + * @param {integer} [alpha=255] - The alpha value. A number between 0 and 255. + * + * @return {this} This CanvasTexture. + */ + setPixel: function (x, y, red, green, blue, alpha) + { + if (alpha === undefined) { alpha = 255; } + + x = Math.abs(Math.floor(x)); + y = Math.abs(Math.floor(y)); + + var index = this.getIndex(x, y); + + if (index > -1) + { + var imageData = this.context.getImageData(x, y, 1, 1); + + imageData.data[0] = red; + imageData.data[1] = green; + imageData.data[2] = blue; + imageData.data[3] = alpha; + + this.context.putImageData(imageData, x, y); + } + + return this; + }, + /** * Get the color of a specific pixel from this texture and store it in a Color object. * From 4b27b37a0cb545654714ef5ac270cd05b0e24c7d Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Dec 2018 11:08:52 +0000 Subject: [PATCH 165/221] Added texture and unit arguments to `batchQuad` and `batchTri`, fixing the y2k bug. --- .../dynamic/DynamicBitmapTextWebGLRenderer.js | 2 +- .../static/BitmapTextWebGLRenderer.js | 2 +- .../blitter/BlitterWebGLRenderer.js | 2 +- .../particles/ParticleManagerWebGLRenderer.js | 5 +---- .../pipelines/ForwardDiffuseLightPipeline.js | 2 +- .../webgl/pipelines/TextureTintPipeline.js | 20 ++++++++++++------- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextWebGLRenderer.js b/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextWebGLRenderer.js index 42d98ec95..1dfa986f5 100644 --- a/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextWebGLRenderer.js +++ b/src/gameobjects/bitmaptext/dynamic/DynamicBitmapTextWebGLRenderer.js @@ -286,7 +286,7 @@ var DynamicBitmapTextWebGLRenderer = function (renderer, src, interpolationPerce ty3 = Math.round(ty3); } - pipeline.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect); + pipeline.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect, texture, 0); } if (crop) diff --git a/src/gameobjects/bitmaptext/static/BitmapTextWebGLRenderer.js b/src/gameobjects/bitmaptext/static/BitmapTextWebGLRenderer.js index 446dd30a2..8d95f99b0 100644 --- a/src/gameobjects/bitmaptext/static/BitmapTextWebGLRenderer.js +++ b/src/gameobjects/bitmaptext/static/BitmapTextWebGLRenderer.js @@ -216,7 +216,7 @@ var BitmapTextWebGLRenderer = function (renderer, src, interpolationPercentage, ty3 = Math.round(ty3); } - pipeline.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect); + pipeline.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect, texture, 0); } }; diff --git a/src/gameobjects/blitter/BlitterWebGLRenderer.js b/src/gameobjects/blitter/BlitterWebGLRenderer.js index ce98e5708..cd9c3cbf9 100644 --- a/src/gameobjects/blitter/BlitterWebGLRenderer.js +++ b/src/gameobjects/blitter/BlitterWebGLRenderer.js @@ -114,7 +114,7 @@ var BlitterWebGLRenderer = function (renderer, src, interpolationPercentage, cam } // TL x/y, BL x/y, BR x/y, TR x/y - if (pipeline.batchQuad(tx0, ty0, tx0, ty1, tx1, ty1, tx1, ty0, frame.u0, frame.v0, frame.u1, frame.v1, tint, tint, tint, tint, tintEffect)) + if (pipeline.batchQuad(tx0, ty0, tx0, ty1, tx1, ty1, tx1, ty0, frame.u0, frame.v0, frame.u1, frame.v1, tint, tint, tint, tint, tintEffect, frame.glTexture, 0)) { prevTextureSourceIndex = -1; } diff --git a/src/gameobjects/particles/ParticleManagerWebGLRenderer.js b/src/gameobjects/particles/ParticleManagerWebGLRenderer.js index 1c549ece4..809e07e66 100644 --- a/src/gameobjects/particles/ParticleManagerWebGLRenderer.js +++ b/src/gameobjects/particles/ParticleManagerWebGLRenderer.js @@ -133,10 +133,7 @@ var ParticleManagerWebGLRenderer = function (renderer, emitterManager, interpola var tint = getTint(particle.tint, alpha); - if (pipeline.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, frame.u0, frame.v0, frame.u1, frame.v1, tint, tint, tint, tint, tintEffect)) - { - pipeline.setTexture2D(texture, 0); - } + pipeline.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, frame.u0, frame.v0, frame.u1, frame.v1, tint, tint, tint, tint, tintEffect, texture, 0); } } }; diff --git a/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js b/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js index 198d7632b..4a86a02dc 100644 --- a/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js +++ b/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js @@ -377,7 +377,7 @@ var ForwardDiffuseLightPipeline = new Class({ this.setTexture2D(texture, 0); - this.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect); + this.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect, texture, 0); }, /** diff --git a/src/renderer/webgl/pipelines/TextureTintPipeline.js b/src/renderer/webgl/pipelines/TextureTintPipeline.js index 8737c3cce..047a7eee5 100644 --- a/src/renderer/webgl/pipelines/TextureTintPipeline.js +++ b/src/renderer/webgl/pipelines/TextureTintPipeline.js @@ -633,13 +633,11 @@ var TextureTintPipeline = new Class({ ty3 = Math.round(ty3); } - // Adds texture to batch (if not present) this.setTexture2D(texture, 0); var tintEffect = (sprite._isTinted && sprite.tintFill); - // Flushes batch if full, which can take the texture batch with it - this.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect); + this.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect, texture, 0); }, /** @@ -679,10 +677,12 @@ var TextureTintPipeline = new Class({ * @param {number} tintBL - The bottom-left tint color value. * @param {number} tintBR - The bottom-right tint color value. * @param {(number|boolean)} tintEffect - The tint effect for the shader to use. + * @param {WebGLTexture} [texture] - WebGLTexture that will be assigned to the current batch if a flush occurs. + * @param {integer} [unit=0] - Texture unit to which the texture needs to be bound. * * @return {boolean} `true` if this method caused the batch to flush, otherwise `false`. */ - batchQuad: function (x0, y0, x1, y1, x2, y2, x3, y3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect) + batchQuad: function (x0, y0, x1, y1, x2, y2, x3, y3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect, texture, unit) { var hasFlushed = false; @@ -691,6 +691,8 @@ var TextureTintPipeline = new Class({ this.flush(); hasFlushed = true; + + this.setTexture2D(texture, unit); } var vertexViewF32 = this.vertexViewF32; @@ -777,10 +779,12 @@ var TextureTintPipeline = new Class({ * @param {number} tintTR - The top-right tint color value. * @param {number} tintBL - The bottom-left tint color value. * @param {(number|boolean)} tintEffect - The tint effect for the shader to use. + * @param {WebGLTexture} [texture] - WebGLTexture that will be assigned to the current batch if a flush occurs. + * @param {integer} [unit=0] - Texture unit to which the texture needs to be bound. * * @return {boolean} `true` if this method caused the batch to flush, otherwise `false`. */ - batchTri: function (x1, y1, x2, y2, x3, y3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintEffect) + batchTri: function (x1, y1, x2, y2, x3, y3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintEffect, texture, unit) { var hasFlushed = false; @@ -788,6 +792,8 @@ var TextureTintPipeline = new Class({ { this.flush(); + this.setTexture2D(texture, unit); + hasFlushed = true; } @@ -1002,7 +1008,7 @@ var TextureTintPipeline = new Class({ this.setTexture2D(texture, 0); - this.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect); + this.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect, texture, 0); }, /** @@ -1060,7 +1066,7 @@ var TextureTintPipeline = new Class({ tint = Utils.getTintAppendFloatAlpha(tint, alpha); - this.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, frame.u0, frame.v0, frame.u1, frame.v1, tint, tint, tint, tint, 0); + this.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, frame.u0, frame.v0, frame.u1, frame.v1, tint, tint, tint, tint, 0, frame.glTexture, 0); }, /** From 05ffb5312fc5d449eaa291b2815380b2cc0470d2 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Dec 2018 11:09:00 +0000 Subject: [PATCH 166/221] Updated docs --- src/renderer/webgl/WebGLRenderer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index 472f76d99..1e45d369d 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -1137,6 +1137,7 @@ var WebGLRenderer = new Class({ * * @param {WebGLTexture} texture - The WebGL texture that needs to be bound. * @param {integer} textureUnit - The texture unit to which the texture will be bound. + * @param {boolean} [flush=true] - Will the current pipeline be flushed if this is a new texture, or not? * * @return {this} This WebGLRenderer instance. */ From 744bcf4791897ff7f3befdb0f05bb934f6733b3c Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Dec 2018 11:09:06 +0000 Subject: [PATCH 167/221] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49862d4c4..011d623f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -187,6 +187,10 @@ one set of bindings ever created, which makes things a lot cleaner. * `Animation.play` and `playReverse` will now accept either a string-based key of the animation to play (like before), or you can pass in an Animation instance, and it will play that animation. * `CanvasTexture.clear` now has 4 new optional arguments: `x, y, width, height` which allow you to define the region of the texture to be cleared. If not provided it will clear the whole texture, which is the same behavior as before. * EarCut, the polygon triangulation library used by the Graphics and WebGL classes, has been upgraded from 2.1.1 to 2.1.4. 2.1.2 fixed a few race conditions where bad input would cause an error. 2.1.3 improved performance for bigger inputs (5-12%) and 2.1.4 fixed a race condition that could lead to a freeze on degenerate input. +* `TextureTintPipeline.batchQuad` and `batchTri` have two new optional arguments `texture` and `unit` which are used to re-set the batch texture should the method cause a batch flush. +* `TextureTintPipeline.requireTextureBatch` is a new internal method that helps speed-up the creation of texture batches. It is used in conjunction with `setTexture2D` and `pushBatch`. +* `TextureTintPipeline.flush` and `TextureTintPipeline.pushBatch` have been optimized to handle zero based texture units as priority. They've also been refactored to avoid creation of empty texture batches. +* The `WebGLRenderer.setTexture2D` method has a new optional argument `flush` which controls if the pipeline is flushed if the given texture is new, or not. This is used internally to skip flushing during an existing flush. ### Bug Fixes @@ -221,6 +225,7 @@ one set of bindings ever created, which makes things a lot cleaner. * `Particle.resetPosition` is a new method that is called when a particle dies, preparing it ready for firing again in the future. * The Canvas `SetTransform` method would save the context state, but it wasn't restored at the end in the following Game Objects: Dynamic Bitmap Text, Graphics, Arc, Curve, Ellipse, Grid, IsoBox, IsoTriangle, Line, Polygon, Rectangle, Star and Triangle. These now all restore the context, meaning if you're using non-canvas sized cameras in Canvas mode, it will now render beyond just the first custom camera. * `Utils.Array.MoveUp` wouldn't let you move an array element to the top-most index in the array. This also impacted `Container.moveUp`. +* The Texture Tint Pipeline had a logic error that would cause every 2001st quad to either be invisible, or pick-up the texture of the 2000th quad by mistake. The `batchQuad` and `batchTri` methods how handle re-assigning the batch texture if they cause a batch flush as part of their process. ### Examples and TypeScript From 9ee0535621f471e7b3d1c8a62a9cfede0d9df2d2 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Dec 2018 11:10:31 +0000 Subject: [PATCH 168/221] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 011d623f0..c34747b84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -157,6 +157,7 @@ one set of bindings ever created, which makes things a lot cleaner. * `CanvasTexture.drawFrame` is a new method that allows you to draw a texture frame to the CanvasTexture based on the texture key and frame given. * `CanvasTexture.getIndex` is a new method that will take an x/y coordinate and return the Image Data index offset used to retrieve the pixel values. * `CanvasTexture.getPixels` is a new method that will take a region as an x/y and width/height and return all of the pixels in that region from the CanvasTexture. +* `CanvasTexture.setPixel` is a new method that sets the given pixel in the CanvasTexture to the color and alpha values provided. ### Updates From 193d1d5c73f565fe409e372e649a123c8e436c6f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Dec 2018 11:56:09 +0000 Subject: [PATCH 169/221] Docs update. --- src/animations/AnimationFrame.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/animations/AnimationFrame.js b/src/animations/AnimationFrame.js index 5639bcf10..f0994a31f 100644 --- a/src/animations/AnimationFrame.js +++ b/src/animations/AnimationFrame.js @@ -19,8 +19,7 @@ var Class = require('../utils/Class'); * A single frame in an Animation sequence. * * An AnimationFrame consists of a reference to the Texture it uses for rendering, references to other - * frames in the animation, and index data. It also has the ability to fire its own `onUpdate` callback - * and modify the animation timing. + * frames in the animation, and index data. It also has the ability to modify the animation timing. * * AnimationFrames are generated automatically by the Animation class. * From cc2981d5901f6c825d885ceae29227ed14786725 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Dec 2018 11:56:13 +0000 Subject: [PATCH 170/221] Update CHANGELOG.md --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c34747b84..449503351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ * The `showAd` method will now emit the `adsnotloaded` event, if there are no ads loaded matching the given Placement ID. * The `showVideo` method will now emit the `adsnotloaded` event, if there are no ads loaded matching the given Placement ID. * Showing an ad will emit the `adfinished` event when the ad is closed, previously this event was called `showad` but the new name better reflects what has happened. +* The Facebook Plugin is now available in the `Phaser.Scene` class template under the `facebook` property (thanks @bryanwood) ### Keyboard Input - New Features @@ -197,6 +198,7 @@ one set of bindings ever created, which makes things a lot cleaner. * The Rectangle Shape object wouldn't render if it didn't have a stroke, or any other objects on the display list (thanks mliko) * When using a font string instead of setting `fontFamily`, `fontSize` and `fontStyle` in either `Text.setStyle` or `setFont`, the style properties wouldn't get set. This isn't a problem while creating the text object, only if modifying it later (thanks @DotTheGreat) +* `Text.toJSON` wasn't saving the font style when using the "font" shorthand to create it. It now saves it correctly. Fix #4141 (thanks @divillysausages) * Disabling camera bounds and then moving the camera to an area in a Tilemap that did not have any tile information would throw an `Uncaught Reference error` as it tried to access tiles that did not exist (thanks @Siyalatas) * Fixed an issue where Sprite Sheets being extracted from a texture atlas would fail if the sheet was either just a single column or single row of sprites. Fix #4096 (thanks @Cirras) * If you created an Arcade Physics Group without passing a configuration object, and passing an array of non-standard children, it would throw a classType runtime error. It now creates a default config object correctly (thanks @pierpo) @@ -227,12 +229,13 @@ one set of bindings ever created, which makes things a lot cleaner. * The Canvas `SetTransform` method would save the context state, but it wasn't restored at the end in the following Game Objects: Dynamic Bitmap Text, Graphics, Arc, Curve, Ellipse, Grid, IsoBox, IsoTriangle, Line, Polygon, Rectangle, Star and Triangle. These now all restore the context, meaning if you're using non-canvas sized cameras in Canvas mode, it will now render beyond just the first custom camera. * `Utils.Array.MoveUp` wouldn't let you move an array element to the top-most index in the array. This also impacted `Container.moveUp`. * The Texture Tint Pipeline had a logic error that would cause every 2001st quad to either be invisible, or pick-up the texture of the 2000th quad by mistake. The `batchQuad` and `batchTri` methods how handle re-assigning the batch texture if they cause a batch flush as part of their process. +* Rotating Sprites that used a Normal Map wouldn't rotate the normal map with it, causing the lighting effects to become irregular. The normal map vectors are now rotated correctly (thanks @sercant for the PR and @fazzamatazz and @ysraelJMM for the report) ### Examples and TypeScript Thanks to the following for helping with the Phaser 3 Examples and TypeScript definitions, either by reporting errors, or even better, fixing them: -@guilhermehto @samvieten @darkwebdev @RoryO @snowbillr @slothyrulez +@guilhermehto @samvieten @darkwebdev @RoryO @snowbillr @slothyrulez @bryanwood @jestarray @matosummer @tfelix ### Phaser Doc Jam From bbe95d96d95e65fe8d8d71a231f56cd3e34819fc Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Dec 2018 11:58:58 +0000 Subject: [PATCH 171/221] Added jsdocs for #4137 --- .../pipelines/ForwardDiffuseLightPipeline.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js b/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js index 610474c33..9925b61d2 100644 --- a/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js +++ b/src/renderer/webgl/pipelines/ForwardDiffuseLightPipeline.js @@ -50,7 +50,12 @@ var ForwardDiffuseLightPipeline = new Class({ this.defaultNormalMap; /** - * Inverse rotation matrix for normal map rotation fixing. + * Inverse rotation matrix for normal map rotations. + * + * @name Phaser.Renderer.WebGL.Pipelines.ForwardDiffuseLightPipeline#inverseRotationMatrix + * @type {Float32Array} + * @private + * @since 3.16.0 */ this.inverseRotationMatrix = new Float32Array([ 1, 0, 0, @@ -425,11 +430,16 @@ var ForwardDiffuseLightPipeline = new Class({ /** * Rotates the normal map vectors inversely by the given angle. * Only works in 2D space. - * @param {number} rotation rotation in angles + * + * @method Phaser.Renderer.WebGL.Pipelines.ForwardDiffuseLightPipeline#setNormalMapRotation + * @since 3.16.0 + * + * @param {number} rotation - The angle of rotation in radians. */ setNormalMapRotation: function (rotation) { var inverseRotationMatrix = this.inverseRotationMatrix; + if (rotation) { var rot = -rotation; @@ -458,7 +468,6 @@ var ForwardDiffuseLightPipeline = new Class({ * @param {Phaser.GameObjects.Sprite} sprite - The texture-based Game Object to add to the batch. * @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera to use for the rendering transform. * @param {Phaser.GameObjects.Components.TransformMatrix} parentTransformMatrix - The transform matrix of the parent container, if set. - * */ batchSprite: function (sprite, camera, parentTransformMatrix) { From cc55ee73cf3df33fa388b8a639a565fa5da5c02f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Dec 2018 12:07:16 +0000 Subject: [PATCH 172/221] Changing `scaleX` or `scaleY` on a `MatterImage` or `MatterSprite` would cause the body scale to become distorted as the setters didn't use the correct factor when resetting the initial scale. Fix #4206 --- CHANGELOG.md | 1 + src/physics/matter-js/components/Transform.js | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 449503351..68aa7c19a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -230,6 +230,7 @@ one set of bindings ever created, which makes things a lot cleaner. * `Utils.Array.MoveUp` wouldn't let you move an array element to the top-most index in the array. This also impacted `Container.moveUp`. * The Texture Tint Pipeline had a logic error that would cause every 2001st quad to either be invisible, or pick-up the texture of the 2000th quad by mistake. The `batchQuad` and `batchTri` methods how handle re-assigning the batch texture if they cause a batch flush as part of their process. * Rotating Sprites that used a Normal Map wouldn't rotate the normal map with it, causing the lighting effects to become irregular. The normal map vectors are now rotated correctly (thanks @sercant for the PR and @fazzamatazz and @ysraelJMM for the report) +* Changing `scaleX` or `scaleY` on a `MatterImage` or `MatterSprite` would cause the body scale to become distorted as the setters didn't use the correct factor when resetting the initial scale. Fix #4206 (thanks @YannCaron) ### Examples and TypeScript diff --git a/src/physics/matter-js/components/Transform.js b/src/physics/matter-js/components/Transform.js index 7478c74da..c87159e8a 100644 --- a/src/physics/matter-js/components/Transform.js +++ b/src/physics/matter-js/components/Transform.js @@ -84,8 +84,9 @@ var Transform = { set: function (value) { - var factor = 1 / this._scaleX; - + var factorX = 1 / this._scaleX; + var factorY = 1 / this._scaleY; + this._scaleX = value; if (this._scaleX === 0) @@ -98,7 +99,7 @@ var Transform = { } // Reset Matter scale back to 1 (sigh) - Body.scale(this.body, factor, this._scaleY); + Body.scale(this.body, factorX, factorY); Body.scale(this.body, value, this._scaleY); } @@ -121,7 +122,8 @@ var Transform = { set: function (value) { - var factor = 1 / this._scaleY; + var factorX = 1 / this._scaleX; + var factorY = 1 / this._scaleY; this._scaleY = value; @@ -134,7 +136,7 @@ var Transform = { this.renderFlags |= _FLAG; } - Body.scale(this.body, this._scaleX, factor); + Body.scale(this.body, factorX, factorY); Body.scale(this.body, this._scaleX, value); } From af5b1f24276ab06a4fb570acc324b902a808a330 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Dec 2018 12:39:47 +0000 Subject: [PATCH 173/221] `StaticBody.reset` in Arcade Physics would ignore the `x` and `y` values given to it. If given, they're now used to reset the parent Game Object before the body is updated. Fix #4224 --- CHANGELOG.md | 1 + src/physics/arcade/StaticBody.js | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68aa7c19a..2706e992b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -231,6 +231,7 @@ one set of bindings ever created, which makes things a lot cleaner. * The Texture Tint Pipeline had a logic error that would cause every 2001st quad to either be invisible, or pick-up the texture of the 2000th quad by mistake. The `batchQuad` and `batchTri` methods how handle re-assigning the batch texture if they cause a batch flush as part of their process. * Rotating Sprites that used a Normal Map wouldn't rotate the normal map with it, causing the lighting effects to become irregular. The normal map vectors are now rotated correctly (thanks @sercant for the PR and @fazzamatazz and @ysraelJMM for the report) * Changing `scaleX` or `scaleY` on a `MatterImage` or `MatterSprite` would cause the body scale to become distorted as the setters didn't use the correct factor when resetting the initial scale. Fix #4206 (thanks @YannCaron) +* `StaticBody.reset` in Arcade Physics would ignore the `x` and `y` values given to it. If given, they're now used to reset the parent Game Object before the body is updated. Fix #4224 (thanks @samme) ### Examples and TypeScript diff --git a/src/physics/arcade/StaticBody.js b/src/physics/arcade/StaticBody.js index 2891788c6..d03aeaa8f 100644 --- a/src/physics/arcade/StaticBody.js +++ b/src/physics/arcade/StaticBody.js @@ -619,14 +619,14 @@ var StaticBody = new Class({ }, /** - * Updates this Static Body's position based on the current Game Object it is bound to. + * Resets this Body to the given coordinates. Also positions its parent Game Object to the same coordinates. * Similar to `updateFromGameObject`, but doesn't modify the Body's dimensions. * * @method Phaser.Physics.Arcade.StaticBody#reset * @since 3.0.0 * - * @param {number} x - The x coordinate to reset the body to. - * @param {number} y - The y coordinate to reset the body to. + * @param {number} [x] - The x coordinate to reset the body to. If not given will use the parent Game Object's coordinate. + * @param {number} [y] - The y coordinate to reset the body to. If not given will use the parent Game Object's coordinate. */ reset: function (x, y) { @@ -637,6 +637,8 @@ var StaticBody = new Class({ this.world.staticTree.remove(this); + gameObject.setPosition(x, y); + gameObject.getTopLeft(this.position); this.updateCenter(); From 7b478d2860ac06db7a4e885e51019ada44314990 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Dec 2018 13:14:59 +0000 Subject: [PATCH 174/221] lint fix --- src/scene/Scene.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scene/Scene.js b/src/scene/Scene.js index aad2c600a..3162ffd99 100644 --- a/src/scene/Scene.js +++ b/src/scene/Scene.js @@ -243,7 +243,8 @@ var Scene = new Class({ */ this.matter; - if(typeof PLUGIN_FBINSTANT){ + if (typeof PLUGIN_FBINSTANT) + { /** * A scene level Facebook Instant Games Plugin. * This property will only be available if defined in the Scene Injection Map, the plugin is installed and configured. From 17e7ddedf745b7248670ae6cbd8b9fc3ad80db46 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Dec 2018 13:15:04 +0000 Subject: [PATCH 175/221] Update CHANGELOG.md --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2706e992b..279ae7e2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -237,7 +237,7 @@ one set of bindings ever created, which makes things a lot cleaner. Thanks to the following for helping with the Phaser 3 Examples and TypeScript definitions, either by reporting errors, or even better, fixing them: -@guilhermehto @samvieten @darkwebdev @RoryO @snowbillr @slothyrulez @bryanwood @jestarray @matosummer @tfelix +@guilhermehto @samvieten @darkwebdev @RoryO @snowbillr @slothyrulez ### Phaser Doc Jam @@ -245,6 +245,10 @@ The Phaser Doc Jam was a community-backed effort to try and get the Phaser 3 API 16patsle - @gurungrahul2 - @icbat - @samme - @telinc1 - anandu pavanan - blackhawx - candelibas - Diego Romero - doronlinder - Elliott Wallace - eric - Georges Gabereau - Haobo Zhang - henriacle - jak6jak - Jake Jensen - James Van Roose - JamesSkemp - joelahoover - Joey - madclaws - marc136 - Mihail Ilinov - naum303 - NicolasRoehm - nuane - rejacobson - Robert Kowalski - rodri042 - rootasjey - sawamara - scottwestover - sir13tommy - stetso - therealsamf - Tigran - willblackmore - zenwaichi +Also, the following helped with the docs outside of the Doc Jam: + +@bryanwood @jestarray @matosummer @tfelix @imilo + ## Version 3.15.1 - Batou - 16th October 2018 * Re-enabled Input Manager resizing, which had been left disabled by mistake. From b8fbd0d2c0944e88deecb910ad8eecf94935b2c5 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 12 Dec 2018 16:50:04 +0000 Subject: [PATCH 176/221] keydown and keyup events now fire for every possible key, no matter if they exist in the KeyCodes list or not. --- CHANGELOG.md | 2 ++ src/input/keyboard/KeyboardManager.js | 2 +- src/input/keyboard/KeyboardPlugin.js | 14 ++++++++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 279ae7e2f..9dd5c5077 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ There is also the `stopPropagation()` function. This works in the same way as `s All the above also works for `keyup` events. +New in 3.16 is the ability to receive a global `keydown` or `keyup` event from any key on the keyboard. Previously, it would only emit the event if it came from one of the keys listed in the KeyCodes file. Now, those global events will fire for any key, regardless of location. + #### Keyboard Captures Key capturing is the way in which you stop a keyboard DOM event from activating anything else in the browser by calling `preventDefault` on it. For example, in tall web pages, pressing the SPACE BAR causes the page to scroll down. Obviously, if this is also the fire or jump button in your game, you don't want this to happen. So the key needs to be 'captured' to prevent it. Equally, you may wish to also capture the arrow keys, for similar reasons. Key capturing is done on a global level. If you set-up the capture of a key in one Scene, it will be captured globally across the whole game. diff --git a/src/input/keyboard/KeyboardManager.js b/src/input/keyboard/KeyboardManager.js index 9e658ee67..270dfb5ce 100644 --- a/src/input/keyboard/KeyboardManager.js +++ b/src/input/keyboard/KeyboardManager.js @@ -188,7 +188,7 @@ var KeyboardManager = new Class({ // Do nothing if event already handled return; } - + _this.queue.push(event); var modified = (event.altKey || event.ctrlKey || event.shiftKey || event.metaKey); diff --git a/src/input/keyboard/KeyboardPlugin.js b/src/input/keyboard/KeyboardPlugin.js index fca90d85a..69fda30b0 100644 --- a/src/input/keyboard/KeyboardPlugin.js +++ b/src/input/keyboard/KeyboardPlugin.js @@ -718,10 +718,13 @@ var KeyboardPlugin = new Class({ key.onDown(event); } - if (!event.cancelled && KeyMap[code] && (!key || !repeat)) + if (!event.cancelled && (!key || !repeat)) { // keydown_code event - this.emit('keydown_' + KeyMap[code], event); + if (KeyMap[code]) + { + this.emit('keydown_' + KeyMap[code], event); + } if (!event.cancelled) { @@ -738,10 +741,13 @@ var KeyboardPlugin = new Class({ key.onUp(event); } - if (!event.cancelled && KeyMap[code]) + if (!event.cancelled) { // keyup_code event - this.emit('keyup_' + KeyMap[code], event); + if (KeyMap[code]) + { + this.emit('keyup_' + KeyMap[code], event); + } if (!event.cancelled) { From caad527b299d77d104800b318825e3ff4afa12d5 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 13 Dec 2018 00:30:13 +0000 Subject: [PATCH 177/221] Added getData and putData methods. --- CHANGELOG.md | 2 ++ src/textures/CanvasTexture.js | 48 +++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dd5c5077..77c29e561 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -161,6 +161,8 @@ one set of bindings ever created, which makes things a lot cleaner. * `CanvasTexture.getIndex` is a new method that will take an x/y coordinate and return the Image Data index offset used to retrieve the pixel values. * `CanvasTexture.getPixels` is a new method that will take a region as an x/y and width/height and return all of the pixels in that region from the CanvasTexture. * `CanvasTexture.setPixel` is a new method that sets the given pixel in the CanvasTexture to the color and alpha values provided. +* `CanvasTexture.getData` is a new method that will extract an ImageData block from the CanvasTexture from the region given. +* `CanvasTexture.putData` is a new method that will put an ImageData block at the given coordinates in a CanvasTexture. ### Updates diff --git a/src/textures/CanvasTexture.js b/src/textures/CanvasTexture.js index 0dbf8a8c3..928e3204a 100644 --- a/src/textures/CanvasTexture.js +++ b/src/textures/CanvasTexture.js @@ -312,6 +312,54 @@ var CanvasTexture = new Class({ return this; }, + /** + * Puts the ImageData into the context of this CanvasTexture at the given coordinates. + * + * @method Phaser.Textures.CanvasTexture#putData + * @since 3.16.0 + * + * @param {ImageData} imageData - The ImageData to put at the given location. + * @param {integer} x - The x coordinate to put the imageData. Must lay within the dimensions of this CanvasTexture and be an integer. + * @param {integer} y - The y coordinate to put the imageData. Must lay within the dimensions of this CanvasTexture and be an integer. + * + * @return {this} This CanvasTexture. + */ + putData: function (imageData, x, y) + { + x = Math.abs(Math.floor(x)); + y = Math.abs(Math.floor(y)); + + this.context.putImageData(imageData, x, y); + + return this; + }, + + /** + * Gets an ImageData region from this CanvasTexture from the position and size specified. + * You can write this back using `CanvasTexture.putData`, or manipulate it. + * + * @method Phaser.Textures.CanvasTexture#getData + * @since 3.16.0 + * + * @param {integer} x - The x coordinate of the top-left of the area to get the ImageData from. Must lay within the dimensions of this CanvasTexture and be an integer. + * @param {integer} y - The y coordinate of the top-left of the area to get the ImageData from. Must lay within the dimensions of this CanvasTexture and be an integer. + * @param {integer} width - The width of the region to get. Must be an integer. + * @param {integer} height - The height of the region to get. Must be an integer. + * + * @return {ImageData} The ImageData extracted from this CanvasTexture. + */ + getData: function (x, y, width, height) + { + x = Clamp(Math.floor(x), 0, this.width - 1); + y = Clamp(Math.floor(y), 0, this.height - 1); + width = Clamp(width, 1, this.width - x); + height = Clamp(height, 1, this.height - y); + + var imageData = this.context.getImageData(x, y, width, height); + + return imageData; + }, + /** * Get the color of a specific pixel from this texture and store it in a Color object. * From a3d2ccf65c4dbf8e3ee0a9964c50690856d93fa8 Mon Sep 17 00:00:00 2001 From: "J.C" Date: Thu, 13 Dec 2018 17:17:02 +0800 Subject: [PATCH 178/221] doc improvement for typescript --- src/textures/TextureManager.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/textures/TextureManager.js b/src/textures/TextureManager.js index e78d5643d..8b83e77ed 100644 --- a/src/textures/TextureManager.js +++ b/src/textures/TextureManager.js @@ -320,7 +320,7 @@ var TextureManager = new Class({ * * @param {string} key - The unique string-based key of the Texture. * @param {HTMLImageElement} source - The source Image element. - * @param {HTMLImageElement} [dataSource] - An optional data Image element. + * @param {HTMLImageElement|HTMLCanvasElement} [dataSource] - An optional data Image element. * * @return {?Phaser.Textures.Texture} The Texture that was created, or `null` if the key is already in use. */ @@ -479,7 +479,7 @@ var TextureManager = new Class({ * @param {string} key - The unique string-based key of the Texture. * @param {HTMLImageElement} source - The source Image element. * @param {object} data - The Texture Atlas data. - * @param {HTMLImageElement} [dataSource] - An optional data Image element. + * @param {HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[]} [dataSource] - An optional data Image element. * * @return {?Phaser.Textures.Texture} The Texture that was created, or `null` if the key is already in use. */ @@ -507,7 +507,7 @@ var TextureManager = new Class({ * @param {string} key - The unique string-based key of the Texture. * @param {(HTMLImageElement|HTMLImageElement[])} source - The source Image element/s. * @param {(object|object[])} data - The Texture Atlas data/s. - * @param {HTMLImageElement} [dataSource] - An optional data Image element. + * @param {HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[]} [dataSource] - An optional data Image element. * * @return {?Phaser.Textures.Texture} The Texture that was created, or `null` if the key is already in use. */ @@ -559,7 +559,7 @@ var TextureManager = new Class({ * @param {string} key - The unique string-based key of the Texture. * @param {HTMLImageElement} source - The source Image element. * @param {object} data - The Texture Atlas data. - * @param {HTMLImageElement} [dataSource] - An optional data Image element. + * @param {HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[]} [dataSource] - An optional data Image element. * * @return {?Phaser.Textures.Texture} The Texture that was created, or `null` if the key is already in use. */ @@ -604,7 +604,7 @@ var TextureManager = new Class({ * @param {string} key - The unique string-based key of the Texture. * @param {HTMLImageElement} source - The source Image element. * @param {object} data - The Texture Atlas XML data. - * @param {HTMLImageElement} [dataSource] - An optional data Image element. + * @param {HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[]} [dataSource] - An optional data Image element. * * @return {?Phaser.Textures.Texture} The Texture that was created, or `null` if the key is already in use. */ @@ -639,7 +639,7 @@ var TextureManager = new Class({ * @param {string} key - The unique string-based key of the Texture. * @param {HTMLImageElement} source - The source Image element. * @param {object} data - The Texture Atlas data. - * @param {HTMLImageElement} [dataSource] - An optional data Image element. + * @param {HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[]} [dataSource] - An optional data Image element. * * @return {?Phaser.Textures.Texture} The Texture that was created, or `null` if the key is already in use. */ From b6c2934e651c3902cca67757c1eeed13f511e1a5 Mon Sep 17 00:00:00 2001 From: "J.C" Date: Thu, 13 Dec 2018 17:17:09 +0800 Subject: [PATCH 179/221] doc improvement for typescript --- src/textures/Texture.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/textures/Texture.js b/src/textures/Texture.js index 93428ed3f..17a9a1174 100644 --- a/src/textures/Texture.js +++ b/src/textures/Texture.js @@ -29,7 +29,7 @@ var TEXTURE_MISSING_ERROR = 'Texture.frame missing: '; * * @param {Phaser.Textures.TextureManager} manager - A reference to the Texture Manager this Texture belongs to. * @param {string} key - The unique string-based key of this Texture. - * @param {(HTMLImageElement[]|HTMLCanvasElement[])} source - An array of sources that are used to create the texture. Usually Images, but can also be a Canvas. + * @param {(HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[])} source - An array of sources that are used to create the texture. Usually Images, but can also be a Canvas. * @param {number} [width] - The width of the Texture. This is optional and automatically derived from the source images. * @param {number} [height] - The height of the Texture. This is optional and automatically derived from the source images. */ @@ -385,7 +385,7 @@ var Texture = new Class({ * @method Phaser.Textures.Texture#setDataSource * @since 3.0.0 * - * @param {(HTMLImageElement|HTMLCanvasElement)} data - The source image. + * @param {(HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[])} data - The source image. */ setDataSource: function (data) { From b7424fd2876d3667dc7ad06732d7577a44cb5826 Mon Sep 17 00:00:00 2001 From: "J.C" Date: Thu, 13 Dec 2018 17:19:49 +0800 Subject: [PATCH 180/221] 1, removed `protected` for a few of members, they are used publicly somewhere, for example `this.loader.textureManager.addAtlasJSONArray` in MultiAtlasFile.prototype.addCache. 2, doc improvement for typescript --- src/loader/LoaderPlugin.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/loader/LoaderPlugin.js b/src/loader/LoaderPlugin.js index 46ae0c70d..c0cccdfbb 100644 --- a/src/loader/LoaderPlugin.js +++ b/src/loader/LoaderPlugin.js @@ -65,7 +65,6 @@ var LoaderPlugin = new Class({ * * @name Phaser.Loader.LoaderPlugin#scene * @type {Phaser.Scene} - * @protected * @since 3.0.0 */ this.scene = scene; @@ -75,7 +74,6 @@ var LoaderPlugin = new Class({ * * @name Phaser.Loader.LoaderPlugin#systems * @type {Phaser.Scenes.Systems} - * @protected * @since 3.0.0 */ this.systems = scene.sys; @@ -85,7 +83,6 @@ var LoaderPlugin = new Class({ * * @name Phaser.Loader.LoaderPlugin#cacheManager * @type {Phaser.Cache.CacheManager} - * @protected * @since 3.7.0 */ this.cacheManager = scene.sys.cache; @@ -95,7 +92,6 @@ var LoaderPlugin = new Class({ * * @name Phaser.Loader.LoaderPlugin#textureManager * @type {Phaser.Textures.TextureManager} - * @protected * @since 3.7.0 */ this.textureManager = scene.sys.textures; From 5d696d49bfca342ba4b3bcd05edf1e87099e96fc Mon Sep 17 00:00:00 2001 From: "J.C" Date: Thu, 13 Dec 2018 17:26:10 +0800 Subject: [PATCH 181/221] doc improvement for typescript, missing `mapping` if use JSON as the config data for the game instance --- src/boot/Config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/boot/Config.js b/src/boot/Config.js index ec7c70666..d03e31544 100644 --- a/src/boot/Config.js +++ b/src/boot/Config.js @@ -165,6 +165,7 @@ var ValueToColor = require('../display/color/ValueToColor'); * @property {boolean} [start] - Whether the plugin should be started automatically. * @property {string} [systemKey] - For a scene plugin, add the plugin to the scene's systems object under this key (`this.sys.KEY`, from the scene). * @property {string} [sceneKey] - For a scene plugin, add the plugin to the scene object under this key (`this.KEY`, from the scene). + * @property {string} [mapping] - If this plugin is to be injected into the Scene Systems, this is the property key map used. * @property {*} [data] - Arbitrary data passed to the plugin's init() method. * * @example From cc164b53992bb852a2b41be643976e8bb0a422b1 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 13 Dec 2018 10:25:53 +0000 Subject: [PATCH 182/221] Fixed camera background in WebGL. --- src/renderer/webgl/pipelines/TextureTintPipeline.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/renderer/webgl/pipelines/TextureTintPipeline.js b/src/renderer/webgl/pipelines/TextureTintPipeline.js index 047a7eee5..9bea5c50c 100644 --- a/src/renderer/webgl/pipelines/TextureTintPipeline.js +++ b/src/renderer/webgl/pipelines/TextureTintPipeline.js @@ -1089,6 +1089,8 @@ var TextureTintPipeline = new Class({ var xw = x + width; var yh = y + height; + this.setTexture2D(); + var tint = Utils.getTintAppendFloatAlphaAndSwap(color, alpha); this.batchQuad(x, y, x, yh, xw, yh, xw, y, 0, 0, 1, 1, tint, tint, tint, tint, 2); From 74d5af20c683c6c8cc7a8598915e61c8835dbbce Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 13 Dec 2018 11:07:20 +0000 Subject: [PATCH 183/221] Tidying up --- src/tilemaps/Tilemap.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/tilemaps/Tilemap.js b/src/tilemaps/Tilemap.js index 8b335cbf7..e3f334e8d 100644 --- a/src/tilemaps/Tilemap.js +++ b/src/tilemaps/Tilemap.js @@ -1968,9 +1968,9 @@ var Tilemap = new Class({ var mapWidth = this.layers[i].width; var mapHeight = this.layers[i].height; - for (var row = 0; row < mapHeight; ++row) + for (var row = 0; row < mapHeight; row++) { - for (var col = 0; col < mapWidth; ++col) + for (var col = 0; col < mapWidth; col++) { var tile = mapData[row][col]; @@ -2014,13 +2014,16 @@ var Tilemap = new Class({ var mapWidth = layer.width; var mapHeight = layer.height; - for (var row = 0; row < mapHeight; ++row) + for (var row = 0; row < mapHeight; row++) { - for (var col = 0; col < mapWidth; ++col) + for (var col = 0; col < mapWidth; col++) { var tile = mapData[row][col]; - if (tile !== null) { tile.setSize(tileWidth, tileHeight); } + if (tile !== null) + { + tile.setSize(tileWidth, tileHeight); + } } } From eef553d4c2fc52edc1ffaa61f5e548dd48c1de5b Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 13 Dec 2018 11:07:53 +0000 Subject: [PATCH 184/221] Fixed layer size calculations. Also changed rendering to use tileset tile sizes, as it should do. --- .../dynamiclayer/DynamicTilemapLayer.js | 2 +- .../staticlayer/StaticTilemapLayer.js | 24 +++++++++---------- .../StaticTilemapLayerCanvasRenderer.js | 10 ++++---- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/tilemaps/dynamiclayer/DynamicTilemapLayer.js b/src/tilemaps/dynamiclayer/DynamicTilemapLayer.js index 297af6db6..54e770a61 100644 --- a/src/tilemaps/dynamiclayer/DynamicTilemapLayer.js +++ b/src/tilemaps/dynamiclayer/DynamicTilemapLayer.js @@ -247,7 +247,7 @@ var DynamicTilemapLayer = new Class({ this.setAlpha(this.layer.alpha); this.setPosition(x, y); this.setOrigin(); - this.setSize(this.layer.tileWidth * this.layer.width, this.layer.tileHeight * this.layer.height); + this.setSize(tileset.tileWidth * this.layer.width, tileset.tileHeight * this.layer.height); this.initPipeline('TextureTintPipeline'); }, diff --git a/src/tilemaps/staticlayer/StaticTilemapLayer.js b/src/tilemaps/staticlayer/StaticTilemapLayer.js index 88014c391..b48e09b69 100644 --- a/src/tilemaps/staticlayer/StaticTilemapLayer.js +++ b/src/tilemaps/staticlayer/StaticTilemapLayer.js @@ -355,7 +355,7 @@ var StaticTilemapLayer = new Class({ this.setAlpha(this.layer.alpha); this.setPosition(x, y); this.setOrigin(); - this.setSize(this.layer.tileWidth * this.layer.width, this.layer.tileHeight * this.layer.height); + this.setSize(tileset.tileWidth * this.layer.width, tileset.tileHeight * this.layer.height); this.updateVBOData(); @@ -596,8 +596,8 @@ var StaticTilemapLayer = new Class({ * @param {integer} vOffset - The vertex offset. * @param {any} tile - The tile being rendered. * @param {any} tileset - The tileset being used for rendering. - * @param {integer} width - The width of the layer. - * @param {integer} height - The height of the layer. + * @param {integer} width - The width of the tileset image in pixels. + * @param {integer} height - The height of the tileset image in pixels. * @param {Phaser.Cameras.Scene2D.Camera} camera - The camera the layer is being rendered with. * @param {integer} tilesetIndex - The tileset index. * @@ -612,19 +612,19 @@ var StaticTilemapLayer = new Class({ return vOffset; } - var u0 = texCoords.x / width; - var v0 = texCoords.y / height; - var u1 = (texCoords.x + tile.width) / width; - var v1 = (texCoords.y + tile.height) / height; - - var matrix = this._tempMatrix; - - var tileWidth = tile.width; - var tileHeight = tile.height; + var tileWidth = tileset.tileWidth; + var tileHeight = tileset.tileHeight; var halfTileWidth = tileWidth / 2; var halfTileHeight = tileHeight / 2; + var u0 = texCoords.x / width; + var v0 = texCoords.y / height; + var u1 = (texCoords.x + tileWidth) / width; + var v1 = (texCoords.y + tileHeight) / height; + + var matrix = this._tempMatrix; + var x = -halfTileWidth; var y = -halfTileHeight; diff --git a/src/tilemaps/staticlayer/StaticTilemapLayerCanvasRenderer.js b/src/tilemaps/staticlayer/StaticTilemapLayerCanvasRenderer.js index 8617858ae..2fb481cde 100644 --- a/src/tilemaps/staticlayer/StaticTilemapLayerCanvasRenderer.js +++ b/src/tilemaps/staticlayer/StaticTilemapLayerCanvasRenderer.js @@ -86,8 +86,10 @@ var StaticTilemapLayerCanvasRenderer = function (renderer, src, interpolationPer if (tileTexCoords) { - var halfWidth = tile.width / 2; - var halfHeight = tile.height / 2; + var tileWidth = tileset.tileWidth; + var tileHeight = tileset.tileHeight; + var halfWidth = tileWidth / 2; + var halfHeight = tileHeight / 2; ctx.save(); @@ -108,9 +110,9 @@ var StaticTilemapLayerCanvasRenderer = function (renderer, src, interpolationPer ctx.drawImage( image, tileTexCoords.x, tileTexCoords.y, - tile.width, tile.height, + tileWidth, tileHeight, -halfWidth, -halfHeight, - tile.width, tile.height + tileWidth, tileHeight ); ctx.restore(); From ffd217dbdd360990e84297bf025102769a1320af Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 13 Dec 2018 11:46:17 +0000 Subject: [PATCH 185/221] Fixed size calculation and updated docs --- CHANGELOG.md | 2 ++ src/tilemaps/dynamiclayer/DynamicTilemapLayer.js | 2 +- src/tilemaps/staticlayer/StaticTilemapLayer.js | 6 +++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77c29e561..48e269a71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -197,6 +197,7 @@ one set of bindings ever created, which makes things a lot cleaner. * `TextureTintPipeline.requireTextureBatch` is a new internal method that helps speed-up the creation of texture batches. It is used in conjunction with `setTexture2D` and `pushBatch`. * `TextureTintPipeline.flush` and `TextureTintPipeline.pushBatch` have been optimized to handle zero based texture units as priority. They've also been refactored to avoid creation of empty texture batches. * The `WebGLRenderer.setTexture2D` method has a new optional argument `flush` which controls if the pipeline is flushed if the given texture is new, or not. This is used internally to skip flushing during an existing flush. +* The Tilemap Layer `width` and `height` properties are now based on the tilemap tile sizes multiplied by the layer dimensions. This corrects an issue with layer sizes being wrong if you called `setBaseTileSize` on a Map. ### Bug Fixes @@ -236,6 +237,7 @@ one set of bindings ever created, which makes things a lot cleaner. * Rotating Sprites that used a Normal Map wouldn't rotate the normal map with it, causing the lighting effects to become irregular. The normal map vectors are now rotated correctly (thanks @sercant for the PR and @fazzamatazz and @ysraelJMM for the report) * Changing `scaleX` or `scaleY` on a `MatterImage` or `MatterSprite` would cause the body scale to become distorted as the setters didn't use the correct factor when resetting the initial scale. Fix #4206 (thanks @YannCaron) * `StaticBody.reset` in Arcade Physics would ignore the `x` and `y` values given to it. If given, they're now used to reset the parent Game Object before the body is updated. Fix #4224 (thanks @samme) +* Static Tilemap Layers wouldn't render correctly if the layer used a tileset with a different size to the base map data (set via `setBaseTileSize`). They now render correctly in WebGL and Canvas, regardless of the base tile size. ### Examples and TypeScript diff --git a/src/tilemaps/dynamiclayer/DynamicTilemapLayer.js b/src/tilemaps/dynamiclayer/DynamicTilemapLayer.js index 54e770a61..dad886933 100644 --- a/src/tilemaps/dynamiclayer/DynamicTilemapLayer.js +++ b/src/tilemaps/dynamiclayer/DynamicTilemapLayer.js @@ -247,7 +247,7 @@ var DynamicTilemapLayer = new Class({ this.setAlpha(this.layer.alpha); this.setPosition(x, y); this.setOrigin(); - this.setSize(tileset.tileWidth * this.layer.width, tileset.tileHeight * this.layer.height); + this.setSize(tilemap.tileWidth * this.layer.width, tilemap.tileHeight * this.layer.height); this.initPipeline('TextureTintPipeline'); }, diff --git a/src/tilemaps/staticlayer/StaticTilemapLayer.js b/src/tilemaps/staticlayer/StaticTilemapLayer.js index b48e09b69..a6d09543f 100644 --- a/src/tilemaps/staticlayer/StaticTilemapLayer.js +++ b/src/tilemaps/staticlayer/StaticTilemapLayer.js @@ -355,7 +355,7 @@ var StaticTilemapLayer = new Class({ this.setAlpha(this.layer.alpha); this.setPosition(x, y); this.setOrigin(); - this.setSize(tileset.tileWidth * this.layer.width, tileset.tileHeight * this.layer.height); + this.setSize(tilemap.tileWidth * this.layer.width, tilemap.tileHeight * this.layer.height); this.updateVBOData(); @@ -416,6 +416,10 @@ var StaticTilemapLayer = new Class({ this.tileset = setList; }, + calculateSize: function () + { + }, + /** * Prepares the VBO data arrays for population by the `upload` method. * From 1bf9be5e120c5f6bdf8ec31c9311d1e37727d65f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 13 Dec 2018 13:03:54 +0000 Subject: [PATCH 186/221] Animation.stop guard. --- src/gameobjects/components/Animation.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/gameobjects/components/Animation.js b/src/gameobjects/components/Animation.js index 7f81941a5..eda08efb2 100644 --- a/src/gameobjects/components/Animation.js +++ b/src/gameobjects/components/Animation.js @@ -882,6 +882,8 @@ var Animation = new Class({ /** * Immediately stops the current animation from playing and dispatches the `animationcomplete` event. * + * If no animation is set, no event will be dispatched. + * * If there is another animation queued (via the `chain` method) then it will start playing immediately. * * @method Phaser.GameObjects.Components.Animation#stop @@ -900,11 +902,14 @@ var Animation = new Class({ var anim = this.currentAnim; var frame = this.currentFrame; - anim.emit('complete', anim, frame); + if (anim) + { + anim.emit('complete', anim, frame); - gameObject.emit('animationcomplete-' + anim.key, anim, frame, gameObject); - - gameObject.emit('animationcomplete', anim, frame, gameObject); + gameObject.emit('animationcomplete-' + anim.key, anim, frame, gameObject); + + gameObject.emit('animationcomplete', anim, frame, gameObject); + } if (this.nextAnim) { From f4f4512d0f121184ed4b44a03bc34bae3c973d32 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 13 Dec 2018 13:09:14 +0000 Subject: [PATCH 187/221] Fixed Math.RND assignment. Fix #4197. --- src/boot/Config.js | 7 ++----- src/math/const.js | 1 + 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/boot/Config.js b/src/boot/Config.js index 62f178c9e..39a9fe371 100644 --- a/src/boot/Config.js +++ b/src/boot/Config.js @@ -10,8 +10,7 @@ var Device = require('../device'); var GetFastValue = require('../utils/object/GetFastValue'); var GetValue = require('../utils/object/GetValue'); var IsPlainObject = require('../utils/object/IsPlainObject'); -var MATH = require('../math/const'); -var RND = require('../math/random-data-generator/RandomDataGenerator'); +var PhaserMath = require('../math/'); var NOOP = require('../utils/NOOP'); var DefaultPlugins = require('../plugins/DefaultPlugins'); var ValueToColor = require('../display/color/ValueToColor'); @@ -370,9 +369,7 @@ var Config = new Class({ */ this.seed = GetValue(config, 'seed', [ (Date.now() * Math.random()).toString() ]); - MATH.RND = new RND(); - - MATH.RND.init(this.seed); + PhaserMath.RND = new PhaserMath.RandomDataGenerator(this.seed); /** * @const {string} Phaser.Boot.Config#gameTitle - The title of the game. diff --git a/src/math/const.js b/src/math/const.js index 982ed77fb..25ba01033 100644 --- a/src/math/const.js +++ b/src/math/const.js @@ -53,6 +53,7 @@ var MATH_CONST = { /** * An instance of the Random Number Generator. + * This is not set until the Game boots. * * @name Phaser.Math.RND * @type {Phaser.Math.RandomDataGenerator} From 7586f4df33082bed16400485dd30401e6e8cd1e1 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 13 Dec 2018 13:10:18 +0000 Subject: [PATCH 188/221] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48e269a71..117790a0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -243,7 +243,7 @@ one set of bindings ever created, which makes things a lot cleaner. Thanks to the following for helping with the Phaser 3 Examples and TypeScript definitions, either by reporting errors, or even better, fixing them: -@guilhermehto @samvieten @darkwebdev @RoryO @snowbillr @slothyrulez +@guilhermehto @samvieten @darkwebdev @RoryO @snowbillr @slothyrulez @jcyuan ### Phaser Doc Jam From aae1cf5ae5f1e12b97908d0429297bea1780ac03 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 13 Dec 2018 13:10:31 +0000 Subject: [PATCH 189/221] Tidying up --- src/tilemaps/staticlayer/StaticTilemapLayer.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tilemaps/staticlayer/StaticTilemapLayer.js b/src/tilemaps/staticlayer/StaticTilemapLayer.js index a6d09543f..03b9956f5 100644 --- a/src/tilemaps/staticlayer/StaticTilemapLayer.js +++ b/src/tilemaps/staticlayer/StaticTilemapLayer.js @@ -416,10 +416,6 @@ var StaticTilemapLayer = new Class({ this.tileset = setList; }, - calculateSize: function () - { - }, - /** * Prepares the VBO data arrays for population by the `upload` method. * @@ -635,13 +631,13 @@ var StaticTilemapLayer = new Class({ if (tile.flipX) { tileWidth *= -1; - x += tile.width; + x += tileset.tileWidth; } if (tile.flipY) { tileHeight *= -1; - y += tile.height; + y += tileset.tileHeight; } var xw = x + tileWidth; From b3c3b4bae7fe0173f217b5d2e18e0e69cacfbd9c Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 13 Dec 2018 13:16:46 +0000 Subject: [PATCH 190/221] Adjust pixel position so scaled tiles don't offset --- src/tilemaps/Tile.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tilemaps/Tile.js b/src/tilemaps/Tile.js index 64d20d405..d8b1f4ca8 100644 --- a/src/tilemaps/Tile.js +++ b/src/tilemaps/Tile.js @@ -710,7 +710,9 @@ var Tile = new Class({ // bottom left, while the Phaser renderer assumes the origin is the top left. The y // coordinate needs to be adjusted by the difference. this.pixelX = this.x * this.baseWidth; - this.pixelY = this.y * this.baseHeight - (this.height - this.baseHeight); + this.pixelY = this.y * this.baseHeight; + + // this.pixelY = this.y * this.baseHeight - (this.height - this.baseHeight); return this; }, From 83f3f9cdeb6c09f1f50d130c65c772c0ddc3a9f2 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 13 Dec 2018 14:24:49 +0000 Subject: [PATCH 191/221] Changed scissor order. --- src/renderer/webgl/WebGLRenderer.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index 1e45d369d..c813ef17b 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -839,10 +839,10 @@ var WebGLRenderer = new Class({ scissorStack.push(scissor); - this.currentScissor = scissor; - this.setScissor(x, y, width, height); + this.currentScissor = scissor; + return scissor; }, @@ -870,12 +870,12 @@ var WebGLRenderer = new Class({ if (cx !== x || cy !== y || cw !== width || ch !== height) { - this.flush(); - // https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/scissor if (width > 0 && height > 0) { + this.flush(); + gl.scissor(x, (this.drawingBufferHeight - y - height), width, height); } } From 524d015e60531b84112ccc01e4c0d8d197f94f69 Mon Sep 17 00:00:00 2001 From: "J.C" Date: Mon, 17 Dec 2018 10:42:46 +0800 Subject: [PATCH 192/221] removeListener / off except 'event' all other parameters should be optional. --- src/events/EventEmitter.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/events/EventEmitter.js b/src/events/EventEmitter.js index 3cc9f2883..1150c7c57 100644 --- a/src/events/EventEmitter.js +++ b/src/events/EventEmitter.js @@ -141,9 +141,9 @@ var EventEmitter = new Class({ * @since 3.0.0 * * @param {(string|symbol)} event - The event name. - * @param {function} fn - Only remove the listeners that match this function. - * @param {*} context - Only remove the listeners that have this context. - * @param {boolean} once - Only remove one-time listeners. + * @param {function} [fn] - Only remove the listeners that match this function. + * @param {*} [context] - Only remove the listeners that have this context. + * @param {boolean} [once] - Only remove one-time listeners. * * @return {Phaser.Events.EventEmitter} `this`. */ @@ -155,9 +155,9 @@ var EventEmitter = new Class({ * @since 3.0.0 * * @param {(string|symbol)} event - The event name. - * @param {function} fn - Only remove the listeners that match this function. - * @param {*} context - Only remove the listeners that have this context. - * @param {boolean} once - Only remove one-time listeners. + * @param {function} [fn] - Only remove the listeners that match this function. + * @param {*} [context] - Only remove the listeners that have this context. + * @param {boolean} [once] - Only remove one-time listeners. * * @return {Phaser.Events.EventEmitter} `this`. */ From d860725d57f4f5cac426237fbde8b058a60cb164 Mon Sep 17 00:00:00 2001 From: "J.C" Date: Mon, 17 Dec 2018 10:56:41 +0800 Subject: [PATCH 193/221] first / last / next / prev should specify the return type as T --- src/structs/List.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/structs/List.js b/src/structs/List.js index 46afbecc0..2b4aa371e 100644 --- a/src/structs/List.js +++ b/src/structs/List.js @@ -710,7 +710,8 @@ var List = new Class({ * The first item in the List or `null` for an empty List. * * @name Phaser.Structs.List#first - * @type {integer} + * @genericUse {T} - [$type] + * @type {*} The first item in the List or `null` for an empty List. * @readonly * @since 3.0.0 */ @@ -736,7 +737,8 @@ var List = new Class({ * The last item in the List, or `null` for an empty List. * * @name Phaser.Structs.List#last - * @type {integer} + * @genericUse {T} - [$type] + * @type {*} The last item in the List, or `null` for an empty List. * @readonly * @since 3.0.0 */ @@ -764,7 +766,8 @@ var List = new Class({ * This property can be read successively after reading {@link #first} or manually setting the {@link #position} to iterate the List. * * @name Phaser.Structs.List#next - * @type {integer} + * @genericUse {T} - [$type] + * @type {*} The next item in the List, or `null` if the entire List has been traversed. * @readonly * @since 3.0.0 */ @@ -792,7 +795,8 @@ var List = new Class({ * This property can be read successively after reading {@link #last} or manually setting the {@link #position} to iterate the List backwards. * * @name Phaser.Structs.List#previous - * @type {integer} + * @genericUse {T} - [$type] + * @type {*} The previous item in the List, or `null` if the entire List has been traversed. * @readonly * @since 3.0.0 */ From 110819e82c3b5813e7fb6bd63f0171b26ec1093e Mon Sep 17 00:00:00 2001 From: "J.C" Date: Mon, 17 Dec 2018 16:11:51 +0800 Subject: [PATCH 194/221] add docs for StableSort & StableSort.inplace --- src/utils/array/StableSort.js | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/utils/array/StableSort.js b/src/utils/array/StableSort.js index 8831aba5d..13d9be1cc 100644 --- a/src/utils/array/StableSort.js +++ b/src/utils/array/StableSort.js @@ -9,13 +9,33 @@ (function() { -// A stable array sort, because `Array#sort()` is not guaranteed stable. -// This is an implementation of merge sort, without recursion. - + /** + * A stable array sort, because `Array#sort()` is not guaranteed stable. + * This is an implementation of merge sort, without recursion. + * + * @function Phaser.Utils.Array.StableSort + * @since 3.0.0 + * + * @param {array} arr - The input array to be sorted. + * @param {function} comp - The comparison handler. + * + * @return {array} The sorted result. + */ var stable = function(arr, comp) { return exec(arr.slice(), comp); }; + /** + * Sort the input array and simply copy it back if the result isn't in the original array, which happens on an odd number of passes. + * + * @function Phaser.Utils.Array.StableSort.inplace + * @since 3.0.0 + * + * @param {array} arr - The input array. + * @param {function} comp - The comparison handler. + * + * @return {array} The sorted array. + */ stable.inplace = function(arr, comp) { var result = exec(arr, comp); From bc9d3511e1e3f66de2690d116d66a1c3a9212316 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 09:55:23 +0000 Subject: [PATCH 195/221] When using `RenderTexture.fill`, the `alpha` argument would be ignored in Canvas mode. It's now used when filling the RenderTexture. --- src/gameobjects/rendertexture/RenderTexture.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gameobjects/rendertexture/RenderTexture.js b/src/gameobjects/rendertexture/RenderTexture.js index e33e87a3d..df35ffca3 100644 --- a/src/gameobjects/rendertexture/RenderTexture.js +++ b/src/gameobjects/rendertexture/RenderTexture.js @@ -409,9 +409,9 @@ var RenderTexture = new Class({ { if (alpha === undefined) { alpha = 1; } - var ur = ((rgb >> 16)|0) & 0xff; - var ug = ((rgb >> 8)|0) & 0xff; - var ub = (rgb|0) & 0xff; + var r = ((rgb >> 16) | 0) & 0xff; + var g = ((rgb >> 8) | 0) & 0xff; + var b = (rgb | 0) & 0xff; if (this.gl) { @@ -419,7 +419,7 @@ var RenderTexture = new Class({ var gl = this.gl; - gl.clearColor(ur / 255.0, ug / 255.0, ub / 255.0, alpha); + gl.clearColor(r / 255, g / 255, b / 255, alpha); gl.clear(gl.COLOR_BUFFER_BIT); @@ -427,7 +427,7 @@ var RenderTexture = new Class({ } else { - this.context.fillStyle = 'rgb(' + ur + ',' + ug + ',' + ub + ')'; + this.context.fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + alpha + ')'; this.context.fillRect(0, 0, this.canvas.width, this.canvas.height); } From 7e732452eb2f19017d58361264fc5e2ec3ecf330 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 10:22:59 +0000 Subject: [PATCH 196/221] Fixed an issue in `WebGLRenderer.setScissor` where it was possible to try and compare the scissor size to a non-current scissor, if called outside of the render loop (i.e. from `RenderTexture.fill`) --- src/renderer/webgl/WebGLRenderer.js | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index c813ef17b..0fb529e29 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -863,21 +863,24 @@ var WebGLRenderer = new Class({ var current = this.currentScissor; - var cx = current[0]; - var cy = current[1]; - var cw = current[2]; - var ch = current[3]; + var setScissor = (width > 0 && height > 0); - if (cx !== x || cy !== y || cw !== width || ch !== height) + if (current && setScissor) { + var cx = current[0]; + var cy = current[1]; + var cw = current[2]; + var ch = current[3]; + + setScissor = (cx !== x || cy !== y || cw !== width || ch !== height); + } + + if (setScissor) + { + this.flush(); + // https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/scissor - - if (width > 0 && height > 0) - { - this.flush(); - - gl.scissor(x, (this.drawingBufferHeight - y - height), width, height); - } + gl.scissor(x, (this.drawingBufferHeight - y - height), width, height); } }, From 56fa0a119ee04478cd245e42136865228502fc24 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 11:31:42 +0000 Subject: [PATCH 197/221] `RenderTexture.fill` in WebGL would use `gl.clear` and a clear color to try and fill the Render Texture. This only worked for full-canvas sized RenderTextures that didn't have a camera zoom applied. It has now been swapped to use the `drawFillRect` method of the Texture Tint Pipeline, allowing it to work properly regardless of camera zoom or size. --- .../rendertexture/RenderTexture.js | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/gameobjects/rendertexture/RenderTexture.js b/src/gameobjects/rendertexture/RenderTexture.js index df35ffca3..4211c24fa 100644 --- a/src/gameobjects/rendertexture/RenderTexture.js +++ b/src/gameobjects/rendertexture/RenderTexture.js @@ -13,6 +13,7 @@ var CONST = require('../../const'); var Frame = require('../../textures/Frame'); var GameObject = require('../GameObject'); var Render = require('./RenderTextureRender'); +var Utils = require('../../renderer/webgl/Utils'); var UUID = require('../../utils/string/UUID'); /** @@ -415,15 +416,19 @@ var RenderTexture = new Class({ if (this.gl) { - this.renderer.setFramebuffer(this.framebuffer, true); + var renderer = this.renderer; - var gl = this.gl; - - gl.clearColor(r / 255, g / 255, b / 255, alpha); - - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderer.setFramebuffer(null, true); + var bounds = this.getBounds(); + + renderer.setFramebuffer(this.framebuffer, true); + + renderer.pipelines.TextureTintPipeline.drawFillRect( + bounds.x, bounds.y, bounds.right, bounds.bottom, + Utils.getTintFromFloats(r / 255, g / 255, b / 255, 1), + alpha + ); + + renderer.setFramebuffer(null, true); } else { From 8f873c87af20e886cea831af43f82e9bf72582fb Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 11:32:36 +0000 Subject: [PATCH 198/221] Clears the framebuffer at the start of every render. --- src/renderer/webgl/WebGLRenderer.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index 0fb529e29..fdea6a73a 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -1776,6 +1776,9 @@ var WebGLRenderer = new Class({ var gl = this.gl; var pipelines = this.pipelines; + // Make sure we are bound to the main frame buffer + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + if (this.config.clearBeforeRender) { gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); From 3b1c578634e43a48b66f502f1308ecd660b6cb89 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 11:39:08 +0000 Subject: [PATCH 199/221] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 117790a0b..868bfd2ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -198,6 +198,7 @@ one set of bindings ever created, which makes things a lot cleaner. * `TextureTintPipeline.flush` and `TextureTintPipeline.pushBatch` have been optimized to handle zero based texture units as priority. They've also been refactored to avoid creation of empty texture batches. * The `WebGLRenderer.setTexture2D` method has a new optional argument `flush` which controls if the pipeline is flushed if the given texture is new, or not. This is used internally to skip flushing during an existing flush. * The Tilemap Layer `width` and `height` properties are now based on the tilemap tile sizes multiplied by the layer dimensions. This corrects an issue with layer sizes being wrong if you called `setBaseTileSize` on a Map. +* The WebGLRenderer will now clear the framebuffer at the start of every render. ### Bug Fixes @@ -238,6 +239,9 @@ one set of bindings ever created, which makes things a lot cleaner. * Changing `scaleX` or `scaleY` on a `MatterImage` or `MatterSprite` would cause the body scale to become distorted as the setters didn't use the correct factor when resetting the initial scale. Fix #4206 (thanks @YannCaron) * `StaticBody.reset` in Arcade Physics would ignore the `x` and `y` values given to it. If given, they're now used to reset the parent Game Object before the body is updated. Fix #4224 (thanks @samme) * Static Tilemap Layers wouldn't render correctly if the layer used a tileset with a different size to the base map data (set via `setBaseTileSize`). They now render correctly in WebGL and Canvas, regardless of the base tile size. +* When using `RenderTexture.fill`, the `alpha` argument would be ignored in Canvas mode. It's now used when filling the RenderTexture. +* Fixed an issue in `WebGLRenderer.setScissor` where it was possible to try and compare the scissor size to a non-current scissor, if called outside of the render loop (i.e. from `RenderTexture.fill`) +* `RenderTexture.fill` in WebGL would use `gl.clear` and a clear color to try and fill the Render Texture. This only worked for full-canvas sized RenderTextures that didn't have a camera zoom applied. It has now been swapped to use the `drawFillRect` method of the Texture Tint Pipeline, allowing it to work properly regardless of camera zoom or size. ### Examples and TypeScript From 90c7d4d0e8bf6adc06d8ec7b4674e51025cd3c37 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 12:12:38 +0000 Subject: [PATCH 200/221] Removed un-needed argument --- src/gameobjects/rendertexture/RenderTexture.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gameobjects/rendertexture/RenderTexture.js b/src/gameobjects/rendertexture/RenderTexture.js index 4211c24fa..d883a67aa 100644 --- a/src/gameobjects/rendertexture/RenderTexture.js +++ b/src/gameobjects/rendertexture/RenderTexture.js @@ -615,7 +615,7 @@ var RenderTexture = new Class({ var gl = this.gl; - this.camera.preRender(1, 1, 1); + this.camera.preRender(1, 1); if (gl) { From 7ee0a717f5095a1a917cb54ce9570b528fbe43d4 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 12:12:47 +0000 Subject: [PATCH 201/221] `Container.getFirst` was using an incorrect Array Utils function `GetFirstElement`, when it should have been using `GetFirst`. It now uses the correct function. Fix #4244 --- src/gameobjects/container/Container.js | 2 +- src/structs/List.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gameobjects/container/Container.js b/src/gameobjects/container/Container.js index 568d756ec..61396731c 100644 --- a/src/gameobjects/container/Container.js +++ b/src/gameobjects/container/Container.js @@ -610,7 +610,7 @@ var Container = new Class({ */ getFirst: function (property, value, startIndex, endIndex) { - return ArrayUtils.GetFirstElement(this.list, property, value, startIndex, endIndex); + return ArrayUtils.GetFirst(this.list, property, value, startIndex, endIndex); }, /** diff --git a/src/structs/List.js b/src/structs/List.js index 15fda9930..6bfdf3cfd 100644 --- a/src/structs/List.js +++ b/src/structs/List.js @@ -283,7 +283,7 @@ var List = new Class({ */ getFirst: function (property, value, startIndex, endIndex) { - return ArrayUtils.GetFirstElement(this.list, property, value, startIndex, endIndex); + return ArrayUtils.GetFirst(this.list, property, value, startIndex, endIndex); }, /** From 8ec71c7bd1814a21460c0572395c4f6b7ccd8681 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 12:12:52 +0000 Subject: [PATCH 202/221] Update CHANGELOG.md --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 868bfd2ca..68d5191c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -240,8 +240,10 @@ one set of bindings ever created, which makes things a lot cleaner. * `StaticBody.reset` in Arcade Physics would ignore the `x` and `y` values given to it. If given, they're now used to reset the parent Game Object before the body is updated. Fix #4224 (thanks @samme) * Static Tilemap Layers wouldn't render correctly if the layer used a tileset with a different size to the base map data (set via `setBaseTileSize`). They now render correctly in WebGL and Canvas, regardless of the base tile size. * When using `RenderTexture.fill`, the `alpha` argument would be ignored in Canvas mode. It's now used when filling the RenderTexture. -* Fixed an issue in `WebGLRenderer.setScissor` where it was possible to try and compare the scissor size to a non-current scissor, if called outside of the render loop (i.e. from `RenderTexture.fill`) +* Fixed an issue in `WebGLRenderer.setScissor` where it was possible to try and compare the scissor size to a non-current scissor, if called outside of the render loop (i.e. from `RenderTexture.fill`) (thanks @hackhat) * `RenderTexture.fill` in WebGL would use `gl.clear` and a clear color to try and fill the Render Texture. This only worked for full-canvas sized RenderTextures that didn't have a camera zoom applied. It has now been swapped to use the `drawFillRect` method of the Texture Tint Pipeline, allowing it to work properly regardless of camera zoom or size. +* `Container.getFirst` was using an incorrect Array Utils function `GetFirstElement`, when it should have been using `GetFirst`. It now uses the correct function. Fix #4244 (thanks @miran248) +* `List.getFirst` was using an incorrect Array Utils function `GetFirstElement`, when it should have been using `GetFirst`. It now uses the correct function. Fix #4244 (thanks @miran248) ### Examples and TypeScript From 4b1ea8db9b514090337da4c165911b48ca11987e Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 13:04:26 +0000 Subject: [PATCH 203/221] `WebGLRenderer.preRender` now calls `gl.clearColor` in order to restore the background clear color in case something, like a Render Texture, has changed it. --- src/renderer/webgl/WebGLRenderer.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index fdea6a73a..270065132 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -1781,6 +1781,10 @@ var WebGLRenderer = new Class({ if (this.config.clearBeforeRender) { + var clearColor = this.config.backgroundColor; + + gl.clearColor(clearColor.redGL, clearColor.greenGL, clearColor.blueGL, 1); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); } From c882b52a3aaccefafe46b31e13b9845f39d02bc6 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 13:35:53 +0000 Subject: [PATCH 204/221] Fixed an issue where changing the viewport or size of a Camera belonging to a RenderTexture, it wouldn't impact the rendering and objects will still render outside of the viewport range. It's now converted to a proper gl scissor rect by the renderer, meaning you can limit the area rendered to by adjusting the internal Render Texture cameras viewport. Fix #4243 --- .../rendertexture/RenderTexture.js | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/gameobjects/rendertexture/RenderTexture.js b/src/gameobjects/rendertexture/RenderTexture.js index d883a67aa..dd718a3f6 100644 --- a/src/gameobjects/rendertexture/RenderTexture.js +++ b/src/gameobjects/rendertexture/RenderTexture.js @@ -414,7 +414,9 @@ var RenderTexture = new Class({ var g = ((rgb >> 8) | 0) & 0xff; var b = (rgb | 0) & 0xff; - if (this.gl) + var gl = this.gl; + + if (gl) { var renderer = this.renderer; @@ -451,17 +453,18 @@ var RenderTexture = new Class({ { if (this.dirty) { - if (this.gl) - { - this.renderer.setFramebuffer(this.framebuffer, true); + var gl = this.gl; - var gl = this.gl; - + if (gl) + { + var renderer = this.renderer; + + renderer.setFramebuffer(this.framebuffer, true); + gl.clearColor(0, 0, 0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - - this.renderer.setFramebuffer(null, true); + + renderer.setFramebuffer(null, true); } else { @@ -619,7 +622,14 @@ var RenderTexture = new Class({ if (gl) { - this.renderer.setFramebuffer(this.framebuffer, true); + var cx = this.camera._cx; + var cy = this.camera._cy; + var cw = this.camera._cw; + var ch = this.camera._ch; + + this.renderer.setFramebuffer(this.framebuffer, false); + + this.renderer.pushScissor(cx, cy, cw, ch, ch); var pipeline = this.pipeline; @@ -629,7 +639,9 @@ var RenderTexture = new Class({ pipeline.flush(); - this.renderer.setFramebuffer(null, true); + this.renderer.setFramebuffer(null, false); + + this.renderer.popScissor(); pipeline.projOrtho(0, pipeline.width, pipeline.height, 0, -1000.0, 1000.0); } @@ -697,12 +709,19 @@ var RenderTexture = new Class({ if (textureFrame) { - this.camera.preRender(1, 1, 1); + this.camera.preRender(1, 1); if (gl) { - this.renderer.setFramebuffer(this.framebuffer, true); - + var cx = this.camera._cx; + var cy = this.camera._cy; + var cw = this.camera._cw; + var ch = this.camera._ch; + + this.renderer.setFramebuffer(this.framebuffer, false); + + this.renderer.pushScissor(cx, cy, cw, ch, ch); + var pipeline = this.pipeline; pipeline.projOrtho(0, this.width, 0, this.height, -1000.0, 1000.0); @@ -711,8 +730,10 @@ var RenderTexture = new Class({ pipeline.flush(); - this.renderer.setFramebuffer(null, true); - + this.renderer.setFramebuffer(null, false); + + this.renderer.popScissor(); + pipeline.projOrtho(0, pipeline.width, pipeline.height, 0, -1000.0, 1000.0); } else From 8eebe518ad0ebb8a440b026b3b43944542faecbd Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 13:36:05 +0000 Subject: [PATCH 205/221] Added optional drawingBufferHeight argument to scissor methods. --- src/renderer/webgl/WebGLRenderer.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index 270065132..bf5df8bb0 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -798,7 +798,7 @@ var WebGLRenderer = new Class({ * @param {string} pipelineName - A unique string-based key for the pipeline. * @param {Phaser.Renderer.WebGL.WebGLPipeline} pipelineInstance - A pipeline instance which must extend WebGLPipeline. * - * @return {Phaser.Renderer.WebGL.WebGLPipeline} The pipline instance that was passed. + * @return {Phaser.Renderer.WebGL.WebGLPipeline} The pipeline instance that was passed. */ addPipeline: function (pipelineName, pipelineInstance) { @@ -828,18 +828,21 @@ var WebGLRenderer = new Class({ * @param {integer} y - The y position of the scissor. * @param {integer} width - The width of the scissor. * @param {integer} height - The height of the scissor. + * @param {integer} [drawingBufferHeight] - Optional drawingBufferHeight override value. * * @return {integer[]} An array containing the scissor values. */ - pushScissor: function (x, y, width, height) + pushScissor: function (x, y, width, height, drawingBufferHeight) { + if (drawingBufferHeight === undefined) { drawingBufferHeight = this.drawingBufferHeight; } + var scissorStack = this.scissorStack; var scissor = [ x, y, width, height ]; scissorStack.push(scissor); - this.setScissor(x, y, width, height); + this.setScissor(x, y, width, height, drawingBufferHeight); this.currentScissor = scissor; @@ -856,8 +859,9 @@ var WebGLRenderer = new Class({ * @param {integer} y - The y position of the scissor. * @param {integer} width - The width of the scissor. * @param {integer} height - The height of the scissor. + * @param {integer} [drawingBufferHeight] - Optional drawingBufferHeight override value. */ - setScissor: function (x, y, width, height) + setScissor: function (x, y, width, height, drawingBufferHeight) { var gl = this.gl; @@ -880,7 +884,7 @@ var WebGLRenderer = new Class({ this.flush(); // https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/scissor - gl.scissor(x, (this.drawingBufferHeight - y - height), width, height); + gl.scissor(x, (drawingBufferHeight - y - height), width, height); } }, From 68a87516dd800ddd37c8ff8622811ab975664535 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 13:36:08 +0000 Subject: [PATCH 206/221] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68d5191c1..3e6353695 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -199,6 +199,9 @@ one set of bindings ever created, which makes things a lot cleaner. * The `WebGLRenderer.setTexture2D` method has a new optional argument `flush` which controls if the pipeline is flushed if the given texture is new, or not. This is used internally to skip flushing during an existing flush. * The Tilemap Layer `width` and `height` properties are now based on the tilemap tile sizes multiplied by the layer dimensions. This corrects an issue with layer sizes being wrong if you called `setBaseTileSize` on a Map. * The WebGLRenderer will now clear the framebuffer at the start of every render. +* `WebGLRenderer.setScissor` now has a new optional argument `drawingBufferHeight` which allows you to specify the drawing buffer height, rather than use the renderers default value. +* `WebGLRenderer.pushScissor` now has a new optional argument `drawingBufferHeight` which allows you to specify the drawing buffer height, rather than use the renderers default value. +* `WebGLRenderer.preRender` now calls `gl.clearColor` in order to restore the background clear color in case something, like a Render Texture, has changed it. ### Bug Fixes @@ -244,6 +247,7 @@ one set of bindings ever created, which makes things a lot cleaner. * `RenderTexture.fill` in WebGL would use `gl.clear` and a clear color to try and fill the Render Texture. This only worked for full-canvas sized RenderTextures that didn't have a camera zoom applied. It has now been swapped to use the `drawFillRect` method of the Texture Tint Pipeline, allowing it to work properly regardless of camera zoom or size. * `Container.getFirst` was using an incorrect Array Utils function `GetFirstElement`, when it should have been using `GetFirst`. It now uses the correct function. Fix #4244 (thanks @miran248) * `List.getFirst` was using an incorrect Array Utils function `GetFirstElement`, when it should have been using `GetFirst`. It now uses the correct function. Fix #4244 (thanks @miran248) +* Fixed an issue where changing the viewport or size of a Camera belonging to a RenderTexture, it wouldn't impact the rendering and objects will still render outside of the viewport range. It's now converted to a proper gl scissor rect by the renderer, meaning you can limit the area rendered to by adjusting the internal Render Texture cameras viewport. Fix #4243 (thanks @hackhat) ### Examples and TypeScript From 41286b5170e02e982b3151577bc2d2180cba764f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 14:58:42 +0000 Subject: [PATCH 207/221] Make sure we bind the framebuffer and pipeline in the boot step --- src/renderer/webgl/WebGLRenderer.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index bf5df8bb0..1cba6a7bc 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -616,6 +616,14 @@ var WebGLRenderer = new Class({ this.pipelines.TextureTintPipeline.currentFrame = blank; this.blankTexture = blank; + + var gl = this.gl; + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + gl.enable(gl.SCISSOR_TEST); + + this.setPipeline(this.pipelines.TextureTintPipeline); }, /** From a2723249a3e33244867f3f86e8e8aa4d7fb0b796 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 15:21:24 +0000 Subject: [PATCH 208/221] `CanvasTexture.destroy` is a new method that specifically handles the destruction of the CanvasTexture and all of its associated typed arrays. This prevents a memory leak when creating and destroying lots of RenderTextures (which are CanvasTexture backed). Fix #4239 --- CHANGELOG.md | 1 + .../rendertexture/RenderTexture.js | 6 ++++++ src/textures/CanvasTexture.js | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e6353695..3bebb335b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -248,6 +248,7 @@ one set of bindings ever created, which makes things a lot cleaner. * `Container.getFirst` was using an incorrect Array Utils function `GetFirstElement`, when it should have been using `GetFirst`. It now uses the correct function. Fix #4244 (thanks @miran248) * `List.getFirst` was using an incorrect Array Utils function `GetFirstElement`, when it should have been using `GetFirst`. It now uses the correct function. Fix #4244 (thanks @miran248) * Fixed an issue where changing the viewport or size of a Camera belonging to a RenderTexture, it wouldn't impact the rendering and objects will still render outside of the viewport range. It's now converted to a proper gl scissor rect by the renderer, meaning you can limit the area rendered to by adjusting the internal Render Texture cameras viewport. Fix #4243 (thanks @hackhat) +* `CanvasTexture.destroy` is a new method that specifically handles the destruction of the CanvasTexture and all of its associated typed arrays. This prevents a memory leak when creating and destroying lots of RenderTextures (which are CanvasTexture backed). Fix #4239 (thanks @sjb933) ### Examples and TypeScript diff --git a/src/gameobjects/rendertexture/RenderTexture.js b/src/gameobjects/rendertexture/RenderTexture.js index dd718a3f6..173824565 100644 --- a/src/gameobjects/rendertexture/RenderTexture.js +++ b/src/gameobjects/rendertexture/RenderTexture.js @@ -980,6 +980,12 @@ var RenderTexture = new Class({ } this.texture.destroy(); + this.camera.destroy(); + + this.canvas = null; + this.context = null; + this.framebuffer = null; + this.texture = null; } } diff --git a/src/textures/CanvasTexture.js b/src/textures/CanvasTexture.js index 928e3204a..71fd96f36 100644 --- a/src/textures/CanvasTexture.js +++ b/src/textures/CanvasTexture.js @@ -595,6 +595,25 @@ var CanvasTexture = new Class({ } return this; + }, + + /** + * Destroys this Texture and releases references to its sources and frames. + * + * @method Phaser.Textures.CanvasTexture#destroy + * @since 3.16.0 + */ + destroy: function () + { + Texture.prototype.destroy.call(this); + + this._source = null; + this.canvas = null; + this.context = null; + this.imageData = null; + this.data = null; + this.pixels = null; + this.buffer = null; } }); From cb57425a34b3cf2821f2f9675dd5864d52c330db Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 15:47:07 +0000 Subject: [PATCH 209/221] The Alpha, Flip and Origin components have been removed from the Mesh Game Object (and by extension, Quad as well) as they are not used in the renderer and should be manipulated via the Mesh properties. Fix #4188 --- CHANGELOG.md | 1 + src/gameobjects/mesh/Mesh.js | 7 ------- src/gameobjects/mesh/MeshWebGLRenderer.js | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bebb335b..c31b8a6df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -249,6 +249,7 @@ one set of bindings ever created, which makes things a lot cleaner. * `List.getFirst` was using an incorrect Array Utils function `GetFirstElement`, when it should have been using `GetFirst`. It now uses the correct function. Fix #4244 (thanks @miran248) * Fixed an issue where changing the viewport or size of a Camera belonging to a RenderTexture, it wouldn't impact the rendering and objects will still render outside of the viewport range. It's now converted to a proper gl scissor rect by the renderer, meaning you can limit the area rendered to by adjusting the internal Render Texture cameras viewport. Fix #4243 (thanks @hackhat) * `CanvasTexture.destroy` is a new method that specifically handles the destruction of the CanvasTexture and all of its associated typed arrays. This prevents a memory leak when creating and destroying lots of RenderTextures (which are CanvasTexture backed). Fix #4239 (thanks @sjb933) +* The Alpha, Flip and Origin components have been removed from the Mesh Game Object (and by extension, Quad as well) as they are not used in the renderer and should be manipulated via the Mesh properties. Fix #4188 (thanks @enriqueto) ### Examples and TypeScript diff --git a/src/gameobjects/mesh/Mesh.js b/src/gameobjects/mesh/Mesh.js index cc2819065..5094b7785 100644 --- a/src/gameobjects/mesh/Mesh.js +++ b/src/gameobjects/mesh/Mesh.js @@ -20,13 +20,10 @@ var MeshRender = require('./MeshRender'); * @webglOnly * @since 3.0.0 * - * @extends Phaser.GameObjects.Components.Alpha * @extends Phaser.GameObjects.Components.BlendMode * @extends Phaser.GameObjects.Components.Depth - * @extends Phaser.GameObjects.Components.Flip * @extends Phaser.GameObjects.Components.GetBounds * @extends Phaser.GameObjects.Components.Mask - * @extends Phaser.GameObjects.Components.Origin * @extends Phaser.GameObjects.Components.Pipeline * @extends Phaser.GameObjects.Components.ScaleMode * @extends Phaser.GameObjects.Components.Size @@ -50,13 +47,10 @@ var Mesh = new Class({ Extends: GameObject, Mixins: [ - Components.Alpha, Components.BlendMode, Components.Depth, - Components.Flip, Components.GetBounds, Components.Mask, - Components.Origin, Components.Pipeline, Components.ScaleMode, Components.Size, @@ -157,7 +151,6 @@ var Mesh = new Class({ this.setTexture(texture, frame); this.setPosition(x, y); this.setSizeToFrame(); - this.setOrigin(); this.initPipeline(); } diff --git a/src/gameobjects/mesh/MeshWebGLRenderer.js b/src/gameobjects/mesh/MeshWebGLRenderer.js index bc8dbfe3c..434f1877d 100644 --- a/src/gameobjects/mesh/MeshWebGLRenderer.js +++ b/src/gameobjects/mesh/MeshWebGLRenderer.js @@ -67,7 +67,7 @@ var MeshWebGLRenderer = function (renderer, src, interpolationPercentage, camera var meshVerticesLength = vertices.length; var vertexCount = Math.floor(meshVerticesLength * 0.5); - if (pipeline.vertexCount + vertexCount >= pipeline.vertexCapacity) + if (pipeline.vertexCount + vertexCount > pipeline.vertexCapacity) { pipeline.flush(); } From 7aabb98b8e51480488b53e8e4b1ab1a3c9d15015 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 18 Dec 2018 17:29:15 +0000 Subject: [PATCH 210/221] Re-enabled IM --- src/input/InputManager.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/input/InputManager.js b/src/input/InputManager.js index 8f5aa8b54..f968fe9df 100644 --- a/src/input/InputManager.js +++ b/src/input/InputManager.js @@ -432,7 +432,6 @@ var InputManager = new Class({ */ resize: function () { - /* this.updateBounds(); // Game config size @@ -446,7 +445,6 @@ var InputManager = new Class({ // Scale factor this.scale.x = gw / bw; this.scale.y = gh / bh; - */ }, /** From c6f72241e3758e11a2bd0c31b4907e6d57e89fbf Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 19 Dec 2018 12:16:13 +0000 Subject: [PATCH 211/221] Added Size component. --- src/structs/Size.js | 290 +++++++++++++++++++++++++++++++++++++++++++ src/structs/index.js | 3 +- 2 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 src/structs/Size.js diff --git a/src/structs/Size.js b/src/structs/Size.js new file mode 100644 index 000000000..1a29fae73 --- /dev/null +++ b/src/structs/Size.js @@ -0,0 +1,290 @@ +/** + * @author Richard Davey + * @copyright 2018 Photon Storm Ltd. + * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} + */ + +var Class = require('../utils/Class'); + +/** + * @classdesc + * The Size component is a simple structure that helps you encapsulate a `width` and `height` and, if required, maintain + * the aspect ratios between them. + * + * @class Size + * @memberof Phaser.Structs + * @constructor + * @since 3.16.0 + * + * @param {number} [width] - The width of the Size component. + * @param {number} [height=width] - The height of the Size component. If not given, it will use the `width`. + * @param {boolean} [lockAspectRatio=false] - Should the aspect ratio between the `width` and `height` be locked? + */ +var Size = new Class({ + + initialize: + + function Size (width, height, lockAspectRatio) + { + if (width === undefined) { width = 0; } + if (height === undefined) { height = width; } + if (lockAspectRatio === undefined) { lockAspectRatio = false; } + + /** + * The width. + * + * @name Phaser.Structs.Size#_width + * @type {number} + * @private + * @since 3.16.0 + */ + this._width = width; + + /** + * The height. + * + * @name Phaser.Structs.Size#_height + * @type {number} + * @private + * @since 3.16.0 + */ + this._height = height; + + /** + * The proportional relationship between the width and height. + * + * This property is read only and is updated automatically when either the `width` or `height` properties are changed, + * providing the aspect ratio lock isn't enabled. + * + * @name Phaser.Structs.Size#ratioH + * @type {number} + * @readonly + * @since 3.16.0 + */ + this.ratioH = (height === 0) ? 0 : width / height; + + /** + * The proportional relationship between the height and width. + * + * This property is read only and is updated automatically when either the `width` or `height` properties are changed, + * providing the aspect ratio lock isn't enabled. + * + * @name Phaser.Structs.Size#ratioV + * @type {number} + * @readonly + * @since 3.16.0 + */ + this.ratioV = (width === 0) ? 0 : height / width; + + /** + * Lock the aspect ratio to its current value? + * + * If enabled, changing the width or height properties will automatically adjust the other based on the aspect ratio. + * + * @name Phaser.Structs.Size#lock + * @type {boolean} + * @since 3.16.0 + */ + this.lock = lockAspectRatio; + }, + + /** + * Lock the aspect ratio to its current value? + * + * If enabled, changing the `width` or `height` properties will automatically adjust the other based on the aspect ratio. + * + * @method Phaser.Structs.Size#setAspectRatioLock + * @since 3.16.0 + * + * @param {boolean} value - `true` to enable the aspect ratio lock or `false` to disable it. + * + * @return {this} This Size instance. + */ + setAspectRatioLock: function (value) + { + this.lock = value; + + return this; + }, + + /** + * Lock the aspect ratio to its current value? + * + * If enabled, changing the `width` or `height` properties will automatically adjust the other based on the aspect ratio. + * + * @method Phaser.Structs.Size#set + * @since 3.16.0 + * + * @param {number} [width] - The width of the Size component. + * @param {number} [height=width] - The height of the Size component. If not given, it will use the `width`. + * @param {boolean} [lockAspectRatio=false] - Should the aspect ratio between the `width` and `height` be locked? + * + * @return {this} This Size instance. + */ + set: function (width, height) + { + if (width === undefined) { width = 0; } + if (height === undefined) { height = width; } + + if (this.lock) + { + this._width = width * this.ratioH; + this._height = height * this.ratioV; + } + else + { + this._width = width; + this.height = height; + } + + return this; + }, + + /** + * Sets the width of this Size component. + * + * If the aspect ratio is locked, changing the width will also automatically update the height. + * + * @method Phaser.Structs.Size#setWidth + * @since 3.16.0 + * + * @param {number} width - The width of the Size component. + * + * @return {this} This Size instance. + */ + setWidth: function (value) + { + this.width = value; + + return this; + }, + + /** + * Gets the width of this Size component. + * + * @method Phaser.Structs.Size#getWidth + * @since 3.16.0 + * + * @return {number} The width of this Size component. + */ + getWidth: function () + { + return this._width; + }, + + /** + * Sets the height of this Size component. + * + * If the aspect ratio is locked, changing the height will also automatically update the width. + * + * @method Phaser.Structs.Size#setHeight + * @since 3.16.0 + * + * @param {number} height - The height of the Size component. + * + * @return {this} This Size instance. + */ + setHeight: function (value) + { + this.height = value; + + return this; + }, + + /** + * Gets the height of this Size component. + * + * @method Phaser.Structs.Size#getHeight + * @since 3.16.0 + * + * @return {number} The height of this Size component. + */ + getHeight: function () + { + return this._height; + }, + + /** + * Returns a string representation of this Size component. + * + * @method Phaser.Structs.Size#toString + * @since 3.16.0 + * + * @return {string} A string representation of this Size component. + */ + toString: function () + { + return '[{ Size (width=' + this._width + ' height=' + this._height + ' ratioH=' + this.ratioH + ' ratioV=' + this.ratioV + ' lock=' + this.lock + ') }]'; + }, + + /** + * The width. + * + * Changing this value will automatically update the `height` if the aspect ratio lock is enabled. + * You can also use the `setWidth` and `getWidth` methods. + * + * @name Phaser.Structs.Size#width + * @type {number} + * @since 3.16.0 + */ + width: { + + get: function () + { + return this._width; + }, + + set: function (value) + { + this._width = value; + + if (this.lock) + { + this._height = value * this.ratioV; + } + else + { + this.ratioH = (this._height === 0) ? 0 : value / this._height; + this.ratioV = (this._width === 0) ? 0 : this._height / value; + } + } + + }, + + /** + * The height. + * + * Changing this value will automatically update the `width` if the aspect ratio lock is enabled. + * You can also use the `setHeight` and `getHeight` methods. + * + * @name Phaser.Structs.Size#height + * @type {number} + * @since 3.16.0 + */ + height: { + + get: function () + { + return this._height; + }, + + set: function (value) + { + this._height = value; + + if (this.lock) + { + this._width = value * this.ratioH; + } + else + { + this.ratioH = (this._height === 0) ? 0 : this._width / value; + this.ratioV = (this._width === 0) ? 0 : value / this._width; + } + } + + } + +}); + +module.exports = Size; diff --git a/src/structs/index.js b/src/structs/index.js index 4c948e140..e3b2d2913 100644 --- a/src/structs/index.js +++ b/src/structs/index.js @@ -14,6 +14,7 @@ module.exports = { Map: require('./Map'), ProcessQueue: require('./ProcessQueue'), RTree: require('./RTree'), - Set: require('./Set') + Set: require('./Set'), + Size: require('./Size') }; From f5fcea898c311bea5c9e5a34a28d6ea9039ecb61 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 19 Dec 2018 17:07:46 +0000 Subject: [PATCH 212/221] Updated Size component to handle fitting, ratios, locking and more. --- src/structs/Size.js | 358 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 303 insertions(+), 55 deletions(-) diff --git a/src/structs/Size.js b/src/structs/Size.js index 1a29fae73..ddba90efc 100644 --- a/src/structs/Size.js +++ b/src/structs/Size.js @@ -4,12 +4,16 @@ * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ +var Clamp = require('../math/Clamp'); var Class = require('../utils/Class'); /** * @classdesc - * The Size component is a simple structure that helps you encapsulate a `width` and `height` and, if required, maintain - * the aspect ratios between them. + * The Size component allows you to set `width` and `height` properties and define the relationship between them. + * + * The component can automatically maintain the aspect ratios between the two values, and clamp them + * to a defined min-max range. You can also control the dominant axis. When dimensions are given to the Size component + * that would cause it to exceed its min-max range, the dimensions are adjusted based on the dominant axis. * * @class Size * @memberof Phaser.Structs @@ -18,17 +22,19 @@ var Class = require('../utils/Class'); * * @param {number} [width] - The width of the Size component. * @param {number} [height=width] - The height of the Size component. If not given, it will use the `width`. - * @param {boolean} [lockAspectRatio=false] - Should the aspect ratio between the `width` and `height` be locked? + * @param {boolean} [lockAspectRatio=false] - Should the aspect ratio be locked? It will be based on the given `width` and `height` arguments. + * @param {boolean} [lockWidth=true] - Set to `true` to make the `width` the dominant axis, or `false` to make `height` the dominant axis. */ var Size = new Class({ initialize: - function Size (width, height, lockAspectRatio) + function Size (width, height, lockAspectRatio, lockWidth) { if (width === undefined) { width = 0; } if (height === undefined) { height = width; } if (lockAspectRatio === undefined) { lockAspectRatio = false; } + if (lockWidth === undefined) { lockWidth = true; } /** * The width. @@ -61,7 +67,7 @@ var Size = new Class({ * @readonly * @since 3.16.0 */ - this.ratioH = (height === 0) ? 0 : width / height; + this.ratioH = (height === 0) ? 1 : width / height; /** * The proportional relationship between the height and width. @@ -74,18 +80,70 @@ var Size = new Class({ * @readonly * @since 3.16.0 */ - this.ratioV = (width === 0) ? 0 : height / width; + this.ratioV = (width === 0) ? 1 : height / width; /** - * Lock the aspect ratio to its current value? + * Set this property to lock the aspect ratios to their current values. * - * If enabled, changing the width or height properties will automatically adjust the other based on the aspect ratio. + * Once enabled, changing the `width` or `height` properties will automatically adjust the other based on the aspect ratio. * - * @name Phaser.Structs.Size#lock + * @name Phaser.Structs.Size#lockAspectRatio * @type {boolean} * @since 3.16.0 */ - this.lock = lockAspectRatio; + this.lockAspectRatio = lockAspectRatio; + + /** + * When scaling the Size based on the min-max range and the aspect ratio, this property controls the priority of + * the axis. If `true` (the default) the `width` will be the dominant axis, and the height will adjust to match it. If `false`, + * the `height` will be the dominant axis, and the `width` will adjust to match it. + * + * @name Phaser.Structs.Size#lockWidth + * @type {boolean} + * @default true + * @since 3.16.0 + */ + this.lockWidth = lockWidth; + + /** + * The minimum allowed width. + * + * @name Phaser.Structs.Size#_minWidth + * @type {number} + * @private + * @since 3.16.0 + */ + this._minWidth = 0; + + /** + * The minimum allowed height. + * + * @name Phaser.Structs.Size#_minHeight + * @type {number} + * @private + * @since 3.16.0 + */ + this._minHeight = 0; + + /** + * The maximum allowed width. + * + * @name Phaser.Structs.Size#_maxWidth + * @type {number} + * @private + * @since 3.16.0 + */ + this._maxWidth = Number.MAX_VALUE; + + /** + * The maximum allowed height. + * + * @name Phaser.Structs.Size#_maxHeight + * @type {number} + * @private + * @since 3.16.0 + */ + this._maxHeight = Number.MAX_VALUE; }, /** @@ -102,41 +160,247 @@ var Size = new Class({ */ setAspectRatioLock: function (value) { - this.lock = value; + this.lockAspectRatio = value; return this; }, /** - * Lock the aspect ratio to its current value? + * Set the minimum width and height values this Size component will allow. * - * If enabled, changing the `width` or `height` properties will automatically adjust the other based on the aspect ratio. + * If enabled, the properties will be clamped to the min-max range, including when locked to their aspect ratios. + * + * Setting this will automatically adjust both the `width` and `height` properties to ensure they are within range. * - * @method Phaser.Structs.Size#set + * @method Phaser.Structs.Size#setMin * @since 3.16.0 * - * @param {number} [width] - The width of the Size component. - * @param {number} [height=width] - The height of the Size component. If not given, it will use the `width`. - * @param {boolean} [lockAspectRatio=false] - Should the aspect ratio between the `width` and `height` be locked? + * @param {number} [width=0] - The minimum allowed width of the Size component. + * @param {number} [height=width] - The minimum allowed height of the Size component. If not given, it will use the `width`. * * @return {this} This Size instance. */ - set: function (width, height) + setMin: function (width, height) { if (width === undefined) { width = 0; } if (height === undefined) { height = width; } - if (this.lock) + this._minWidth = width; + this._minHeight = height; + + return this.update(); + }, + + /** + * Set the maximum width and height values this Size component will allow. + * + * If enabled, the properties will be clamped to the min-max range, including when locked to their aspect ratios. + * + * Setting this will automatically adjust both the `width` and `height` properties to ensure they are within range. + * + * @method Phaser.Structs.Size#setMax + * @since 3.16.0 + * + * @param {number} [width=Number.MAX_VALUE] - The maximum allowed width of the Size component. + * @param {number} [height=width] - The maximum allowed height of the Size component. If not given, it will use the `width`. + * + * @return {this} This Size instance. + */ + setMax: function (width, height) + { + if (width === undefined) { width = Number.MAX_VALUE; } + if (height === undefined) { height = width; } + + this._maxWidth = width; + this._maxHeight = height; + + return this.update(); + }, + + /** + * Calls `setSize` with the current width and height. + * This has the effect of applying min-max clamping and axis locking to the current values. + * + * @method Phaser.Structs.Size#update + * @since 3.16.0 + * + * @return {this} This Size instance. + */ + update: function () + { + return this.setSize(this._width, this._height); + }, + + /** + * Updates the `ratioH` and `ratioV` properties based on the current width and height. + * + * They are only updated if `lockAspectRatio` is `false`. + * + * @method Phaser.Structs.Size#updateRatios + * @since 3.16.0 + * + * @return {this} This Size instance. + */ + updateRatios: function () + { + if (!this.lockAspectRatio) { - this._width = width * this.ratioH; - this._height = height * this.ratioV; + this.ratioH = (this._height === 0) ? 1 : this._width / this._height; + this.ratioV = (this._width === 0) ? 1 : this._height / this._width; } - else + + return this; + }, + + /** + * Sets a new width for this Size component. + * + * The new width is clamped to the min-max range automatically. + * + * Additionally, if the aspect ratio is locked, the height will also be adjusted based on the new width. + * + * @method Phaser.Structs.Size#updateWidth + * @since 3.16.0 + * + * @param {number} width - The new width of the Size component. + * + * @return {this} This Size instance. + */ + updateWidth: function (width) + { + width = Clamp(width, this._minWidth, this._maxWidth); + + if (this.lockAspectRatio) { - this._width = width; - this.height = height; + // What's the new height? + var height = width * this.ratioV; + + // height takes priority + if (!this.lockWidth) + { + if (height < this._minHeight) + { + height = this._minHeight; + } + else if (height > this._maxHeight) + { + height = this._maxHeight; + } + + // Re-adjust the width based on the dominant height + width = height * this.ratioH; + } } + this._width = width; + this._height = height; + + return this.updateRatios(); + }, + + /** + * Sets a new height for this Size component. + * + * The new height is clamped to the min-max range automatically. + * + * Additionally, if the aspect ratio is locked, the width will also be adjusted based on the new height. + * + * @method Phaser.Structs.Size#updateHeight + * @since 3.16.0 + * + * @param {number} height - The new height of the Size component. + * + * @return {this} This Size instance. + */ + updateHeight: function (height) + { + height = Clamp(height, this._minHeight, this._maxHeight); + + if (this.lockAspectRatio) + { + // What's the new width? + var width = height * this.ratioH; + + // width takes priority + if (this.lockWidth) + { + if (width < this._minWidth) + { + width = this._minWidth; + } + else if (width > this._maxWidth) + { + width = this._maxWidth; + } + + // Re-adjust the height based on the dominant width + height = width * this.ratioV; + } + } + + this._width = width; + this._height = height; + + return this.updateRatios(); + }, + + /** + * Set the width and height of this Size component, adjusting for the aspect ratio, if locked. + * + * @method Phaser.Structs.Size#setSize + * @since 3.16.0 + * + * @param {number} [width] - The width of the Size component. + * @param {number} [height=width] - The height of the Size component. If not given, it will use the `width`. + * + * @return {this} This Size instance. + */ + setSize: function (width, height) + { + if (width === undefined) { width = 0; } + if (height === undefined) { height = width; } + + return (this.lockWidth) ? this.updateWidth(width) : this.updateHeight(height); + }, + + /** + * The `width` and `height` are adjusted to fit inside the given dimensions, while keeping the current aspect ratio. + * + * There may be some space inside the parent area which is not covered if its aspect ratio differs. + * + * @method Phaser.Structs.Size#fitTo + * @since 3.16.0 + * + * @param {number} width - The width of the Size component. + * @param {number} height - The height of the Size component. + * + * @return {this} This Size instance. + */ + fitTo: function (width, height) + { + // Get the aspect ratios in case we need to expand or shrink to fit + var newRatio = (height === 0) ? 1 : width / height; + + var newWidth = width; + var newHeight = height; + + // Get the larger aspect ratio of the two. + // If aspect ratio is 1 then no adjustment needed + if (this.ratioH > newRatio) + { + newHeight = width / this.ratioH; + } + else if (this.ratioH < newRatio) + { + newWidth = height * this.ratioH; + } + + this._width = newWidth; + this._height = newHeight; + + this.ratioH = (this._height === 0) ? 1 : this._width / this._height; + this.ratioV = (this._width === 0) ? 1 : this._height / this._width; + return this; }, @@ -154,9 +418,7 @@ var Size = new Class({ */ setWidth: function (value) { - this.width = value; - - return this; + return this.updateWidth(value); }, /** @@ -186,9 +448,7 @@ var Size = new Class({ */ setHeight: function (value) { - this.height = value; - - return this; + return this.updateHeight(value); }, /** @@ -214,11 +474,15 @@ var Size = new Class({ */ toString: function () { - return '[{ Size (width=' + this._width + ' height=' + this._height + ' ratioH=' + this.ratioH + ' ratioV=' + this.ratioV + ' lock=' + this.lock + ') }]'; + return '[{ Size (width=' + this._width + ' height=' + this._height + ' ratioH=' + this.ratioH + ' ratioV=' + this.ratioV + ' lockAspectRatio=' + this.lockAspectRatio + ') }]'; }, /** - * The width. + * The width of this Size component. + * + * This value is clamped to the range specified by `minWidth` and `maxWidth`, if enabled. + * + * A width can never be less than zero. * * Changing this value will automatically update the `height` if the aspect ratio lock is enabled. * You can also use the `setWidth` and `getWidth` methods. @@ -236,23 +500,17 @@ var Size = new Class({ set: function (value) { - this._width = value; - - if (this.lock) - { - this._height = value * this.ratioV; - } - else - { - this.ratioH = (this._height === 0) ? 0 : value / this._height; - this.ratioV = (this._width === 0) ? 0 : this._height / value; - } + this.updateWidth(value); } }, /** - * The height. + * The height of this Size component. + * + * This value is clamped to the range specified by `minHeight` and `maxHeight`, if enabled. + * + * A height can never be less than zero. * * Changing this value will automatically update the `width` if the aspect ratio lock is enabled. * You can also use the `setHeight` and `getHeight` methods. @@ -270,17 +528,7 @@ var Size = new Class({ set: function (value) { - this._height = value; - - if (this.lock) - { - this._width = value * this.ratioH; - } - else - { - this.ratioH = (this._height === 0) ? 0 : this._width / value; - this.ratioV = (this._width === 0) ? 0 : value / this._width; - } + this.updateHeight(value); } } From 81c4c546281aae0d3d79a803259c74b789b71fb9 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 19 Dec 2018 17:08:06 +0000 Subject: [PATCH 213/221] Beta 4 --- src/const.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/const.js b/src/const.js index dcbbc7d1d..c2060cd7c 100644 --- a/src/const.js +++ b/src/const.js @@ -20,7 +20,7 @@ var CONST = { * @type {string} * @since 3.0.0 */ - VERSION: '3.16.0 Beta 3', + VERSION: '3.16.0 Beta 4', BlendModes: require('./renderer/BlendModes'), From e33bf4f7c08a169b4f9dc1ca46d9171eeda788c2 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 19 Dec 2018 17:08:14 +0000 Subject: [PATCH 214/221] Swapping to Size component --- src/dom/ScaleManager.js | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/dom/ScaleManager.js b/src/dom/ScaleManager.js index 3b9dedbf0..e73061802 100644 --- a/src/dom/ScaleManager.js +++ b/src/dom/ScaleManager.js @@ -7,8 +7,10 @@ var Class = require('../utils/Class'); var CONST = require('./const'); var NOOP = require('../utils/NOOP'); -var Vec2 = require('../math/Vector2'); var Rectangle = require('../geom/rectangle/Rectangle'); +var Size = require('../structs/Size'); +var SnapFloor = require('../math/snap/SnapFloor'); +var Vec2 = require('../math/Vector2'); /** * @classdesc @@ -41,19 +43,25 @@ var ScaleManager = new Class({ this.scaleMode = 0; // The base game size, as requested in the game config - this.width = 0; - this.height = 0; + this.gameSize = new Size(); // The canvas size, which is the base game size * zoom * resolution - this.canvasWidth = 0; - this.canvasHeight = 0; + this.canvasSize = new Size(); + + // this.width = 0; + // this.height = 0; + + // this.canvasWidth = 0; + // this.canvasHeight = 0; this.resolution = 1; this.zoom = 1; // The actual displayed canvas size (after refactoring in CSS depending on the scale mode, parent, etc) - this.displayWidth = 0; - this.displayHeight = 0; + this.displaySize = new Size(); + + // this.displayWidth = 0; + // this.displayHeight = 0; // The scale factor between the base game size and the displayed size this.scale = new Vec2(1); @@ -71,6 +79,8 @@ var ScaleManager = new Class({ this.allowFullScreen = false; + this.snap = new Vec2(1, 1); + this.listeners = { orientationChange: NOOP, From a40b6056f594b7b2216e42c25b6eee9a0cafc201 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 20 Dec 2018 12:12:20 +0000 Subject: [PATCH 215/221] Added jsdocs --- src/geom/rectangle/FitInside.js | 16 ++++++++-------- src/geom/rectangle/FitOutside.js | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/geom/rectangle/FitInside.js b/src/geom/rectangle/FitInside.js index 90c0e01a8..4064fa6b0 100644 --- a/src/geom/rectangle/FitInside.js +++ b/src/geom/rectangle/FitInside.js @@ -6,22 +6,22 @@ var GetAspectRatio = require('./GetAspectRatio'); -// Fits the target rectangle into the source rectangle. -// Preserves aspect ratio. -// Scales and centers the target rectangle to the source rectangle - /** - * [description] + * Adjusts the target rectangle, changing its width, height and position, + * so that it fits inside the area of the source rectangle, while maintaining its original + * aspect ratio. + * + * Unlike the `FitOutside` function, there may be some space inside the source area not covered. * * @function Phaser.Geom.Rectangle.FitInside * @since 3.0.0 * * @generic {Phaser.Geom.Rectangle} O - [target,$return] * - * @param {Phaser.Geom.Rectangle} target - [description] - * @param {Phaser.Geom.Rectangle} source - [description] + * @param {Phaser.Geom.Rectangle} target - The target rectangle to adjust. + * @param {Phaser.Geom.Rectangle} source - The source rectangle to envlope the target in. * - * @return {Phaser.Geom.Rectangle} [description] + * @return {Phaser.Geom.Rectangle} The modified target rectangle instance. */ var FitInside = function (target, source) { diff --git a/src/geom/rectangle/FitOutside.js b/src/geom/rectangle/FitOutside.js index a78bbdbcd..be7941bef 100644 --- a/src/geom/rectangle/FitOutside.js +++ b/src/geom/rectangle/FitOutside.js @@ -6,22 +6,22 @@ var GetAspectRatio = require('./GetAspectRatio'); -// Fits the target rectangle around the source rectangle. -// Preserves aspect ration. -// Scales and centers the target rectangle to the source rectangle - /** - * [description] + * Adjusts the target rectangle, changing its width, height and position, + * so that it fully covers the area of the source rectangle, while maintaining its original + * aspect ratio. + * + * Unlike the `FitInside` function, the target rectangle may extend further out than the source. * * @function Phaser.Geom.Rectangle.FitOutside * @since 3.0.0 * * @generic {Phaser.Geom.Rectangle} O - [target,$return] * - * @param {Phaser.Geom.Rectangle} target - [description] - * @param {Phaser.Geom.Rectangle} source - [description] + * @param {Phaser.Geom.Rectangle} target - The target rectangle to adjust. + * @param {Phaser.Geom.Rectangle} source - The source rectangle to envlope the target in. * - * @return {Phaser.Geom.Rectangle} [description] + * @return {Phaser.Geom.Rectangle} The modified target rectangle instance. */ var FitOutside = function (target, source) { From 52519a19327ef1fbc2c388bef385ac46d462b51d Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 20 Dec 2018 12:12:31 +0000 Subject: [PATCH 216/221] Updated docs and added envelope method. --- src/structs/Size.js | 69 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/src/structs/Size.js b/src/structs/Size.js index ddba90efc..ab3f3da66 100644 --- a/src/structs/Size.js +++ b/src/structs/Size.js @@ -156,7 +156,7 @@ var Size = new Class({ * * @param {boolean} value - `true` to enable the aspect ratio lock or `false` to disable it. * - * @return {this} This Size instance. + * @return {this} This Size component instance. */ setAspectRatioLock: function (value) { @@ -178,7 +178,7 @@ var Size = new Class({ * @param {number} [width=0] - The minimum allowed width of the Size component. * @param {number} [height=width] - The minimum allowed height of the Size component. If not given, it will use the `width`. * - * @return {this} This Size instance. + * @return {this} This Size component instance. */ setMin: function (width, height) { @@ -204,7 +204,7 @@ var Size = new Class({ * @param {number} [width=Number.MAX_VALUE] - The maximum allowed width of the Size component. * @param {number} [height=width] - The maximum allowed height of the Size component. If not given, it will use the `width`. * - * @return {this} This Size instance. + * @return {this} This Size component instance. */ setMax: function (width, height) { @@ -224,7 +224,7 @@ var Size = new Class({ * @method Phaser.Structs.Size#update * @since 3.16.0 * - * @return {this} This Size instance. + * @return {this} This Size component instance. */ update: function () { @@ -239,7 +239,7 @@ var Size = new Class({ * @method Phaser.Structs.Size#updateRatios * @since 3.16.0 * - * @return {this} This Size instance. + * @return {this} This Size component instance. */ updateRatios: function () { @@ -264,7 +264,7 @@ var Size = new Class({ * * @param {number} width - The new width of the Size component. * - * @return {this} This Size instance. + * @return {this} This Size component instance. */ updateWidth: function (width) { @@ -310,7 +310,7 @@ var Size = new Class({ * * @param {number} height - The new height of the Size component. * - * @return {this} This Size instance. + * @return {this} This Size component instance. */ updateHeight: function (height) { @@ -353,7 +353,7 @@ var Size = new Class({ * @param {number} [width] - The width of the Size component. * @param {number} [height=width] - The height of the Size component. If not given, it will use the `width`. * - * @return {this} This Size instance. + * @return {this} This Size component instance. */ setSize: function (width, height) { @@ -364,17 +364,18 @@ var Size = new Class({ }, /** - * The `width` and `height` are adjusted to fit inside the given dimensions, while keeping the current aspect ratio. + * The `width` and `height` are adjusted to fit inside the given dimensions, while keeping the current aspect ratio, + * regardless if the aspect ratio is locked or not. * * There may be some space inside the parent area which is not covered if its aspect ratio differs. * * @method Phaser.Structs.Size#fitTo * @since 3.16.0 * - * @param {number} width - The width of the Size component. - * @param {number} height - The height of the Size component. + * @param {number} width - The new width of the Size component. + * @param {number} height - The new height of the Size component. * - * @return {this} This Size instance. + * @return {this} This Size component instance. */ fitTo: function (width, height) { @@ -398,8 +399,44 @@ var Size = new Class({ this._width = newWidth; this._height = newHeight; - this.ratioH = (this._height === 0) ? 1 : this._width / this._height; - this.ratioV = (this._width === 0) ? 1 : this._height / this._width; + return this; + }, + + /** + * The `width` and `height` are adjusted to fit inside the given dimensions, while keeping the current aspect ratio, + * regardless if the aspect ratio is locked or not. + * + * There may be some space inside the parent area which is not covered if its aspect ratio differs. + * + * @method Phaser.Structs.Size#fitTo + * @since 3.16.0 + * + * @param {number} width - The new width of the Size component. + * @param {number} height - The new height of the Size component. + * + * @return {this} This Size component instance. + */ + envelope: function (width, height) + { + // Get the aspect ratio in case we need to expand or shrink to fit + var newRatio = (height === 0) ? 1 : width / height; + + var newWidth = width; + var newHeight = height; + + if (this.ratioH > newRatio) + { + newWidth = height * this.ratioH; + // target.setSize(source.height * ratio, source.height); + } + else if (this.ratioH < newRatio) + { + newHeight = width / this.ratioH; + // target.setSize(source.width, source.width / ratio); + } + + this._width = newWidth; + this._height = newHeight; return this; }, @@ -414,7 +451,7 @@ var Size = new Class({ * * @param {number} width - The width of the Size component. * - * @return {this} This Size instance. + * @return {this} This Size component instance. */ setWidth: function (value) { @@ -444,7 +481,7 @@ var Size = new Class({ * * @param {number} height - The height of the Size component. * - * @return {this} This Size instance. + * @return {this} This Size component instance. */ setHeight: function (value) { From ef0b18f88bcb96841288cced6536becbbe186322 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 20 Dec 2018 12:12:49 +0000 Subject: [PATCH 217/221] If a Map entry exists, it is updated with the new value, rather than skipped. --- src/structs/Map.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/structs/Map.js b/src/structs/Map.js index ac84967aa..7ade64572 100644 --- a/src/structs/Map.js +++ b/src/structs/Map.js @@ -78,6 +78,7 @@ var Map = new Class({ /** * Adds an element with a specified `key` and `value` to this Map. + * If the `key` already exists, the value will be replaced. * * @method Phaser.Structs.Map#set * @since 3.0.0 @@ -95,10 +96,11 @@ var Map = new Class({ { if (!this.has(key)) { - this.entries[key] = value; this.size++; } + this.entries[key] = value; + return this; }, From cc280d8950d7d5fe30c28bee17475468701d31e5 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 21 Dec 2018 02:47:10 +0000 Subject: [PATCH 218/221] Removed dead code --- src/structs/Size.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/structs/Size.js b/src/structs/Size.js index ab3f3da66..1b44d0471 100644 --- a/src/structs/Size.js +++ b/src/structs/Size.js @@ -379,14 +379,11 @@ var Size = new Class({ */ fitTo: function (width, height) { - // Get the aspect ratios in case we need to expand or shrink to fit var newRatio = (height === 0) ? 1 : width / height; var newWidth = width; var newHeight = height; - // Get the larger aspect ratio of the two. - // If aspect ratio is 1 then no adjustment needed if (this.ratioH > newRatio) { newHeight = width / this.ratioH; @@ -418,7 +415,6 @@ var Size = new Class({ */ envelope: function (width, height) { - // Get the aspect ratio in case we need to expand or shrink to fit var newRatio = (height === 0) ? 1 : width / height; var newWidth = width; @@ -427,12 +423,10 @@ var Size = new Class({ if (this.ratioH > newRatio) { newWidth = height * this.ratioH; - // target.setSize(source.height * ratio, source.height); } else if (this.ratioH < newRatio) { newHeight = width / this.ratioH; - // target.setSize(source.width, source.width / ratio); } this._width = newWidth; From 98c68b8595fc1aa0acfcd80d0701b751b82b9d3f Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 21 Dec 2018 02:47:14 +0000 Subject: [PATCH 219/221] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c31b8a6df..8a5388180 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -202,6 +202,7 @@ one set of bindings ever created, which makes things a lot cleaner. * `WebGLRenderer.setScissor` now has a new optional argument `drawingBufferHeight` which allows you to specify the drawing buffer height, rather than use the renderers default value. * `WebGLRenderer.pushScissor` now has a new optional argument `drawingBufferHeight` which allows you to specify the drawing buffer height, rather than use the renderers default value. * `WebGLRenderer.preRender` now calls `gl.clearColor` in order to restore the background clear color in case something, like a Render Texture, has changed it. +* `Map.set` will now update an existing value if you provide it with a key that already exists within the Map. Previously, if you tried to set the value of a key that existed it would be skipped. ### Bug Fixes From 5aef34884cc6ea1b488dd69915412b704a00ab94 Mon Sep 17 00:00:00 2001 From: jestarray <34615798+jestarray@users.noreply.github.com> Date: Fri, 21 Dec 2018 08:25:42 -0800 Subject: [PATCH 220/221] texture optional frame parameters not specifying frame works on said methods --- src/textures/TextureManager.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/textures/TextureManager.js b/src/textures/TextureManager.js index 8b83e77ed..60e2bf2b0 100644 --- a/src/textures/TextureManager.js +++ b/src/textures/TextureManager.js @@ -915,7 +915,7 @@ var TextureManager = new Class({ * @param {integer} x - The x coordinate of the pixel within the Texture. * @param {integer} y - The y coordinate of the pixel within the Texture. * @param {string} key - The unique string-based key of the Texture. - * @param {(string|integer)} frame - The string or index of the Frame. + * @param {(string|integer)} [frame] - The string or index of the Frame. * * @return {?Phaser.Display.Color} A Color object populated with the color values of the requested pixel, * or `null` if the coordinates were out of bounds. @@ -962,7 +962,7 @@ var TextureManager = new Class({ * @param {integer} x - The x coordinate of the pixel within the Texture. * @param {integer} y - The y coordinate of the pixel within the Texture. * @param {string} key - The unique string-based key of the Texture. - * @param {(string|integer)} frame - The string or index of the Frame. + * @param {(string|integer)} [frame] - The string or index of the Frame. * * @return {integer} A value between 0 and 255, or `null` if the coordinates were out of bounds. */ @@ -1006,7 +1006,7 @@ var TextureManager = new Class({ * * @param {Phaser.GameObjects.GameObject} gameObject - The Game Object the texture would be set on. * @param {string} key - The unique string-based key of the Texture. - * @param {(string|integer)} frame - The string or index of the Frame. + * @param {(string|integer)} [frame] - The string or index of the Frame. * * @return {Phaser.GameObjects.GameObject} The Game Object the texture was set on. */ From a18c83805839586810a8373c5b60c3e68bce9648 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 21 Dec 2018 18:51:59 +0000 Subject: [PATCH 221/221] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a5388180..796de0510 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -256,7 +256,7 @@ one set of bindings ever created, which makes things a lot cleaner. Thanks to the following for helping with the Phaser 3 Examples and TypeScript definitions, either by reporting errors, or even better, fixing them: -@guilhermehto @samvieten @darkwebdev @RoryO @snowbillr @slothyrulez @jcyuan +@guilhermehto @samvieten @darkwebdev @RoryO @snowbillr @slothyrulez @jcyuan @jestarray ### Phaser Doc Jam