Merge remote-tracking branch 'upstream/master' into feature-multi-image-loader

This commit is contained in:
iamchristopher 2018-04-11 14:03:18 -04:00
commit 95e44527c5
73 changed files with 3049 additions and 845 deletions

View file

@ -4,13 +4,13 @@
### New Features ### New Features
* A new property was added to Matter.World, `correction` which is used in the Engine.update call and allows you to adjust the time * A new property was added to Matter.World, `correction` which is used in the Engine.update call and allows you to adjust the time being passed to the simulation. The default value is 1 to remain consistent with previous releases.
being passed to the simulation. The default value is 1 to remain consistent with previous releases.
* Group.destroy has a new optional argument `destroyChildren` which will automatically call `destroy` on all children of a Group if set to true (the default is false, hence it doesn't change the public API). Fix #3246 (thanks @DouglasLapsley)
* Matter Physics now has a new config property `getDelta` which allows you to specify your own function to calculate the delta value given to the Matter Engine when it updates. * Matter Physics now has a new config property `getDelta` which allows you to specify your own function to calculate the delta value given to the Matter Engine when it updates.
* Matter Physics has two new methods: `set60Hz` and `set30Hz` which will set an Engine update rate of 60Hz and 30Hz respectively. 60Hz being the default. * Matter Physics has two new methods: `set60Hz` and `set30Hz` which will set an Engine update rate of 60Hz and 30Hz respectively. 60Hz being the default.
* Matter Physics has a new config and run-time property `autoUpdate`, which defaults to `true`. When enabled the Matter Engine will update in sync with the game step (set by Request Animation Frame). The delta value given to Matter is now controlled by the `getDelta` function. * Matter Physics has a new config and run-time property `autoUpdate`, which defaults to `true`. When enabled the Matter Engine will update in sync with the game step (set by Request Animation Frame). The delta value given to Matter is now controlled by the `getDelta` function.
* Matter Physics has a new method `step` which manually advances the physics simulation by one iteration, using whatever delta and correction values you pass in to it. When used in combination with `autoUpdate=false` you can now explicitly control the update frequency of the physics simulation and unbind it from the game step. * Matter Physics has a new method `step` which manually advances the physics simulation by one iteration, using whatever delta and correction values you pass in to it. When used in combination with `autoUpdate=false` you can now explicitly control the update frequency of the physics simulation and unbind it from the game step.
* Matter Physics has two new debug properties: `debugShowJoint` and `debugJointColor`. If defined they will display joints in Matter bodies during the postUpdate debug phase (only if debug is enabled) (thanks @OmarShehata)
* Group.destroy has a new optional argument `destroyChildren` which will automatically call `destroy` on all children of a Group if set to true (the default is false, hence it doesn't change the public API). Fix #3246 (thanks @DouglasLapsley)
* WebAudioSound.setMute is a chainable way to mute a single Sound instance. * WebAudioSound.setMute is a chainable way to mute a single Sound instance.
* WebAudioSound.setVolume is a chainable way to set the volume of a single Sound instance. * WebAudioSound.setVolume is a chainable way to set the volume of a single Sound instance.
* WebAudioSound.setSeek is a chainable way to set seek to a point of a single Sound instance. * WebAudioSound.setSeek is a chainable way to set seek to a point of a single Sound instance.
@ -20,11 +20,33 @@ being passed to the simulation. The default value is 1 to remain consistent with
* HTML5AudioSound.setSeek is a chainable way to set seek to a point of a single Sound instance. * HTML5AudioSound.setSeek is a chainable way to set seek to a point of a single Sound instance.
* HTML5AudioSound.setLoop is a chainable way to set the loop state of a single Sound instance. * HTML5AudioSound.setLoop is a chainable way to set the loop state of a single Sound instance.
* BitmapText has a new property `letterSpacing` which accepts a positive or negative number to add / reduce spacing between characters (thanks @wtravO) * BitmapText has a new property `letterSpacing` which accepts a positive or negative number to add / reduce spacing between characters (thanks @wtravO)
* Matter Physics has two new debug properties: `debugShowJoint` and `debugJointColor`. If defined they will display joints in Matter bodies during the postUpdate debug phase (only if debug is enabled) (thanks @OmarShehata)
* You can now pass a Sprite Sheet or Canvas as the Texture key to `Tilemap.addTileset` and it will work in WebGL, where-as before it would display a corrupted tilemap. Fix #3407 (thanks @Zykino) * You can now pass a Sprite Sheet or Canvas as the Texture key to `Tilemap.addTileset` and it will work in WebGL, where-as before it would display a corrupted tilemap. Fix #3407 (thanks @Zykino)
* Graphics.slice allows you to easily draw a Pacman, or slice of pie shape to a Graphics object. * Graphics.slice allows you to easily draw a Pacman, or slice of pie shape to a Graphics object.
* List.addCallback is a new optional callback that is invoked every time a new child is added to the List. You can use this to have a callback fire when children are added to the Display List. * List.addCallback is a new optional callback that is invoked every time a new child is added to the List. You can use this to have a callback fire when children are added to the Display List.
* List.removeCallback is a new optional callback that is invoked every time a new child is removed from the List. You can use this to have a callback fire when children are removed from the Display List. * List.removeCallback is a new optional callback that is invoked every time a new child is removed from the List. You can use this to have a callback fire when children are removed from the Display List.
* ScenePlugin.restart allows you to restart the current Scene. It's the same result as calling `ScenePlugin.start` without any arguments, but is more clear.
* Utils.Array.Add allows you to add one or more items safely to an array, with optional limits and callbacks.
* Utils.Array.AddAt allows you to add one or more items safely to an array at a specified position, with optional limits and callbacks.
* Utils.Array.BringToTop allows you to bring an array element to the top of the array.
* Utils.Array.CountAllMatching will scan an array and count all elements with properties matching the given value.
* Utils.Array.Each will pass each element of an array to a given callback, with optional arguments.
* Utils.Array.EachInRange will pass each element of an array in a given range to a callback, with optional arguments.
* Utils.Array.GetAll will return all elements from an array, with optional property and value comparisons.
* Utils.Array.GetFirst will return the first element in an array, with optional property and value comparisons.
* Utils.Array.GetRandomElement has been renamed to GetRandom and will return a random element from an array.
* Utils.Array.MoveDown will move the given array element down one position in the array.
* Utils.Array.MoveTo will move the given array element to the given position in the array.
* Utils.Array.MoveUp will move the given array element up one position in the array.
* Utils.Array.Remove will remove the given element or array of elements from the array, with an optional callback.
* Utils.Array.RemoveAt will remove the element from the given position in the array, with an optional callback.
* Utils.Array.RemoveBetween will remove the elements between the given range in the array, with an optional callback.
* Utils.Array.Replace will replace an existing element in an array with a new one.
* Utils.Array.SendToBack allows you to send an array element to the bottom of the array.
* Utils.Array.SetAll will set a property on all elements of an array to the given value, with optional range limits.
* Utils.Array.Swap will swap the position of two elements in an array.
* TransformMatrix.destroy is a new method that will clear out the array and object used by a Matrix internally.
* BaseSound, and by extension WebAudioSound and HTMLAudioSound, will now emit a `destroy` event when they are destroyed (thanks @rexrainbow)
* A new property was added to the Scene config: `mapAdd` which is used to extend the default injection map of a scene instead of overwriting it (thanks @sebashwa)
### Bug Fixes ### Bug Fixes
@ -44,11 +66,22 @@ being passed to the simulation. The default value is 1 to remain consistent with
* Line.getPointA and Line.getPointB incorrectly set the values into the Vector2 (thanks @Tomas2h) * Line.getPointA and Line.getPointB incorrectly set the values into the Vector2 (thanks @Tomas2h)
* DynamicTilemapLayer now uses the ComputedSize component, which stops it breaking if you call `setDisplaySize` (thanks Babsobar) * DynamicTilemapLayer now uses the ComputedSize component, which stops it breaking if you call `setDisplaySize` (thanks Babsobar)
* StaticTilemapLayer now uses the ComputedSize component, which stops it breaking if you call `setDisplaySize` (thanks Babsobar) * StaticTilemapLayer now uses the ComputedSize component, which stops it breaking if you call `setDisplaySize` (thanks Babsobar)
* CanvasPool.first always returned `null`, and now returns the first available Canvas. Fix #3520 (thanks @mchiasson)
* When starting a new Scene with an optional `data` argument it wouldn't get passed through if the Scene was not yet available (i.e. the game had not fully booted). The data is now passed to the Scene `init` and `create` methods and stored in the Scene Settings `data` property. Fix #3363 (thanks @pixelhijack)
* Tween.restart handles removed tweens properly and reads them back into the active queue for the TweenManager (thanks @wtravO)
* Tween.resume will now call `Tween.play` on a tween that was paused due to its config object, not as a result of having its paused method called. Fix #3452 (thanks @jazen)
* LoaderPlugin.isReady referenced a constant that no longer exists. Fix #3503 (thanks @Twilrom)
* Tween Timeline.destroy was trying to call `destroy` on Tweens instead of `stop` (thanks @Antriel)
* Calling `setOffset` on a Static Arcade Physics Body would break because the method was missing. It has been added and now functions as expected. Fix #3465 (thanks @josephjaniga and @DouglasLapsley)
* Calling Impact.World.remove(body) during a Body.updateCallback would cause the internal loop to crash when trying to access a now missing body. Two extra checks are in place to avoid this (thanks @iamDecode)
* If `setInteractive` is called on a Game Object that fails to set a hit area, it will no longer try to assign `dropZone` to an undefined `input` property.
* The Matter SetBody Component will no longer try to call `setOrigin` unless the Game Object has the origin component (which not all do, like Graphics and Container)
* Matter Image and Matter Sprite didn't define a `destroy` method, causing an error when trying to destroy the parent Game Object. Fix #3516 (thanks @RollinSafary)
* Fixed loading normals with multi image load (thanks @iamchristopher) * Fixed loading normals with multi image load (thanks @iamchristopher)
### Updates ### Updates
* The RTree library (rbush) used by Phaser 3 suffered from violating CSP policies by dynamically creating Functions at run-time in an eval-like manner. These are now defined via generators. Fix #3441 (thanks @jamierocks @Colbydude) * The RTree library (rbush) used by Phaser 3 suffered from violating CSP policies by dynamically creating Functions at run-time in an eval-like manner. These are now defined via generators. Fix #3441 (thanks @jamierocks @Colbydude @jdotrjs)
* BaseSound has had its `rate` and `detune` properties removed as they are always set in the overriding class. * BaseSound has had its `rate` and `detune` properties removed as they are always set in the overriding class.
* BaseSound `setRate` and `setDetune` from the 3.3.0 release have moved to the WebAudioSound and HTML5AudioSound classes respectively, as they each handle the values differently. * BaseSound `setRate` and `setDetune` from the 3.3.0 release have moved to the WebAudioSound and HTML5AudioSound classes respectively, as they each handle the values differently.
* The file `InteractiveObject.js` has been renamed to `CreateInteractiveObject.js` to more accurately reflect what it does and to avoid type errors in the docs. * The file `InteractiveObject.js` has been renamed to `CreateInteractiveObject.js` to more accurately reflect what it does and to avoid type errors in the docs.
@ -66,12 +99,30 @@ being passed to the simulation. The default value is 1 to remain consistent with
* List.removeAt has a new optional argument `skipCallback`. * List.removeAt has a new optional argument `skipCallback`.
* List.removeBetween has a new optional argument `skipCallback`. * List.removeBetween has a new optional argument `skipCallback`.
* List.removeAll has a new optional argument `skipCallback`. * List.removeAll has a new optional argument `skipCallback`.
* When using the `extend` property of a Scene config object it will now block overwriting the Scene `sys` property.
* When using the `extend` property of a Scene config object, if you define a property called `data` that has an object set, it will populate the Scenes Data Manager with those values.
* SceneManager._processing has been renamed to `isProcessing` which is now a boolean, not an integer. It's also now public and read-only.
* SceneManager.isBooted is a new boolean read-only property that lets you know if the Scene Manager has performed its initial boot sequence.
* TransformMatrix has the following new getter and setters: `a`, `b`, `c`, `d`, `tx` and `ty`. It also has the following new getters: `scaleX`, `scaleY` and `rotation`.
* List.getByKey has been removed. Use `List.getFirst` instead which offers the exact same functionality.
* List.sortIndexHandler has been removed because it's no longer required.
* List.sort no longer takes an array as its argument, instead it only sorts the List contents by the defined property.
* List.addMultiple has been removed. Used `List.add` instead which offers the exact same functionality.
* List is now internally using all of the new Utils.Array functions.
* Rectangle.Union will now cache all vars internally so you can use one of the input rectangles as the output rectangle without corrupting it.
* When shutting down a Matter World it will now call MatterEvents.off, clearing all events, and also `removeAllListeners` for any local events.
### Animation Component Updates ### Animation System Updates
We have refactored the Animation API to make it more consistent with the rest of Phaser 3 and to fix some issues. All of the following changes apply to the Animation Component: We have refactored the Animation API to make it more consistent with the rest of Phaser 3 and to fix some issues. All of the following changes apply to the Animation Component:
* Animation durations, delays and repeatDelays are all now specified in milliseconds, not seconds like before. This makes them consistent with Tweens, Sounds and other parts of v3. You can still use the `frameRate` property to set the speed of an animation in frames per second. * Animation durations, delays and repeatDelays are all now specified in milliseconds, not seconds like before. This makes them consistent with Tweens, Sounds and other parts of v3. You can still use the `frameRate` property to set the speed of an animation in frames per second.
* All of the Animation callbacks have been removed, including `onStart`, `onRepeat`, `onUpdate` and `onComplete` and the corresponding params arrays like `onStartParams` and the property `callbackScope`. The reason for this is that they were all set on a global level, meaning that if you had 100 Sprites sharing the same animation, it was impossible to set the callbacks to fire for just one of those Sprites, but instead they would fire for all 100 and it was up to you to figure out which Sprite you wanted to update. Instead of callbacks animations now dispatch events on the Game Objects in which they are running. This means you can now do `sprite.on('animationstart')` and it will be invoked at the same point the old `onStart` callback would have been. The new events are: `animationstart`, `animtionrepeat`, `animationupdate` and `animationcomplete`. They're all dispatched from the Game Object that has the animation playing, not from the animation itself. This allows you far more control over what happens in the callbacks and we believe generally makes them more useful.
* The AnimationFrame.onUpdate callback has been removed. You can now use the `animationupdate` event dispatched from the Game Object itself and check the 2nd argument, which is the animation frame.
* Animation.stopAfterDelay is a new method that will stop a Sprites animation after the given time in ms.
* Animation.stopOnRepeat is a new method that will stop a Sprites animation when it goes to repeat.
* Animation.stopOnFrame is a new method that will stop a Sprites animation when it sets the given frame.
* Animation.stop no longer has the `dispatchCallbacks` argument, because it dispatches an event which you can choose to ignore.
* `delay` method has been removed. * `delay` method has been removed.
* `setDelay` allows you to define the delay before playback begins. * `setDelay` allows you to define the delay before playback begins.
* `getDelay` returns the animation playback delay value. * `getDelay` returns the animation playback delay value.
@ -113,7 +164,7 @@ We have refactored the Animation API to make it more consistent with the rest of
My thanks to the following for helping with the Phaser 3 Examples, Docs and TypeScript definitions, either by reporting errors, fixing them or helping author the docs: My thanks to the following for helping with the Phaser 3 Examples, Docs and TypeScript definitions, either by reporting errors, fixing them or helping author the docs:
@gabegordon @melissaelopez @samid737 @nbs @tgrajewski @pagesrichie @hexus @mbrickn @erd0s @icbat @Matthew-Herman @ampled @gabegordon @melissaelopez @samid737 @nbs @tgrajewski @pagesrichie @hexus @mbrickn @erd0s @icbat @Matthew-Herman @ampled @mkimmet @PaNaVTEC

View file

@ -118,6 +118,12 @@ The documentation for Phaser 3 is an on-going project. Please help us by searchi
They are automatically generated from the jsdoc comments in the Phaser source code. If you wish to help refine them then you must edit the Phaser jsdoc blocks directly. You can find more details, including the source to the conversion tool we wrote in the Docs repo. They are automatically generated from the jsdoc comments in the Phaser source code. If you wish to help refine them then you must edit the Phaser jsdoc blocks directly. You can find more details, including the source to the conversion tool we wrote in the Docs repo.
### Webpack
We use Webpack to build Phaser and we take advantage of several features specific to Webpack to do this, including `raw-loader` to handle our shader files and build-time flags for renderer swapping.
If you wish to use Webpack with Phaser then please use our [Phaser 3 Project Template](https://github.com/photonstorm/phaser3-project-template) as it's already set-up to handle the build conditions Phaser needs.
### License ### License
Phaser is released under the [MIT License](https://opensource.org/licenses/MIT). Phaser is released under the [MIT License](https://opensource.org/licenses/MIT).

View file

@ -8,10 +8,11 @@ var RotateAroundDistance = require('../math/RotateAroundDistance');
var DistanceBetween = require('../math/distance/DistanceBetween'); var DistanceBetween = require('../math/distance/DistanceBetween');
/** /**
* [description] * Rotates each item around the given point by the given angle.
* *
* @function Phaser.Actions.RotateAround * @function Phaser.Actions.RotateAround
* @since 3.0.0 * @since 3.0.0
* @see Phaser.Math.RotateAroundDistance
* *
* @generic {Phaser.GameObjects.GameObject[]} G - [items,$return] * @generic {Phaser.GameObjects.GameObject[]} G - [items,$return]
* *

View file

@ -7,10 +7,11 @@
var ArrayShuffle = require('../utils/array/Shuffle'); var ArrayShuffle = require('../utils/array/Shuffle');
/** /**
* [description] * Shuffles the array in place. The shuffled array is both modified and returned.
* *
* @function Phaser.Actions.Shuffle * @function Phaser.Actions.Shuffle
* @since 3.0.0 * @since 3.0.0
* @see Phaser.Utils.Array.Shuffle
* *
* @generic {Phaser.GameObjects.GameObject[]} G - [items,$return] * @generic {Phaser.GameObjects.GameObject[]} G - [items,$return]
* *

View file

@ -34,7 +34,6 @@ var GetValue = require('../utils/object/GetValue');
* @property {(string|number)} frame - [description] * @property {(string|number)} frame - [description]
* @property {float} [duration=0] - [description] * @property {float} [duration=0] - [description]
* @property {boolean} [visible] - [description] * @property {boolean} [visible] - [description]
* @property {function} [onUpdate] - [description]
*/ */
/** /**
@ -51,16 +50,6 @@ var GetValue = require('../utils/object/GetValue');
* @property {boolean} [yoyo=false] - Should the animation yoyo? (reverse back down to the start) before repeating? * @property {boolean} [yoyo=false] - Should the animation yoyo? (reverse back down to the start) before repeating?
* @property {boolean} [showOnStart=false] - Should sprite.visible = true when the animation starts to play? * @property {boolean} [showOnStart=false] - Should sprite.visible = true when the animation starts to play?
* @property {boolean} [hideOnComplete=false] - Should sprite.visible = false when the animation finishes? * @property {boolean} [hideOnComplete=false] - Should sprite.visible = false when the animation finishes?
* @property {*} [callbackScope] - [description]
* @property {(false|function)} [onStart=false] - [description]
* @property {Array.<*>} [onStartParams] - [description]
* @property {(false|function)} [onRepeat=false] - [description]
* @property {Array.<*>} [onRepeatParams] - [description]
* @property {(false|function)} [onUpdate=false] - [description]
* @property {Array.<*>} [onUpdateParams] - [description]
* @property {(false|function)} [onComplete=false] - [description]
* @property {Array.<*>} [onCompleteParams] - [description]
*/ */
/** /**
@ -250,88 +239,6 @@ var Animation = new Class({
*/ */
this.hideOnComplete = GetValue(config, 'hideOnComplete', false); this.hideOnComplete = GetValue(config, 'hideOnComplete', false);
/**
* [description]
*
* @name Phaser.Animations.Animation#callbackScope
* @type {*}
* @since 3.0.0
*/
this.callbackScope = GetValue(config, 'callbackScope', this);
/**
* [description]
*
* @name Phaser.Animations.Animation#onStart
* @type {(false|function)}
* @since 3.0.0
*/
this.onStart = GetValue(config, 'onStart', false);
/**
* [description]
*
* @name Phaser.Animations.Animation#onStartParams
* @type {Array.<*>}
* @since 3.0.0
*/
this.onStartParams = GetValue(config, 'onStartParams', []);
/**
* [description]
*
* @name Phaser.Animations.Animation#onRepeat
* @type {(false|function)}
* @since 3.0.0
*/
this.onRepeat = GetValue(config, 'onRepeat', false);
/**
* [description]
*
* @name Phaser.Animations.Animation#onRepeatParams
* @type {Array.<*>}
* @since 3.0.0
*/
this.onRepeatParams = GetValue(config, 'onRepeatParams', []);
/**
* Called for EVERY frame of the animation.
* See AnimationFrame.onUpdate for a frame specific callback.
*
* @name Phaser.Animations.Animation#onUpdate
* @type {(false|function)}
* @since 3.0.0
*/
this.onUpdate = GetValue(config, 'onUpdate', false);
/**
* [description]
*
* @name Phaser.Animations.Animation#onUpdateParams
* @type {Array.<*>}
* @since 3.0.0
*/
this.onUpdateParams = GetValue(config, 'onUpdateParams', []);
/**
* [description]
*
* @name Phaser.Animations.Animation#onComplete
* @type {(false|function)}
* @since 3.0.0
*/
this.onComplete = GetValue(config, 'onComplete', false);
/**
* [description]
*
* @name Phaser.Animations.Animation#onCompleteParams
* @type {Array.<*>}
* @since 3.0.0
*/
this.onCompleteParams = GetValue(config, 'onCompleteParams', []);
/** /**
* Global pause. All Game Objects using this Animation instance are impacted by this property. * Global pause. All Game Objects using this Animation instance are impacted by this property.
* *
@ -431,7 +338,7 @@ var Animation = new Class({
component.parent.visible = false; component.parent.visible = false;
} }
component.stop(true); component.stop();
}, },
/** /**
@ -536,7 +443,6 @@ var Animation = new Class({
animationFrame = new Frame(key, frame, index, textureFrame); animationFrame = new Frame(key, frame, index, textureFrame);
animationFrame.duration = GetValue(item, 'duration', 0); animationFrame.duration = GetValue(item, 'duration', 0);
animationFrame.onUpdate = GetValue(item, 'onUpdate', null);
animationFrame.isFirst = (!prev); animationFrame.isFirst = (!prev);
@ -627,8 +533,6 @@ var Animation = new Class({
component._repeat = this.repeat; component._repeat = this.repeat;
component._repeatDelay = this.repeatDelay; component._repeatDelay = this.repeatDelay;
component._yoyo = this.yoyo; component._yoyo = this.yoyo;
component._callbackArgs[1] = this;
component._updateParams = component._callbackArgs.concat(this.onUpdateParams);
} }
component.updateFrame(this.frames[startFrame]); component.updateFrame(this.frames[startFrame]);
@ -784,6 +688,11 @@ var Animation = new Class({
*/ */
repeatAnimation: function (component) repeatAnimation: function (component)
{ {
if (component._pendingStop === 2)
{
return this.completeAnimation(component);
}
if (component._repeatDelay > 0 && component.pendingRepeat === false) if (component._repeatDelay > 0 && component.pendingRepeat === false)
{ {
component.pendingRepeat = true; component.pendingRepeat = true;
@ -798,13 +707,13 @@ var Animation = new Class({
component.updateFrame(component.currentFrame.nextFrame); component.updateFrame(component.currentFrame.nextFrame);
this.getNextTick(component); if (component.isPlaying)
component.pendingRepeat = false;
if (this.onRepeat)
{ {
this.onRepeat.apply(this.callbackScope, component._callbackArgs.concat(this.onRepeatParams)); this.getNextTick(component);
component.pendingRepeat = false;
component.parent.emit('animationrepeat', this, component.currentFrame, component.repeatCounter);
} }
} }
}, },

View file

@ -142,16 +142,6 @@ var AnimationFrame = new Class({
* @since 3.0.0 * @since 3.0.0
*/ */
this.progress = 0; this.progress = 0;
/**
* A frame specific callback, invoked if this frame gets displayed and the callback is set.
*
* @name Phaser.Animations.AnimationFrame#onUpdate
* @type {?function}
* @default null
* @since 3.0.0
*/
this.onUpdate = null;
}, },
/** /**
@ -180,7 +170,6 @@ var AnimationFrame = new Class({
destroy: function () destroy: function ()
{ {
this.frame = undefined; this.frame = undefined;
this.onUpdate = undefined;
} }
}); });

View file

@ -98,6 +98,7 @@ var ValueToColor = require('../display/color/ValueToColor');
* @property {object} [images] - [description] * @property {object} [images] - [description]
* @property {string} [images.default] - [description] * @property {string} [images.default] - [description]
* @property {string} [images.missing] - [description] * @property {string} [images.missing] - [description]
* @property {object} [physics] - [description]
*/ */
/** /**

View file

@ -154,7 +154,7 @@ var Game = new Class({
this.cache = new CacheManager(this); this.cache = new CacheManager(this);
/** /**
* [description] * An instance of the Data Manager
* *
* @name Phaser.Game#registry * @name Phaser.Game#registry
* @type {Phaser.Data.DataManager} * @type {Phaser.Data.DataManager}

View file

@ -550,7 +550,7 @@ var Camera = new Class({
{ {
var object = renderableObjects[index]; var object = renderableObjects[index];
if (!object.hasOwnProperty('width')) if (!object.hasOwnProperty('width') || object.parentContainer)
{ {
culledObjects.push(object); culledObjects.push(object);
continue; continue;
@ -628,7 +628,7 @@ var Camera = new Class({
{ {
var object = interactiveObjects[index].gameObject; var object = interactiveObjects[index].gameObject;
if (!object.hasOwnProperty('width')) if (!object.hasOwnProperty('width') || object.parentContainer)
{ {
culledObjects.push(interactiveObjects[index]); culledObjects.push(interactiveObjects[index]);
continue; continue;
@ -655,73 +655,6 @@ var Camera = new Class({
return culledObjects; return culledObjects;
}, },
/**
* [description]
*
* @method Phaser.Cameras.Scene2D.Camera#cullTilemap
* @since 3.0.0
*
* @param {Phaser.Tilemaps.Tilemap} tilemap - [description]
*
* @return {Phaser.GameObjects.GameObject[]} [description]
*/
cullTilemap: function (tilemap)
{
var cameraMatrix = this.matrix.matrix;
var mva = cameraMatrix[0];
var mvb = cameraMatrix[1];
var mvc = cameraMatrix[2];
var mvd = cameraMatrix[3];
/* First Invert Matrix */
var determinant = (mva * mvd) - (mvb * mvc);
var tiles = tilemap.tiles;
if (!determinant)
{
return tiles;
}
var mve = cameraMatrix[4];
var mvf = cameraMatrix[5];
var scrollX = this.scrollX;
var scrollY = this.scrollY;
var cameraW = this.width;
var cameraH = this.height;
var culledObjects = this.culledObjects;
var length = tiles.length;
var tileW = tilemap.tileWidth;
var tileH = tilemap.tileHeight;
var cullW = cameraW + tileW;
var cullH = cameraH + tileH;
var scrollFactorX = tilemap.scrollFactorX;
var scrollFactorY = tilemap.scrollFactorY;
determinant = 1 / determinant;
culledObjects.length = 0;
for (var index = 0; index < length; ++index)
{
var tile = tiles[index];
var tileX = (tile.x - (scrollX * scrollFactorX));
var tileY = (tile.y - (scrollY * scrollFactorY));
var tx = (tileX * mva + tileY * mvc + mve);
var ty = (tileX * mvb + tileY * mvd + mvf);
var tw = ((tileX + tileW) * mva + (tileY + tileH) * mvc + mve);
var th = ((tileX + tileW) * mvb + (tileY + tileH) * mvd + mvf);
if (tx > -tileW && ty > -tileH && tw < cullW && th < cullH)
{
culledObjects.push(tile);
}
}
return culledObjects;
},
/** /**
* Fades the Camera in from the given color over the duration specified. * Fades the Camera in from the given color over the duration specified.
* *

View file

@ -126,13 +126,15 @@ var CanvasPool = function ()
{ {
if (canvasType === undefined) { canvasType = CONST.CANVAS; } if (canvasType === undefined) { canvasType = CONST.CANVAS; }
pool.forEach(function (container) for (var i = 0; i < pool.length; i++)
{ {
var container = pool[i];
if (!container.parent && container.type === canvasType) if (!container.parent && container.type === canvasType)
{ {
return container; return container;
} }
}); }
return null; return null;
}; };

View file

@ -13,7 +13,7 @@
* *
* @param {HTMLElement} element - The element to be added to the DOM. Usually a Canvas object. * @param {HTMLElement} element - The element to be added to the DOM. Usually a Canvas object.
* @param {(string|HTMLElement)} [parent] - The parent in which to add the element. Can be a string which is passed to `getElementById` or an actual DOM object. * @param {(string|HTMLElement)} [parent] - The parent in which to add the element. Can be a string which is passed to `getElementById` or an actual DOM object.
* @param {boolean} [overflowHidden=true] - [description] * @param {boolean} [overflowHidden=true] - Whether or not to hide overflowing content inside the parent.
* *
* @return {HTMLElement} The element that was added to the DOM. * @return {HTMLElement} The element that was added to the DOM.
*/ */

View file

@ -195,10 +195,11 @@ var GameObject = new Class({
}, },
/** /**
* [description] * Adds a DataManager to this object.
* *
* @method Phaser.GameObjects.GameObject#setDataEnabled * @method Phaser.GameObjects.GameObject#setDataEnabled
* @since 3.0.0 * @since 3.0.0
* @see Phaser.Data.DataManager
* *
* @return {Phaser.GameObjects.GameObject} This GameObject. * @return {Phaser.GameObjects.GameObject} This GameObject.
*/ */
@ -374,6 +375,8 @@ var GameObject = new Class({
this.scene = undefined; this.scene = undefined;
this.parentContainer = undefined;
this.removeAllListeners(); this.removeAllListeners();
} }

View file

@ -6,6 +6,40 @@
var Class = require('../../utils/Class'); var Class = require('../../utils/Class');
/**
* This event is dispatched when an animation starts playing.
*
* @event Phaser.GameObjects.Components.Animation#onStartEvent
* @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation.
* @param {Phaser.Animations.AnimationFrame} frame - Reference to the current Animation Frame.
*/
/**
* This event is dispatched when an animation repeats.
*
* @event Phaser.GameObjects.Components.Animation#onRepeatEvent
* @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation.
* @param {Phaser.Animations.AnimationFrame} frame - Reference to the current Animation Frame.
* @param {integer} repeatCount - The number of times this animation has repeated.
*/
/**
* This event is dispatched when an animation updates. This happens when the animation frame changes,
* based on the animation frame rate and other factors like timeScale and delay.
*
* @event Phaser.GameObjects.Components.Animation#onUpdateEvent
* @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation.
* @param {Phaser.Animations.AnimationFrame} frame - Reference to the current Animation Frame.
*/
/**
* This event is dispatched when an animation completes playing, either naturally or via Animation.stop.
*
* @event Phaser.GameObjects.Components.Animation#onCompleteEvent
* @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation.
* @param {Phaser.Animations.AnimationFrame} frame - Reference to the current Animation Frame.
*/
/** /**
* @classdesc * @classdesc
* A Game Object Animation Controller. * A Game Object Animation Controller.
@ -246,24 +280,29 @@ var Animation = new Class({
this._wasPlaying = false; this._wasPlaying = false;
/** /**
* Container for the callback arguments. * Internal property tracking if this Animation is waiting to stop.
* *
* @name Phaser.GameObjects.Components.Animation#_callbackArgs * 0 = No
* @type {array} * 1 = Waiting for ms to pass
* 2 = Waiting for repeat
* 3 = Waiting for specific frame
*
* @name Phaser.GameObjects.Components.Animation#_pendingStop
* @type {integer}
* @private * @private
* @since 3.0.0 * @since 3.4.0
*/ */
this._callbackArgs = [ parent, null ]; this._pendingStop = 0;
/** /**
* Container for the update arguments. * Internal property used by _pendingStop.
* *
* @name Phaser.GameObjects.Components.Animation#_updateParams * @name Phaser.GameObjects.Components.Animation#_pendingStopValue
* @type {array} * @type {any}
* @private * @private
* @since 3.0.0 * @since 3.4.0
*/ */
this._updateParams = []; this._pendingStopValue;
}, },
/** /**
@ -438,6 +477,7 @@ var Animation = new Class({
* Plays an Animation on the Game Object that owns this Animation Component. * Plays an Animation on the Game Object that owns this Animation Component.
* *
* @method Phaser.GameObjects.Components.Animation#play * @method Phaser.GameObjects.Components.Animation#play
* @fires Phaser.GameObjects.Components.Animation#onStartEvent
* @since 3.0.0 * @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} key - The string-based key of the animation to play, as defined previously in the Animation Manager.
@ -475,10 +515,7 @@ var Animation = new Class({
gameObject.visible = true; gameObject.visible = true;
} }
if (anim.onStart) gameObject.emit('animationstart', this.currentAnim, this.currentFrame);
{
anim.onStart.apply(anim.callbackScope, this._callbackArgs.concat(anim.onStartParams));
}
return gameObject; return gameObject;
}, },
@ -588,7 +625,7 @@ var Animation = new Class({
/** /**
* Gets the amount of delay between repeats, if any. * Gets the amount of delay between repeats, if any.
* *
* @method Phaser.GameObjects.Components.Animation#getRepeatDelay * @method Phaser.GameObjects.Components.Animation#getRepeatDelay
* @since 3.4.0 * @since 3.4.0
* *
@ -647,27 +684,78 @@ var Animation = new Class({
}, },
/** /**
* Stops the current animation from playing and optionally dispatches any onComplete callbacks. * Immediately stops the current animation from playing and dispatches the `animationcomplete` event.
* *
* @method Phaser.GameObjects.Components.Animation#stop * @method Phaser.GameObjects.Components.Animation#stop
* @fires Phaser.GameObjects.Components.Animation#onCompleteEvent
* @since 3.0.0 * @since 3.0.0
* *
* @param {boolean} [dispatchCallbacks=false] - [description]
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component. * @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/ */
stop: function (dispatchCallbacks) stop: function ()
{ {
if (dispatchCallbacks === undefined) { dispatchCallbacks = false; } this._pendingStop = 0;
this.isPlaying = false; this.isPlaying = false;
var anim = this.currentAnim; var gameObject = this.parent;
if (dispatchCallbacks && anim.onComplete) gameObject.emit('animationcomplete', this.currentAnim, this.currentFrame);
{
anim.onComplete.apply(anim.callbackScope, this._callbackArgs.concat(anim.onCompleteParams)); return gameObject;
} },
/**
* Stops the current animation from playing after the specified time delay, given in milliseconds.
*
* @method Phaser.GameObjects.Components.Animation#stopAfterDelay
* @fires Phaser.GameObjects.Components.Animation#onCompleteEvent
* @since 3.4.0
*
* @param {integer} delay - The number of miliseconds to wait before stopping this animation.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
stopAfterDelay: function (delay)
{
this._pendingStop = 1;
this._pendingStopValue = delay;
return this.parent;
},
/**
* Stops the current animation from playing when it next repeats.
*
* @method Phaser.GameObjects.Components.Animation#stopOnRepeat
* @fires Phaser.GameObjects.Components.Animation#onCompleteEvent
* @since 3.4.0
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
stopOnRepeat: function ()
{
this._pendingStop = 2;
return this.parent;
},
/**
* Stops the current animation from playing when it next sets the given frame.
* If this frame doesn't exist within the animation it will not stop it from playing.
*
* @method Phaser.GameObjects.Components.Animation#stopOnFrame
* @fires Phaser.GameObjects.Components.Animation#onCompleteEvent
* @since 3.4.0
*
* @param {Phaser.Animations.AnimationFrame} delay - The frame to check before stopping this animation.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
stopOnFrame: function (frame)
{
this._pendingStop = 3;
this._pendingStopValue = frame;
return this.parent; return this.parent;
}, },
@ -729,16 +817,24 @@ var Animation = new Class({
*/ */
update: function (timestamp, delta) update: function (timestamp, delta)
{ {
if (!this.isPlaying || this.currentAnim.paused) if (this.currentAnim && (this.isPlaying || !this.currentAnim.paused))
{ {
return; this.accumulator += delta * this._timeScale;
}
this.accumulator += delta * this._timeScale; if (this._pendingStop === 1)
{
this._pendingStopValue -= delta;
if (this.accumulator >= this.nextTick) if (this._pendingStopValue <= 0)
{ {
this.currentAnim.setFrame(this); return this.currentAnim.completeAnimation(this);
}
}
if (this.accumulator >= this.nextTick)
{
this.currentAnim.setFrame(this);
}
} }
}, },
@ -780,6 +876,7 @@ var Animation = new Class({
* Internal frame change handler. * Internal frame change handler.
* *
* @method Phaser.GameObjects.Components.Animation#updateFrame * @method Phaser.GameObjects.Components.Animation#updateFrame
* @fires Phaser.GameObjects.Components.Animation#onUpdateEvent
* @private * @private
* @since 3.0.0 * @since 3.0.0
* *
@ -798,14 +895,11 @@ var Animation = new Class({
var anim = this.currentAnim; var anim = this.currentAnim;
if (anim.onUpdate) gameObject.emit('animationupdate', anim, animationFrame);
{
anim.onUpdate.apply(anim.callbackScope, this._updateParams);
}
if (animationFrame.onUpdate) if (this._pendingStop === 3 && this._pendingStopValue === animationFrame)
{ {
animationFrame.onUpdate(gameObject, animationFrame); this.currentAnim.completeAnimation(this);
} }
} }
}, },
@ -859,9 +953,6 @@ var Animation = new Class({
this.currentAnim = null; this.currentAnim = null;
this.currentFrame = null; this.currentFrame = null;
this._callbackArgs = [];
this._updateParams = [];
} }
}); });

View file

@ -20,6 +20,7 @@ var GetBounds = {
/** /**
* Gets the center coordinate of this Game Object, regardless of origin. * Gets the center coordinate of this Game Object, regardless of origin.
* The returned point is calculated in local space and does not factor in any parent containers
* *
* @method Phaser.GameObjects.Components.GetBounds#getCenter * @method Phaser.GameObjects.Components.GetBounds#getCenter
* @since 3.0.0 * @since 3.0.0
@ -42,6 +43,7 @@ var GetBounds = {
/** /**
* Gets the top-left corner coordinate of this Game Object, regardless of origin. * Gets the top-left corner coordinate of this Game Object, regardless of origin.
* The returned point is calculated in local space and does not factor in any parent containers
* *
* @method Phaser.GameObjects.Components.GetBounds#getTopLeft * @method Phaser.GameObjects.Components.GetBounds#getTopLeft
* @since 3.0.0 * @since 3.0.0
@ -69,6 +71,7 @@ var GetBounds = {
/** /**
* Gets the top-right corner coordinate of this Game Object, regardless of origin. * Gets the top-right corner coordinate of this Game Object, regardless of origin.
* The returned point is calculated in local space and does not factor in any parent containers
* *
* @method Phaser.GameObjects.Components.GetBounds#getTopRight * @method Phaser.GameObjects.Components.GetBounds#getTopRight
* @since 3.0.0 * @since 3.0.0
@ -96,6 +99,7 @@ var GetBounds = {
/** /**
* Gets the bottom-left corner coordinate of this Game Object, regardless of origin. * Gets the bottom-left corner coordinate of this Game Object, regardless of origin.
* The returned point is calculated in local space and does not factor in any parent containers
* *
* @method Phaser.GameObjects.Components.GetBounds#getBottomLeft * @method Phaser.GameObjects.Components.GetBounds#getBottomLeft
* @since 3.0.0 * @since 3.0.0
@ -123,6 +127,7 @@ var GetBounds = {
/** /**
* Gets the bottom-right corner coordinate of this Game Object, regardless of origin. * Gets the bottom-right corner coordinate of this Game Object, regardless of origin.
* The returned point is calculated in local space and does not factor in any parent containers
* *
* @method Phaser.GameObjects.Components.GetBounds#getBottomRight * @method Phaser.GameObjects.Components.GetBounds#getBottomRight
* @since 3.0.0 * @since 3.0.0
@ -167,25 +172,60 @@ var GetBounds = {
// We can use the output object to temporarily store the x/y coords in: // We can use the output object to temporarily store the x/y coords in:
this.getTopLeft(output); var TLx, TLy, TRx, TRy, BLx, BLy, BRx, BRy;
var TLx = output.x; // Instead of doing a check if parent container is
var TLy = output.y; // defined per corner we only do it once.
if (this.parentContainer)
{
var parentMatrix = this.parentContainer.getWorldTransformMatrix();
this.getTopRight(output); this.getTopLeft(output);
parentMatrix.transformPoint(output.x, output.y, output);
var TRx = output.x; TLx = output.x;
var TRy = output.y; TLy = output.y;
this.getBottomLeft(output); this.getTopRight(output);
parentMatrix.transformPoint(output.x, output.y, output);
var BLx = output.x; TRx = output.x;
var BLy = output.y; TRy = output.y;
this.getBottomRight(output); this.getBottomLeft(output);
parentMatrix.transformPoint(output.x, output.y, output);
var BRx = output.x; BLx = output.x;
var BRy = output.y; BLy = output.y;
this.getBottomRight(output);
parentMatrix.transformPoint(output.x, output.y, output);
BRx = output.x;
BRy = output.y;
}
else
{
this.getTopLeft(output);
TLx = output.x;
TLy = output.y;
this.getTopRight(output);
TRx = output.x;
TRy = output.y;
this.getBottomLeft(output);
BLx = output.x;
BLy = output.y;
this.getBottomRight(output);
BRx = output.x;
BRy = output.y;
}
output.x = Math.min(TLx, TRx, BLx, BRx); output.x = Math.min(TLx, TRx, BLx, BRx);
output.y = Math.min(TLy, TRy, BLy, BRy); output.y = Math.min(TLy, TRy, BLy, BRy);

View file

@ -5,9 +5,9 @@
*/ */
var MATH_CONST = require('../../math/const'); var MATH_CONST = require('../../math/const');
var TransformMatrix = require('./TransformMatrix');
var WrapAngle = require('../../math/angle/Wrap'); var WrapAngle = require('../../math/angle/Wrap');
var WrapAngleDegrees = require('../../math/angle/WrapDegrees'); var WrapAngleDegrees = require('../../math/angle/WrapDegrees');
var TransformMatrix = require('./TransformMatrix');
// global bitmask flag for GameObject.renderMask (used by Scale) // global bitmask flag for GameObject.renderMask (used by Scale)
var _FLAG = 4; // 0100 var _FLAG = 4; // 0100
@ -371,14 +371,44 @@ var Transform = {
return this; return this;
}, },
/**
* Gets the local transform matrix for this Game Object.
*
* @method Phaser.GameObjects.Components.Transform#getLocalTransformMatrix
* @since 3.4.0
*
* @param {Phaser.GameObjects.Components.TransformMatrix} [tempMatrix] - The matrix to populate with the values from this Game Object.
*
* @return {Phaser.GameObjects.Components.TransformMatrix} The populated Transform Matrix.
*/
getLocalTransformMatrix: function (tempMatrix) getLocalTransformMatrix: function (tempMatrix)
{ {
if (tempMatrix === undefined) { tempMatrix = new TransformMatrix(); }
return tempMatrix.applyITRS(this.x, this.y, this._rotation, this._scaleX, this._scaleY); return tempMatrix.applyITRS(this.x, this.y, this._rotation, this._scaleX, this._scaleY);
}, },
/**
* Gets the world transform matrix for this Game Object, factoring in any parent Containers.
*
* @method Phaser.GameObjects.Components.Transform#getWorldTransformMatrix
* @since 3.4.0
*
* @param {Phaser.GameObjects.Components.TransformMatrix} [tempMatrix] - The matrix to populate with the values from this Game Object.
*
* @return {Phaser.GameObjects.Components.TransformMatrix} The populated Transform Matrix.
*/
getWorldTransformMatrix: function (tempMatrix) getWorldTransformMatrix: function (tempMatrix)
{ {
if (tempMatrix === undefined) { tempMatrix = new TransformMatrix(); }
var parent = this.parentContainer; var parent = this.parentContainer;
if (!parent)
{
return tempMatrix();
}
var parents = []; var parents = [];
while (parent) while (parent)
@ -393,10 +423,11 @@ var Transform = {
for (var i = 0; i < length; ++i) for (var i = 0; i < length; ++i)
{ {
rootContainer = parents[i]; parent = parents[i];
tempMatrix.translate(rootContainer.x, rootContainer.y);
tempMatrix.rotate(rootContainer.rotation); tempMatrix.translate(parent.x, parent.y);
tempMatrix.scale(rootContainer.scaleX, rootContainer.scaleY); tempMatrix.rotate(parent._rotation);
tempMatrix.scale(parent._scaleX, parent._scaleY);
} }
tempMatrix.translate(this.x, this.y); tempMatrix.translate(this.x, this.y);

View file

@ -60,6 +60,183 @@ var TransformMatrix = new Class({
}; };
}, },
/**
* [description]
*
* @name Phaser.GameObjects.Components.TransformMatrix#a
* @type {number}
* @since 3.4.0
*/
a: {
get: function ()
{
return this.matrix[0];
},
set: function (value)
{
this.matrix[0] = value;
}
},
/**
* [description]
*
* @name Phaser.GameObjects.Components.TransformMatrix#b
* @type {number}
* @since 3.4.0
*/
b: {
get: function ()
{
return this.matrix[1];
},
set: function (value)
{
this.matrix[1] = value;
}
},
/**
* [description]
*
* @name Phaser.GameObjects.Components.TransformMatrix#c
* @type {number}
* @since 3.4.0
*/
c: {
get: function ()
{
return this.matrix[2];
},
set: function (value)
{
this.matrix[2] = value;
}
},
/**
* [description]
*
* @name Phaser.GameObjects.Components.TransformMatrix#d
* @type {number}
* @since 3.4.0
*/
d: {
get: function ()
{
return this.matrix[3];
},
set: function (value)
{
this.matrix[3] = value;
}
},
/**
* [description]
*
* @name Phaser.GameObjects.Components.TransformMatrix#tx
* @type {number}
* @since 3.4.0
*/
tx: {
get: function ()
{
return this.matrix[4];
},
set: function (value)
{
this.matrix[4] = value;
}
},
/**
* [description]
*
* @name Phaser.GameObjects.Components.TransformMatrix#ty
* @type {number}
* @since 3.4.0
*/
ty: {
get: function ()
{
return this.matrix[5];
},
set: function (value)
{
this.matrix[5] = value;
}
},
/**
* [description]
*
* @name Phaser.GameObjects.Components.TransformMatrix#rotation
* @type {number}
* @readOnly
* @since 3.4.0
*/
rotation: {
get: function ()
{
return Math.acos(this.a / this.scaleX) * (Math.atan(-this.c / this.a) < 0 ? -1 : 1);
}
},
/**
* [description]
*
* @name Phaser.GameObjects.Components.TransformMatrix#scaleX
* @type {number}
* @readOnly
* @since 3.4.0
*/
scaleX: {
get: function ()
{
return Math.sqrt((this.a * this.a) + (this.c * this.c));
}
},
/**
* [description]
*
* @name Phaser.GameObjects.Components.TransformMatrix#scaleY
* @type {number}
* @readOnly
* @since 3.4.0
*/
scaleY: {
get: function ()
{
return Math.sqrt((this.b * this.b) + (this.d * this.d));
}
},
/** /**
* [description] * [description]
* *
@ -140,8 +317,18 @@ var TransformMatrix = new Class({
{ {
var radianSin = Math.sin(radian); var radianSin = Math.sin(radian);
var radianCos = Math.cos(radian); var radianCos = Math.cos(radian);
var matrix = this.matrix;
var a = matrix[0];
var b = matrix[1];
var c = matrix[2];
var d = matrix[3];
return this.transform(radianCos, radianSin, -radianSin, radianCos, 0, 0); matrix[0] = a * radianCos + c * radianSin;
matrix[1] = b * radianCos + d * radianSin;
matrix[2] = a * -radianSin + c * radianCos;
matrix[3] = b * -radianSin + d * radianCos;
return this;
}, },
/** /**
@ -371,20 +558,32 @@ var TransformMatrix = new Class({
{ {
var matrix = this.matrix; var matrix = this.matrix;
var sr = Math.sin(rotation); var radianSin = Math.sin(rotation);
var cr = Math.cos(rotation); var radianCos = Math.cos(rotation);
// Translate // Translate
matrix[4] = x; matrix[4] = x;
matrix[5] = y; matrix[5] = y;
// Rotate and Scale // Rotate and Scale
matrix[0] = cr * scaleX; matrix[0] = radianCos * scaleX;
matrix[1] = -sr * scaleX; matrix[1] = radianSin * scaleX;
matrix[2] = sr * scaleY; matrix[2] = -radianSin * scaleY;
matrix[3] = cr * scaleY; matrix[3] = radianCos * scaleY;
return this; return this;
},
/**
* Destroys this Transform Matrix.
*
* @method Phaser.GameObjects.Components.TransformMatrix#destroy
* @since 3.4.0
*/
destroy: function ()
{
this.matrix = null;
this.decomposedMatrix = null;
} }
}); });

File diff suppressed because it is too large Load diff

View file

@ -45,9 +45,22 @@ var ContainerCanvasRenderer = function (renderer, container, interpolationPercen
transformMatrix.scale(container.scaleX, container.scaleY); transformMatrix.scale(container.scaleX, container.scaleY);
} }
var alpha = container._alpha;
var scrollFactorX = container.scrollFactorX;
var scrollFactorY = container.scrollFactorY;
for (var index = 0; index < children.length; ++index) for (var index = 0; index < children.length; ++index)
{ {
children[index].renderCanvas(renderer, children[index], interpolationPercentage, camera, transformMatrix); var child = children[index];
var childAlpha = child._alpha;
var childScrollFactorX = child.scrollFactorX;
var childScrollFactorY = child.scrollFactorY;
child.setScrollFactor(childScrollFactorX * scrollFactorX, childScrollFactorY * scrollFactorY);
child.setAlpha(childAlpha * alpha);
child.renderCanvas(renderer, child, interpolationPercentage, camera, transformMatrix);
child.setAlpha(childAlpha);
child.setScrollFactor(childScrollFactorX, childScrollFactorY);
} }
}; };

View file

@ -45,9 +45,22 @@ var ContainerWebGLRenderer = function (renderer, container, interpolationPercent
transformMatrix.scale(container.scaleX, container.scaleY); transformMatrix.scale(container.scaleX, container.scaleY);
} }
var alpha = container._alpha;
var scrollFactorX = container.scrollFactorX;
var scrollFactorY = container.scrollFactorY;
for (var index = 0; index < children.length; ++index) for (var index = 0; index < children.length; ++index)
{ {
children[index].renderWebGL(renderer, children[index], interpolationPercentage, camera, transformMatrix); var child = children[index];
var childAlpha = child._alpha;
var childScrollFactorX = child.scrollFactorX;
var childScrollFactorY = child.scrollFactorY;
child.setScrollFactor(childScrollFactorX * scrollFactorX, childScrollFactorY * scrollFactorY);
child.setAlpha(childAlpha * alpha);
child.renderWebGL(renderer, child, interpolationPercentage, camera, transformMatrix);
child.setAlpha(childAlpha);
child.setScrollFactor(childScrollFactorX, childScrollFactorY);
} }
}; };

View file

@ -915,10 +915,10 @@ var Graphics = new Class({
/** /**
* Creates a pie-chart slice shape centered at `x`, `y` with the given radius. * Creates a pie-chart slice shape centered at `x`, `y` with the given radius.
* You must define the start and end angle of the slice. * You must define the start and end angle of the slice.
* *
* Setting the `anticlockwise` argument to `true` creates a shape similar to Pacman. * Setting the `anticlockwise` argument to `true` creates a shape similar to Pacman.
* Setting it to `false` creates a shape like a slice of pie. * Setting it to `false` creates a shape like a slice of pie.
* *
* This method will begin a new path and close the path at the end of it. * This method will begin a new path and close the path at the end of it.
* To display the actual slice you need to call either `strokePath` or `fillPath` after it. * To display the actual slice you need to call either `strokePath` or `fillPath` after it.
* *
@ -1133,7 +1133,7 @@ var Graphics = new Class({
if (ctx) if (ctx)
{ {
this.renderCanvas(sys.game.renderer, this, 0, Graphics.TargetCamera, ctx); this.renderCanvas(sys.game.renderer, this, 0.0, Graphics.TargetCamera, null, ctx);
if (sys.game.renderer.gl && texture) if (sys.game.renderer.gl && texture)
{ {

View file

@ -70,7 +70,7 @@ var GraphicsCanvasRenderer = function (renderer, src, interpolationPercentage, c
} }
ctx.save(); ctx.save();
if (parentMatrix !== undefined) if (parentMatrix)
{ {
var matrix = parentMatrix.matrix; var matrix = parentMatrix.matrix;
ctx.transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); ctx.transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);

View file

@ -11,7 +11,7 @@ var DeathZone = require('./zones/DeathZone');
var EdgeZone = require('./zones/EdgeZone'); var EdgeZone = require('./zones/EdgeZone');
var EmitterOp = require('./EmitterOp'); var EmitterOp = require('./EmitterOp');
var GetFastValue = require('../../utils/object/GetFastValue'); var GetFastValue = require('../../utils/object/GetFastValue');
var GetRandomElement = require('../../utils/array/GetRandomElement'); var GetRandom = require('../../utils/array/GetRandom');
var HasAny = require('../../utils/object/HasAny'); var HasAny = require('../../utils/object/HasAny');
var HasValue = require('../../utils/object/HasValue'); var HasValue = require('../../utils/object/HasValue');
var Particle = require('./Particle'); var Particle = require('./Particle');
@ -943,7 +943,7 @@ var ParticleEmitter = new Class({
} }
else if (this.randomFrame) else if (this.randomFrame)
{ {
return GetRandomElement(this.frames); return GetRandom(this.frames);
} }
else else
{ {

View file

@ -24,15 +24,13 @@ var Union = function (rectA, rectB, out)
{ {
if (out === undefined) { out = new Rectangle(); } if (out === undefined) { out = new Rectangle(); }
// Cache vars so we can use one of the input rects as the output rect
var x = Math.min(rectA.x, rectB.x); var x = Math.min(rectA.x, rectB.x);
var y = Math.min(rectA.y, rectB.y); var y = Math.min(rectA.y, rectB.y);
var w = Math.max(rectA.right, rectB.right) - x;
var h = Math.max(rectA.bottom, rectB.bottom) - y;
return out.setTo( return out.setTo(x, y, w, h);
x,
y,
Math.max(rectA.right, rectB.right) - x,
Math.max(rectA.bottom, rectB.bottom) - y
);
}; };
module.exports = Union; module.exports = Union;

View file

@ -12,6 +12,7 @@ var Mouse = require('./mouse/MouseManager');
var Pointer = require('./Pointer'); var Pointer = require('./Pointer');
var Rectangle = require('../geom/rectangle/Rectangle'); var Rectangle = require('../geom/rectangle/Rectangle');
var Touch = require('./touch/TouchManager'); var Touch = require('./touch/TouchManager');
var TransformMatrix = require('../gameobjects/components/TransformMatrix');
var TransformXY = require('../math/TransformXY'); var TransformXY = require('../math/TransformXY');
/** /**
@ -195,6 +196,16 @@ var InputManager = new Class({
*/ */
this._tempHitTest = []; this._tempHitTest = [];
/**
* [description]
*
* @name Phaser.Input.InputManager#_tempMatrix
* @type {Phaser.GameObjects.Components.TransformMatrix}
* @private
* @since 3.4.0
*/
this._tempMatrix = new TransformMatrix();
game.events.once('boot', this.boot, this); game.events.once('boot', this.boot, this);
}, },
@ -383,6 +394,8 @@ var InputManager = new Class({
var res = this.game.config.resolution; var res = this.game.config.resolution;
var matrix = this._tempMatrix;
for (var i = 0; i < culledGameObjects.length; i++) for (var i = 0; i < culledGameObjects.length; i++)
{ {
var gameObject = culledGameObjects[i]; var gameObject = culledGameObjects[i];
@ -395,7 +408,16 @@ var InputManager = new Class({
var px = tempPoint.x * res + (camera.scrollX * gameObject.scrollFactorX) - camera.scrollX; var px = tempPoint.x * res + (camera.scrollX * gameObject.scrollFactorX) - camera.scrollX;
var py = tempPoint.y * res + (camera.scrollY * gameObject.scrollFactorY) - camera.scrollY; var py = tempPoint.y * res + (camera.scrollY * gameObject.scrollFactorY) - camera.scrollY;
TransformXY(px, py, gameObject.x, gameObject.y, gameObject.rotation, gameObject.scaleX, gameObject.scaleY, point); if (gameObject.parentContainer)
{
gameObject.getWorldTransformMatrix(matrix);
TransformXY(px, py, matrix.tx, matrix.ty, matrix.rotation, matrix.scaleX, matrix.scaleY, point);
}
else
{
TransformXY(px, py, gameObject.x, gameObject.y, gameObject.rotation, gameObject.scaleX, gameObject.scaleY, point);
}
if (this.pointWithinHitArea(gameObject, point.x, point.y)) if (this.pointWithinHitArea(gameObject, point.x, point.y))
{ {

View file

@ -422,7 +422,10 @@ var InputPlugin = new Class({
this.setHitArea(gameObject, shape, callback); this.setHitArea(gameObject, shape, callback);
} }
gameObject.input.dropZone = dropZone; if (gameObject.input)
{
gameObject.input.dropZone = dropZone;
}
return this; return this;
}, },
@ -1154,6 +1157,13 @@ var InputPlugin = new Class({
for (var i = 0; i < gameObjects.length; i++) for (var i = 0; i < gameObjects.length; i++)
{ {
var gameObject = gameObjects[i]; var gameObject = gameObjects[i];
if (gameObject.type === 'Container')
{
console.warn('Container.setInteractive() must specify a Shape');
continue;
}
var frame = gameObject.frame; var frame = gameObject.frame;
var width = 0; var width = 0;

View file

@ -190,13 +190,24 @@ var KeyboardManager = new Class({
this.target.removeEventListener('keyup', this.handler); this.target.removeEventListener('keyup', this.handler);
}, },
/**
* @typedef {object} CursorKeys
*
* @property {Phaser.Input.Keyboard.Key} [up] - [description]
* @property {Phaser.Input.Keyboard.Key} [down] - [description]
* @property {Phaser.Input.Keyboard.Key} [left] - [description]
* @property {Phaser.Input.Keyboard.Key} [right] - [description]
* @property {Phaser.Input.Keyboard.Key} [space] - [description]
* @property {Phaser.Input.Keyboard.Key} [shift] - [description]
*/
/** /**
* Creates and returns an object containing 4 hotkeys for Up, Down, Left and Right, and also space and shift. * Creates and returns an object containing 4 hotkeys for Up, Down, Left and Right, and also space and shift.
* *
* @method Phaser.Input.Keyboard.KeyboardManager#createCursorKeys * @method Phaser.Input.Keyboard.KeyboardManager#createCursorKeys
* @since 3.0.0 * @since 3.0.0
* *
* @return {object} [description] * @return {CursorKeys} [description]
*/ */
createCursorKeys: function () createCursorKeys: function ()
{ {

View file

@ -369,7 +369,7 @@ var LoaderPlugin = new Class({
*/ */
isReady: function () isReady: function ()
{ {
return (this.state === CONST.LOADER_IDLE || this.state === CONST.LOADER_COMPLETE || this.state === CONST.LOADER_FAILED); return (this.state === CONST.LOADER_IDLE || this.state === CONST.LOADER_COMPLETE);
}, },
/** /**

View file

@ -7,8 +7,10 @@
var CircleContains = require('../../geom/circle/Contains'); var CircleContains = require('../../geom/circle/Contains');
var Class = require('../../utils/Class'); var Class = require('../../utils/Class');
var CONST = require('./const'); var CONST = require('./const');
var RadToDeg = require('../../math/RadToDeg');
var Rectangle = require('../../geom/rectangle/Rectangle'); var Rectangle = require('../../geom/rectangle/Rectangle');
var RectangleContains = require('../../geom/rectangle/Contains'); var RectangleContains = require('../../geom/rectangle/Contains');
var TransformMatrix = require('../../gameobjects/components/TransformMatrix');
var Vector2 = require('../../math/Vector2'); var Vector2 = require('../../math/Vector2');
/** /**
@ -48,6 +50,9 @@ var Body = new Class({
function Body (world, gameObject) function Body (world, gameObject)
{ {
var width = (gameObject.width) ? gameObject.width : 64;
var height = (gameObject.height) ? gameObject.height : 64;
/** /**
* [description] * [description]
* *
@ -66,6 +71,23 @@ var Body = new Class({
*/ */
this.gameObject = gameObject; this.gameObject = gameObject;
/**
* [description]
*
* @name Phaser.Physics.Arcade.Body#transform
* @type {object}
* @since 3.4.0
*/
this.transform = {
x: gameObject.x,
y: gameObject.y,
rotation: gameObject.angle,
scaleX: gameObject.scaleX,
scaleY: gameObject.scaleY,
displayOriginX: gameObject.displayOriginX,
displayOriginY: gameObject.displayOriginY
};
/** /**
* [description] * [description]
* *
@ -148,7 +170,7 @@ var Body = new Class({
* @type {Phaser.Math.Vector2} * @type {Phaser.Math.Vector2}
* @since 3.0.0 * @since 3.0.0
*/ */
this.prev = new Vector2(this.position.x, this.position.y); this.prev = new Vector2(gameObject.x, gameObject.y);
/** /**
* [description] * [description]
@ -185,7 +207,7 @@ var Body = new Class({
* @type {number} * @type {number}
* @since 3.0.0 * @since 3.0.0
*/ */
this.width = gameObject.width; this.width = width;
/** /**
* [description] * [description]
@ -194,7 +216,7 @@ var Body = new Class({
* @type {number} * @type {number}
* @since 3.0.0 * @since 3.0.0
*/ */
this.height = gameObject.height; this.height = height;
/** /**
* [description] * [description]
@ -203,7 +225,7 @@ var Body = new Class({
* @type {number} * @type {number}
* @since 3.0.0 * @since 3.0.0
*/ */
this.sourceWidth = gameObject.width; this.sourceWidth = width;
/** /**
* [description] * [description]
@ -212,7 +234,7 @@ var Body = new Class({
* @type {number} * @type {number}
* @since 3.0.0 * @since 3.0.0
*/ */
this.sourceHeight = gameObject.height; this.sourceHeight = height;
if (gameObject.frame) if (gameObject.frame)
{ {
@ -227,7 +249,7 @@ var Body = new Class({
* @type {number} * @type {number}
* @since 3.0.0 * @since 3.0.0
*/ */
this.halfWidth = Math.abs(gameObject.width / 2); this.halfWidth = Math.abs(width / 2);
/** /**
* [description] * [description]
@ -236,7 +258,7 @@ var Body = new Class({
* @type {number} * @type {number}
* @since 3.0.0 * @since 3.0.0
*/ */
this.halfHeight = Math.abs(gameObject.height / 2); this.halfHeight = Math.abs(height / 2);
/** /**
* [description] * [description]
@ -709,6 +731,8 @@ var Body = new Class({
* @since 3.0.0 * @since 3.0.0
*/ */
this._bounds = new Rectangle(); this._bounds = new Rectangle();
this._tempMatrix = new TransformMatrix();
}, },
/** /**
@ -721,6 +745,29 @@ var Body = new Class({
{ {
var sprite = this.gameObject; var sprite = this.gameObject;
// Container?
var transform = this.transform;
if (sprite.parentContainer)
{
var matrix = sprite.getWorldTransformMatrix(this._tempMatrix);
transform.x = matrix.tx;
transform.y = matrix.ty;
transform.rotation = RadToDeg(matrix.rotation);
transform.scaleX = matrix.scaleX;
transform.scaleY = matrix.scaleY;
}
else
{
transform.x = sprite.x;
transform.y = sprite.y;
transform.rotation = sprite.angle;
transform.scaleX = sprite.scaleX;
transform.scaleY = sprite.scaleY;
}
if (this.syncBounds) if (this.syncBounds)
{ {
var b = sprite.getBounds(this._bounds); var b = sprite.getBounds(this._bounds);
@ -734,8 +781,8 @@ var Body = new Class({
} }
else else
{ {
var asx = Math.abs(sprite.scaleX); var asx = Math.abs(transform.scaleX);
var asy = Math.abs(sprite.scaleY); var asy = Math.abs(transform.scaleY);
if (asx !== this._sx || asy !== this._sy) if (asx !== this._sx || asy !== this._sy)
{ {
@ -803,16 +850,17 @@ var Body = new Class({
this.embedded = false; this.embedded = false;
// Updates the transform values
this.updateBounds(); this.updateBounds();
var sprite = this.gameObject; var sprite = this.transform;
this.position.x = sprite.x + sprite.scaleX * (this.offset.x - sprite.displayOriginX); this.position.x = sprite.x + sprite.scaleX * (this.offset.x - sprite.displayOriginX);
this.position.y = sprite.y + sprite.scaleY * (this.offset.y - sprite.displayOriginY); this.position.y = sprite.y + sprite.scaleY * (this.offset.y - sprite.displayOriginY);
this.updateCenter(); this.updateCenter();
this.rotation = sprite.angle; this.rotation = sprite.rotation;
this.preRotation = this.rotation; this.preRotation = this.rotation;
@ -918,6 +966,9 @@ var Body = new Class({
} }
} }
// this.transform.x += this._dx;
// this.transform.y += this._dy;
this.gameObject.x += this._dx; this.gameObject.x += this._dx;
this.gameObject.y += this._dy; this.gameObject.y += this._dy;

View file

@ -443,8 +443,14 @@ var StaticBody = new Class({
this.world.staticTree.remove(this); this.world.staticTree.remove(this);
this.position.x -= this.offset.x;
this.position.y -= this.offset.y;
this.offset.set(x, y); this.offset.set(x, y);
this.position.x += this.offset.x;
this.position.y += this.offset.y;
this.updateCenter(); this.updateCenter();
this.world.staticTree.insert(this); this.world.staticTree.insert(this);

View file

@ -632,7 +632,7 @@ var World = new Class({
{ {
body = bodies[i]; body = bodies[i];
if (!body.skipHash()) if (body && !body.skipHash())
{ {
this.checkHash(body, hash, size); this.checkHash(body, hash, size);
} }
@ -648,7 +648,7 @@ var World = new Class({
{ {
body = bodies[i]; body = bodies[i];
if (body.willDrawDebug()) if (body && body.willDrawDebug())
{ {
body.drawDebug(graphics); body.drawDebug(graphics);
} }

View file

@ -4,7 +4,6 @@
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/ */
var Bodies = require('./lib/factory/Bodies');
var Class = require('../../utils/Class'); var Class = require('../../utils/Class');
var Components = require('./components'); var Components = require('./components');
var GameObject = require('../../gameobjects/GameObject'); var GameObject = require('../../gameobjects/GameObject');
@ -113,20 +112,13 @@ var MatterImage = new Class({
var shape = GetFastValue(options, 'shape', null); var shape = GetFastValue(options, 'shape', null);
if (!shape) if (shape)
{ {
this.body = Bodies.rectangle(x, y, this.width, this.height, options); this.setBody(shape, options);
this.body.gameObject = this;
if (GetFastValue(options, 'addToWorld', true))
{
world.add(this.body);
}
} }
else else
{ {
this.setBody(shape, options); this.setRectangle(this.width, this.height, options);
} }
this.setPosition(x, y); this.setPosition(x, y);

View file

@ -5,7 +5,6 @@
*/ */
var AnimationComponent = require('../../gameobjects/components/Animation'); var AnimationComponent = require('../../gameobjects/components/Animation');
var Bodies = require('./lib/factory/Bodies');
var Class = require('../../utils/Class'); var Class = require('../../utils/Class');
var Components = require('./components'); var Components = require('./components');
var GameObject = require('../../gameobjects/GameObject'); var GameObject = require('../../gameobjects/GameObject');
@ -120,20 +119,13 @@ var MatterSprite = new Class({
var shape = GetFastValue(options, 'shape', null); var shape = GetFastValue(options, 'shape', null);
if (!shape) if (shape)
{ {
this.body = Bodies.rectangle(x, y, this.width, this.height, options); this.setBody(shape, options);
this.body.gameObject = this;
if (GetFastValue(options, 'addToWorld', true))
{
world.add(this.body);
}
} }
else else
{ {
this.setBody(shape, options); this.setRectangle(this.width, this.height, options);
} }
this.setPosition(x, y); this.setPosition(x, y);

View file

@ -894,6 +894,10 @@ var World = new Class({
*/ */
shutdown: function () shutdown: function ()
{ {
MatterEvents.off();
this.removeAllListeners();
MatterWorld.clear(this.localWorld, false); MatterWorld.clear(this.localWorld, false);
Engine.clear(this.engine); Engine.clear(this.engine);

View file

@ -114,7 +114,7 @@ var SetBody = {
var _this = this; var _this = this;
this.body.destroy = function () body.destroy = function destroy ()
{ {
_this.world.remove(_this.body); _this.world.remove(_this.body);
_this.body.gameObject = null; _this.body.gameObject = null;
@ -122,10 +122,13 @@ var SetBody = {
if (addToWorld) if (addToWorld)
{ {
this.world.add(this.body); this.world.add(body);
} }
this.setOrigin(body.render.sprite.xOffset, body.render.sprite.yOffset); if (this._originComponent)
{
this.setOrigin(body.render.sprite.xOffset, body.render.sprite.yOffset);
}
return this; return this;
}, },

View file

@ -441,22 +441,20 @@ var CanvasRenderer = new Class({
} }
ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.globalCompositeOperation = 'source-over';
if (camera._fadeAlpha > 0 || camera._flashAlpha > 0) if (camera._fadeAlpha > 0)
{ {
ctx.globalCompositeOperation = 'source-over';
// fade rendering // fade rendering
ctx.fillStyle = 'rgb(' + (camera._fadeRed * 255) + ',' + (camera._fadeGreen * 255) + ',' + (camera._fadeBlue * 255) + ')'; ctx.fillStyle = 'rgba(' + (camera._fadeRed * 255) + ',' + (camera._fadeGreen * 255) + ',' + (camera._fadeBlue * 255) + ',' + camera._fadeAlpha + ')';
ctx.globalAlpha = camera._fadeAlpha;
ctx.fillRect(camera.x, camera.y, camera.width, camera.height); ctx.fillRect(camera.x, camera.y, camera.width, camera.height);
}
if (camera._flashAlpha > 0)
{
// flash rendering // flash rendering
ctx.fillStyle = 'rgb(' + (camera._flashRed * 255) + ',' + (camera._flashGreen * 255) + ',' + (camera._flashBlue * 255) + ')'; ctx.fillStyle = 'rgba(' + (camera._flashRed * 255) + ',' + (camera._flashGreen * 255) + ',' + (camera._flashBlue * 255) + ',' + camera._flashAlpha + ')';
ctx.globalAlpha = camera._flashAlpha;
ctx.fillRect(camera.x, camera.y, camera.width, camera.height); ctx.fillRect(camera.x, camera.y, camera.width, camera.height);
ctx.globalAlpha = 1.0;
} }
// Reset the camera scissor // Reset the camera scissor

View file

@ -91,14 +91,36 @@ var SceneManager = new Class({
this._queue = []; this._queue = [];
/** /**
* The number of Scenes to process. * Boot time data to merge.
* *
* @name Phaser.Scenes.SceneManager#_processing * @name Phaser.Scenes.SceneManager#_data
* @type {integer} * @type {object}
* @private * @private
* @since 3.4.0
*/
this._data = {};
/**
* Is the Scene Manager actively processing the Scenes list?
*
* @name Phaser.Scenes.SceneManager#isProcessing
* @type {boolean}
* @default false
* @readOnly
* @since 3.0.0 * @since 3.0.0
*/ */
this._processing = 0; this.isProcessing = false;
/**
* Has the Scene Manager properly started?
*
* @name Phaser.Scenes.SceneManager#isBooted
* @type {boolean}
* @default false
* @readOnly
* @since 3.4.0
*/
this.isBooted = false;
if (sceneConfig) if (sceneConfig)
{ {
@ -132,6 +154,11 @@ var SceneManager = new Class({
*/ */
bootQueue: function () bootQueue: function ()
{ {
if (this.isBooted)
{
return;
}
var i; var i;
var entry; var entry;
var key; var key;
@ -166,6 +193,17 @@ var SceneManager = new Class({
this.scenes.push(newScene); this.scenes.push(newScene);
// Any data to inject?
if (this._data[key])
{
newScene.sys.settings.data = this._data[key].data;
if (this._data[key].autoStart)
{
entry.autoStart = true;
}
}
if (entry.autoStart || newScene.sys.settings.active) if (entry.autoStart || newScene.sys.settings.active)
{ {
this._start.push(key); this._start.push(key);
@ -175,6 +213,10 @@ var SceneManager = new Class({
// Clear the pending lists // Clear the pending lists
this._pending.length = 0; this._pending.length = 0;
this._data = {};
this.isBooted = true;
// _start might have been populated by the above // _start might have been populated by the above
for (i = 0; i < this._start.length; i++) for (i = 0; i < this._start.length; i++)
{ {
@ -211,7 +253,7 @@ var SceneManager = new Class({
{ {
entry = this._pending[i]; entry = this._pending[i];
this.add(entry.key, entry.scene, entry.autoStart); this.add(entry.key, entry.scene, entry.autoStart, entry.data);
} }
// _start might have been populated by this.add // _start might have been populated by this.add
@ -259,21 +301,23 @@ var SceneManager = new Class({
* @param {string} key - A unique key used to reference the Scene, i.e. `MainMenu` or `Level1`. * @param {string} key - A unique key used to reference the Scene, i.e. `MainMenu` or `Level1`.
* @param {(Phaser.Scene|SettingsConfig|function)} sceneConfig - The config for the Scene * @param {(Phaser.Scene|SettingsConfig|function)} sceneConfig - The config for the Scene
* @param {boolean} [autoStart=false] - If `true` the Scene will be started immediately after being added. * @param {boolean} [autoStart=false] - If `true` the Scene will be started immediately after being added.
* @param {object} [data] - Optional data object. This will be set as Scene.settings.data and passed to `Scene.init`.
* *
* @return {?Phaser.Scene} The added Scene, if it was added immediately. * @return {?Phaser.Scene} The added Scene, if it was added immediately, otherwise `null`.
*/ */
add: function (key, sceneConfig, autoStart) add: function (key, sceneConfig, autoStart, data)
{ {
if (autoStart === undefined) { autoStart = false; } if (autoStart === undefined) { autoStart = false; }
if (data === undefined) { data = {}; }
// if not booted, then put scene into a holding pattern // If processing or not booted then put scene into a holding pattern
if (this._processing === 1 || !this.game.isBooted) if (this.isProcessing || !this.isBooted)
{ {
this._pending.push({ this._pending.push({
key: key, key: key,
scene: sceneConfig, scene: sceneConfig,
autoStart: autoStart, autoStart: autoStart,
data: {} data: data
}); });
return null; return null;
@ -298,6 +342,9 @@ var SceneManager = new Class({
newScene = this.createSceneFromFunction(key, sceneConfig); newScene = this.createSceneFromFunction(key, sceneConfig);
} }
// Any data to inject?
newScene.sys.settings.data = data;
// Replace key in case the scene changed it // Replace key in case the scene changed it
key = newScene.sys.settings.key; key = newScene.sys.settings.key;
@ -307,13 +354,13 @@ var SceneManager = new Class({
if (autoStart || newScene.sys.settings.active) if (autoStart || newScene.sys.settings.active)
{ {
if (this.game.isBooted) if (this._pending.length)
{ {
this.start(key); this._start.push(key);
} }
else else
{ {
this._start.push(key); this.start(key);
} }
} }
@ -338,7 +385,7 @@ var SceneManager = new Class({
*/ */
remove: function (key) remove: function (key)
{ {
if (this._processing) if (this.isProcessing)
{ {
this._queue.push({ op: 'remove', keyA: key, keyB: null }); this._queue.push({ op: 'remove', keyA: key, keyB: null });
} }
@ -468,7 +515,7 @@ var SceneManager = new Class({
{ {
this.processQueue(); this.processQueue();
this._processing = 1; this.isProcessing = true;
// Loop through the active scenes in reverse order // Loop through the active scenes in reverse order
for (var i = this.scenes.length - 1; i >= 0; i--) for (var i = this.scenes.length - 1; i >= 0; i--)
@ -523,7 +570,7 @@ var SceneManager = new Class({
} }
} }
this._processing = 0; this.isProcessing = false;
}, },
/** /**
@ -693,7 +740,17 @@ var SceneManager = new Class({
{ {
for (var propertyKey in sceneConfig.extend) for (var propertyKey in sceneConfig.extend)
{ {
newScene[propertyKey] = sceneConfig.extend[propertyKey]; var value = sceneConfig.extend[propertyKey];
if (propertyKey === 'data' && newScene.hasOwnProperty('data') && typeof value === 'object')
{
// Populate the DataManager
newScene.data.merge(value);
}
else if (propertyKey !== 'sys')
{
newScene[propertyKey] = value;
}
} }
} }
@ -935,27 +992,19 @@ var SceneManager = new Class({
* @since 3.0.0 * @since 3.0.0
* *
* @param {string} key - The Scene to start. * @param {string} key - The Scene to start.
* @param {object} [data] - The Scene data. * @param {object} [data] - Optional data object to pass to Scene.Settings and Scene.init.
* *
* @return {Phaser.Scenes.SceneManager} This SceneManager. * @return {Phaser.Scenes.SceneManager} This SceneManager.
*/ */
start: function (key, data) start: function (key, data)
{ {
if (data === undefined) { data = {}; } // If the Scene Manager is not running, then put the Scene into a holding pattern
if (!this.isBooted)
// If the Game is not booted, then put the Scene into a holding pattern
if (!this.game.isBooted)
{ {
for (var i = 0; i < this._pending.length; i++) this._data[key] = {
{ autoStart: true,
var entry = this._pending[i]; data: data
};
if (entry.key === key)
{
entry.autoStart = true;
entry.data = data;
}
}
return this; return this;
} }
@ -1097,7 +1146,7 @@ var SceneManager = new Class({
*/ */
bringToTop: function (key) bringToTop: function (key)
{ {
if (this._processing) if (this.isProcessing)
{ {
this._queue.push({ op: 'bringToTop', keyA: key, keyB: null }); this._queue.push({ op: 'bringToTop', keyA: key, keyB: null });
} }
@ -1131,7 +1180,7 @@ var SceneManager = new Class({
*/ */
sendToBack: function (key) sendToBack: function (key)
{ {
if (this._processing) if (this.isProcessing)
{ {
this._queue.push({ op: 'sendToBack', keyA: key, keyB: null }); this._queue.push({ op: 'sendToBack', keyA: key, keyB: null });
} }
@ -1163,7 +1212,7 @@ var SceneManager = new Class({
*/ */
moveDown: function (key) moveDown: function (key)
{ {
if (this._processing) if (this.isProcessing)
{ {
this._queue.push({ op: 'moveDown', keyA: key, keyB: null }); this._queue.push({ op: 'moveDown', keyA: key, keyB: null });
} }
@ -1197,7 +1246,7 @@ var SceneManager = new Class({
*/ */
moveUp: function (key) moveUp: function (key)
{ {
if (this._processing) if (this.isProcessing)
{ {
this._queue.push({ op: 'moveUp', keyA: key, keyB: null }); this._queue.push({ op: 'moveUp', keyA: key, keyB: null });
} }
@ -1239,7 +1288,7 @@ var SceneManager = new Class({
return this; return this;
} }
if (this._processing) if (this.isProcessing)
{ {
this._queue.push({ op: 'moveAbove', keyA: keyA, keyB: keyB }); this._queue.push({ op: 'moveAbove', keyA: keyA, keyB: keyB });
} }
@ -1283,7 +1332,7 @@ var SceneManager = new Class({
return this; return this;
} }
if (this._processing) if (this.isProcessing)
{ {
this._queue.push({ op: 'moveBelow', keyA: keyA, keyB: keyB }); this._queue.push({ op: 'moveBelow', keyA: keyA, keyB: keyB });
} }
@ -1307,6 +1356,19 @@ var SceneManager = new Class({
return this; return this;
}, },
/**
* Queue a Scene operation for the next update.
*
* @method Phaser.Scenes.SceneManager#queueOp
* @private
* @since 3.0.0
*
* @param {string} op - The operation to perform.
* @param {(string|Phaser.Scene)} keyA - Scene A.
* @param {(string|Phaser.Scene)} [keyB] - Scene B.
*
* @return {Phaser.Scenes.SceneManager} This SceneManager.
*/
queueOp: function (op, keyA, keyB) queueOp: function (op, keyA, keyB)
{ {
this._queue.push({ op: op, keyA: keyA, keyB: keyB }); this._queue.push({ op: op, keyA: keyA, keyB: keyB });
@ -1332,7 +1394,7 @@ var SceneManager = new Class({
return this; return this;
} }
if (this._processing) if (this.isProcessing)
{ {
this._queue.push({ op: 'swapPosition', keyA: keyA, keyB: keyB }); this._queue.push({ op: 'swapPosition', keyA: keyA, keyB: keyB });
} }

View file

@ -121,6 +121,34 @@ var ScenePlugin = new Class({
return this; return this;
}, },
/**
* Restarts this Scene.
*
* @method Phaser.Scenes.ScenePlugin#restart
* @since 3.4.0
*
* @param {object} [data] - The Scene data.
*
* @return {Phaser.Scenes.ScenePlugin} This ScenePlugin object.
*/
restart: function (data)
{
var key = this.key;
if (this.settings.status !== CONST.RUNNING)
{
this.manager.queueOp('stop', key);
this.manager.queueOp('start', key, data);
}
else
{
this.manager.stop(key);
this.manager.start(key, data);
}
return this;
},
/** /**
* Add the Scene into the Scene Manager and start it if 'autoStart' is true or the Scene config 'active' property is set. * Add the Scene into the Scene Manager and start it if 'autoStart' is true or the Scene config 'active' property is set.
* *

View file

@ -6,6 +6,7 @@
var CONST = require('./const'); var CONST = require('./const');
var GetValue = require('../utils/object/GetValue'); var GetValue = require('../utils/object/GetValue');
var Merge = require('../utils/object/Merge');
var InjectionMap = require('./InjectionMap'); var InjectionMap = require('./InjectionMap');
// TODO 22/03/2018 Fix "plugins" type // TODO 22/03/2018 Fix "plugins" type
@ -18,7 +19,8 @@ var InjectionMap = require('./InjectionMap');
* @property {boolean} [visible=true] - [description] * @property {boolean} [visible=true] - [description]
* @property {(false|LoaderFileObject[])} [files=false] - [description] * @property {(false|LoaderFileObject[])} [files=false] - [description]
* @property {?(InputJSONCameraObject|InputJSONCameraObject[])} [cameras=null] - [description] * @property {?(InputJSONCameraObject|InputJSONCameraObject[])} [cameras=null] - [description]
* @property {Object.<string, string>} [map] - [description] * @property {Object.<string, string>} [map] - Overwrites the default injection map for a scene.
* @property {Object.<string, string>} [mapAdd] - Extends the injection map for a scene.
* @property {object} [physics={}] - [description] * @property {object} [physics={}] - [description]
* @property {object} [loader={}] - [description] * @property {object} [loader={}] - [description]
* @property {(false|*)} [plugins=false] - [description] * @property {(false|*)} [plugins=false] - [description]
@ -87,7 +89,7 @@ var Settings = {
// Scene Property Injection Map // Scene Property Injection Map
map: GetValue(config, 'map', InjectionMap), map: GetValue(config, 'map', Merge(InjectionMap, GetValue(config, 'mapAdd', {}))),
// Physics // Physics

View file

@ -491,6 +491,7 @@ var Systems = new Class({
/** /**
* Start this Scene running and rendering. * Start this Scene running and rendering.
* Called automatically by the SceneManager.
* *
* @method Phaser.Scenes.Systems#start * @method Phaser.Scenes.Systems#start
* @since 3.0.0 * @since 3.0.0
@ -499,9 +500,12 @@ var Systems = new Class({
*/ */
start: function (data) start: function (data)
{ {
this.settings.status = CONST.START; if (data)
{
this.settings.data = data;
}
this.settings.data = data; this.settings.status = CONST.START;
this.settings.active = true; this.settings.active = true;
this.settings.visible = true; this.settings.visible = true;

View file

@ -12,7 +12,7 @@ var NOOP = require('../utils/NOOP');
/** /**
* @classdesc * @classdesc
* Class containing all the shared state and behaviour of a sound object, independent of the implementation. * Class containing all the shared state and behavior of a sound object, independent of the implementation.
* *
* @class BaseSound * @class BaseSound
* @extends Phaser.Events.EventEmitter * @extends Phaser.Events.EventEmitter
@ -120,10 +120,15 @@ var BaseSound = new Class({
* @since 3.0.0 * @since 3.0.0
*/ */
this.config = { this.config = {
/**
* Initializing delay config setting mute: false,
*/ volume: 1,
rate: 1,
detune: 0,
seek: 0,
loop: false,
delay: 0 delay: 0
}; };
/** /**
@ -517,6 +522,7 @@ var BaseSound = new Class({
return; return;
} }
this.emit('destroy', this);
this.pendingRemove = true; this.pendingRemove = true;
this.manager = null; this.manager = null;
this.key = ''; this.key = '';

View file

@ -541,7 +541,7 @@ var WebAudioSound = new Class({
var now = this.manager.context.currentTime; var now = this.manager.context.currentTime;
if (this.source) if (this.source && typeof this.totalRate === 'number')
{ {
this.source.playbackRate.setValueAtTime(this.totalRate, now); this.source.playbackRate.setValueAtTime(this.totalRate, now);
} }

View file

@ -4,8 +4,10 @@
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/ */
var ArrayUtils = require('../utils/array');
var Class = require('../utils/Class'); var Class = require('../utils/Class');
var NOOP = require('../utils/NOOP'); var NOOP = require('../utils/NOOP');
var StableSort = require('../utils/array/StableSort');
/** /**
* @callback EachListCallback * @callback EachListCallback
@ -82,6 +84,15 @@ var List = new Class({
* @since 3.4.0 * @since 3.4.0
*/ */
this.removeCallback = NOOP; this.removeCallback = NOOP;
/**
* The property key to sort by.
*
* @name Phaser.Structs.List#_sortKey
* @type {string}
* @since 3.4.0
*/
this._sortKey = '';
}, },
/** /**
@ -99,25 +110,13 @@ var List = new Class({
*/ */
add: function (child, skipCallback) add: function (child, skipCallback)
{ {
if (Array.isArray(child)) if (skipCallback)
{ {
return this.addMultiple(child, skipCallback); return ArrayUtils.Add(this.list, child);
} }
else else
{ {
// Is child already in this display list? return ArrayUtils.Add(this.list, child, 0, this.addCallback, this);
if (this.getIndex(child) === -1)
{
this.list.push(child);
if (!skipCallback)
{
this.addCallback(this, child);
}
}
return child;
} }
}, },
@ -137,53 +136,14 @@ var List = new Class({
*/ */
addAt: function (child, index, skipCallback) addAt: function (child, index, skipCallback)
{ {
if (index === undefined) { index = 0; } if (skipCallback)
if (this.list.length === 0)
{ {
return this.add(child, skipCallback); return ArrayUtils.AddAt(this.list, child, index);
} }
else
if (index >= 0 && index <= this.list.length)
{ {
if (this.getIndex(child) === -1) return ArrayUtils.AddAt(this.list, child, index, 0, this.addCallback, this);
{
this.list.splice(index, 0, child);
if (!skipCallback)
{
this.addCallback(this, child);
}
}
} }
return child;
},
/**
* [description]
*
* @method Phaser.Structs.List#addMultiple
* @since 3.0.0
*
* @genericUse {T[]} - [children,$return]
*
* @param {Array.<*>} children - [description]
* @param {boolean} [skipCallback=false] - Skip calling the List.addCallback if this child is added successfully.
*
* @return {Array.<*>} [description]
*/
addMultiple: function (children, skipCallback)
{
if (Array.isArray(children))
{
for (var i = 0; i < children.length; i++)
{
this.add(children[i], skipCallback);
}
}
return children;
}, },
/** /**
@ -222,30 +182,37 @@ var List = new Class({
}, },
/** /**
* Given an array of objects, sort the array and return it, * Sort the contents of this List so the items are in order based
* so that the objects are in index order with the lowest at the bottom. * on the given property. For example, `sort('alpha')` would sort the List
* contents based on the value of their `alpha` property.
* *
* @method Phaser.Structs.List#sort * @method Phaser.Structs.List#sort
* @since 3.0.0 * @since 3.0.0
* *
* @genericUse {T[]} - [children,$return] * @genericUse {T[]} - [children,$return]
* *
* @param {Array.<*>} children - [description] * @param {string} property - The property to lexically sort by.
* *
* @return {Array.<*>} [description] * @return {Array.<*>} [description]
*/ */
sort: function (children) sort: function (property)
{ {
if (children === undefined) { children = this.list; } if (property)
{
this._sortKey = property;
return children.sort(this.sortIndexHandler.bind(this)); StableSort.inplace(this.list, this.sortHandler);
}
return this;
}, },
/** /**
* [description] * [description]
* *
* @method Phaser.Structs.List#sortIndexHandler * @method Phaser.Structs.List#sortHandler
* @since 3.0.0 * @private
* @since 3.4.0
* *
* @genericUse {T} - [childA,childB] * @genericUse {T} - [childA,childB]
* *
@ -254,58 +221,15 @@ var List = new Class({
* *
* @return {integer} [description] * @return {integer} [description]
*/ */
sortIndexHandler: function (childA, childB) sortHandler: function (childA, childB)
{ {
// The lower the index, the lower down the display list they are return childA[this._sortKey] - childB[this._sortKey];
var indexA = this.getIndex(childA);
var indexB = this.getIndex(childB);
if (indexA < indexB)
{
return -1;
}
else if (indexA > indexB)
{
return 1;
}
// Technically this shouldn't happen, but if the GO wasn't part of this display list then it'll
// have an index of -1, so in some cases it can
return 0;
}, },
/** /**
* Gets the first item from the set based on the property strictly equaling the value given. * Searches for the first instance of a child with its `name`
* Returns null if not found.
*
* @method Phaser.Structs.List#getByKey
* @since 3.0.0
*
* @genericUse {T} - [value]
* @genericUse {T | null} - [$return]
*
* @param {string} property - The property to check against the value.
* @param {*} value - The value to check if the property strictly equals.
*
* @return {?*} The item that was found, or null if nothing matched.
*/
getByKey: function (property, value)
{
for (var i = 0; i < this.list.length; i++)
{
if (this.list[i][property] === value)
{
return this.list[i];
}
}
return null;
},
/**
* Searches the Group for the first instance of a child with the `name`
* property matching the given argument. Should more than one child have * property matching the given argument. Should more than one child have
* the same name only the first instance is returned. * the same name only the first is returned.
* *
* @method Phaser.Structs.List#getByName * @method Phaser.Structs.List#getByName
* @since 3.0.0 * @since 3.0.0
@ -318,7 +242,7 @@ var List = new Class({
*/ */
getByName: function (name) getByName: function (name)
{ {
return this.getByKey('name', name); return ArrayUtils.GetFirst(this.list, 'name', name);
}, },
/** /**
@ -336,17 +260,7 @@ var List = new Class({
*/ */
getRandom: function (startIndex, length) getRandom: function (startIndex, length)
{ {
if (startIndex === undefined) { startIndex = 0; } return ArrayUtils.GetRandom(this.list, startIndex, length);
if (length === undefined) { length = this.list.length; }
if (length === 0 || length > this.list.length)
{
return null;
}
var randomIndex = startIndex + Math.floor(Math.random() * length);
return this.list[randomIndex];
}, },
/** /**
@ -367,20 +281,7 @@ var List = new Class({
*/ */
getFirst: function (property, value, startIndex, endIndex) getFirst: function (property, value, startIndex, endIndex)
{ {
if (startIndex === undefined) { startIndex = 0; } return ArrayUtils.GetFirstElement(this.list, property, value, startIndex, endIndex);
if (endIndex === undefined) { endIndex = this.list.length; }
for (var i = startIndex; i < endIndex; i++)
{
var child = this.list[i];
if (child[property] === value)
{
return child;
}
}
return null;
}, },
/** /**
@ -388,7 +289,11 @@ var List = new Class({
* *
* You can optionally specify a matching criteria using the `property` and `value` arguments. * You can optionally specify a matching criteria using the `property` and `value` arguments.
* *
* For example: `getAll('visible', true)` would return only children that have their visible property set. * For example: `getAll('parent')` would return only children that have a property called `parent`.
*
* You can also specify a value to compare the property to:
*
* `getAll('visible', true)` would return only children that have their visible property set to `true`.
* *
* Optionally you can specify a start and end index. For example if this List had 100 children, * Optionally you can specify a start and end index. For example if this List had 100 children,
* and you set `startIndex` to 0 and `endIndex` to 50, it would return matches from only * and you set `startIndex` to 0 and `endIndex` to 50, it would return matches from only
@ -402,36 +307,14 @@ var List = new Class({
* *
* @param {string} [property] - An optional property to test against the value argument. * @param {string} [property] - An optional property to test against the value argument.
* @param {*} [value] - If property is set then Child.property must strictly equal this value to be included in the results. * @param {*} [value] - If property is set then Child.property must strictly equal this value to be included in the results.
* @param {integer} [startIndex=0] - The first child index to start the search from. * @param {integer} [startIndex] - The first child index to start the search from.
* @param {integer} [endIndex] - The last child index to search up until. * @param {integer} [endIndex] - The last child index to search up until.
* *
* @return {Array.<*>} [description] * @return {Array.<*>} [description]
*/ */
getAll: function (property, value, startIndex, endIndex) getAll: function (property, value, startIndex, endIndex)
{ {
if (startIndex === undefined) { startIndex = 0; } return ArrayUtils.GetAll(this.list, property, value, startIndex, endIndex);
if (endIndex === undefined) { endIndex = this.list.length; }
var output = [];
for (var i = startIndex; i < endIndex; i++)
{
var child = this.list[i];
if (property)
{
if (child[property] === value)
{
output.push(child);
}
}
else
{
output.push(child);
}
}
return output;
}, },
/** /**
@ -449,19 +332,7 @@ var List = new Class({
*/ */
count: function (property, value) count: function (property, value)
{ {
var total = 0; return ArrayUtils.CountAllMatching(this.list, property, value);
for (var i = 0; i < this.list.length; i++)
{
var child = this.list[i];
if (child[property] === value)
{
total++;
}
}
return total;
}, },
/** /**
@ -477,21 +348,7 @@ var List = new Class({
*/ */
swap: function (child1, child2) swap: function (child1, child2)
{ {
if (child1 === child2) ArrayUtils.Swap(this.list, child1, child2);
{
return;
}
var index1 = this.getIndex(child1);
var index2 = this.getIndex(child2);
if (index1 < 0 || index2 < 0)
{
throw new Error('List.swap: Supplied objects must be children of the same list');
}
this.list[index1] = child2;
this.list[index2] = child1;
}, },
/** /**
@ -509,20 +366,7 @@ var List = new Class({
*/ */
moveTo: function (child, index) moveTo: function (child, index)
{ {
var currentIndex = this.getIndex(child); return ArrayUtils.MoveTo(this.list, child, index);
if (currentIndex === -1 || index < 0 || index >= this.list.length)
{
throw new Error('List.moveTo: The supplied index is out of bounds');
}
// Remove
this.list.splice(currentIndex, 1);
// Add in new location
this.list.splice(index, 0, child);
return child;
}, },
/** /**
@ -540,19 +384,14 @@ var List = new Class({
*/ */
remove: function (child, skipCallback) remove: function (child, skipCallback)
{ {
var index = this.list.indexOf(child); if (skipCallback)
if (index !== -1)
{ {
this.list.splice(index, 1); return ArrayUtils.Remove(this.list, child);
}
if (!skipCallback) else
{ {
this.removeCallback(this, child); return ArrayUtils.Remove(this.list, child, this.removeCallback, this);
}
} }
return child;
}, },
/** /**
@ -570,19 +409,14 @@ var List = new Class({
*/ */
removeAt: function (index, skipCallback) removeAt: function (index, skipCallback)
{ {
var child = this.list[index]; if (skipCallback)
if (child)
{ {
this.children.splice(index, 1); return ArrayUtils.RemoveAt(this.list, index);
}
if (!skipCallback) else
{ {
this.removeCallback(this, child); return ArrayUtils.RemoveAt(this.list, index, this.removeCallback, this);
}
} }
return child;
}, },
/** /**
@ -593,37 +427,21 @@ var List = new Class({
* *
* @genericUse {T[]} - [$return] * @genericUse {T[]} - [$return]
* *
* @param {integer} [beginIndex=0] - [description] * @param {integer} [startIndex=0] - [description]
* @param {integer} [endIndex] - [description] * @param {integer} [endIndex] - [description]
* @param {boolean} [skipCallback=false] - Skip calling the List.removeCallback. * @param {boolean} [skipCallback=false] - Skip calling the List.removeCallback.
* *
* @return {Array.<*>} [description] * @return {Array.<*>} [description]
*/ */
removeBetween: function (beginIndex, endIndex, skipCallback) removeBetween: function (startIndex, endIndex, skipCallback)
{ {
if (beginIndex === undefined) { beginIndex = 0; } if (skipCallback)
if (endIndex === undefined) { endIndex = this.list.length; }
var range = endIndex - beginIndex;
if (range > 0 && range <= endIndex)
{ {
var removed = this.list.splice(beginIndex, range); return ArrayUtils.RemoveBetween(this.list, startIndex, endIndex);
if (!skipCallback)
{
this.removeCallback(this, removed);
}
return removed;
}
else if (range === 0 && this.list.length === 0)
{
return [];
} }
else else
{ {
throw new Error('List.removeBetween: Range Error, numeric values are outside the acceptable range'); return ArrayUtils.RemoveBetween(this.list, startIndex, endIndex, this.removeCallback, this);
} }
}, },
@ -665,13 +483,7 @@ var List = new Class({
*/ */
bringToTop: function (child) bringToTop: function (child)
{ {
if (this.getIndex(child) < this.list.length) return ArrayUtils.BringToTop(this.list, child);
{
this.remove(child, true);
this.add(child, true);
}
return child;
}, },
/** /**
@ -688,13 +500,7 @@ var List = new Class({
*/ */
sendToBack: function (child) sendToBack: function (child)
{ {
if (this.getIndex(child) > 0) return ArrayUtils.SendToBack(this.list, child);
{
this.remove(child, true);
this.addAt(child, 0, true);
}
return child;
}, },
/** /**
@ -711,17 +517,7 @@ var List = new Class({
*/ */
moveUp: function (child) moveUp: function (child)
{ {
var a = this.getIndex(child); ArrayUtils.MoveUp(this.list, child);
if (a !== -1 && a < this.list.length - 1)
{
var b = this.getAt(a + 1);
if (b)
{
this.swap(child, b);
}
}
return child; return child;
}, },
@ -740,17 +536,7 @@ var List = new Class({
*/ */
moveDown: function (child) moveDown: function (child)
{ {
var a = this.getIndex(child); ArrayUtils.MoveDown(this.list, child);
if (a > 0)
{
var b = this.getAt(a - 1);
if (b)
{
this.swap(child, b);
}
}
return child; return child;
}, },
@ -784,13 +570,7 @@ var List = new Class({
*/ */
shuffle: function () shuffle: function ()
{ {
for (var i = this.list.length - 1; i > 0; i--) ArrayUtils.Shuffle(this.list);
{
var j = Math.floor(Math.random() * (i + 1));
var temp = this.list[i];
this.list[i] = this.list[j];
this.list[j] = temp;
}
return this; return this;
}, },
@ -810,16 +590,7 @@ var List = new Class({
*/ */
replace: function (oldChild, newChild) replace: function (oldChild, newChild)
{ {
var index = this.getIndex(oldChild); return ArrayUtils.Replace(this.list, oldChild, newChild);
if (index !== -1)
{
this.remove(oldChild);
this.addAt(newChild, index);
return oldChild;
}
}, },
/** /**
@ -847,18 +618,16 @@ var List = new Class({
* *
* @genericUse {T} - [value] * @genericUse {T} - [value]
* *
* @param {string} key - [description] * @param {string} property - [description]
* @param {*} value - [description] * @param {*} value - [description]
* @param {integer} [startIndex] - The first child index to start the search from.
* @param {integer} [endIndex] - The last child index to search up until.
*/ */
setAll: function (key, value) setAll: function (property, value, startIndex, endIndex)
{ {
for (var i = 0; i < this.list.length; i++) ArrayUtils.SetAll(this.list, property, value, startIndex, endIndex);
{
if (this.list[i]) return this;
{
this.list[i][key] = value;
}
}
}, },
/** /**
@ -873,11 +642,11 @@ var List = new Class({
* @param {*} [thisArg] - Value to use as `this` when executing callback. * @param {*} [thisArg] - Value to use as `this` when executing callback.
* @param {...*} [args] - Additional arguments that will be passed to the callback, after the child. * @param {...*} [args] - Additional arguments that will be passed to the callback, after the child.
*/ */
each: function (callback, thisArg) each: function (callback, context)
{ {
var args = [ null ]; var args = [ null ];
for (var i = 1; i < arguments.length; i++) for (var i = 2; i < arguments.length; i++)
{ {
args.push(arguments[i]); args.push(arguments[i]);
} }
@ -885,7 +654,8 @@ var List = new Class({
for (i = 0; i < this.list.length; i++) for (i = 0; i < this.list.length; i++)
{ {
args[0] = this.list[i]; args[0] = this.list[i];
callback.apply(thisArg, args);
callback.apply(context, args);
} }
}, },

View file

@ -465,29 +465,41 @@ rbush.prototype = {
_initFormat: function (format) _initFormat: function (format)
{ {
// data format (minX, minY, maxX, maxY accessors) // format: [minX, minY, maxX, maxY accessors]
// accessors will be dotted names
// Because we have historically used eval-based function constructor
// the format accerrsors need to have their leading dots stripped to
// obtain the actual accessor
format = format.map(
function (f)
{
return f.substring(1);
}
);
// Do not use string-generated Functions for CSP policies // Do not use string-generated Functions for CSP policies
// Instead a combination of anonymous functions and grabbing // Instead a combination of anonymous functions and grabbing properties
// properties by string is used. // by string is used.
var compareArr = function (accessor) // cf. https://github.com/photonstorm/phaser/issues/3441
{ // and https://github.com/photonstorm/phaser/issues/3535
return function (a, b)
{ var mkCompareFn = function(attr) {
return this[a + accessor] - this[b + accessor]; return function(a, b) {
}; return a[attr] - b[attr];
};
}; };
this.compareMinX = compareArr(format[0]); this.compareMinX = mkCompareFn(format[0]);
this.compareMinY = compareArr(format[1]); this.compareMinY = mkCompareFn(format[1]);
this.toBBox = function (a) this.toBBox = function(a)
{ {
return { return {
minX: a + format[0], minX: a[format[0]],
minY: a + format[1], minY: a[format[1]],
maxX: a + format[2], maxX: a[format[2]],
maxy: a + format[3] maxY: a[format[3]],
}; };
}; };
} }

View file

@ -22,7 +22,13 @@ var GetFastValue = require('../../utils/object/GetFastValue');
* @param {integer} y - [description] * @param {integer} y - [description]
* @param {integer} width - [description] * @param {integer} width - [description]
* @param {integer} height - [description] * @param {integer} height - [description]
* @param {object} config - [description] * @param {object} config - An object describing how to parse the Sprite Sheet.
* @param {number} config.frameWidth - Width in pixels of a single frame in the sprite sheet.
* @param {number} [config.frameHeight] - Height in pixels of a single frame in the sprite sheet. Defaults to frameWidth if not provided.
* @param {number} [config.startFrame=0] - [description]
* @param {number} [config.endFrame=-1] - [description]
* @param {number} [config.margin=0] - If the frames have been drawn with a margin, specify the amount here.
* @param {number} [config.spacing=0] - If the frames have been drawn with spacing between them, specify the amount here.
* *
* @return {Phaser.Textures.Texture} The Texture modified by this parser. * @return {Phaser.Textures.Texture} The Texture modified by this parser.
*/ */

View file

@ -8,7 +8,7 @@ var GetFastValue = require('../../utils/object/GetFastValue');
/** /**
* Parses a Sprite Sheet and adds the Frames to the Texture, where the Sprite Sheet is stored as a frame within an Atlas. * Parses a Sprite Sheet and adds the Frames to the Texture, where the Sprite Sheet is stored as a frame within an Atlas.
* *
* In Phaser terminology a Sprite Sheet is a texture containing different frames, but each frame is the exact * In Phaser terminology a Sprite Sheet is a texture containing different frames, but each frame is the exact
* same size and cannot be trimmed or rotated. * same size and cannot be trimmed or rotated.
* *
@ -18,7 +18,13 @@ var GetFastValue = require('../../utils/object/GetFastValue');
* *
* @param {Phaser.Textures.Texture} texture - The Texture to add the Frames to. * @param {Phaser.Textures.Texture} texture - The Texture to add the Frames to.
* @param {Phaser.Textures.Frame} frame - The Frame that contains the Sprite Sheet. * @param {Phaser.Textures.Frame} frame - The Frame that contains the Sprite Sheet.
* @param {object} config - [description] * @param {object} config - An object describing how to parse the Sprite Sheet.
* @param {number} config.frameWidth - Width in pixels of a single frame in the sprite sheet.
* @param {number} [config.frameHeight] - Height in pixels of a single frame in the sprite sheet. Defaults to frameWidth if not provided.
* @param {number} [config.startFrame=0] - [description]
* @param {number} [config.endFrame=-1] - [description]
* @param {number} [config.margin=0] - If the frames have been drawn with a margin, specify the amount here.
* @param {number} [config.spacing=0] - If the frames have been drawn with spacing between them, specify the amount here.
* *
* @return {Phaser.Textures.Texture} The Texture modified by this parser. * @return {Phaser.Textures.Texture} The Texture modified by this parser.
*/ */

View file

@ -5,7 +5,7 @@
*/ */
var GetTilesWithin = require('./GetTilesWithin'); var GetTilesWithin = require('./GetTilesWithin');
var GetRandomElement = require('../../utils/array/GetRandomElement'); var GetRandom = require('../../utils/array/GetRandom');
/** /**
* Randomizes the indexes of a rectangular region of tiles (in tile coordinates) within the * Randomizes the indexes of a rectangular region of tiles (in tile coordinates) within the
@ -44,7 +44,7 @@ var Randomize = function (tileX, tileY, width, height, indexes, layer)
for (i = 0; i < tiles.length; i++) for (i = 0; i < tiles.length; i++)
{ {
tiles[i].index = GetRandomElement(indexes); tiles[i].index = GetRandom(indexes);
} }
}; };

View file

@ -8,7 +8,7 @@ var GetTilesWithin = require('./GetTilesWithin');
/** /**
* Randomizes the indexes of a rectangular region of tiles (in tile coordinates) within the * Randomizes the indexes of a rectangular region of tiles (in tile coordinates) within the
* specified layer. Each tile will recieve a new index. New indexes are drawn from the given * specified layer. Each tile will receive a new index. New indexes are drawn from the given
* weightedIndexes array. An example weighted array: * weightedIndexes array. An example weighted array:
* *
* [ * [

View file

@ -852,7 +852,7 @@ var Timeline = new Class({
{ {
for (var i = 0; i < this.data.length; i++) for (var i = 0; i < this.data.length; i++)
{ {
this.data[i].destroy(); this.data[i].stop();
} }
} }

View file

@ -409,8 +409,16 @@ var Tween = new Class({
*/ */
restart: function () restart: function ()
{ {
this.stop(); if (this.state === TWEEN_CONST.REMOVED)
this.play(); {
this.seek(0);
this.parent.makeActive(this);
}
else
{
this.stop();
this.play();
}
}, },
/** /**
@ -475,7 +483,8 @@ var Tween = new Class({
}, },
/** /**
* [description] * Called by TweenManager.preUpdate as part of its loop to check pending and active tweens.
* Should not be called directly.
* *
* @method Phaser.Tweens.Tween#init * @method Phaser.Tweens.Tween#init
* @since 3.0.0 * @since 3.0.0
@ -511,6 +520,7 @@ var Tween = new Class({
if (this.paused && !this.parentIsTimeline) if (this.paused && !this.parentIsTimeline)
{ {
this.state = TWEEN_CONST.PENDING_ADD; this.state = TWEEN_CONST.PENDING_ADD;
this._pausedState = TWEEN_CONST.INIT;
return false; return false;
} }
@ -726,6 +736,10 @@ var Tween = new Class({
this.state = this._pausedState; this.state = this._pausedState;
} }
else
{
this.play();
}
return this; return this;
}, },

111
src/utils/array/Add.js Normal file
View file

@ -0,0 +1,111 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Adds the given item, or array of items, to the array.
*
* Each item must be unique within the array.
*
* The array is modified in-place and returned.
*
* You can optionally specify a limit to the maximum size of the array. If the quantity of items being
* added will take the array length over this limit, it will stop adding once the limit is reached.
*
* You can optionally specify a callback to be invoked for each item successfully added to the array.
*
* @function Phaser.Utils.Array.Add
* @since 3.4.0
*
* @param {array} array - The array to be added to.
* @param {any|any[]} item - The item, or array of items, to add to the array. Each item must be unique within the array.
* @param {integer} [limit] - Optional limit which caps the size of the array.
* @param {function} [callback] - A callback to be invoked for each item successfully added to the array.
* @param {object} [context] - The context in which the callback is invoked.
*
* @return {array} The input array.
*/
var Add = function (array, item, limit, callback, context)
{
if (context === undefined) { context = array; }
if (limit > 0)
{
var remaining = limit - array.length;
// There's nothing more we can do here, the array is full
if (remaining <= 0)
{
return null;
}
}
// Fast path to avoid array mutation and iteration
if (!Array.isArray(item))
{
if (array.indexOf(item) === -1)
{
array.push(item);
if (callback)
{
callback.call(context, item);
}
return item;
}
else
{
return null;
}
}
// If we got this far, we have an array of items to insert
// Ensure all the items are unique
var itemLength = item.length - 1;
while (itemLength >= 0)
{
if (array.indexOf(item[itemLength]) !== -1)
{
// Already exists in array, so remove it
item.pop();
}
itemLength--;
}
// Anything left?
itemLength = item.length;
if (itemLength === 0)
{
return null;
}
if (limit > 0 && itemLength > remaining)
{
item.splice(remaining);
itemLength = remaining;
}
for (var i = 0; i < itemLength; i++)
{
var entry = item[i];
array.push(entry);
if (callback)
{
callback.call(context, entry);
}
}
return item;
};
module.exports = Add;

116
src/utils/array/AddAt.js Normal file
View file

@ -0,0 +1,116 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Adds the given item, or array of items, to the array starting at the index specified.
*
* Each item must be unique within the array.
*
* Existing elements in the array are shifted up.
*
* The array is modified in-place and returned.
*
* You can optionally specify a limit to the maximum size of the array. If the quantity of items being
* added will take the array length over this limit, it will stop adding once the limit is reached.
*
* You can optionally specify a callback to be invoked for each item successfully added to the array.
*
* @function Phaser.Utils.Array.AddAt
* @since 3.4.0
*
* @param {array} array - The array to be added to.
* @param {any|any[]} item - The item, or array of items, to add to the array.
* @param {integer} [index=0] - The index in the array where the item will be inserted.
* @param {integer} [limit] - Optional limit which caps the size of the array.
* @param {function} [callback] - A callback to be invoked for each item successfully added to the array.
* @param {object} [context] - The context in which the callback is invoked.
*
* @return {array} The input array.
*/
var AddAt = function (array, item, index, limit, callback, context)
{
if (index === undefined) { index = 0; }
if (context === undefined) { context = array; }
if (limit > 0)
{
var remaining = limit - array.length;
// There's nothing more we can do here, the array is full
if (remaining <= 0)
{
return null;
}
}
// Fast path to avoid array mutation and iteration
if (!Array.isArray(item))
{
if (array.indexOf(item) === -1)
{
array.splice(index, 0, item);
if (callback)
{
callback.call(context, entry);
}
return item;
}
else
{
return null;
}
}
// If we got this far, we have an array of items to insert
// Ensure all the items are unique
var itemLength = item.length - 1;
while (itemLength >= 0)
{
if (array.indexOf(item[itemLength]) !== -1)
{
// Already exists in array, so remove it
item.pop();
}
itemLength--;
}
// Anything left?
itemLength = item.length;
if (itemLength === 0)
{
return null;
}
// Truncate to the limit
if (limit > 0 && itemLength > remaining)
{
item.splice(remaining);
itemLength = remaining;
}
for (var i = itemLength; i > 0; i--)
{
var entry = item[i];
array.splice(index, 0, entry);
if (callback)
{
callback.call(context, entry);
}
}
return item;
};
module.exports = AddAt;

View file

@ -0,0 +1,32 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Moves the given element to the top of the array.
* The array is modified in-place.
*
* @function Phaser.Utils.Array.BringToTop
* @since 3.4.0
*
* @param {array} array - The array.
* @param {*} item - The element to move.
*
* @return {*} The element that was moved.
*/
var BringToTop = function (array, item)
{
var currentIndex = array.indexOf(item);
if (currentIndex !== -1 && currentIndex < array.length - 2)
{
array.splice(currentIndex, 1);
array.push(item);
}
return item;
};
module.exports = BringToTop;

View file

@ -0,0 +1,46 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var SafeRange = require('./SafeRange');
/**
* Returns the total number of elements in the array which have a property matching the given value.
*
* @function Phaser.Utils.Array.CountAllMatching
* @since 3.4.0
*
* @param {array} array - The array to search.
* @param {string} property - The property to test on each array element.
* @param {*} value - The value to test the property against. Must pass a strict (`===`) comparison check.
* @param {integer} [startIndex] - An optional start index to search from.
* @param {integer} [endIndex] - An optional end index to search to.
*
* @return {integer} The total number of elements with properties matching the given value.
*/
var CountAllMatching = function (array, property, value, startIndex, endIndex)
{
if (startIndex === undefined) { startIndex = 0; }
if (endIndex === undefined) { endIndex = array.length; }
var total = 0;
if (SafeRange(array, startIndex, endIndex))
{
for (var i = startIndex; i < endIndex; i++)
{
var child = array[i];
if (child[property] === value)
{
total++;
}
}
}
return total;
};
module.exports = CountAllMatching;

40
src/utils/array/Each.js Normal file
View file

@ -0,0 +1,40 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Passes each element in the array to the given callback.
*
* @function Phaser.Utils.Array.Each
* @since 3.4.0
*
* @param {array} array - The array to search.
* @param {function} callback - A callback to be invoked for each item in the array.
* @param {object} context - The context in which the callback is invoked.
* @param {...*} [args] - Additional arguments that will be passed to the callback, after the child.
*
* @return {array} The input array.
*/
var Each = function (array, callback, context)
{
var i;
var args = [ null ];
for (i = 2; i < arguments.length; i++)
{
args.push(arguments[i]);
}
for (i = 0; i < array.length; i++)
{
args[0] = array[i];
callback.apply(context, args);
}
return array;
};
module.exports = Each;

View file

@ -0,0 +1,50 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var SafeRange = require('./SafeRange');
/**
* Passes each element in the array, between the start and end indexes, to the given callback.
*
* @function Phaser.Utils.Array.EachInRange
* @since 3.4.0
*
* @param {array} array - The array to search.
* @param {function} callback - A callback to be invoked for each item in the array.
* @param {object} context - The context in which the callback is invoked.
* @param {integer} startIndex - The start index to search from.
* @param {integer} endIndex - The end index to search to.
* @param {...*} [args] - Additional arguments that will be passed to the callback, after the child.
*
* @return {array} The input array.
*/
var EachInRange = function (array, callback, context, startIndex, endIndex)
{
if (startIndex === undefined) { startIndex = 0; }
if (endIndex === undefined) { endIndex = array.length; }
if (SafeRange(array, startIndex, endIndex))
{
var i;
var args = [ null ];
for (i = 5; i < arguments.length; i++)
{
args.push(arguments[i]);
}
for (i = startIndex; i < endIndex; i++)
{
args[0] = array[i];
callback.apply(context, args);
}
}
return array;
};
module.exports = EachInRange;

56
src/utils/array/GetAll.js Normal file
View file

@ -0,0 +1,56 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var SafeRange = require('./SafeRange');
/**
* Returns all elements in the array.
*
* You can optionally specify a matching criteria using the `property` and `value` arguments.
*
* For example: `getAll('visible', true)` would return only elements that have their visible property set.
*
* Optionally you can specify a start and end index. For example if the array had 100 elements,
* and you set `startIndex` to 0 and `endIndex` to 50, it would return matches from only
* the first 50 elements.
*
* @function Phaser.Utils.Array.GetAll
* @since 3.4.0
*
* @param {array} array - The array to search.
* @param {string} [property] - The property to test on each array element.
* @param {*} [value] - The value to test the property against. Must pass a strict (`===`) comparison check.
* @param {integer} [startIndex] - An optional start index to search from.
* @param {integer} [endIndex] - An optional end index to search to.
*
* @return {array} All matching elements from the array.
*/
var GetAll = function (array, property, value, startIndex, endIndex)
{
if (startIndex === undefined) { startIndex = 0; }
if (endIndex === undefined) { endIndex = array.length; }
var output = [];
if (SafeRange(array, startIndex, endIndex))
{
for (var i = startIndex; i < endIndex; i++)
{
var child = array[i];
if (!property ||
(property && value === undefined && child.hasOwnProperty(property)) ||
(property && value !== undefined && child[property] === value))
{
output.push(child);
}
}
}
return output;
};
module.exports = GetAll;

View file

@ -0,0 +1,53 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var SafeRange = require('./SafeRange');
/**
* Returns the first element in the array.
*
* You can optionally specify a matching criteria using the `property` and `value` arguments.
*
* For example: `getAll('visible', true)` would return the first element that had its `visible` property set.
*
* Optionally you can specify a start and end index. For example if the array had 100 elements,
* and you set `startIndex` to 0 and `endIndex` to 50, it would search only the first 50 elements.
*
* @function Phaser.Utils.Array.GetFirst
* @since 3.4.0
*
* @param {array} array - The array to search.
* @param {string} [property] - The property to test on each array element.
* @param {*} [value] - The value to test the property against. Must pass a strict (`===`) comparison check.
* @param {integer} [startIndex=0] - An optional start index to search from.
* @param {integer} [endIndex=array.length] - An optional end index to search up to (but not included)
*
* @return {object} The first matching element from the array, or `null` if no element could be found in the range given.
*/
var GetFirst = function (array, property, value, startIndex, endIndex)
{
if (startIndex === undefined) { startIndex = 0; }
if (endIndex === undefined) { endIndex = array.length; }
if (SafeRange(array, startIndex, endIndex))
{
for (var i = startIndex; i < endIndex; i++)
{
var child = array[i];
if (!property ||
(property && value === undefined && child.hasOwnProperty(property)) ||
(property && value !== undefined && child[property] === value))
{
return child;
}
}
}
return null;
};
module.exports = GetFirst;

View file

@ -5,25 +5,25 @@
*/ */
/** /**
* [description] * Returns a Random element from the array.
* *
* @function Phaser.Utils.Array.GetRandomElement * @function Phaser.Utils.Array.GetRandom
* @since 3.0.0 * @since 3.0.0
* *
* @param {array} array - The array to select the random entry from. * @param {array} array - The array to select the random entry from.
* @param {integer} [start=0] - [description] * @param {integer} [startIndex=0] - An optional start index.
* @param {integer} [length=array.length] - [description] * @param {integer} [length=array.length] - An optional length, the total number of elements (from the startIndex) to choose from.
* *
* @return {object} A random element from the array, or `null` if no element could be found in the range given. * @return {object} A random element from the array, or `null` if no element could be found in the range given.
*/ */
var GetRandomElement = function (array, start, length) var GetRandom = function (array, startIndex, length)
{ {
if (start === undefined) { start = 0; } if (startIndex === undefined) { startIndex = 0; }
if (length === undefined) { length = array.length; } if (length === undefined) { length = array.length; }
var randomIndex = start + Math.floor(Math.random() * length); var randomIndex = startIndex + Math.floor(Math.random() * length);
return (array[randomIndex] === undefined) ? null : array[randomIndex]; return (array[randomIndex] === undefined) ? null : array[randomIndex];
}; };
module.exports = GetRandomElement; module.exports = GetRandom;

View file

@ -0,0 +1,36 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Moves the given array element down one place in the array.
* The array is modified in-place.
*
* @function Phaser.Utils.Array.MoveDown
* @since 3.4.0
*
* @param {array} array - The input array.
* @param {*} item - The element to move down the array.
*
* @return {array} The input array.
*/
var MoveDown = function (array, item)
{
var currentIndex = array.indexOf(item);
if (currentIndex > 0)
{
var item2 = array[currentIndex - 1];
var index2 = array.indexOf(item2);
array[currentIndex] = item2;
array[index2] = item;
}
return array;
};
module.exports = MoveDown;

41
src/utils/array/MoveTo.js Normal file
View file

@ -0,0 +1,41 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Moves an element in an array to a new position within the same array.
* The array is modified in-place.
*
* @function Phaser.Utils.Array.MoveTo
* @since 3.4.0
*
* @param {array} array - The array.
* @param {*} item - The element to move.
* @param {integer} index - The new index that the element will be moved to.
*
* @return {*} The element that was moved.
*/
var MoveTo = function (array, item, index)
{
var currentIndex = array.indexOf(item);
if (currentIndex === -1 || index < 0 || index >= array.length)
{
throw new Error('Supplied index out of bounds');
}
if (currentIndex !== index)
{
// Remove
array.splice(currentIndex, 1);
// Add in new location
array.splice(index, 0, item);
}
return item;
};
module.exports = MoveTo;

36
src/utils/array/MoveUp.js Normal file
View file

@ -0,0 +1,36 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Moves the given array element up one place in the array.
* The array is modified in-place.
*
* @function Phaser.Utils.Array.MoveUp
* @since 3.4.0
*
* @param {array} array - The input array.
* @param {*} item - The element to move up the array.
*
* @return {array} The input array.
*/
var MoveUp = function (array, item)
{
var currentIndex = array.indexOf(item);
if (currentIndex !== -1 && currentIndex < array.length - 2)
{
var item2 = array[currentIndex + 1];
var index2 = array.indexOf(item2);
array[currentIndex] = item2;
array[index2] = item;
}
return array;
};
module.exports = MoveUp;

85
src/utils/array/Remove.js Normal file
View file

@ -0,0 +1,85 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var SpliceOne = require('./SpliceOne');
/**
* Removes the given item, or array of items, from the array.
*
* The array is modified in-place.
*
* You can optionally specify a callback to be invoked for each item successfully removed from the array.
*
* @function Phaser.Utils.Array.Remove
* @since 3.4.0
*
* @param {array} array - The array to be modified.
* @param {*|Array.<*>} item - The item, or array of items, to be removed from the array.
* @param {function} [callback] - A callback to be invoked for each item successfully removed from the array.
* @param {object} [context] - The context in which the callback is invoked.
*
* @return {*|Array.<*>} The item, or array of items, that were successfully removed from the array.
*/
var Remove = function (array, item, callback, context)
{
if (context === undefined) { context = array; }
var index;
// Fast path to avoid array mutation and iteration
if (!Array.isArray(item))
{
index = array.indexOf(item);
if (index !== -1)
{
SpliceOne(array, index);
if (callback)
{
callback.call(context, item);
}
return item;
}
else
{
return null;
}
}
// If we got this far, we have an array of items to remove
var itemLength = item.length - 1;
while (itemLength >= 0)
{
var entry = item[itemLength];
index = array.indexOf(entry);
if (index !== -1)
{
SpliceOne(array, index);
if (callback)
{
callback.call(context, entry);
}
}
else
{
// Item wasn't found in the array, so remove it from our return results
item.pop();
}
itemLength--;
}
return item;
};
module.exports = Remove;

View file

@ -0,0 +1,45 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var SpliceOne = require('./SpliceOne');
/**
* Removes the item from the given position in the array.
*
* The array is modified in-place.
*
* You can optionally specify a callback to be invoked for the item if it is successfully removed from the array.
*
* @function Phaser.Utils.Array.RemoveAt
* @since 3.4.0
*
* @param {array} array - The array to be modified.
* @param {integer} index - The array index to remove the item from. The index must be in bounds or it will throw an error.
* @param {function} [callback] - A callback to be invoked for the item removed from the array.
* @param {object} [context] - The context in which the callback is invoked.
*
* @return {*} The item that was removed.
*/
var RemoveAt = function (array, index, callback, context)
{
if (context === undefined) { context = array; }
if (index < 0 || index > array.length - 1)
{
throw new Error('Index out of bounds');
}
var item = SpliceOne(array, index);
if (callback)
{
callback.call(context, item);
}
return item;
};
module.exports = RemoveAt;

View file

@ -0,0 +1,57 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var SafeRange = require('./SafeRange');
/**
* Removes the item within the given range in the array.
*
* The array is modified in-place.
*
* You can optionally specify a callback to be invoked for the item/s successfully removed from the array.
*
* @function Phaser.Utils.Array.RemoveBetween
* @since 3.4.0
*
* @param {array} array - The array to be modified.
* @param {integer} startIndex - The start index to remove from.
* @param {integer} endIndex - The end index to remove to.
* @param {function} [callback] - A callback to be invoked for the item removed from the array.
* @param {object} [context] - The context in which the callback is invoked.
*
* @return {Array.<*>} An array of items that were removed.
*/
var RemoveBetween = function (array, startIndex, endIndex, callback, context)
{
if (startIndex === undefined) { startIndex = 0; }
if (endIndex === undefined) { endIndex = array.length; }
if (context === undefined) { context = array; }
if (SafeRange(array, startIndex, endIndex))
{
var size = endIndex - startIndex;
var removed = array.splice(startIndex, size);
if (callback)
{
for (var i = 0; i < removed.length; i++)
{
var entry = removed[i];
callback.call(context, entry);
}
}
return removed;
}
else
{
return [];
}
};
module.exports = RemoveBetween;

View file

@ -0,0 +1,37 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Replaces an element of the array with the new element.
* The new element cannot already be a member of the array.
* The array is modified in-place.
*
* @function Phaser.Utils.Array.Replace
* @since 3.4.0
*
* @param {*} oldChild - The element in the array that will be replaced.
* @param {*} newChild - The element to be inserted into the array at the position of `oldChild`.
*
* @return {boolean} Returns true if the oldChild was successfully replaced, otherwise returns false.
*/
var Replace = function (array, oldChild, newChild)
{
var index1 = array.indexOf(oldChild);
var index2 = array.indexOf(newChild);
if (index1 !== -1 && index2 === -1)
{
array[index1] = newChild;
return true;
}
else
{
return false;
}
};
module.exports = Replace;

View file

@ -0,0 +1,43 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Tests if the start and end indexes are a safe range for the given array.
*
* @function Phaser.Utils.Array.SafeRange
* @since 3.4.0
*
* @param {array} array - The array to check.
* @param {integer} startIndex - The start index.
* @param {integer} endIndex - The end index.
* @param {boolean} [throwError=true] - Throw an error if the range is out of bounds.
*
* @return {boolean} True if the range is safe, otherwise false.
*/
var SafeRange = function (array, startIndex, endIndex, throwError)
{
var len = array.length;
if (startIndex < 0 ||
startIndex > len ||
startIndex >= endIndex ||
endIndex > len ||
startIndex + endIndex > len)
{
if (throwError)
{
throw new Error('Range Error: Values outside acceptable range');
}
return false;
}
else
{
return true;
}
};
module.exports = SafeRange;

View file

@ -0,0 +1,32 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Moves the given element to the bottom of the array.
* The array is modified in-place.
*
* @function Phaser.Utils.Array.SendToBack
* @since 3.4.0
*
* @param {array} array - The array.
* @param {*} item - The element to move.
*
* @return {*} The element that was moved.
*/
var SendToBack = function (array, item)
{
var currentIndex = array.indexOf(item);
if (currentIndex !== -1 && currentIndex > 0)
{
array.splice(currentIndex, 1);
array.unshift(item);
}
return item;
};
module.exports = SendToBack;

49
src/utils/array/SetAll.js Normal file
View file

@ -0,0 +1,49 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var SafeRange = require('./SafeRange');
/**
* Scans the array for elements with the given property. If found, the property is set to the `value`.
*
* For example: `SetAll('visible', true)` would set all elements that have a `visible` property to `false`.
*
* Optionally you can specify a start and end index. For example if the array had 100 elements,
* and you set `startIndex` to 0 and `endIndex` to 50, it would update only the first 50 elements.
*
* @function Phaser.Utils.Array.SetAll
* @since 3.4.0
*
* @param {array} array - The array to search.
* @param {string} property - The property to test for on each array element.
* @param {*} value - The value to set the property to.
* @param {integer} [startIndex] - An optional start index to search from.
* @param {integer} [endIndex] - An optional end index to search to.
*
* @return {array} The input array.
*/
var SetAll = function (array, property, value, startIndex, endIndex)
{
if (startIndex === undefined) { startIndex = 0; }
if (endIndex === undefined) { endIndex = array.length; }
if (SafeRange(array, startIndex, endIndex))
{
for (var i = startIndex; i < endIndex; i++)
{
var entry = array[i];
if (entry.hasOwnProperty(property))
{
entry[property] = value;
}
}
}
return array;
};
module.exports = SetAll;

View file

@ -4,10 +4,9 @@
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/ */
// Based on code by Mike Reinstein
/** /**
* Removes a single item from an array and returns it without creating gc (like the native splice does) * Removes a single item from an array and returns it without creating gc, like the native splice does.
* Based on code by Mike Reinstein.
* *
* @function Phaser.Utils.Array.SpliceOne * @function Phaser.Utils.Array.SpliceOne
* @since 3.0.0 * @since 3.0.0

42
src/utils/array/Swap.js Normal file
View file

@ -0,0 +1,42 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Swaps the position of two elements in the given array.
* The elements must exist in the same array.
* The array is modified in-place.
*
* @function Phaser.Utils.Array.Swap
* @since 3.4.0
*
* @param {array} array - The input array.
* @param {*} item1 - The first element to swap.
* @param {*} item2 - The second element to swap.
*
* @return {array} The input array.
*/
var Swap = function (array, item1, item2)
{
if (item1 === item2)
{
return;
}
var index1 = array.indexOf(item1);
var index2 = array.indexOf(item2);
if (index1 < 0 || index2 < 0)
{
throw new Error('Supplied items must be elements of the same array');
}
array[index1] = item2;
array[index2] = item1;
return array;
};
module.exports = Swap;

View file

@ -10,17 +10,38 @@
module.exports = { module.exports = {
FindClosestInSorted: require('./FindClosestInSorted'),
GetRandomElement: require('./GetRandomElement'),
Matrix: require('./matrix'), Matrix: require('./matrix'),
Add: require('./Add'),
AddAt: require('./AddAt'),
BringToTop: require('./BringToTop'),
CountAllMatching: require('./CountAllMatching'),
Each: require('./Each'),
EachInRange: require('./EachInRange'),
FindClosestInSorted: require('./FindClosestInSorted'),
GetAll: require('./GetAll'),
GetFirst: require('./GetFirst'),
GetRandom: require('./GetRandom'),
MoveDown: require('./MoveDown'),
MoveTo: require('./MoveTo'),
MoveUp: require('./MoveUp'),
NumberArray: require('./NumberArray'), NumberArray: require('./NumberArray'),
NumberArrayStep: require('./NumberArrayStep'), NumberArrayStep: require('./NumberArrayStep'),
QuickSelect: require('./QuickSelect'), QuickSelect: require('./QuickSelect'),
Range: require('./Range'), Range: require('./Range'),
Remove: require('./Remove'),
RemoveAt: require('./RemoveAt'),
RemoveBetween: require('./RemoveBetween'),
RemoveRandomElement: require('./RemoveRandomElement'), RemoveRandomElement: require('./RemoveRandomElement'),
Replace: require('./Replace'),
RotateLeft: require('./RotateLeft'), RotateLeft: require('./RotateLeft'),
RotateRight: require('./RotateRight'), RotateRight: require('./RotateRight'),
SafeRange: require('./SafeRange'),
SendToBack: require('./SendToBack'),
SetAll: require('./SetAll'),
Shuffle: require('./Shuffle'), Shuffle: require('./Shuffle'),
SpliceOne: require('./SpliceOne') SpliceOne: require('./SpliceOne'),
StableSort: require('./StableSort'),
Swap: require('./Swap')
}; };

View file

@ -4,21 +4,17 @@
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/ */
// Source object
// The key as a string, can only be 1 level deep (no periods), must exist at the top level of the source object
// The default value to use if the key doesn't exist
/** /**
* [description] * Finds the key within the top level of the {@link source} object, or returns {@link defaultValue}
* *
* @function Phaser.Utils.Object.GetFastValue * @function Phaser.Utils.Object.GetFastValue
* @since 3.0.0 * @since 3.0.0
* *
* @param {object} source - [description] * @param {object} source - The object to search
* @param {string} key - [description] * @param {string} key - The key for the property on source. Must exist at the top level of the source object (no periods)
* @param {*} [defaultValue] - [description] * @param {*} [defaultValue] - The default value to use if the key does not exist.
* *
* @return {*} [description] * @return {*} The value if found; otherwise, defaultValue (null if none provided)
*/ */
var GetFastValue = function (source, key, defaultValue) var GetFastValue = function (source, key, defaultValue)
{ {

View file

@ -5,14 +5,23 @@
*/ */
/** /**
* [description] * Capitalizes the first letter of a string if there is one.
* @example
* UppercaseFirst('abc');
* // returns 'Abc'
* @example
* UppercaseFirst('the happy family');
* // returns 'The happy family'
* @example
* UppercaseFirst('');
* // returns ''
* *
* @function Phaser.Utils.String.UppercaseFirst * @function Phaser.Utils.String.UppercaseFirst
* @since 3.0.0 * @since 3.0.0
* *
* @param {string} str - [description] * @param {string} str - The string to capitalize.
* *
* @return {string} [description] * @return {string} A new string, same as the first, but with the first letter capitalized.
*/ */
var UppercaseFirst = function (str) var UppercaseFirst = function (str)
{ {