Merge branch 'master' into Branch_v3.15.1

This commit is contained in:
J.C 2018-12-20 12:42:25 +08:00 committed by GitHub
commit 580cc36ad4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
317 changed files with 31517 additions and 9226 deletions

View file

@ -10,6 +10,9 @@ src/utils/object/Extend.js
src/structs/RTree.js
src/dom/_ScaleManager.js
src/dom/VisualBounds.js
plugins/spine/src/spine-canvas.js
plugins/spine/src/spine-webgl.js
webpack.*
webpack.config.js
webpack.dist.config.js
webpack.fb.config.js

View file

@ -2,25 +2,270 @@
## Version 3.16.0 - Ishikawa - in development
### Facebook Instant Games Updates and Fixes
* Added the `Leaderboard.getConnectedScores` method, to get a list of scores from player connected entries.
* The `loadPlayerPhoto` function in the Instant Games plugin now listens for the updated Loader event correctly, causing the `photocomplete` event to fire properly.
* `Leaderboard.setScore` now emits the LeaderboardScore object with the `setscore` event, as the documentation said it did.
* `Leaderboard.getPlayerScore` now only populates the `playerScore` property if the entry isn't `null`.
* If the `setScore` or `getPlayerScore` calls fail, it will return `null` as the score instance, instead of causing a run-time error.
* You can now pass an object or a string to `setScore` and objects will be automatically stringified.
* The `preloadAds` method will now only create an AdInstance object if the interstitial `loadSync` promise resolves.
* The `preloadVideoAds` method will now only create an AdInstance object if the interstitial `loadSync` promise resolves.
* The `preloadAds` method will now emit the `adsnofill` event, if there are no ads in the inventory to load.
* The `preloadVideoAds` method will now emit the `adsnofill` event, if there are no ads in the inventory to load.
* The `showAd` method will now emit the `adsnotloaded` event, if there are no ads loaded matching the given Placement ID.
* The `showVideo` method will now emit the `adsnotloaded` event, if there are no ads loaded matching the given Placement ID.
* Showing an ad will emit the `adfinished` event when the ad is closed, previously this event was called `showad` but the new name better reflects what has happened.
* The Facebook Plugin is now available in the `Phaser.Scene` class template under the `facebook` property (thanks @bryanwood)
### Keyboard Input - New Features
The specificity of the Keyboard events has been changed to allow you more control over event handling. Previously, the Keyboard Plugin would emit the global `keydown_CODE` event first (where CODE was a keycode string, like `keydown_A`), then it would emit the global `keydown` event. In previous versions, `Key` objects, created via `this.input.keyboard.addKey()`, didn't emit events.
The `Key` class now extends EventEmitter and emits two new events directly: `down` and `up`. This means you can listen for an event from a Key you've created, i.e.: `yourKey.on('up', handler)`.
The order has also now changed. If it exists, the Key object will dispatch its `down` event first. Then the Keyboard Plugin will dispatch `keydown_CODE` and finally the least specific of them all, `keydown` will be dispatched.
You also now have the ability to cancel this at any stage either on a local or global level. All events handlers are sent an event object which you can call `event.stopImmediatePropagation()` on. This will immediately stop any further listeners from being invoked in the current Scene. Therefore, if you call `stopImmediatePropagation()` in the `Key.on` handler, then the Keyboard Plugin will not emit either the `keydown_CODE` or `keydown` global events. You can also call `stopImmediatePropagation()` during the `keydown_CODE` handler, to stop it reaching the global `keydown` handler. As `keydown` is last, calling it there has no effect.
There is also the `stopPropagation()` function. This works in the same way as `stopImmediatePropagation` but instead of being local, it works across all of the Scenes in your game. For example, if you had 3 active Scenes (A, B and C, with A at the top of the Scene list), all listening for the same key, calling `stopPropagation()` in Scene A would stop the event from reaching any handlers in Scenes B or C. Remember that events flow down the Scene list from top to bottom. So, the top-most rendering Scene in the Scene list has priority over any Scene below it.
All the above also works for `keyup` events.
New in 3.16 is the ability to receive a global `keydown` or `keyup` event from any key on the keyboard. Previously, it would only emit the event if it came from one of the keys listed in the KeyCodes file. Now, those global events will fire for any key, regardless of location.
#### Keyboard Captures
Key capturing is the way in which you stop a keyboard DOM event from activating anything else in the browser by calling `preventDefault` on it. For example, in tall web pages, pressing the SPACE BAR causes the page to scroll down. Obviously, if this is also the fire or jump button in your game, you don't want this to happen. So the key needs to be 'captured' to prevent it. Equally, you may wish to also capture the arrow keys, for similar reasons. Key capturing is done on a global level. If you set-up the capture of a key in one Scene, it will be captured globally across the whole game.
In 3.16 you now do this using the new `KeyboardPlugin.addCapture` method. This takes keycodes as its argument. You can either pass in a single key code (i.e. 32 for the Space Bar), an array of key codes, or a comma-delimited string - in which case the string is parsed and each code it can work out is captured.
To remove a capture you can use the `KeyboardPlugin.removeCapture` method, which takes the same style arguments as adding captures. To clear all captures call `KeyboardPlugin.clearCaptures`. Again, remember that these actions are global.
You can also temporarily enable and disable capturing using `KeyboardPlugin.enableGlobalCapture` and `KeyboardPlugin.disableGlobalCapture`. This means if you set-up a bunch of key captures, but then need to disable them all for a while (perhaps you swap focus to a DOM text field), you can call `disableGlobalCapture` to do this, and when finished in the DOM you can enable captures again with `enableGlobalCapture`, without having to clear and re-create them all.
Default captures can be defined in the Game Config in the `input.keyboard.captures` object. The captures are actually stored in the `KeyboardManager` class. The `KeyboardPlugin` is just a proxy to methods in the Keyboard Manager, but is how you should interface with it.
* `KeyboardPlugin.addCapture` is a new method that allows you to define a set of keycodes to have the default browser behaviors disabled on.
* `KeyboardPlugin.removeCapture` is a new method that removes specific previously set key captures.
* `KeyboardPlugin.clearCaptures` is a new method that removes all key captures.
* `KeyboardPlugin.getCaptures` is a new method that returns an array of all current key captures.
* `KeyboardPlugin.enableGlobalCapture` is a new method that enables any key captures that have been created.
* `KeyboardPlugin.disableGlobalCapture` is a new method that disables any key captures that have been created, without removing them from the captures list.
* `KeyboardPlugin.addKey` has a new boolean argument `enableCapture`, which is true by default, that will add a key capture for the Key being created.
* `KeyboardPlugin.addKeys` has a new boolean argument `enableCapture`, which is true by default, that will add a key capture for any Key created by the method.
#### Other Keyboard Updates and Fixes
* There is a new class called `KeyboardManager`. This class is created by the global Input Manager, if keyboard access has been enabled in the Game config. It's responsible for handling all browser keyboard events. Previously, the `KeyboardPlugin` did this. Which meant that every Scene that had its own Keyboard Plugin was binding more native keyboard events. This was causing problems with parallel Scenes when needing to capture keys. the `KeyboardPlugin` class still exists, and is still the main point of interface when you call `this.input.keyboard` in a Scene, but DOM event handling responsibility has been taken away from it. This means there's no only
one set of bindings ever created, which makes things a lot cleaner.
* There is a new Game and Scene Config setting `input.keyboard.capture` which is an array of KeyCodes that the Keyboard Plugin will capture all non-modified key events on. By default it is empty. You can populate it in the config, or use the new capture methods.
* The Keyboard Manager will now call `preventDefault` only on non-modified key presses, stopping the keyboard event from hitting the browser. Previously, capturing the R key, for example, would block a CTRL+R page reload, but it now ignores it because of the key modifier.
* `Key.emitOnRepeat` is a new boolean property that controls if the Key will continuously emit a `down` event while being held down (true), or emit the event just once, on first press, and then skip future events (false).
* `Key.setEmitOnRepeat` is a new chainable method for setting the `emitOnRepeat` property.
* The `KeyboardPlugin.addKeys` method has a new optional boolean `emitOnRepeat` which sets that property on all Key objects it creates as part of the call. It defaults to `false`.
* The `KeyboardPlugin.addKey` method has a new optional boolean `emitOnRepeat` which sets that property on the Key object it creates. It defaults to `false`.
* The `Key` class now extends EventEmitter and emits two events directly: `down` and `up`. This means you can listen for an event from a Key you've created, i.e.: `yourKey.on('up', handler)`.
* The following Key Codes have been added, which include some missing alphabet letters in Persian and Arabic: `SEMICOLON_FIREFOX`, `COLON`, `COMMA_FIREFOX_WINDOWS`, `COMMA_FIREFOX`, `BRACKET_RIGHT_FIREFOX` and `BRACKET_LEFT_FIREFOX` (thanks @wmateam)
* `Key.onDown` is a new method that handles the Key being pressed down, including down repeats.
* `Key.onUp` is a new method that handles the Key being released.
* `Key.destroy` is a new method that handles Key instance destruction. It is called automatically in `KeyboardPlugin.destroy`.
* The `Key.preventDefault` property has been removed. This is now handled by the global keyboard capture methods.
* `Key.metaKey` is a new boolean property which indicates if the Meta Key was held down when the Key was pressed. On a Mac the Meta Key is Command. On a Windows keyboard, it's the Windows key.
* `InputManager.keyboard` is a new property that instantiates the global Keyboard Manager, if enabled in the game config.
* The `KeyboardPlugin.addKey` method has a new boolean property `enableCapture` which automatically prevents default on the Key being created.
* The `KeyboardPlugin.addKeys` method has a new boolean property `enableCapture` which automatically prevents default on Keys being created.
* `Phaser.Input.Keyboard.ProcessKeyDown` has been removed as it's no longer required, `Key.onDown` handles it instead.
* `Phaser.Input.Keyboard.ProcessKeyUp` has been removed as it's no longer required, `Key.onUp` handles it instead.
* The Keyboard Manager has a property called `captures` which is an array of keycodes, as populated by the Game Config. Any key code in the array will have `preventDefault` called on it if pressed.
* `KeyboardPlugin.manager` is a new property that references the Keyboard Manager and is used internally.
* `KeyboardPlugin.target` has been removed as it's no longer used by the class.
* `KeyboardPlugin.queue` has been removed as it's no longer used by the class.
* `KeyboardPlugin.onKeyHandler` has been removed as it's no longer used by the class.
### Mouse and Touch Input - New Features, Updates and Fixes
* The Mouse Manager class has been updated to remove some commented out code and refine the `startListeners` method.
* When enabling a Game Object for input it will now use the `width` and `height` properties of the Game Object first, falling back to the frame size if not found. This stops a bug when enabling BitmapText objects for input and it using the font texture as the hit area size, rather than the text itself.
* `Pointer.smoothFactor` is a float-value that allows you to automatically apply smoothing to the Pointer position as it moves. This is ideal when you want something smoothly tracking a pointer in a game, or are need a smooth drawing motion for an art package. The default value is zero, meaning disabled. Set to a small number, such as 0.2, to enable.
* `Config.inputSmoothFactor` is a new property that allows you to set the smoothing factor for all Pointers the game creators. The default value is zero, which is disabled. Set in the game config as `input: { smoothFactor: value }`.
* `InputManager.transformPointer` has a new boolean argument `wasMove`, which controls if the pointer is being transformed after a move or up/down event.
* `Pointer.velocity` is a new Vector2 that contains the velocity of the Pointer, based on the current and previous positions. The velocity is smoothed out each frame, according to the `Pointer.motionFactor` property. This is done for more accurate gesture recognition. The velocity is updated based on Pointer movement, it doesn't require a button to be pressed first.
* `Pointer.angle` is a new property that contains the angle of the Pointer, in radians, based on the current and previous positions. The angle is smoothed out each frame, according to the `Pointer.motionFactor` property. This is done for more accurate gesture recognition. The angle is updated based on Pointer movement, it doesn't require a button to be pressed first.
* `Pointer.distance` is a new property that contains the distance of the Pointer, in radians, based on the current and previous positions. The distance is smoothed out each frame, according to the `Pointer.motionFactor` property. This is done for more accurate gesture recognition. The distance is updated based on Pointer movement, it doesn't require a button to be pressed first.
* `Pointer.motionFactor` is a new property that controls how much smoothing to apply to the Pointer positions each frame. This value is passed to the Smooth Step Interpolation that is used to calculate the velocity, angle and distance of the Pointer. It's applied every frame, until the midPoint reaches the current position of the Pointer. The default value is 0.2.
* The Input Plugin was emitting a `preUpdate` event, with the capital U, instead of `preupdate`. This has now been corrected. Fix #4185 (thanks @gadelan)
* `Pointer.updateMotion` is a new method that is called automatically, each step, by the Input Manager. It's responsible for calculating the Pointer velocity, angle and distance properties.
* `Pointer.time` is a new property that holds the time the Pointer was last updated by the Game step.
* `Pointer.getDistance` has been updated. If called while a button is being held down, it will return the distance between the Pointer's current position and it's down position. If called when a Pointer doesn't have a button down, it will return the historic distance between the up and down positions.
* `Pointer.getDistanceX` is a new method that will return the horizontal distance between the Pointer's previous and current coordinates. If called while a button is being held down, it will return the distance between the Pointer's current position and it's down position. If called when a Pointer doesn't have a button down, it will return the historic distance between the up and down positions.
* `Pointer.getDistanceY` is a new method that will return the horizontal distance between the Pointer's previous and current coordinates. If called while a button is being held down, it will return the distance between the Pointer's current position and it's down position. If called when a Pointer doesn't have a button down, it will return the historic distance between the up and down positions.
* `Pointer.getDuration` is a new method that will return the duration the Pointer was held down for. If the Pointer has a button pressed down at the time this method is called, it will return the duration since the Pointer's was pressed down. If no button is held down, it will return the last recorded duration, based on the time the Pointer button was released.
* `Pointer.getAngle` is a new method that will return the angle between the Pointer coordinates. If the Pointer has a button pressed down at the time this method is called, it will return the angle between the Pointer's `downX` and `downY` values and the current position. If no button is held down, it will return the last recorded angle, based on where the Pointer was when the button was released.
* In previous versions, the VisibilityHandler would create a `mousedown` listener for the game canvas and then call `window.focus` when detected (assuming the game config `autoFocus` property was `true`). Responsibility for this has now been handled to the Mouse Manager `onMouseDown` handler.
* In previous versions, the VisibilityHandler would create a `mouseout` listener for the game canvas and then set `game.isOver` when detected. Responsibility for this has now been handled to the Mouse Manager, which sets the new Input Manager `isOver` property directly.
* In previous versions, the VisibilityHandler would create a `mouseover` listener for the game canvas and then set `game.isOver` when detected. Responsibility for this has now been handled to the Mouse Manager, which sets the new Input Manager `isOver` property directly.
* The `Phaser.Game.isOver` property has been moved. You can now find it in the Input Manager and it's also accessible via the Input Plugin, which means you can do `this.input.isOver` from within a Scene. This makes more sense as it's input related and not a game level property.
* The Input Plugin has a new event you can listen to: `gameover`, which is triggered whenever the mouse or a pointer is moved over the Game canvas. Listen to it with `this.input.on('gameover')` from within a Scene.
* The Input Plugin has a new event you can listen to: `gameout`, which is triggered whenever the mouse or a pointer leaves the Game canvas. Listen to it with `this.input.on('gameout')` from within a Scene.
* The Game used to emit a `mouseover` event when the mouse entered the game canvas. This is no longer emitted by the Game itself and can instead be listened for using the new Input Plugin event `gameover`.
* The Game used to emit a `mouseout` event when the mouse left the game canvas. This is no longer emitted by the Game itself and can instead be listened for using the new Input Plugin event `gameout`.
* If the `window` object exists (which it will in normal browser environments) new `mouseup` and `touchend` event listeners are bound to it and trigger the normal `mouseup` or `touchend` events within the internal input system. This means if you will now get a `pointerup` event from the Input Plugin even if the pointer is released outside of the game canvas. Pointers will also no longer think they are still 'down' if released outside the canvas and then moved inside again in their new state.
* The window will now have focus called on it by the Touch Manager, as well as the Mouse Manager, is the `autoFocus` game config property is enabled.
* The Input Plugin has a new event you can listen to: `pointerdownoutside`, which is triggered whenever the mouse or a pointer is pressed down while outside of the Game canvas. Listen to it with `this.input.on('pointerdownoutside')` from within a Scene.
* The Input Plugin has a new event you can listen to: `pointerupoutside`, which is triggered whenever the mouse or a pointer is released while outside of the Game canvas. Listen to it with `this.input.on('pointerupoutside')` from within a Scene.
* `Pointer.downElement` is a new property that holds the target of the DOM Event that triggered when the Pointer was pressed down. If this is within the game, this will be the game canvas element.
* `Pointer.upElement` is a new property that holds the target of the DOM Event that triggered when the Pointer was released. If this is within the game, this will be the game canvas element.
### New Features
* You can now load external Scene files using the new `load.sceneFile` method. This allows you to dynamically load a Scene into the Scene Manager of your game, and swap to it at will. Please see the documentation and examples for further details.
* The data object being sent to the Dynamic Bitmap Text callback now has a new property `parent`, which is a reference to the Bitmap Text instance that owns the data object (thanks ornyth)
* The WebGL Renderer has a new method `clearPipeline`, which will clear down the current pipeline and reset the blend mode, ready for the context to be passed to a 3rd party library.
* The WebGL Renderer has a new method `rebindPipeline`, which will rebind the given pipeline instance, reset the blank texture and reset the blend mode. Which is useful for recovering from 3rd party libs that have modified the gl context.
* Game Objects have a new property called `state`. Use this to track the state of a Game Object during its lifetime. For example, it could move from a state of 'moving', to 'attacking', to 'dead'. Phaser itself will never set this property, although plugins are allowed to.
* Game Objects have a new method called `setState` which will set the state property in a chainable call.
* `BlendModes.ERASE` is a new blend mode that will erase the object being drawn. When used in conjunction with a Render Texture it allows for effects that let you erase parts of the texture, in either Canvas or WebGL. When used with a transparent game canvas, it allows you to erase parts of the canvas, showing the web page background through.
* `BlendModes.SOURCE_IN` is a new Canvas-only blend mode, that allows you to use the `source-in` composite operation when rendering Game Objects.
* `BlendModes.SOURCE_OUT` is a new Canvas-only blend mode, that allows you to use the `source-out` composite operation when rendering Game Objects.
* `BlendModes.SOURCE_ATOP` is a new Canvas-only blend mode, that allows you to use the `source-atop` composite operation when rendering Game Objects.
* `BlendModes.DESTINATION_OVER` is a new Canvas-only blend mode, that allows you to use the `destination-over` composite operation when rendering Game Objects.
* `BlendModes.DESTINATION_IN` is a new Canvas-only blend mode, that allows you to use the `destination-in` composite operation when rendering Game Objects.
* `BlendModes.DESTINATION_OUT` is a new Canvas-only blend mode, that allows you to use the `destination-out` composite operation when rendering Game Objects.
* `BlendModes.DESTINATION_ATOP` is a new Canvas-only blend mode, that allows you to use the `destination-atop` composite operation when rendering Game Objects.
* `BlendModes.LIGHTER` is a new Canvas-only blend mode, that allows you to use the `lighter` composite operation when rendering Game Objects.
* `BlendModes.COPY` is a new Canvas-only blend mode, that allows you to use the `copy` composite operation when rendering Game Objects.
* `BlendModes.XOR` is a new Canvas-only blend mode, that allows you to use the `xor` composite operation when rendering Game Objects.
* `RenderTexture.erase` is a new method that will take an object, or array of objects, and draw them to the Render Texture using an ERASE blend mode, resulting in them being removed from the Render Texture. This is really handy for making a bitmap masked texture in Canvas or WebGL (without using an actual mask), or for 'cutting away' part of a texture.
* There is a new boolean Game Config property called `customEnvironment`. If set to `true` it will skip the internal Feature checks when working out which type of renderer to create, allowing you to run Phaser under non-native web environments. If using this value, you _must_ set an explicit `renderType` of either CANVAS or WEBGL. It cannot be left as AUTO. Fix #4166 (thanks @jcyuan)
* `Animation.nextFrame` will advance an animation to the next frame in the sequence instantly, regardless of the animation time or state. You can call this on a Sprite: `sprite.anims.nextFrame()` (thanks rgk25)
* `Animation.previousFrame` will set an animation to the previous frame in the sequence instantly, regardless of the animation time or state. You can call this on a Sprite: `sprite.anims.previousFrame()` (thanks rgk25)
* `Geom.Intersects.PointToLine` has a new optional argument `lineThickness` (which defaults to 1). This allows you to determine if the point intersects a line of a given thickness, where the line-ends are circular (not square).
* `Geom.Line.GetNearestPoint` is a new static method that will return the nearest point on a line to the given point.
* `Geom.Line.GetShortestDistance` is a new static method that will return the shortest distance from a line to the given point.
* `Camera.getBounds` is a new method that will return a rectangle containing the bounds of the camera.
* `Camera.centerOnX` will move the camera horizontally to be centered on the given coordinate, without changing its vertical placement.
* `Camera.centerOnY` will move the camera vertically to be centered on the given coordinate, without changing its horizontally placement.
* `AnimationManager.exists` is a new method that will check to see if an Animation using the given key already exists or not and returns a boolean.
* `animationstart-key` is a new Animation key specific event emitted by a Game Object. For example, if you had an animation with a key of 'explode' you can now listen for `animationstart-explode`.
* `animationrestart-key` is a new Animation key specific event emitted by a Game Object. For example, if you had an animation with a key of 'explode' you can now listen for `animationrestart-explode`.
* `animationcomplete-key` is a new Animation key specific event emitted by a Game Object. For example, if you had an animation with a key of 'explode' you can now listen for `animationcomplete-explode`.
* `animationupdate-key` is a new Animation key specific event emitted by a Game Object. For example, if you had an animation with a key of 'explode' you can now listen for `animationupdate-explode`.
* The Animation class now extends the Event Emitter and dispatches events itself. This allows you to listen for events from a specific Animation, rather than via a Game Object. This is handy, for example, if you had an explosion animation that you wanted to trigger a sound effect when it started. You can now listen for the events from the Animation object directly.
* The Animation class now emits the `start` event when played (either forward, or in reverse) by any Game Object.
* The Animation class now emits the `restart` event when it restarts playing on any Game Object.
* The Animation class now emits the `complete` event when it finishes playing on any Game Object.
* The Animation Component has a new method called `chain` which allows you to line-up another animation to start playing as soon as the current one stops, no matter how it stops (either by reaching its natural end, or directly by having stop called on it). You can chain a new animation at any point, including before the current one starts playing, during it, or when it ends (via its `animationcomplete` callback). Chained animations are specific to a Game Object, meaning different Game Objects can have different chained animations without impacting the global animation they're playing.
* `CanvasTexture.drawFrame` is a new method that allows you to draw a texture frame to the CanvasTexture based on the texture key and frame given.
* `CanvasTexture.getIndex` is a new method that will take an x/y coordinate and return the Image Data index offset used to retrieve the pixel values.
* `CanvasTexture.getPixels` is a new method that will take a region as an x/y and width/height and return all of the pixels in that region from the CanvasTexture.
* `CanvasTexture.setPixel` is a new method that sets the given pixel in the CanvasTexture to the color and alpha values provided.
* `CanvasTexture.getData` is a new method that will extract an ImageData block from the CanvasTexture from the region given.
* `CanvasTexture.putData` is a new method that will put an ImageData block at the given coordinates in a CanvasTexture.
### Updates
* You can now modify `this.physics.world.debugGraphic.defaultStrokeWidth` to set the stroke width of any debug drawn body, previously it was always 1 (thanks @samme)
* `TextStyle.setFont` has a new optional argument `updateText` which will sets if the text should be automatically updated or not (thanks @DotTheGreat)
* `ProcessQueue.destroy` now sets the internal `toProcess` counter to zero.
* The `PathFollower.pathRotationVerticalAdjust` property has been removed. It was supposed to flipY a follower when it reversed path direction, but after some testing it appears it has never worked and it's easier to do this using events, so the property and associated config value are removed. The `verticalAdjust` argument from the `setRotateToPath` method has been removed as well.
* The config value `preserveDrawingBuffer` has been removed as it has never been used by the WebGL Renderer.
* `PluginManager.install` returns `null` if the plugin failed to install in all cases.
* `PluginFile` will now install the plugin into the _current_ Scene as long as the `start` or `mapping` arguments are provided.
* MATH_CONST no longer requires or sets the Random Data Generator, this is now done in the Game Config, allowing you to require the math constants without pulling in a whole copy of the RNG with it.
* The Dynamic Bitmap Text Canvas Renderer was creating a new data object every frame for the callback. It now uses the `callbackData` object instead, like the WebGL renderer does.
* `WebGLRenderer.setBlendMode` has a new optional argument `force`, which will force the given blend mode to be set, regardless of the current settings.
* The method `DisplayList.sortGameObjects` has been removed. It has thrown a runtime error since v3.3.0! which no-one even spotted, a good indication of how little the method is used. The display list is automatically sorted anyway, so if you need to sort a small section of it, just use the standard JavaScript Array sort method (thanks ornyth)
* The method `DisplayList.getTopGameObject` has been removed. It has thrown a runtime error since v3.3.0! which no-one even spotted, a good indication of how little the method is used (thanks ornyth)
* `WebGLRenderer.setFramebuffer` has a new optional boolean argument `updateScissor`, which will reset the scissor to match the framebuffer size, or clear it.
* `WebAudioSoundManager.onFocus` will not try to resume the Audio Context if it's still locked.
* `WebAudioSoundManager.onBlur` will not try to suspend the Audio Context if it's still locked.
* When using `ScenePlugin.add`, to add a new Scene to the Scene Manager, it didn't allow you to include the optional Scene data object. You can now pass this in the call (thanks @kainage)
* `Graphics.stroke` is a new alias for the `strokePath` method, to keep the calls consistent with the Canvas Rendering Context API.
* `Graphics.fill` is a new alias for the `fillPath` method, to keep the calls consistent with the Canvas Rendering Context API.
* `LoaderPlugin.sceneManager` is a new property that is a reference to the global Scene Manager, useful for Plugins.
* Whenever `Camera.roundPixels` was enabled it would use a bitwise operation to truncate the float (`x |= 0`) - this has been replaced across all files that used it, with a call to `Math.round` instead. This gives far better results when zooming cameras both in and out of a Scene, stopping thin gaps appearing between closely packed Game Objects.
* `AnimationManager.create` will now return a boolean `false` if the given key is invalid (i.e. undefined or falsey).
* `AnimationManager.create` will no longer raise a console warning if the animation key is already in use. Instead, it will return the animation belonging to that key. A brand new animation will only be created if the key isn't already in use. When this happens, the `add` event is emitted by the Animation Manager. If no event is emitted, the animation already existed.
* `ArcadePhysics.Body.destroy` will now only add itself to the World `pendingDestroy` list if the world property exists. This prevents `Cannot read property 'pendingDestroy' of undefined` errors if you try to delete a physics body in a callback and then immediately change Scene (which tells the physics work to also delete all bodies)
* The Animation Component `restart` method has had is sole `key` argument removed. Previously, you had to pass in the key of the animation you wished to reverse, but now you can just call the method directly, and as long as there is an animation playing, it will automatically start playing in reverse, without the nee for a key (the way it should have been originally)
* `Animation.play` and `playReverse` will now accept either a string-based key of the animation to play (like before), or you can pass in an Animation instance, and it will play that animation.
* `CanvasTexture.clear` now has 4 new optional arguments: `x, y, width, height` which allow you to define the region of the texture to be cleared. If not provided it will clear the whole texture, which is the same behavior as before.
* EarCut, the polygon triangulation library used by the Graphics and WebGL classes, has been upgraded from 2.1.1 to 2.1.4. 2.1.2 fixed a few race conditions where bad input would cause an error. 2.1.3 improved performance for bigger inputs (5-12%) and 2.1.4 fixed a race condition that could lead to a freeze on degenerate input.
* `TextureTintPipeline.batchQuad` and `batchTri` have two new optional arguments `texture` and `unit` which are used to re-set the batch texture should the method cause a batch flush.
* `TextureTintPipeline.requireTextureBatch` is a new internal method that helps speed-up the creation of texture batches. It is used in conjunction with `setTexture2D` and `pushBatch`.
* `TextureTintPipeline.flush` and `TextureTintPipeline.pushBatch` have been optimized to handle zero based texture units as priority. They've also been refactored to avoid creation of empty texture batches.
* The `WebGLRenderer.setTexture2D` method has a new optional argument `flush` which controls if the pipeline is flushed if the given texture is new, or not. This is used internally to skip flushing during an existing flush.
* The Tilemap Layer `width` and `height` properties are now based on the tilemap tile sizes multiplied by the layer dimensions. This corrects an issue with layer sizes being wrong if you called `setBaseTileSize` on a Map.
* The WebGLRenderer will now clear the framebuffer at the start of every render.
* `WebGLRenderer.setScissor` now has a new optional argument `drawingBufferHeight` which allows you to specify the drawing buffer height, rather than use the renderers default value.
* `WebGLRenderer.pushScissor` now has a new optional argument `drawingBufferHeight` which allows you to specify the drawing buffer height, rather than use the renderers default value.
* `WebGLRenderer.preRender` now calls `gl.clearColor` in order to restore the background clear color in case something, like a Render Texture, has changed it.
### Bug Fixes
* The Rectangle Shape object wouldn't render if it didn't have a stroke, or any other objects on the display list (thanks mliko)
* When using a font string instead of setting `fontFamily`, `fontSize` and `fontStyle` in either `Text.setStyle` or `setFont`, the style properties wouldn't get set. This isn't a problem while creating the text object, only if modifying it later (thanks @DotTheGreat)
* `Text.toJSON` wasn't saving the font style when using the "font" shorthand to create it. It now saves it correctly. Fix #4141 (thanks @divillysausages)
* Disabling camera bounds and then moving the camera to an area in a Tilemap that did not have any tile information would throw an `Uncaught Reference error` as it tried to access tiles that did not exist (thanks @Siyalatas)
* Fixed an issue where Sprite Sheets being extracted from a texture atlas would fail if the sheet was either just a single column or single row of sprites. Fix #4096 (thanks @Cirras)
* If you created an Arcade Physics Group without passing a configuration object, and passing an array of non-standard children, it would throw a classType runtime error. It now creates a default config object correctly (thanks @pierpo)
* The `Camera.cull` method has been restructured so it now calculates if a Game Object is correctly in view or not, before culling it. Although not used internally, if you need to cull objects for a camera, you can now safely use this method. Fix #4092 (thanks @Cirras)
* The Tiled Parser would ignore animated tile data if it was in the new Tiled 1.2 format. This is now accounted for, as well as 1.0 (thanks @nkholski)
* `Array.Matrix.ReverseRows` was actually reversing the columns, but now reverses the rows.
* `Array.Matrix.ReverseColumns` was actually reversing the rows, but now reverses the columns.
* UnityAtlas now sets the correct file type key if using a config file object.
* Starting with version 3.13 in the Canvas Renderer, it was possible for long-running scripts to start to get bogged-down in `fillRect` calls if the game had a background color set. The context is now saved properly to avoid this. Fix #4056 (thanks @Aveyder)
* Render Textures created larger than the size of the default canvas would be automatically clipped when drawn to in WebGL. They now reset the gl scissor and drawing height property in order to draw to their full size, regardless of the canvas size. Fix #4139 (thanks @chaoyang805 @iamchristopher)
* The `cameraFilter` property of a Game Object will now allow full bitmasks to be set (a value of -1), instead of just those > 0 (thanks @stuartkeith)
* The `PathFollower.startFollow` method now properly uses the `startAt` argument to the method, so you can start a follower off at any point along the path. Fix #3688 (thanks @DannyT @diteix)
* Static Circular Arcade Physics Bodies now render as circles in the debug display, instead of showing their rectangle bounds (thanks @maikthomas)
* Changing the mute flag on an `HTML5AudioSound` instance, via the `mute` setter, now works, as it does via the Sound Manager (thanks @Waclaw-I @neon-dev)
* Changing the volume on an `HTML5AudioSound` instance, via the `volume` setter, now works, as it does via the Sound Manager (thanks @Waclaw-I)
* The Dynamic Tilemap Layer WebGL renderer was drawing tiles at the incorrect position if the layer was scaled. Fix #4104 (thanks @the-realest-stu)
* `Tile.tileset` now returns the specific Tileset associated with the tile, rather than an array of them. Fix #4095 (thanks @quadrupleslap)
* `Tile.getCollisionGroup` wouldn't return the correct Group after the change to support multiple Tilesets. It now returns the group properly (thanks @jbpuryear)
* `Tile.getTileData` wouldn't return the correct data after the change to support multiple Tilesets. It now returns the tile data properly (thanks @jbpuryear)
* The `GetTileAt` and `RemoveTileAt` components would error with "Cannot read property 'index' of undefined" if the tile was undefined rather than null. It now handles both cases (thanks @WaSa42)
* Changing `TileSprite.width` or `TileSprite.height` will now flag the texture as dirty and call `updateDisplayOrigin`, allowing you to resize TileSprites dynamically in both Canvas and WebGL.
* `RandomDataGenerator.shuffle` has been fixed to use the proper modifier in the calculation, allowing for a more even distribution (thanks wayfinder)
* The Particle Emitter was not recycling dead particles correctly, so it was creating new objects every time it emitted (the old particles were then left to the browsers gc to clear up). This has now been recoded, so the emitter will properly keep track of dead particles and re-use them (thanks @Waclaw-I for the initial PR)
* `ParticleEmitter.indexSortCallback` has been removed as it's no longer required.
* `Particle.index` has been removed, as it's no longer required. Particles don't need to keep track of their index any more.
* The Particle Emitter no longer needs to call the StableSort.inplace during its preUpdate, saving cpu.
* `Particle.resetPosition` is a new method that is called when a particle dies, preparing it ready for firing again in the future.
* The Canvas `SetTransform` method would save the context state, but it wasn't restored at the end in the following Game Objects: Dynamic Bitmap Text, Graphics, Arc, Curve, Ellipse, Grid, IsoBox, IsoTriangle, Line, Polygon, Rectangle, Star and Triangle. These now all restore the context, meaning if you're using non-canvas sized cameras in Canvas mode, it will now render beyond just the first custom camera.
* `Utils.Array.MoveUp` wouldn't let you move an array element to the top-most index in the array. This also impacted `Container.moveUp`.
* The Texture Tint Pipeline had a logic error that would cause every 2001st quad to either be invisible, or pick-up the texture of the 2000th quad by mistake. The `batchQuad` and `batchTri` methods how handle re-assigning the batch texture if they cause a batch flush as part of their process.
* Rotating Sprites that used a Normal Map wouldn't rotate the normal map with it, causing the lighting effects to become irregular. The normal map vectors are now rotated correctly (thanks @sercant for the PR and @fazzamatazz and @ysraelJMM for the report)
* Changing `scaleX` or `scaleY` on a `MatterImage` or `MatterSprite` would cause the body scale to become distorted as the setters didn't use the correct factor when resetting the initial scale. Fix #4206 (thanks @YannCaron)
* `StaticBody.reset` in Arcade Physics would ignore the `x` and `y` values given to it. If given, they're now used to reset the parent Game Object before the body is updated. Fix #4224 (thanks @samme)
* Static Tilemap Layers wouldn't render correctly if the layer used a tileset with a different size to the base map data (set via `setBaseTileSize`). They now render correctly in WebGL and Canvas, regardless of the base tile size.
* When using `RenderTexture.fill`, the `alpha` argument would be ignored in Canvas mode. It's now used when filling the RenderTexture.
* Fixed an issue in `WebGLRenderer.setScissor` where it was possible to try and compare the scissor size to a non-current scissor, if called outside of the render loop (i.e. from `RenderTexture.fill`) (thanks @hackhat)
* `RenderTexture.fill` in WebGL would use `gl.clear` and a clear color to try and fill the Render Texture. This only worked for full-canvas sized RenderTextures that didn't have a camera zoom applied. It has now been swapped to use the `drawFillRect` method of the Texture Tint Pipeline, allowing it to work properly regardless of camera zoom or size.
* `Container.getFirst` was using an incorrect Array Utils function `GetFirstElement`, when it should have been using `GetFirst`. It now uses the correct function. Fix #4244 (thanks @miran248)
* `List.getFirst` was using an incorrect Array Utils function `GetFirstElement`, when it should have been using `GetFirst`. It now uses the correct function. Fix #4244 (thanks @miran248)
* Fixed an issue where changing the viewport or size of a Camera belonging to a RenderTexture, it wouldn't impact the rendering and objects will still render outside of the viewport range. It's now converted to a proper gl scissor rect by the renderer, meaning you can limit the area rendered to by adjusting the internal Render Texture cameras viewport. Fix #4243 (thanks @hackhat)
* `CanvasTexture.destroy` is a new method that specifically handles the destruction of the CanvasTexture and all of its associated typed arrays. This prevents a memory leak when creating and destroying lots of RenderTextures (which are CanvasTexture backed). Fix #4239 (thanks @sjb933)
* The Alpha, Flip and Origin components have been removed from the Mesh Game Object (and by extension, Quad as well) as they are not used in the renderer and should be manipulated via the Mesh properties. Fix #4188 (thanks @enriqueto)
### Examples and TypeScript
Thanks to the following for helping with the Phaser 3 Examples and TypeScript definitions, either by reporting errors, or even better, fixing them:
@guilhermehto
@guilhermehto @samvieten @darkwebdev @RoryO @snowbillr @slothyrulez @jcyuan
### Phaser Doc Jam
The [Phaser Doc Jam](http://docjam.phaser.io) is an on-going effort to ensure that the Phaser 3 API has 100% documentation coverage. Thanks to the monumental effort of myself and the following people we're now really close to that goal! My thanks to:
The Phaser Doc Jam was a community-backed effort to try and get the Phaser 3 API documentation to 100% coverage. The Doc Jam is now over and I offer my thanks to the following who helped with docs in this release:
-
16patsle - @gurungrahul2 - @icbat - @samme - @telinc1 - anandu pavanan - blackhawx - candelibas - Diego Romero - doronlinder - Elliott Wallace - eric - Georges Gabereau - Haobo Zhang - henriacle - jak6jak - Jake Jensen - James Van Roose - JamesSkemp - joelahoover - Joey - madclaws - marc136 - Mihail Ilinov - naum303 - NicolasRoehm - nuane - rejacobson - Robert Kowalski - rodri042 - rootasjey - sawamara - scottwestover - sir13tommy - stetso - therealsamf - Tigran - willblackmore - zenwaichi
If you'd like to help finish off the last parts of documentation then take a look at the [Doc Jam site](http://docjam.phaser.io).
Also, the following helped with the docs outside of the Doc Jam:
@bryanwood @jestarray @matosummer @tfelix @imilo
## Version 3.15.1 - Batou - 16th October 2018

View file

@ -157,7 +157,7 @@ Also, please subscribe to the [Phaser World](https://phaser.io/community/newslet
### Facebook Instant Games
Phaser 3.13 introduced the new [Facebook Instant Games](https://developers.facebook.com/docs/games/instant-games) Plugin. The plugin provides a seamless bridge between Phaser and version 6.2 of the Facebook Instant Games SDK. Every single SDK function is available via the plugin and we will keep track of the official SDK to make sure they stay in sync.
Phaser 3.13 introduced the new [Facebook Instant Games](http://phaser.io/news/2018/10/facebook-instant-games-phaser-tutorial) Plugin. The plugin provides a seamless bridge between Phaser and version 6.2 of the Facebook Instant Games SDK. Every single SDK function is available via the plugin and we will keep track of the official SDK to make sure they stay in sync.
The plugin offers the following features:
@ -177,6 +177,12 @@ The plugin offers the following features:
* Easily preload a set of interstitial ads, in both banner and video form, then display the ad at any point in your game, with in-built tracking of ads displayed and inventory available.
* Plus other features, such as logging to FB Analytics, creating short cuts, switching games, etc.
We've 3 tutorials related to Facebook Instant Games and Phaser:
* [Getting Started with Facebook Instant Games](http://phaser.io/news/2018/10/facebook-instant-games-phaser-tutorial)
* [Facebook Instant Games Leaderboards Tutorial](http://phaser.io/news/2018/11/facebook-instant-games-leaderboards-tutorial)
* [Displaying Ads in your Instant Games](http://phaser.io/news/2018/12/facebook-instant-games-ads-tutorial)
A special build of Phaser with the Facebook Instant Games Plugin ready-enabled is [available on jsDelivr](https://www.jsdelivr.com/projects/phaser). Include the following in your html:
```html
@ -305,7 +311,7 @@ Read our [comprehensive guide](https://phaser.io/phaser3/devlog/127) on creating
### Building from Source
If you wish to build Phaser 3 from source, ensure you have the required packages by cloning the repository and then running `npm install`.
If you wish to build Phaser 3 from source, ensure you have the required packages by cloning the repository and then running `npm install` on your source directory.
You can then run `webpack` to create a development build in the `build` folder which includes source maps for local testing. You can also `npm run dist` to create a minified packaged build in the `dist` folder. For a list of all commands available use `npm run help`.
@ -382,8 +388,8 @@ All rights reserved.
"Above all, video games are meant to be just one thing: fun. Fun for everyone." - Satoru Iwata
[get-js]: https://github.com/photonstorm/phaser/releases/download/v3.11/phaser.js
[get-minjs]: https://github.com/photonstorm/phaser/releases/download/v3.11/phaser.min.js
[get-js]: https://github.com/photonstorm/phaser/releases/download/v3.15.1/phaser.js
[get-minjs]: https://github.com/photonstorm/phaser/releases/download/v3.15.1/phaser.min.js
[clone-http]: https://github.com/photonstorm/phaser.git
[clone-ssh]: git@github.com:photonstorm/phaser.git
[clone-ghwin]: github-windows://openRepo/https://github.com/photonstorm/phaser
@ -392,4 +398,4 @@ All rights reserved.
[issues]: https://github.com/photonstorm/phaser/issues
[examples]: https://github.com/photonstorm/phaser3-examples
[contribute]: https://github.com/photonstorm/phaser/blob/master/.github/CONTRIBUTING.md
[forum]: http://www.html5gamedevs.com/forum/33-phaser-3/
[forum]: https://phaser.discourse.group/

4070
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
{
"name": "phaser",
"version": "3.15.1",
"release": "Batou",
"version": "3.16.0",
"release": "Ishikawa",
"description": "A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers.",
"author": "Richard Davey <rich@photonstorm.com> (http://www.photonstorm.com)",
"logo": "https://raw.github.com/photonstorm/phaser/master/phaser-logo-small.png",
@ -25,6 +25,13 @@
"distfb": "webpack --config webpack.fb.dist.config.js",
"distfull": "npm run dist && npm run distfb",
"plugin.cam3d": "webpack --config plugins/camera3d/webpack.config.js",
"plugin.spine": "webpack --config plugins/spine/webpack.config.js",
"plugin.spine.dist": "webpack --config plugins/spine/webpack.auto.dist.config.js",
"plugin.spine.watch": "webpack --config plugins/spine/webpack.auto.config.js --watch --display-modules",
"plugin.spine.canvas.dist": "webpack --config plugins/spine/webpack.canvas.dist.config.js",
"plugin.spine.canvas.watch": "webpack --config plugins/spine/webpack.canvas.config.js --watch --display-modules",
"plugin.spine.webgl.dist": "webpack --config plugins/spine/webpack.webgl.dist.config.js",
"plugin.spine.webgl.watch": "webpack --config plugins/spine/webpack.webgl.config.js --watch",
"lint": "eslint --config .eslintrc.json \"src/**/*.js\"",
"lintfix": "eslint --config .eslintrc.json \"src/**/*.js\" --fix",
"sloc": "node-sloc \"./src\" --include-extensions \"js\"",
@ -49,13 +56,15 @@
"eslint-plugin-es5": "^1.3.1",
"fs-extra": "^6.0.0",
"node-sloc": "^0.1.11",
"uglifyjs-webpack-plugin": "^1.2.7",
"uglifyjs-webpack-plugin": "^1.3.0",
"vivid-cli": "^1.1.2",
"webpack": "^4.16.0",
"webpack-cli": "^2.1.5",
"webpack": "^4.23.0",
"webpack-cli": "^3.1.1",
"webpack-shell-plugin": "^0.5.0"
},
"dependencies": {
"eventemitter3": "^3.1.0"
"eventemitter3": "^3.1.0",
"exports-loader": "^0.7.0",
"imports-loader": "^0.8.0"
}
}

View file

@ -13,11 +13,11 @@
* @property {boolean} video - Is this a video ad?
*/
var AdInstance = function (instance, video)
var AdInstance = function (placementID, instance, video)
{
return {
instance: instance,
placementID: instance.getPlacementID(),
placementID: placementID,
shown: false,
video: video
};

View file

@ -687,7 +687,7 @@ var FacebookInstantGamesPlugin = new Class({
scene.load.image(key, this.playerPhotoURL);
scene.load.once('filecomplete_image_' + key, function ()
scene.load.once('filecomplete-image-' + key, function ()
{
this.emit('photocomplete', key);
@ -1870,6 +1870,10 @@ var FacebookInstantGamesPlugin = new Class({
* Attempt to create an instance of an interstitial ad.
*
* If the instance is created successfully then the ad is preloaded ready for display in-game via the method `showAd()`.
*
* If the ad loads it will emit the `adloaded` event, passing the AdInstance as the only parameter.
*
* If the ad cannot be displayed because there was no inventory to fill it, it will emit the `adsnofill` event.
*
* @method Phaser.FacebookInstantGamesPlugin#preloadAds
* @since 3.13.0
@ -1912,18 +1916,36 @@ var FacebookInstantGamesPlugin = new Class({
for (i = 0; i < placementID.length; i++)
{
var id = placementID[i];
var data;
FBInstant.getInterstitialAdAsync(id).then(function (data)
FBInstant.getInterstitialAdAsync(id).then(function (interstitial)
{
var ad = AdInstance(data, true);
data = interstitial;
return interstitial.loadAsync();
}).then(function ()
{
var ad = AdInstance(id, data, false);
_this.ads.push(ad);
return ad.loadAsync();
_this.emit('adloaded', ad);
}).catch(function (e)
{
console.warn(e);
if (e.code === 'ADS_NO_FILL')
{
_this.emit('adsnofill', id);
}
else if (e.code === 'ADS_FREQUENT_LOAD')
{
_this.emit('adsfrequentload', id);
}
else
{
console.warn(e);
}
});
}
@ -1931,9 +1953,13 @@ var FacebookInstantGamesPlugin = new Class({
},
/**
* Attempt to create an instance of an interstitial video ad.
* Attempt to create an instance of an rewarded video ad.
*
* If the instance is created successfully then the ad is preloaded ready for display in-game via the method `showVideo()`.
*
* If the ad loads it will emit the `adloaded` event, passing the AdInstance as the only parameter.
*
* If the ad cannot be displayed because there was no inventory to fill it, it will emit the `adsnofill` event.
*
* @method Phaser.FacebookInstantGamesPlugin#preloadVideoAds
* @since 3.13.0
@ -1976,18 +2002,36 @@ var FacebookInstantGamesPlugin = new Class({
for (i = 0; i < placementID.length; i++)
{
var id = placementID[i];
var data;
FBInstant.getRewardedVideoAsync(id).then(function (data)
FBInstant.getRewardedVideoAsync(id).then(function (reward)
{
var ad = AdInstance(data, true);
data = reward;
return reward.loadAsync();
}).then(function ()
{
var ad = AdInstance(id, data, true);
_this.ads.push(ad);
return ad.loadAsync();
_this.emit('adloaded', ad);
}).catch(function (e)
{
console.warn(e);
if (e.code === 'ADS_NO_FILL')
{
_this.emit('adsnofill', id);
}
else if (e.code === 'ADS_FREQUENT_LOAD')
{
_this.emit('adsfrequentload', id);
}
else
{
console.warn(e);
}
});
}
@ -1997,9 +2041,9 @@ var FacebookInstantGamesPlugin = new Class({
/**
* Displays a previously loaded interstitial ad.
*
* If the ad is successfully displayed this plugin will emit the `showad` event, with the AdInstance object as its parameter.
* If the ad is successfully displayed this plugin will emit the `adfinished` event, with the AdInstance object as its parameter.
*
* If the ad cannot be displayed because there was no inventory to fill it, it will emit the `adsnofill` event.
* If the ad cannot be displayed, it will emit the `adsnotloaded` event.
*
* @method Phaser.FacebookInstantGamesPlugin#showAd
* @since 3.13.0
@ -2022,18 +2066,20 @@ var FacebookInstantGamesPlugin = new Class({
{
ad.shown = true;
_this.emit('showad', ad);
_this.emit('adfinished', ad);
}).catch(function (e)
{
if (e.code === 'ADS_NO_FILL')
if (e.code === 'ADS_NOT_LOADED')
{
_this.emit('adsnofill');
_this.emit('adsnotloaded', ad);
}
else
else if (e.code === 'RATE_LIMITED')
{
console.warn(e);
_this.emit('adratelimited', ad);
}
_this.emit('adshowerror', e, ad);
});
}
}
@ -2044,9 +2090,9 @@ var FacebookInstantGamesPlugin = new Class({
/**
* Displays a previously loaded interstitial video ad.
*
* If the ad is successfully displayed this plugin will emit the `showad` event, with the AdInstance object as its parameter.
* If the ad is successfully displayed this plugin will emit the `adfinished` event, with the AdInstance object as its parameter.
*
* If the ad cannot be displayed because there was no inventory to fill it, it will emit the `adsnofill` event.
* If the ad cannot be displayed, it will emit the `adsnotloaded` event.
*
* @method Phaser.FacebookInstantGamesPlugin#showVideo
* @since 3.13.0
@ -2069,18 +2115,20 @@ var FacebookInstantGamesPlugin = new Class({
{
ad.shown = true;
_this.emit('showad', ad);
_this.emit('adfinished', ad);
}).catch(function (e)
{
if (e.code === 'ADS_NO_FILL')
if (e.code === 'ADS_NOT_LOADED')
{
_this.emit('adsnofill');
_this.emit('adsnotloaded', ad);
}
else
else if (e.code === 'RATE_LIMITED')
{
console.warn(e);
_this.emit('adratelimited', ad);
}
_this.emit('adshowerror', e, ad);
});
}
}

View file

@ -139,13 +139,15 @@ var Leaderboard = new Class({
*
* The data is requested in an async call, so the result isn't available immediately.
*
* When the call completes this Leaderboard will emit the `setscore` event along with the score, any extra data and the name of the Leaderboard.
* When the call completes this Leaderboard will emit the `setscore` event along with the LeaderboardScore object and the name of the Leaderboard.
*
* If the save fails the event will send `null` as the score value.
*
* @method Phaser.FacebookInstantGamesPlugin.Leaderboard#setScore
* @since 3.13.0
*
* @param {integer} score - The new score for the player. Must be a 64-bit integer number.
* @param {string} [data] - Metadata to associate with the stored score. Must be less than 2KB in size.
* @param {(string|any)} [data] - Metadata to associate with the stored score. Must be less than 2KB in size. If an object is given it will be passed to `JSON.stringify`.
*
* @return {this} This Leaderboard instance.
*/
@ -153,11 +155,27 @@ var Leaderboard = new Class({
{
if (data === undefined) { data = ''; }
if (typeof data === 'object')
{
data = JSON.stringify(data);
}
var _this = this;
this.ref.setScoreAsync(score, data).then(function (entry)
{
_this.emit('setscore', entry.getScore(), entry.getExtraData(), _this.name);
if (entry)
{
var score = LeaderboardScore(entry);
_this.playerScore = score;
_this.emit('setscore', score, _this.name);
}
else
{
_this.emit('setscore', null, _this.name);
}
}).catch(function (e)
{
@ -173,6 +191,8 @@ var Leaderboard = new Class({
* The data is requested in an async call, so the result isn't available immediately.
*
* When the call completes this Leaderboard will emit the `getplayerscore` event along with the score and the name of the Leaderboard.
*
* If the player has not yet saved a score, the event will send `null` as the score value, and `playerScore` will be set to `null` as well.
*
* @method Phaser.FacebookInstantGamesPlugin.Leaderboard#getPlayerScore
* @since 3.13.0
@ -185,11 +205,18 @@ var Leaderboard = new Class({
this.ref.getPlayerEntryAsync().then(function (entry)
{
var score = LeaderboardScore(entry);
if (entry)
{
var score = LeaderboardScore(entry);
_this.playerScore = score;
_this.emit('getplayerscore', score, _this.name);
_this.playerScore = score;
_this.emit('getplayerscore', score, _this.name);
}
else
{
_this.emit('getplayerscore', null, _this.name);
}
}).catch(function (e)
{
@ -204,7 +231,7 @@ var Leaderboard = new Class({
*
* The data is requested in an async call, so the result isn't available immediately.
*
* When the call completes this Leaderboard will emit the `getplayerscore` event along with the score and the name of the Leaderboard.
* When the call completes this Leaderboard will emit the `getscores` event along with an array of LeaderboardScore entries and the name of the Leaderboard.
*
* @method Phaser.FacebookInstantGamesPlugin.Leaderboard#getScores
* @since 3.13.0
@ -237,6 +264,47 @@ var Leaderboard = new Class({
console.warn(e);
});
return this;
},
/**
* Retrieves a set of leaderboard entries, based on the current player's connected players (including the current player), ordered by local rank within the set of connected players.
*
* The data is requested in an async call, so the result isn't available immediately.
*
* When the call completes this Leaderboard will emit the `getconnectedscores` event along with an array of LeaderboardScore entries and the name of the Leaderboard.
*
* @method Phaser.FacebookInstantGamesPlugin.Leaderboard#getConnectedScores
* @since 3.16.0
*
* @param {integer} [count=10] - The number of entries to attempt to fetch from the leaderboard. Currently, up to a maximum of 100 entries may be fetched per query.
* @param {integer} [offset=0] - The offset from the top of the leaderboard that entries will be fetched from.
*
* @return {this} This Leaderboard instance.
*/
getConnectedScores: function (count, offset)
{
if (count === undefined) { count = 10; }
if (offset === undefined) { offset = 0; }
var _this = this;
this.ref.getConnectedPlayerEntriesAsync().then(function (entries)
{
_this.scores = [];
entries.forEach(function (entry)
{
_this.scores.push(LeaderboardScore(entry));
});
_this.emit('getconnectedscores', _this.scores, _this.name);
}).catch(function (e)
{
console.warn(e);
});
return this;
}

View file

@ -0,0 +1,13 @@
var fs = require('fs-extra');
var source = './plugins/spine/dist/';
var dest = '../phaser3-examples/public/plugins/';
if (fs.existsSync(dest))
{
fs.copySync(source, dest, { overwrite: true });
}
else
{
console.log('Copy-to-Examples failed: Phaser 3 Examples not present at ../phaser3-examples');
}

19720
plugins/spine/dist/SpineWebGLPlugin.js vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,190 @@
/**
* @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 Class = require('../../../src/utils/Class');
var ScenePlugin = require('../../../src/plugins/ScenePlugin');
var SpineFile = require('./SpineFile');
var SpineGameObject = require('./gameobject/SpineGameObject');
var runtime;
/**
* @classdesc
* TODO
*
* @class SpinePlugin
* @extends Phaser.Plugins.ScenePlugin
* @constructor
* @since 3.16.0
*
* @param {Phaser.Scene} scene - A reference to the Scene that has installed this plugin.
* @param {Phaser.Plugins.PluginManager} pluginManager - A reference to the Phaser Plugin Manager.
*/
var SpinePlugin = new Class({
Extends: ScenePlugin,
initialize:
function SpinePlugin (scene, pluginManager, SpineRuntime)
{
console.log('BaseSpinePlugin created');
ScenePlugin.call(this, scene, pluginManager);
var game = pluginManager.game;
// Create a custom cache to store the spine data (.atlas files)
this.cache = game.cache.addCustom('spine');
this.json = game.cache.json;
this.textures = game.textures;
this.skeletonRenderer;
this.drawDebug = false;
// Register our file type
pluginManager.registerFileType('spine', this.spineFileCallback, scene);
// Register our game object
pluginManager.registerGameObject('spine', this.createSpineFactory(this));
runtime = SpineRuntime;
},
spineFileCallback: function (key, jsonURL, atlasURL, jsonXhrSettings, atlasXhrSettings)
{
var multifile;
if (Array.isArray(key))
{
for (var i = 0; i < key.length; i++)
{
multifile = new SpineFile(this, key[i]);
this.addFile(multifile.files);
}
}
else
{
multifile = new SpineFile(this, key, jsonURL, atlasURL, jsonXhrSettings, atlasXhrSettings);
this.addFile(multifile.files);
}
return this;
},
/**
* Creates a new Spine Game Object and adds it to the Scene.
*
* @method Phaser.GameObjects.GameObjectFactory#spineFactory
* @since 3.16.0
*
* @param {number} x - The horizontal position of this Game Object.
* @param {number} y - The vertical position of this Game Object.
* @param {string} texture - The key of the Texture this Game Object will use to render with, as stored in the Texture Manager.
* @param {(string|integer)} [frame] - An optional frame from the Texture this Game Object is rendering with.
*
* @return {Phaser.GameObjects.Spine} The Game Object that was created.
*/
createSpineFactory: function (plugin)
{
var callback = function (x, y, key, animationName, loop)
{
var spineGO = new SpineGameObject(this.scene, plugin, x, y, key, animationName, loop);
this.displayList.add(spineGO);
this.updateList.add(spineGO);
return spineGO;
};
return callback;
},
getRuntime: function ()
{
return runtime;
},
createSkeleton: function (key, skeletonJSON)
{
var atlas = this.getAtlas(key);
var atlasLoader = new runtime.AtlasAttachmentLoader(atlas);
var skeletonJson = new runtime.SkeletonJson(atlasLoader);
var data = (skeletonJSON) ? skeletonJSON : this.json.get(key);
var skeletonData = skeletonJson.readSkeletonData(data);
var skeleton = new runtime.Skeleton(skeletonData);
return { skeletonData: skeletonData, skeleton: skeleton };
},
getBounds: function (skeleton)
{
var offset = new runtime.Vector2();
var size = new runtime.Vector2();
skeleton.getBounds(offset, size, []);
return { offset: offset, size: size };
},
createAnimationState: function (skeleton)
{
var stateData = new runtime.AnimationStateData(skeleton.data);
var state = new runtime.AnimationState(stateData);
return { stateData: stateData, state: state };
},
/**
* The Scene that owns this plugin is shutting down.
* We need to kill and reset all internal properties as well as stop listening to Scene events.
*
* @method Camera3DPlugin#shutdown
* @private
* @since 3.0.0
*/
shutdown: function ()
{
var eventEmitter = this.systems.events;
eventEmitter.off('update', this.update, this);
eventEmitter.off('shutdown', this.shutdown, this);
this.removeAll();
},
/**
* The Scene that owns this plugin is being destroyed.
* We need to shutdown and then kill off all external references.
*
* @method Camera3DPlugin#destroy
* @private
* @since 3.0.0
*/
destroy: function ()
{
this.shutdown();
this.pluginManager = null;
this.game = null;
this.scene = null;
this.systems = null;
}
});
module.exports = SpinePlugin;

View file

@ -0,0 +1,63 @@
/**
* @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 Class = require('../../../src/utils/Class');
var BaseSpinePlugin = require('./BaseSpinePlugin');
var SpineCanvas = require('SpineCanvas');
/**
* @classdesc
* Just the Canvas Runtime.
*
* @class SpinePlugin
* @extends Phaser.Plugins.ScenePlugin
* @constructor
* @since 3.16.0
*
* @param {Phaser.Scene} scene - A reference to the Scene that has installed this plugin.
* @param {Phaser.Plugins.PluginManager} pluginManager - A reference to the Phaser Plugin Manager.
*/
var SpineCanvasPlugin = new Class({
Extends: BaseSpinePlugin,
initialize:
function SpineCanvasPlugin (scene, pluginManager)
{
console.log('SpineCanvasPlugin created');
BaseSpinePlugin.call(this, scene, pluginManager, SpineCanvas);
},
boot: function ()
{
this.skeletonRenderer = new SpineCanvas.canvas.SkeletonRenderer(this.game.context);
},
getAtlas: function (key)
{
var atlasData = this.cache.get(key);
if (!atlasData)
{
console.warn('No atlas data for: ' + key);
return;
}
var textures = this.textures;
var atlas = new SpineCanvas.TextureAtlas(atlasData, function (path)
{
return new SpineCanvas.canvas.CanvasTexture(textures.get(path).getSourceImage());
});
return atlas;
}
});
module.exports = SpineCanvasPlugin;

View file

@ -0,0 +1,325 @@
/**
* @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 Class = require('../../../src/utils/Class');
var GetFastValue = require('../../../src/utils/object/GetFastValue');
var ImageFile = require('../../../src/loader/filetypes/ImageFile.js');
var IsPlainObject = require('../../../src/utils/object/IsPlainObject');
var JSONFile = require('../../../src/loader/filetypes/JSONFile.js');
var MultiFile = require('../../../src/loader/MultiFile.js');
var TextFile = require('../../../src/loader/filetypes/TextFile.js');
/**
* @typedef {object} Phaser.Loader.FileTypes.SpineFileConfig
*
* @property {string} key - The key of the file. Must be unique within both the Loader and the Texture Manager.
* @property {string} [textureURL] - The absolute or relative URL to load the texture image file from.
* @property {string} [textureExtension='png'] - The default file extension to use for the image texture if no url is provided.
* @property {XHRSettingsObject} [textureXhrSettings] - Extra XHR Settings specifically for the texture image file.
* @property {string} [normalMap] - The filename of an associated normal map. It uses the same path and url to load as the texture image.
* @property {string} [atlasURL] - The absolute or relative URL to load the atlas data file from.
* @property {string} [atlasExtension='txt'] - The default file extension to use for the atlas data if no url is provided.
* @property {XHRSettingsObject} [atlasXhrSettings] - Extra XHR Settings specifically for the atlas data file.
*/
/**
* @classdesc
* A Spine File suitable for loading by the Loader.
*
* These are created when you use the Phaser.Loader.LoaderPlugin#spine method and are not typically created directly.
*
* For documentation about what all the arguments and configuration options mean please see Phaser.Loader.LoaderPlugin#spine.
*
* @class SpineFile
* @extends Phaser.Loader.MultiFile
* @memberof Phaser.Loader.FileTypes
* @constructor
*
* @param {Phaser.Loader.LoaderPlugin} loader - A reference to the Loader that is responsible for this file.
* @param {(string|Phaser.Loader.FileTypes.UnityAtlasFileConfig)} key - The key to use for this file, or a file configuration object.
* @param {string|string[]} [textureURL] - The absolute or relative URL to load the texture image file from. If undefined or `null` it will be set to `<key>.png`, i.e. if `key` was "alien" then the URL will be "alien.png".
* @param {string} [atlasURL] - The absolute or relative URL to load the texture atlas data file from. If undefined or `null` it will be set to `<key>.txt`, i.e. if `key` was "alien" then the URL will be "alien.txt".
* @param {XHRSettingsObject} [textureXhrSettings] - An XHR Settings configuration object for the atlas image file. Used in replacement of the Loaders default XHR Settings.
* @param {XHRSettingsObject} [atlasXhrSettings] - An XHR Settings configuration object for the atlas data file. Used in replacement of the Loaders default XHR Settings.
*/
var SpineFile = new Class({
Extends: MultiFile,
initialize:
function SpineFile (loader, key, jsonURL, atlasURL, jsonXhrSettings, atlasXhrSettings)
{
var json;
var atlas;
if (IsPlainObject(key))
{
var config = key;
key = GetFastValue(config, 'key');
json = new JSONFile(loader, {
key: key,
url: GetFastValue(config, 'jsonURL'),
extension: GetFastValue(config, 'jsonExtension', 'json'),
xhrSettings: GetFastValue(config, 'jsonXhrSettings')
});
atlas = new TextFile(loader, {
key: key,
url: GetFastValue(config, 'atlasURL'),
extension: GetFastValue(config, 'atlasExtension', 'atlas'),
xhrSettings: GetFastValue(config, 'atlasXhrSettings')
});
}
else
{
json = new JSONFile(loader, key, jsonURL, jsonXhrSettings);
atlas = new TextFile(loader, key, atlasURL, atlasXhrSettings);
}
atlas.cache = loader.cacheManager.custom.spine;
MultiFile.call(this, loader, 'spine', key, [ json, atlas ]);
},
/**
* Called by each File when it finishes loading.
*
* @method Phaser.Loader.MultiFile#onFileComplete
* @since 3.7.0
*
* @param {Phaser.Loader.File} file - The File that has completed processing.
*/
onFileComplete: function (file)
{
var index = this.files.indexOf(file);
if (index !== -1)
{
this.pending--;
if (file.type === 'text')
{
// Inspect the data for the files to now load
var content = file.data.split('\n');
// Extract the textures
var textures = [];
for (var t = 0; t < content.length; t++)
{
var line = content[t];
if (line.trim() === '' && t < content.length - 1)
{
line = content[t + 1];
textures.push(line);
}
}
var config = this.config;
var loader = this.loader;
var currentBaseURL = loader.baseURL;
var currentPath = loader.path;
var currentPrefix = loader.prefix;
var baseURL = GetFastValue(config, 'baseURL', currentBaseURL);
var path = GetFastValue(config, 'path', currentPath);
var prefix = GetFastValue(config, 'prefix', currentPrefix);
var textureXhrSettings = GetFastValue(config, 'textureXhrSettings');
loader.setBaseURL(baseURL);
loader.setPath(path);
loader.setPrefix(prefix);
for (var i = 0; i < textures.length; i++)
{
var textureURL = textures[i];
var key = '_SP_' + textureURL;
var image = new ImageFile(loader, key, textureURL, textureXhrSettings);
this.addToMultiFile(image);
loader.addFile(image);
}
// Reset the loader settings
loader.setBaseURL(currentBaseURL);
loader.setPath(currentPath);
loader.setPrefix(currentPrefix);
}
}
},
/**
* Adds this file to its target cache upon successful loading and processing.
*
* @method Phaser.Loader.FileTypes.SpineFile#addToCache
* @since 3.16.0
*/
addToCache: function ()
{
if (this.isReadyToProcess())
{
var fileJSON = this.files[0];
fileJSON.addToCache();
var fileText = this.files[1];
fileText.addToCache();
for (var i = 2; i < this.files.length; i++)
{
var file = this.files[i];
var key = file.key.substr(4).trim();
this.loader.textureManager.addImage(key, file.data);
file.pendingDestroy();
}
this.complete = true;
}
}
});
/**
* Adds a Unity YAML based Texture Atlas, or array of atlases, to the current load queue.
*
* You can call this method from within your Scene's `preload`, along with any other files you wish to load:
*
* ```javascript
* function preload ()
* {
* this.load.unityAtlas('mainmenu', 'images/MainMenu.png', 'images/MainMenu.txt');
* }
* ```
*
* The file is **not** loaded right away. It is added to a queue ready to be loaded either when the loader starts,
* or if it's already running, when the next free load slot becomes available. This happens automatically if you
* are calling this from within the Scene's `preload` method, or a related callback. Because the file is queued
* it means you cannot use the file immediately after calling this method, but must wait for the file to complete.
* The typical flow for a Phaser Scene is that you load assets in the Scene's `preload` method and then when the
* Scene's `create` method is called you are guaranteed that all of those assets are ready for use and have been
* loaded.
*
* If you call this from outside of `preload` then you are responsible for starting the Loader afterwards and monitoring
* its events to know when it's safe to use the asset. Please see the Phaser.Loader.LoaderPlugin class for more details.
*
* Phaser expects the atlas data to be provided in a YAML formatted text file as exported from Unity.
*
* Phaser can load all common image types: png, jpg, gif and any other format the browser can natively handle.
*
* The key must be a unique String. It is used to add the file to the global Texture Manager upon a successful load.
* The key should be unique both in terms of files being loaded and files already present in the Texture Manager.
* Loading a file using a key that is already taken will result in a warning. If you wish to replace an existing file
* then remove it from the Texture Manager first, before loading a new one.
*
* Instead of passing arguments you can pass a configuration object, such as:
*
* ```javascript
* this.load.unityAtlas({
* key: 'mainmenu',
* textureURL: 'images/MainMenu.png',
* atlasURL: 'images/MainMenu.txt'
* });
* ```
*
* See the documentation for `Phaser.Loader.FileTypes.SpineFileConfig` for more details.
*
* Once the atlas has finished loading you can use frames from it as textures for a Game Object by referencing its key:
*
* ```javascript
* this.load.unityAtlas('mainmenu', 'images/MainMenu.png', 'images/MainMenu.json');
* // and later in your game ...
* this.add.image(x, y, 'mainmenu', 'background');
* ```
*
* To get a list of all available frames within an atlas please consult your Texture Atlas software.
*
* If you have specified a prefix in the loader, via `Loader.setPrefix` then this value will be prepended to this files
* key. For example, if the prefix was `MENU.` and the key was `Background` the final key will be `MENU.Background` and
* this is what you would use to retrieve the image from the Texture Manager.
*
* The URL can be relative or absolute. If the URL is relative the `Loader.baseURL` and `Loader.path` values will be prepended to it.
*
* If the URL isn't specified the Loader will take the key and create a filename from that. For example if the key is "alien"
* and no URL is given then the Loader will set the URL to be "alien.png". It will always add `.png` as the extension, although
* this can be overridden if using an object instead of method arguments. If you do not desire this action then provide a URL.
*
* Phaser also supports the automatic loading of associated normal maps. If you have a normal map to go with this image,
* then you can specify it by providing an array as the `url` where the second element is the normal map:
*
* ```javascript
* this.load.unityAtlas('mainmenu', [ 'images/MainMenu.png', 'images/MainMenu-n.png' ], 'images/MainMenu.txt');
* ```
*
* Or, if you are using a config object use the `normalMap` property:
*
* ```javascript
* this.load.unityAtlas({
* key: 'mainmenu',
* textureURL: 'images/MainMenu.png',
* normalMap: 'images/MainMenu-n.png',
* atlasURL: 'images/MainMenu.txt'
* });
* ```
*
* The normal map file is subject to the same conditions as the image file with regard to the path, baseURL, CORs and XHR Settings.
* Normal maps are a WebGL only feature.
*
* Note: The ability to load this type of file will only be available if the Unity Atlas File type has been built into Phaser.
* It is available in the default build but can be excluded from custom builds.
*
* @method Phaser.Loader.LoaderPlugin#spine
* @fires Phaser.Loader.LoaderPlugin#addFileEvent
* @since 3.16.0
*
* @param {(string|Phaser.Loader.FileTypes.SpineFileConfig|Phaser.Loader.FileTypes.SpineFileConfig[])} key - The key to use for this file, or a file configuration object, or array of them.
* @param {string|string[]} [textureURL] - The absolute or relative URL to load the texture image file from. If undefined or `null` it will be set to `<key>.png`, i.e. if `key` was "alien" then the URL will be "alien.png".
* @param {string} [atlasURL] - The absolute or relative URL to load the texture atlas data file from. If undefined or `null` it will be set to `<key>.txt`, i.e. if `key` was "alien" then the URL will be "alien.txt".
* @param {XHRSettingsObject} [textureXhrSettings] - An XHR Settings configuration object for the atlas image file. Used in replacement of the Loaders default XHR Settings.
* @param {XHRSettingsObject} [atlasXhrSettings] - An XHR Settings configuration object for the atlas data file. Used in replacement of the Loaders default XHR Settings.
*
* @return {Phaser.Loader.LoaderPlugin} The Loader instance.
FileTypesManager.register('spine', function (key, jsonURL, atlasURL, jsonXhrSettings, atlasXhrSettings)
{
var multifile;
// Supports an Object file definition in the key argument
// Or an array of objects in the key argument
// Or a single entry where all arguments have been defined
if (Array.isArray(key))
{
for (var i = 0; i < key.length; i++)
{
multifile = new SpineFile(this, key[i]);
this.addFile(multifile.files);
}
}
else
{
multifile = new SpineFile(this, key, jsonURL, atlasURL, jsonXhrSettings, atlasXhrSettings);
this.addFile(multifile.files);
}
return this;
});
*/
module.exports = SpineFile;

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}
*/
var Class = require('../../../src/utils/Class');
var BaseSpinePlugin = require('./BaseSpinePlugin');
var SpineCanvas = require('SpineCanvas');
var SpineWebGL = require('SpineWebGL');
var runtime;
/**
* @classdesc
* Both Canvas and WebGL Runtimes together in a single plugin.
*
* @class SpinePlugin
* @extends Phaser.Plugins.ScenePlugin
* @constructor
* @since 3.16.0
*
* @param {Phaser.Scene} scene - A reference to the Scene that has installed this plugin.
* @param {Phaser.Plugins.PluginManager} pluginManager - A reference to the Phaser Plugin Manager.
*/
var SpineCanvasPlugin = new Class({
Extends: BaseSpinePlugin,
initialize:
function SpineCanvasPlugin (scene, pluginManager)
{
console.log('SpinePlugin created');
BaseSpinePlugin.call(this, scene, pluginManager);
var game = pluginManager.game;
runtime = (game.config.renderType === 1) ? SpineCanvas : SpineWebGL;
},
boot: function ()
{
this.skeletonRenderer = (this.game.config.renderType === 1) ? SpineCanvas.canvas.SkeletonRenderer(this.game.context) : SpineWebGL;
},
getRuntime: function ()
{
return runtime;
},
createSkeleton: function (key)
{
var atlasData = this.cache.get(key);
if (!atlasData)
{
console.warn('No skeleton data for: ' + key);
return;
}
var textures = this.textures;
var useWebGL = this.game.config.renderType;
var atlas = new runtime.TextureAtlas(atlasData, function (path)
{
if (useWebGL)
{
// return new SpineCanvas.canvas.CanvasTexture(textures.get(path).getSourceImage());
}
else
{
return new SpineCanvas.canvas.CanvasTexture(textures.get(path).getSourceImage());
}
});
var atlasLoader = new runtime.AtlasAttachmentLoader(atlas);
var skeletonJson = new runtime.SkeletonJson(atlasLoader);
var skeletonData = skeletonJson.readSkeletonData(this.json.get(key));
var skeleton = new runtime.Skeleton(skeletonData);
return { skeletonData: skeletonData, skeleton: skeleton };
},
getBounds: function (skeleton)
{
var offset = new runtime.Vector2();
var size = new runtime.Vector2();
skeleton.getBounds(offset, size, []);
return { offset: offset, size: size };
},
createAnimationState: function (skeleton)
{
var stateData = new runtime.AnimationStateData(skeleton.data);
var state = new runtime.AnimationState(stateData);
return { stateData: stateData, state: state };
}
});
module.exports = SpineCanvasPlugin;

View file

@ -0,0 +1,90 @@
/**
* @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 Class = require('../../../src/utils/Class');
var BaseSpinePlugin = require('./BaseSpinePlugin');
var SpineWebGL = require('SpineWebGL');
var Matrix4 = require('../../../src/math/Matrix4');
/**
* @classdesc
* Just the WebGL Runtime.
*
* @class SpinePlugin
* @extends Phaser.Plugins.ScenePlugin
* @constructor
* @since 3.16.0
*
* @param {Phaser.Scene} scene - A reference to the Scene that has installed this plugin.
* @param {Phaser.Plugins.PluginManager} pluginManager - A reference to the Phaser Plugin Manager.
*/
var SpineWebGLPlugin = new Class({
Extends: BaseSpinePlugin,
initialize:
function SpineWebGLPlugin (scene, pluginManager)
{
console.log('SpineWebGLPlugin created');
BaseSpinePlugin.call(this, scene, pluginManager, SpineWebGL);
this.gl;
this.mvp;
this.shader;
this.batcher;
this.debugRenderer;
this.debugShader;
},
boot: function ()
{
var gl = this.game.renderer.gl;
this.gl = gl;
this.mvp = new Matrix4();
// Create a simple shader, mesh, model-view-projection matrix and SkeletonRenderer.
this.shader = SpineWebGL.webgl.Shader.newTwoColoredTextured(gl);
this.batcher = new SpineWebGL.webgl.PolygonBatcher(gl);
this.skeletonRenderer = new SpineWebGL.webgl.SkeletonRenderer(gl);
this.skeletonRenderer.premultipliedAlpha = true;
this.shapes = new SpineWebGL.webgl.ShapeRenderer(gl);
this.debugRenderer = new SpineWebGL.webgl.SkeletonDebugRenderer(gl);
this.debugShader = SpineWebGL.webgl.Shader.newColored(gl);
},
getAtlas: function (key)
{
var atlasData = this.cache.get(key);
if (!atlasData)
{
console.warn('No atlas data for: ' + key);
return;
}
var textures = this.textures;
var gl = this.game.renderer.gl;
var atlas = new SpineWebGL.TextureAtlas(atlasData, function (path)
{
return new SpineWebGL.webgl.GLTexture(gl, textures.get(path).getSourceImage());
});
return atlas;
}
});
module.exports = SpineWebGLPlugin;

View file

@ -0,0 +1,298 @@
/**
* @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 Class = require('../../../../src/utils/Class');
var ComponentsAlpha = require('../../../../src/gameobjects/components/Alpha');
var ComponentsBlendMode = require('../../../../src/gameobjects/components/BlendMode');
var ComponentsDepth = require('../../../../src/gameobjects/components/Depth');
var ComponentsFlip = require('../../../../src/gameobjects/components/Flip');
var ComponentsScrollFactor = require('../../../../src/gameobjects/components/ScrollFactor');
var ComponentsTransform = require('../../../../src/gameobjects/components/Transform');
var ComponentsVisible = require('../../../../src/gameobjects/components/Visible');
var GameObject = require('../../../../src/gameobjects/GameObject');
var SpineGameObjectRender = require('./SpineGameObjectRender');
/**
* @classdesc
* TODO
*
* @class SpineGameObject
* @constructor
* @since 3.16.0
*
* @param {Phaser.Scene} scene - A reference to the Scene that has installed this plugin.
* @param {Phaser.Plugins.PluginManager} pluginManager - A reference to the Phaser Plugin Manager.
*/
var SpineGameObject = new Class({
Extends: GameObject,
Mixins: [
ComponentsAlpha,
ComponentsBlendMode,
ComponentsDepth,
ComponentsFlip,
ComponentsScrollFactor,
ComponentsTransform,
ComponentsVisible,
SpineGameObjectRender
],
initialize:
function SpineGameObject (scene, plugin, x, y, key, animationName, loop)
{
GameObject.call(this, scene, 'Spine');
this.plugin = plugin;
this.runtime = plugin.getRuntime();
this.skeleton = null;
this.skeletonData = null;
this.state = null;
this.stateData = null;
this.drawDebug = false;
this.timeScale = 1;
this.setPosition(x, y);
if (key)
{
this.setSkeleton(key, animationName, loop);
}
},
setSkeletonFromJSON: function (atlasDataKey, skeletonJSON, animationName, loop)
{
return this.setSkeleton(atlasDataKey, skeletonJSON, animationName, loop);
},
setSkeleton: function (atlasDataKey, animationName, loop, skeletonJSON)
{
var data = this.plugin.createSkeleton(atlasDataKey, skeletonJSON);
this.skeletonData = data.skeletonData;
var skeleton = data.skeleton;
skeleton.flipY = (this.scene.sys.game.config.renderType === 1);
skeleton.setToSetupPose();
skeleton.updateWorldTransform();
skeleton.setSkinByName('default');
this.skeleton = skeleton;
// AnimationState
data = this.plugin.createAnimationState(skeleton);
if (this.state)
{
this.state.clearListeners();
this.state.clearListenerNotifications();
}
this.state = data.state;
this.stateData = data.stateData;
var _this = this;
this.state.addListener({
event: function (trackIndex, event)
{
// Event on a Track
_this.emit('spine.event', _this, trackIndex, event);
},
complete: function (trackIndex, loopCount)
{
// Animation on Track x completed, loop count
_this.emit('spine.complete', _this, trackIndex, loopCount);
},
start: function (trackIndex)
{
// Animation on Track x started
_this.emit('spine.start', _this, trackIndex);
},
end: function (trackIndex)
{
// Animation on Track x ended
_this.emit('spine.end', _this, trackIndex);
}
});
if (animationName)
{
this.setAnimation(0, animationName, loop);
}
return this;
},
// http://esotericsoftware.com/spine-runtimes-guide
getAnimationList: function ()
{
var output = [];
var skeletonData = this.skeletonData;
if (skeletonData)
{
for (var i = 0; i < skeletonData.animations.length; i++)
{
output.push(skeletonData.animations[i].name);
}
}
return output;
},
play: function (animationName, loop)
{
if (loop === undefined)
{
loop = false;
}
return this.setAnimation(0, animationName, loop);
},
setAnimation: function (trackIndex, animationName, loop)
{
this.state.setAnimation(trackIndex, animationName, loop);
return this;
},
addAnimation: function (trackIndex, animationName, loop, delay)
{
return this.state.addAnimation(trackIndex, animationName, loop, delay);
},
setEmptyAnimation: function (trackIndex, mixDuration)
{
this.state.setEmptyAnimation(trackIndex, mixDuration);
return this;
},
clearTrack: function (trackIndex)
{
this.state.clearTrack(trackIndex);
return this;
},
clearTracks: function ()
{
this.state.clearTracks();
return this;
},
setSkinByName: function (skinName)
{
this.skeleton.setSkinByName(skinName);
return this;
},
setSkin: function (newSkin)
{
var skeleton = this.skeleton;
skeleton.setSkin(newSkin);
skeleton.setSlotsToSetupPose();
this.state.apply(skeleton);
return this;
},
setMix: function (fromName, toName, duration)
{
this.stateData.setMix(fromName, toName, duration);
return this;
},
findBone: function (boneName)
{
return this.skeleton.findBone(boneName);
},
findBoneIndex: function (boneName)
{
return this.skeleton.findBoneIndex(boneName);
},
findSlot: function (slotName)
{
return this.skeleton.findSlot(slotName);
},
findSlotIndex: function (slotName)
{
return this.skeleton.findSlotIndex(slotName);
},
getBounds: function ()
{
return this.plugin.getBounds(this.skeleton);
},
preUpdate: function (time, delta)
{
var skeleton = this.skeleton;
skeleton.flipX = this.flipX;
skeleton.flipY = this.flipY;
this.state.update((delta / 1000) * this.timeScale);
this.state.apply(skeleton);
this.emit('spine.update', skeleton);
skeleton.updateWorldTransform();
},
/**
* Internal destroy handler, called as part of the destroy process.
*
* @method Phaser.GameObjects.RenderTexture#preDestroy
* @protected
* @since 3.16.0
*/
preDestroy: function ()
{
if (this.state)
{
this.state.clearListeners();
this.state.clearListenerNotifications();
}
this.plugin = null;
this.runtime = null;
this.skeleton = null;
this.skeletonData = null;
this.state = null;
this.stateData = null;
}
});
module.exports = SpineGameObject;

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 SetTransform = require('../../../../src/renderer/canvas/utils/SetTransform');
/**
* Renders this Game Object with the Canvas Renderer to the given Camera.
* The object will not render if any of its renderFlags are set or it is being actively filtered out by the Camera.
* This method should not be called directly. It is a utility function of the Render module.
*
* @method Phaser.GameObjects.SpineGameObject#renderCanvas
* @since 3.16.0
* @private
*
* @param {Phaser.Renderer.Canvas.CanvasRenderer} renderer - A reference to the current active Canvas renderer.
* @param {Phaser.GameObjects.SpineGameObject} src - The Game Object being rendered in this call.
* @param {number} interpolationPercentage - Reserved for future use and custom pipelines.
* @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera that is rendering the Game Object.
* @param {Phaser.GameObjects.Components.TransformMatrix} parentMatrix - This transform matrix is defined if the game object is nested
*/
var SpineGameObjectCanvasRenderer = function (renderer, src, interpolationPercentage, camera, parentMatrix)
{
var context = renderer.currentContext;
var plugin = src.plugin;
var skeleton = src.skeleton;
var skeletonRenderer = plugin.skeletonRenderer;
if (!skeleton || !SetTransform(renderer, context, src, camera, parentMatrix))
{
return;
}
skeletonRenderer.ctx = context;
context.save();
skeletonRenderer.draw(skeleton);
if (plugin.drawDebug || src.drawDebug)
{
context.strokeStyle = '#00ff00';
context.beginPath();
context.moveTo(-1000, 0);
context.lineTo(1000, 0);
context.moveTo(0, -1000);
context.lineTo(0, 1000);
context.stroke();
}
context.restore();
};
module.exports = SpineGameObjectCanvasRenderer;

View file

@ -0,0 +1,33 @@
/**
* @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 SpineGameObject = require('./SpineGameObject');
var GameObjectFactory = require('../../../../src/gameobjects/GameObjectFactory');
/**
* Creates a new Spine Game Object Game Object and adds it to the Scene.
*
* Note: This method will only be available if the Spine Plugin has been built or loaded into Phaser.
*
* @method Phaser.GameObjects.GameObjectFactory#spine
* @since 3.16.0
*
* @param {number} x - The horizontal position of this Game Object.
* @param {number} y - The vertical position of this Game Object.
* @param {string} texture - The key of the Texture this Game Object will use to render with, as stored in the Texture Manager.
* @param {(string|integer)} [frame] - An optional frame from the Texture this Game Object is rendering with.
*
* @return {Phaser.GameObjects.SpineGameObject} The Game Object that was created.
*/
GameObjectFactory.register('spine', function (x, y, key, animation)
{
var spine = new SpineGameObject(this.scene, x, y, key, animation);
this.displayList.add(spine);
this.updateList.add(spine);
return spine;
});

View file

@ -0,0 +1,25 @@
/**
* @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 renderWebGL = require('../../../../src/utils/NOOP');
var renderCanvas = require('../../../../src/utils/NOOP');
if (typeof WEBGL_RENDERER)
{
renderWebGL = require('./SpineGameObjectWebGLRenderer');
}
if (typeof CANVAS_RENDERER)
{
renderCanvas = require('./SpineGameObjectCanvasRenderer');
}
module.exports = {
renderWebGL: renderWebGL,
renderCanvas: renderCanvas
};

View file

@ -0,0 +1,121 @@
/**
* @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 CounterClockwise = require('../../../../src/math/angle/CounterClockwise');
/**
* Renders this Game Object with the Canvas Renderer to the given Camera.
* The object will not render if any of its renderFlags are set or it is being actively filtered out by the Camera.
* This method should not be called directly. It is a utility function of the Render module.
*
* @method Phaser.GameObjects.SpineGameObject#renderCanvas
* @since 3.16.0
* @private
*
* @param {Phaser.Renderer.Canvas.CanvasRenderer} renderer - A reference to the current active Canvas renderer.
* @param {Phaser.GameObjects.SpineGameObject} src - The Game Object being rendered in this call.
* @param {number} interpolationPercentage - Reserved for future use and custom pipelines.
* @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera that is rendering the Game Object.
* @param {Phaser.GameObjects.Components.TransformMatrix} parentMatrix - This transform matrix is defined if the game object is nested
*/
var SpineGameObjectWebGLRenderer = function (renderer, src, interpolationPercentage, camera, parentMatrix)
{
var pipeline = renderer.currentPipeline;
var plugin = src.plugin;
var mvp = plugin.mvp;
var shader = plugin.shader;
var batcher = plugin.batcher;
var runtime = src.runtime;
var skeleton = src.skeleton;
var skeletonRenderer = plugin.skeletonRenderer;
if (!skeleton)
{
return;
}
renderer.clearPipeline();
var camMatrix = renderer._tempMatrix1;
var spriteMatrix = renderer._tempMatrix2;
var calcMatrix = renderer._tempMatrix3;
// - 90 degrees to account for the difference in Spine vs. Phaser rotation
spriteMatrix.applyITRS(src.x, src.y, src.rotation - 1.5707963267948966, src.scaleX, src.scaleY);
camMatrix.copyFrom(camera.matrix);
if (parentMatrix)
{
// Multiply the camera by the parent matrix
camMatrix.multiplyWithOffset(parentMatrix, -camera.scrollX * src.scrollFactorX, -camera.scrollY * src.scrollFactorY);
// Undo the camera scroll
spriteMatrix.e = src.x;
spriteMatrix.f = src.y;
// Multiply by the Sprite matrix, store result in calcMatrix
camMatrix.multiply(spriteMatrix, calcMatrix);
}
else
{
spriteMatrix.e -= camera.scrollX * src.scrollFactorX;
spriteMatrix.f -= camera.scrollY * src.scrollFactorY;
// Multiply by the Sprite matrix, store result in calcMatrix
camMatrix.multiply(spriteMatrix, calcMatrix);
}
var width = renderer.width;
var height = renderer.height;
var data = calcMatrix.decomposeMatrix();
mvp.ortho(0, width, 0, height, 0, 1);
mvp.translateXYZ(data.translateX, height - data.translateY, 0);
mvp.rotateZ(CounterClockwise(data.rotation));
mvp.scaleXYZ(data.scaleX, data.scaleY, 1);
// For a Stage 1 release we'll handle it like this:
shader.bind();
shader.setUniformi(runtime.webgl.Shader.SAMPLER, 0);
shader.setUniform4x4f(runtime.webgl.Shader.MVP_MATRIX, mvp.val);
// For Stage 2, we'll move to using a custom pipeline, so Spine objects are batched
batcher.begin(shader);
skeletonRenderer.premultipliedAlpha = true;
skeletonRenderer.draw(batcher, skeleton);
batcher.end();
shader.unbind();
if (plugin.drawDebug || src.drawDebug)
{
var debugShader = plugin.debugShader;
var debugRenderer = plugin.debugRenderer;
var shapes = plugin.shapes;
debugShader.bind();
debugShader.setUniform4x4f(runtime.webgl.Shader.MVP_MATRIX, mvp.val);
shapes.begin(debugShader);
debugRenderer.draw(shapes, skeleton);
shapes.end();
debugShader.unbind();
}
renderer.rebindPipeline(pipeline);
};
module.exports = SpineGameObjectWebGLRenderer;

View file

@ -0,0 +1,27 @@
Spine Runtimes Software License v2.5
Copyright (c) 2013-2016, Esoteric Software
All rights reserved.
You are granted a perpetual, non-exclusive, non-sublicensable, and
non-transferable license to use, install, execute, and perform the Spine
Runtimes software and derivative works solely for personal or internal
use. Without the written permission of Esoteric Software (see Section 2 of
the Spine Software License Agreement), you may not (a) modify, translate,
adapt, or develop new applications using the Spine Runtimes or otherwise
create derivative works or improvements of the Spine Runtimes or (b) remove,
delete, alter, or obscure any trademarks or any copyright, trademark, patent,
or other intellectual property or proprietary rights notices on or in the
Software, including any copy thereof. Redistributions in binary or source
form must include this license and terms.
THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,76 @@
'use strict';
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const exec = require('child_process').exec;
module.exports = {
mode: 'development',
context: `${__dirname}/src/`,
entry: {
'SpinePlugin': './SpinePlugin.js'
},
output: {
path: `${__dirname}/dist/`,
filename: '[name].js',
library: 'SpinePlugin',
libraryTarget: 'umd',
sourceMapFilename: '[file].map',
devtoolModuleFilenameTemplate: 'webpack:///[resource-path]', // string
devtoolFallbackModuleFilenameTemplate: 'webpack:///[resource-path]?[hash]', // string
umdNamedDefine: true
},
performance: { hints: false },
module: {
rules: [
{
test: require.resolve('./src/runtimes/spine-canvas.js'),
use: 'imports-loader?this=>window'
},
{
test: require.resolve('./src/runtimes/spine-canvas.js'),
use: 'exports-loader?spine'
},
{
test: require.resolve('./src/runtimes/spine-webgl.js'),
use: 'imports-loader?this=>window'
},
{
test: require.resolve('./src/runtimes/spine-webgl.js'),
use: 'exports-loader?spine'
}
]
},
resolve: {
alias: {
'SpineCanvas': './runtimes/spine-canvas.js',
'SpineWebGL': './runtimes/spine-webgl.js'
},
},
plugins: [
new webpack.DefinePlugin({
"typeof CANVAS_RENDERER": JSON.stringify(true),
"typeof WEBGL_RENDERER": JSON.stringify(true)
}),
new CleanWebpackPlugin([ 'dist' ]),
{
apply: (compiler) => {
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
exec('node plugins/spine/copy-to-examples.js', (err, stdout, stderr) => {
if (stdout) process.stdout.write(stdout);
if (stderr) process.stderr.write(stderr);
});
});
}
}
],
devtool: 'source-map'
};

View file

@ -0,0 +1,94 @@
'use strict';
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const exec = require('child_process').exec;
module.exports = {
mode: 'production',
context: `${__dirname}/src/`,
entry: {
'SpinePlugin': './SpineWebGLPlugin.js',
'SpinePlugin.min': './SpineWebGLPlugin.js'
},
output: {
path: `${__dirname}/dist/`,
filename: '[name].js',
library: 'SpinePlugin',
libraryTarget: 'umd',
sourceMapFilename: '[file].map',
devtoolModuleFilenameTemplate: 'webpack:///[resource-path]', // string
devtoolFallbackModuleFilenameTemplate: 'webpack:///[resource-path]?[hash]', // string
umdNamedDefine: true
},
performance: { hints: false },
module: {
rules: [
{
test: require.resolve('./src/runtimes/spine-canvas.js'),
use: 'imports-loader?this=>window'
},
{
test: require.resolve('./src/runtimes/spine-canvas.js'),
use: 'exports-loader?spine'
},
{
test: require.resolve('./src/runtimes/spine-webgl.js'),
use: 'imports-loader?this=>window'
},
{
test: require.resolve('./src/runtimes/spine-webgl.js'),
use: 'exports-loader?spine'
}
]
},
resolve: {
alias: {
'SpineCanvas': './runtimes/spine-canvas.js',
'SpineWebGL': './runtimes/spine-webgl.js'
},
},
optimization: {
minimizer: [
new UglifyJSPlugin({
include: /\.min\.js$/,
parallel: true,
sourceMap: false,
uglifyOptions: {
compress: true,
ie8: false,
ecma: 5,
output: {comments: false},
warnings: false
},
warningsFilter: () => false
})
]
},
plugins: [
new webpack.DefinePlugin({
"typeof CANVAS_RENDERER": JSON.stringify(true),
"typeof WEBGL_RENDERER": JSON.stringify(true)
}),
new CleanWebpackPlugin([ 'dist' ]),
{
apply: (compiler) => {
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
exec('node plugins/spine/copy-to-examples.js', (err, stdout, stderr) => {
if (stdout) process.stdout.write(stdout);
if (stderr) process.stderr.write(stderr);
});
});
}
}
]
};

View file

@ -0,0 +1,76 @@
'use strict';
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const exec = require('child_process').exec;
module.exports = {
mode: 'development',
context: `${__dirname}/src/`,
entry: {
'SpineCanvasPlugin': './SpineCanvasPlugin.js'
},
output: {
path: `${__dirname}/dist/`,
filename: '[name].js',
library: 'SpineCanvasPlugin',
libraryTarget: 'umd',
sourceMapFilename: '[file].map',
devtoolModuleFilenameTemplate: 'webpack:///[resource-path]', // string
devtoolFallbackModuleFilenameTemplate: 'webpack:///[resource-path]?[hash]', // string
umdNamedDefine: true
},
performance: { hints: false },
module: {
rules: [
{
test: require.resolve('./src/runtimes/spine-canvas.js'),
use: 'imports-loader?this=>window'
},
{
test: require.resolve('./src/runtimes/spine-canvas.js'),
use: 'exports-loader?spine'
},
{
test: require.resolve('./src/runtimes/spine-webgl.js'),
use: 'imports-loader?this=>window'
},
{
test: require.resolve('./src/runtimes/spine-webgl.js'),
use: 'exports-loader?spine'
}
]
},
resolve: {
alias: {
'SpineCanvas': './runtimes/spine-canvas.js',
'SpineWebGL': './runtimes/spine-webgl.js'
},
},
plugins: [
new webpack.DefinePlugin({
"typeof CANVAS_RENDERER": JSON.stringify(true),
"typeof WEBGL_RENDERER": JSON.stringify(false)
}),
new CleanWebpackPlugin([ 'dist' ]),
{
apply: (compiler) => {
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
exec('node plugins/spine/copy-to-examples.js', (err, stdout, stderr) => {
if (stdout) process.stdout.write(stdout);
if (stderr) process.stderr.write(stderr);
});
});
}
}
],
devtool: 'source-map'
};

View file

@ -0,0 +1,94 @@
'use strict';
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const exec = require('child_process').exec;
module.exports = {
mode: 'production',
context: `${__dirname}/src/`,
entry: {
'SpineCanvasPlugin': './SpineCanvasPlugin.js',
'SpineCanvasPlugin.min': './SpineCanvasPlugin.js'
},
output: {
path: `${__dirname}/dist/`,
filename: '[name].js',
library: 'SpineCanvasPlugin',
libraryTarget: 'umd',
sourceMapFilename: '[file].map',
devtoolModuleFilenameTemplate: 'webpack:///[resource-path]', // string
devtoolFallbackModuleFilenameTemplate: 'webpack:///[resource-path]?[hash]', // string
umdNamedDefine: true
},
performance: { hints: false },
module: {
rules: [
{
test: require.resolve('./src/runtimes/spine-canvas.js'),
use: 'imports-loader?this=>window'
},
{
test: require.resolve('./src/runtimes/spine-canvas.js'),
use: 'exports-loader?spine'
},
{
test: require.resolve('./src/runtimes/spine-webgl.js'),
use: 'imports-loader?this=>window'
},
{
test: require.resolve('./src/runtimes/spine-webgl.js'),
use: 'exports-loader?spine'
}
]
},
resolve: {
alias: {
'SpineCanvas': './runtimes/spine-canvas.js',
'SpineWebGL': './runtimes/spine-webgl.js'
},
},
optimization: {
minimizer: [
new UglifyJSPlugin({
include: /\.min\.js$/,
parallel: true,
sourceMap: false,
uglifyOptions: {
compress: true,
ie8: false,
ecma: 5,
output: {comments: false},
warnings: false
},
warningsFilter: () => false
})
]
},
plugins: [
new webpack.DefinePlugin({
"typeof CANVAS_RENDERER": JSON.stringify(true),
"typeof WEBGL_RENDERER": JSON.stringify(false)
}),
new CleanWebpackPlugin([ 'dist' ]),
{
apply: (compiler) => {
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
exec('node plugins/spine/copy-to-examples.js', (err, stdout, stderr) => {
if (stdout) process.stdout.write(stdout);
if (stderr) process.stderr.write(stderr);
});
});
}
}
]
};

View file

@ -0,0 +1,76 @@
'use strict';
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const exec = require('child_process').exec;
module.exports = {
mode: 'development',
context: `${__dirname}/src/`,
entry: {
'SpineWebGLPlugin': './SpineWebGLPlugin.js'
},
output: {
path: `${__dirname}/dist/`,
filename: '[name].js',
library: 'SpineWebGLPlugin',
libraryTarget: 'umd',
sourceMapFilename: '[file].map',
devtoolModuleFilenameTemplate: 'webpack:///[resource-path]', // string
devtoolFallbackModuleFilenameTemplate: 'webpack:///[resource-path]?[hash]', // string
umdNamedDefine: true
},
performance: { hints: false },
module: {
rules: [
{
test: require.resolve('./src/runtimes/spine-canvas.js'),
use: 'imports-loader?this=>window'
},
{
test: require.resolve('./src/runtimes/spine-canvas.js'),
use: 'exports-loader?spine'
},
{
test: require.resolve('./src/runtimes/spine-webgl.js'),
use: 'imports-loader?this=>window'
},
{
test: require.resolve('./src/runtimes/spine-webgl.js'),
use: 'exports-loader?spine'
}
]
},
resolve: {
alias: {
'SpineCanvas': './runtimes/spine-canvas.js',
'SpineWebGL': './runtimes/spine-webgl.js'
},
},
plugins: [
new webpack.DefinePlugin({
"typeof CANVAS_RENDERER": JSON.stringify(false),
"typeof WEBGL_RENDERER": JSON.stringify(true)
}),
new CleanWebpackPlugin([ 'dist' ]),
{
apply: (compiler) => {
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
exec('node plugins/spine/copy-to-examples.js', (err, stdout, stderr) => {
if (stdout) process.stdout.write(stdout);
if (stderr) process.stderr.write(stderr);
});
});
}
}
],
devtool: 'source-map'
};

View file

@ -0,0 +1,94 @@
'use strict';
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const exec = require('child_process').exec;
module.exports = {
mode: 'production',
context: `${__dirname}/src/`,
entry: {
'SpineWebGLPlugin': './SpineWebGLPlugin.js',
'SpineWebGLPlugin.min': './SpineWebGLPlugin.js'
},
output: {
path: `${__dirname}/dist/`,
filename: '[name].js',
library: 'SpineWebGLPlugin',
libraryTarget: 'umd',
sourceMapFilename: '[file].map',
devtoolModuleFilenameTemplate: 'webpack:///[resource-path]', // string
devtoolFallbackModuleFilenameTemplate: 'webpack:///[resource-path]?[hash]', // string
umdNamedDefine: true
},
performance: { hints: false },
module: {
rules: [
{
test: require.resolve('./src/runtimes/spine-canvas.js'),
use: 'imports-loader?this=>window'
},
{
test: require.resolve('./src/runtimes/spine-canvas.js'),
use: 'exports-loader?spine'
},
{
test: require.resolve('./src/runtimes/spine-webgl.js'),
use: 'imports-loader?this=>window'
},
{
test: require.resolve('./src/runtimes/spine-webgl.js'),
use: 'exports-loader?spine'
}
]
},
resolve: {
alias: {
'SpineCanvas': './runtimes/spine-canvas.js',
'SpineWebGL': './runtimes/spine-webgl.js'
},
},
optimization: {
minimizer: [
new UglifyJSPlugin({
include: /\.min\.js$/,
parallel: true,
sourceMap: false,
uglifyOptions: {
compress: true,
ie8: false,
ecma: 5,
output: {comments: false},
warnings: false
},
warningsFilter: () => false
})
]
},
plugins: [
new webpack.DefinePlugin({
"typeof CANVAS_RENDERER": JSON.stringify(false),
"typeof WEBGL_RENDERER": JSON.stringify(true)
}),
new CleanWebpackPlugin([ 'dist' ]),
{
apply: (compiler) => {
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
exec('node plugins/spine/copy-to-examples.js', (err, stdout, stderr) => {
if (stdout) process.stdout.write(stdout);
if (stderr) process.stderr.write(stderr);
});
});
}
}
]
};

View file

@ -6,6 +6,7 @@
var Clamp = require('../math/Clamp');
var Class = require('../utils/Class');
var EventEmitter = require('eventemitter3');
var FindClosestInSorted = require('../utils/array/FindClosestInSorted');
var Frame = require('./AnimationFrame');
var GetValue = require('../utils/object/GetValue');
@ -65,6 +66,7 @@ var GetValue = require('../utils/object/GetValue');
*
* @class Animation
* @memberof Phaser.Animations
* @extends Phaser.Events.EventEmitter
* @constructor
* @since 3.0.0
*
@ -74,10 +76,14 @@ var GetValue = require('../utils/object/GetValue');
*/
var Animation = new Class({
Extends: EventEmitter,
initialize:
function Animation (manager, key, config)
{
EventEmitter.call(this);
/**
* A reference to the global Animation Manager
*
@ -797,13 +803,20 @@ var Animation = new Class({
component.pendingRepeat = false;
component.parent.emit('animationrepeat', this, component.currentFrame, component.repeatCounter, component.parent);
var frame = component.currentFrame;
var parent = component.parent;
this.emit('repeat', this, frame);
parent.emit('animationrepeat-' + this.key, this, frame, component.repeatCounter, parent);
parent.emit('animationrepeat', this, frame, component.repeatCounter, parent);
}
}
},
/**
* [description]
* Sets the texture frame the animation uses for rendering.
*
* @method Phaser.Animations.Animation#setFrame
* @since 3.0.0
@ -824,7 +837,7 @@ var Animation = new Class({
},
/**
* [description]
* Converts the animation data to JSON.
*
* @method Phaser.Animations.Animation#toJSON
* @since 3.0.0
@ -939,6 +952,8 @@ var Animation = new Class({
*/
destroy: function ()
{
this.removeAllListeners();
this.manager.off('pauseall', this.pause, this);
this.manager.off('resumeall', this.resume, this);

View file

@ -19,8 +19,7 @@ var Class = require('../utils/Class');
* A single frame in an Animation sequence.
*
* An AnimationFrame consists of a reference to the Texture it uses for rendering, references to other
* frames in the animation, and index data. It also has the ability to fire its own `onUpdate` callback
* and modify the animation timing.
* frames in the animation, and index data. It also has the ability to modify the animation timing.
*
* AnimationFrames are generated automatically by the Animation class.
*

View file

@ -14,8 +14,8 @@ var Pad = require('../utils/string/Pad');
/**
* @typedef {object} JSONAnimationManager
*
* @property {JSONAnimation[]} anims - [description]
* @property {number} globalTimeScale - [description]
* @property {JSONAnimation[]} anims - An array of all Animations added to the Animation Manager.
* @property {number} globalTimeScale - The global time scale of the Animation Manager.
*/
/**
@ -67,7 +67,9 @@ var AnimationManager = new Class({
this.textureManager = null;
/**
* [description]
* The global time scale of the Animation Manager.
*
* This scales the time delta between two frames, thus influencing the speed of time for the Animation Manager.
*
* @name Phaser.Animations.AnimationManager#globalTimeScale
* @type {number}
@ -77,7 +79,9 @@ var AnimationManager = new Class({
this.globalTimeScale = 1;
/**
* [description]
* The Animations registered in the Animation Manager.
*
* This map should be modified with the {@link #add} and {@link #create} methods of the Animation Manager.
*
* @name Phaser.Animations.AnimationManager#anims
* @type {Phaser.Structs.Map.<string, Phaser.Animations.Animation>}
@ -87,7 +91,7 @@ var AnimationManager = new Class({
this.anims = new CustomMap();
/**
* [description]
* Whether the Animation Manager is paused along with all of its Animations.
*
* @name Phaser.Animations.AnimationManager#paused
* @type {boolean}
@ -97,7 +101,7 @@ var AnimationManager = new Class({
this.paused = false;
/**
* [description]
* The name of this Animation Manager.
*
* @name Phaser.Animations.AnimationManager#name
* @type {string}
@ -109,7 +113,7 @@ var AnimationManager = new Class({
},
/**
* [description]
* Registers event listeners after the Game boots.
*
* @method Phaser.Animations.AnimationManager#boot
* @since 3.0.0
@ -122,14 +126,14 @@ var AnimationManager = new Class({
},
/**
* [description]
* Adds an existing Animation to the Animation Manager.
*
* @method Phaser.Animations.AnimationManager#add
* @fires AddAnimationEvent
* @since 3.0.0
*
* @param {string} key - [description]
* @param {Phaser.Animations.Animation} animation - [description]
* @param {string} key - The key under which the Animation should be added. The Animation will be updated with it. Must be unique.
* @param {Phaser.Animations.Animation} animation - The Animation which should be added to the Animation Manager.
*
* @return {Phaser.Animations.AnimationManager} This Animation Manager.
*/
@ -151,42 +155,73 @@ var AnimationManager = new Class({
},
/**
* [description]
* Checks to see if the given key is already in use within the Animation Manager or not.
*
* Animations are global. Keys created in one scene can be used from any other Scene in your game. They are not Scene specific.
*
* @method Phaser.Animations.AnimationManager#exists
* @since 3.16.0
*
* @param {string} key - The key of the Animation to check.
*
* @return {boolean} `true` if the Animation already exists in the Animation Manager, or `false` if the key is available.
*/
exists: function (key)
{
return this.anims.has(key);
},
/**
* Creates a new Animation and adds it to the Animation Manager.
*
* Animations are global. Once created, you can use them in any Scene in your game. They are not Scene specific.
*
* If an invalid key is given this method will return `false`.
*
* If you pass the key of an animation that already exists in the Animation Manager, that animation will be returned.
*
* A brand new animation is only created if the key is valid and not already in use.
*
* If you wish to re-use an existing key, call `AnimationManager.remove` first, then this method.
*
* @method Phaser.Animations.AnimationManager#create
* @fires AddAnimationEvent
* @since 3.0.0
*
* @param {AnimationConfig} config - [description]
* @param {AnimationConfig} config - The configuration settings for the Animation.
*
* @return {Phaser.Animations.Animation} The Animation that was created.
* @return {(Phaser.Animations.Animation|false)} The Animation that was created, or `false` is the key is already in use.
*/
create: function (config)
{
var key = config.key;
if (!key || this.anims.has(key))
var anim = false;
if (key)
{
console.warn('Invalid Animation Key, or Key already in use: ' + key);
return;
anim = this.get(key);
if (!anim)
{
anim = new Animation(this, key, config);
this.anims.set(key, anim);
this.emit('add', key, anim);
}
}
var anim = new Animation(this, key, config);
this.anims.set(key, anim);
this.emit('add', key, anim);
return anim;
},
/**
* [description]
* Loads this Animation Manager's Animations and settings from a JSON object.
*
* @method Phaser.Animations.AnimationManager#fromJSON
* @since 3.0.0
*
* @param {(string|JSONAnimationManager|JSONAnimation)} data - [description]
* @param {(string|JSONAnimationManager|JSONAnimation)} data - The JSON object to parse.
* @param {boolean} [clearCurrentAnimations=false] - If set to `true`, the current animations will be removed (`anims.clear()`). If set to `false` (default), the animations in `data` will be added.
*
* @return {Phaser.Animations.Animation[]} An array containing all of the Animation objects that were created as a result of this call.
@ -232,19 +267,17 @@ var AnimationManager = new Class({
/**
* @typedef {object} GenerateFrameNamesConfig
*
* @property {string} [prefix=''] - [description]
* @property {integer} [start=0] - [description]
* @property {integer} [end=0] - [description]
* @property {string} [suffix=''] - [description]
* @property {integer} [zeroPad=0] - [description]
* @property {AnimationFrameConfig[]} [outputArray=[]] - [description]
* @property {boolean} [frames=false] - [description]
* @property {string} [prefix=''] - The string to append to every resulting frame name if using a range or an array of `frames`.
* @property {integer} [start=0] - If `frames` is not provided, the number of the first frame to return.
* @property {integer} [end=0] - If `frames` is not provided, the number of the last frame to return.
* @property {string} [suffix=''] - The string to append to every resulting frame name if using a range or an array of `frames`.
* @property {integer} [zeroPad=0] - The minimum expected lengths of each resulting frame's number. Numbers will be left-padded with zeroes until they are this long, then prepended and appended to create the resulting frame name.
* @property {AnimationFrameConfig[]} [outputArray=[]] - The array to append the created configuration objects to.
* @property {boolean} [frames=false] - If provided as an array, the range defined by `start` and `end` will be ignored and these frame numbers will be used.
*/
/**
* Generate an array of {@link AnimationFrameConfig} objects from a texture key and configuration object.
*
* Generates objects with string frame names, as configured by the given {@link AnimationFrameConfig}.
* [description]
*
* @method Phaser.Animations.AnimationManager#generateFrameNames
* @since 3.0.0
@ -419,7 +452,7 @@ var AnimationManager = new Class({
* @param {string} key - The key of the animation to load.
* @param {(string|integer)} [startFrame] - The name of a start frame to set on the loaded animation.
*
* @return {Phaser.GameObjects.GameObject} [description]
* @return {Phaser.GameObjects.GameObject} The Game Object with the animation loaded into it.
*/
load: function (child, key, startFrame)
{
@ -574,7 +607,7 @@ var AnimationManager = new Class({
},
/**
* [description]
* Get the animation data as javascript object by giving key, or get the data of all animations as array of objects, if key wasn't provided.
*
* @method Phaser.Animations.AnimationManager#toJSON
* @since 3.0.0
@ -606,7 +639,8 @@ var AnimationManager = new Class({
},
/**
* [description]
* Destroy this Animation Manager and clean up animation definitions and references to other objects.
* This method should not be called directly. It will be called automatically as a response to a `destroy` event from the Phaser.Game instance.
*
* @method Phaser.Animations.AnimationManager#destroy
* @since 3.0.0

View file

@ -10,7 +10,7 @@ var Device = require('../device');
var GetFastValue = require('../utils/object/GetFastValue');
var GetValue = require('../utils/object/GetValue');
var IsPlainObject = require('../utils/object/IsPlainObject');
var MATH = require('../math/const');
var PhaserMath = require('../math/');
var NOOP = require('../utils/NOOP');
var DefaultPlugins = require('../plugins/DefaultPlugins');
var ValueToColor = require('../display/color/ValueToColor');
@ -27,6 +27,18 @@ var ValueToColor = require('../display/color/ValueToColor');
* @param {Phaser.Game} game - The game.
*/
/**
* Config object containing various sound settings.
*
* @typedef {object} AudioConfig
*
* @property {boolean} [disableWebAudio=false] - Use HTML5 Audio instead of Web Audio.
* @property {AudioContext} [context] - An existing Web Audio context.
* @property {boolean} [noAudio=false] - Disable all audio output.
*
* @see Phaser.Sound.SoundManagerCreator
*/
/**
* @typedef {object} InputConfig
*
@ -35,19 +47,21 @@ var ValueToColor = require('../display/color/ValueToColor');
* @property {(boolean|TouchInputConfig)} [touch=true] - Touch input configuration. `true` uses the default configuration and `false` disables touch input.
* @property {(boolean|GamepadInputConfig)} [gamepad=false] - Gamepad input configuration. `true` enables gamepad input.
* @property {integer} [activePointers=1] - The maximum number of touch pointers. See {@link Phaser.Input.InputManager#pointers}.
* @property {number} [smoothFactor=0] - The smoothing factor to apply during Pointer movement. See {@link Phaser.Input.Pointer#smoothFactor}.
*/
/**
* @typedef {object} MouseInputConfig
*
* @property {*} [target=null] - Where the Mouse Manager listens for mouse input events. The default is the game canvas.
* @property {boolean} [capture=true] - Whether mouse input events have preventDefault() called on them.
* @property {boolean} [capture=true] - Whether mouse input events have `preventDefault` called on them.
*/
/**
* @typedef {object} KeyboardInputConfig
*
* @property {*} [target=window] - Where the Keyboard Manager listens for keyboard input events.
* @property {?integer} [capture] - `preventDefault` will be called on every non-modified key which has a key code in this array. By default it is empty.
*/
/**
@ -74,11 +88,11 @@ var ValueToColor = require('../display/color/ValueToColor');
/**
* @typedef {object} FPSConfig
*
* @property {integer} [min=10] - The minimum acceptable rendering rate, in frames per second.
* @property {integer} [min=5] - The minimum acceptable rendering rate, in frames per second.
* @property {integer} [target=60] - The optimum rendering rate, in frames per second.
* @property {boolean} [forceSetTimeOut=false] - Use setTimeout instead of requestAnimationFrame to run the game loop.
* @property {integer} [deltaHistory=10] - Calculate the average frame delta from this many consecutive frame intervals.
* @property {integer} [panicMax=120] - [description]
* @property {integer} [panicMax=120] - The amount of frames the time step counts before we trust the delta values again.
*/
/**
@ -91,7 +105,6 @@ var ValueToColor = require('../display/color/ValueToColor');
* @property {boolean} [transparent=false] - Whether the game canvas will be transparent.
* @property {boolean} [clearBeforeRender=true] - Whether the game canvas will be cleared between each rendering frame.
* @property {boolean} [premultipliedAlpha=true] - In WebGL mode, the drawing buffer contains colors with pre-multiplied alpha.
* @property {boolean} [preserveDrawingBuffer=false] - In WebGL mode, the drawing buffer won't be cleared automatically each frame.
* @property {boolean} [failIfMajorPerformanceCaveat=false] - Let the browser abort creating a WebGL context if it judges performance would be unacceptable.
* @property {string} [powerPreference='default'] - "high-performance", "low-power" or "default". A hint to the browser on how much device power the game might use.
* @property {integer} [batchSize=2000] - The default WebGL batch size.
@ -123,14 +136,14 @@ var ValueToColor = require('../display/color/ValueToColor');
/**
* @typedef {object} LoaderConfig
*
* @property {string} [baseURL] - An URL used to resolve paths given to the loader. Example: 'http://labs.phaser.io/assets/'.
* @property {string} [path] - An URL path used to resolve relative paths given to the loader. Example: 'images/sprites/'.
* @property {string} [baseURL] - A URL used to resolve paths given to the loader. Example: 'http://labs.phaser.io/assets/'.
* @property {string} [path] - A URL path used to resolve relative paths given to the loader. Example: 'images/sprites/'.
* @property {integer} [maxParallelDownloads=32] - The maximum number of resources the loader will start loading at once.
* @property {(string|undefined)} [crossOrigin=undefined] - 'anonymous', 'use-credentials', or `undefined`. If you're not making cross-origin requests, leave this as `undefined`. See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes}.
* @property {string} [responseType] - The response type of the XHR request, e.g. `blob`, `text`, etc.
* @property {boolean} [async=true] - Should the XHR request use async or not?
* @property {string} [user] - Optional username for the XHR request.
* @property {string} [password] - Optional password for the XHR request.
* @property {string} [user] - Optional username for all XHR requests.
* @property {string} [password] - Optional password for all XHR requests.
* @property {integer} [timeout=0] - Optional XHR timeout value, in ms.
*/
@ -249,57 +262,57 @@ var Config = new Class({
var defaultBannerTextColor = '#ffffff';
/**
* @const {(integer|string)} Phaser.Boot.Config#width - [description]
* @const {(integer|string)} Phaser.Boot.Config#width - The width of the underlying canvas, in pixels.
*/
this.width = GetValue(config, 'width', 1024);
/**
* @const {(integer|string)} Phaser.Boot.Config#height - [description]
* @const {(integer|string)} Phaser.Boot.Config#height - The height of the underlying canvas, in pixels.
*/
this.height = GetValue(config, 'height', 768);
/**
* @const {number} Phaser.Boot.Config#zoom - [description]
* @const {number} Phaser.Boot.Config#zoom - The zoom factor, as used by the Scale Manager.
*/
this.zoom = GetValue(config, 'zoom', 1);
/**
* @const {number} Phaser.Boot.Config#resolution - [description]
* @const {number} Phaser.Boot.Config#resolution - The canvas device pixel resolution.
*/
this.resolution = GetValue(config, 'resolution', 1);
/**
* @const {?*} Phaser.Boot.Config#parent - [description]
* @const {?*} Phaser.Boot.Config#parent - A parent DOM element into which the canvas created by the renderer will be injected.
*/
this.parent = GetValue(config, 'parent', null);
/**
* @const {integer} Phaser.Boot.Config#scaleMode - [description]
* @const {integer} Phaser.Boot.Config#scaleMode - The scale mode as used by the Scale Manager. The default is zero, which is no scaling.
*/
this.scaleMode = GetValue(config, 'scaleMode', 0);
/**
* @const {boolean} Phaser.Boot.Config#expandParent - [description]
* @const {boolean} Phaser.Boot.Config#expandParent - Is the Scale Manager allowed to adjust the size of the parent container?
*/
this.expandParent = GetValue(config, 'expandParent', false);
/**
* @const {integer} Phaser.Boot.Config#minWidth - [description]
* @const {integer} Phaser.Boot.Config#minWidth - The minimum width, in pixels, the canvas will scale down to. A value of zero means no minimum.
*/
this.minWidth = GetValue(config, 'minWidth', 0);
/**
* @const {integer} Phaser.Boot.Config#maxWidth - [description]
* @const {integer} Phaser.Boot.Config#maxWidth - The maximum width, in pixels, the canvas will scale up to. A value of zero means no maximum.
*/
this.maxWidth = GetValue(config, 'maxWidth', 0);
/**
* @const {integer} Phaser.Boot.Config#minHeight - [description]
* @const {integer} Phaser.Boot.Config#minHeight - The minimum height, in pixels, the canvas will scale down to. A value of zero means no minimum.
*/
this.minHeight = GetValue(config, 'minHeight', 0);
/**
* @const {integer} Phaser.Boot.Config#maxHeight - [description]
* @const {integer} Phaser.Boot.Config#maxHeight - The maximum height, in pixels, the canvas will scale up to. A value of zero means no maximum.
*/
this.maxHeight = GetValue(config, 'maxHeight', 0);
@ -338,21 +351,26 @@ var Config = new Class({
this.context = GetValue(config, 'context', null);
/**
* @const {?string} Phaser.Boot.Config#canvasStyle - [description]
* @const {?string} Phaser.Boot.Config#canvasStyle - Optional CSS attributes to be set on the canvas object created by the renderer.
*/
this.canvasStyle = GetValue(config, 'canvasStyle', null);
/**
* @const {?object} Phaser.Boot.Config#sceneConfig - [description]
* @const {boolean} Phaser.Boot.Config#customEnvironment - Is Phaser running under a custom (non-native web) environment? If so, set this to `true` to skip internal Feature detection. If `true` the `renderType` cannot be left as `AUTO`.
*/
this.customEnvironment = GetValue(config, 'customEnvironment', false);
/**
* @const {?object} Phaser.Boot.Config#sceneConfig - The default Scene configuration object.
*/
this.sceneConfig = GetValue(config, 'scene', null);
/**
* @const {string[]} Phaser.Boot.Config#seed - [description]
* @const {string[]} Phaser.Boot.Config#seed - A seed which the Random Data Generator will use. If not given, a dynamic seed based on the time is used.
*/
this.seed = GetValue(config, 'seed', [ (Date.now() * Math.random()).toString() ]);
MATH.RND.init(this.seed);
PhaserMath.RND = new PhaserMath.RandomDataGenerator(this.seed);
/**
* @const {string} Phaser.Boot.Config#gameTitle - The title of the game.
@ -370,108 +388,118 @@ var Config = new Class({
this.gameVersion = GetValue(config, 'version', '');
/**
* @const {boolean} Phaser.Boot.Config#autoFocus - [description]
* @const {boolean} Phaser.Boot.Config#autoFocus - If `true` the window will automatically be given focus immediately and on any future mousedown event.
*/
this.autoFocus = GetValue(config, 'autoFocus', true);
// DOM Element Container
/**
* @const {?boolean} Phaser.Boot.Config#domCreateContainer - [description]
* @const {?boolean} Phaser.Boot.Config#domCreateContainer - EXPERIMENTAL: Do not currently use.
*/
this.domCreateContainer = GetValue(config, 'dom.createContainer', false);
/**
* @const {?boolean} Phaser.Boot.Config#domBehindCanvas - [description]
* @const {?boolean} Phaser.Boot.Config#domBehindCanvas - EXPERIMENTAL: Do not currently use.
*/
this.domBehindCanvas = GetValue(config, 'dom.behindCanvas', false);
// Input
/**
* @const {boolean} Phaser.Boot.Config#inputKeyboard - [description]
* @const {boolean} Phaser.Boot.Config#inputKeyboard - Enable the Keyboard Plugin. This can be disabled in games that don't need keyboard input.
*/
this.inputKeyboard = GetValue(config, 'input.keyboard', true);
/**
* @const {*} Phaser.Boot.Config#inputKeyboardEventTarget - [description]
* @const {*} Phaser.Boot.Config#inputKeyboardEventTarget - The DOM Target to listen for keyboard events on. Defaults to `window` if not specified.
*/
this.inputKeyboardEventTarget = GetValue(config, 'input.keyboard.target', window);
/**
* @const {(boolean|object)} Phaser.Boot.Config#inputMouse - [description]
* @const {?integer[]} Phaser.Boot.Config#inputKeyboardCapture - `preventDefault` will be called on every non-modified key which has a key code in this array. By default, it is empty.
*/
this.inputKeyboardCapture = GetValue(config, 'input.keyboard.capture', []);
/**
* @const {(boolean|object)} Phaser.Boot.Config#inputMouse - Enable the Mouse Plugin. This can be disabled in games that don't need mouse input.
*/
this.inputMouse = GetValue(config, 'input.mouse', true);
/**
* @const {?*} Phaser.Boot.Config#inputMouseEventTarget - [description]
* @const {?*} Phaser.Boot.Config#inputMouseEventTarget - The DOM Target to listen for mouse events on. Defaults to the game canvas if not specified.
*/
this.inputMouseEventTarget = GetValue(config, 'input.mouse.target', null);
/**
* @const {boolean} Phaser.Boot.Config#inputMouseCapture - [description]
* @const {boolean} Phaser.Boot.Config#inputMouseCapture - Should mouse events be captured? I.e. have prevent default called on them.
*/
this.inputMouseCapture = GetValue(config, 'input.mouse.capture', true);
/**
* @const {boolean} Phaser.Boot.Config#inputTouch - [description]
* @const {boolean} Phaser.Boot.Config#inputTouch - Enable the Touch Plugin. This can be disabled in games that don't need touch input.
*/
this.inputTouch = GetValue(config, 'input.touch', Device.input.touch);
/**
* @const {?*} Phaser.Boot.Config#inputTouchEventTarget - [description]
* @const {?*} Phaser.Boot.Config#inputTouchEventTarget - The DOM Target to listen for touch events on. Defaults to the game canvas if not specified.
*/
this.inputTouchEventTarget = GetValue(config, 'input.touch.target', null);
/**
* @const {boolean} Phaser.Boot.Config#inputTouchCapture - [description]
* @const {boolean} Phaser.Boot.Config#inputTouchCapture - Should touch events be captured? I.e. have prevent default called on them.
*/
this.inputTouchCapture = GetValue(config, 'input.touch.capture', true);
/**
* @const {integer} Phaser.Boot.Config#inputActivePointers - [description]
* @const {integer} Phaser.Boot.Config#inputActivePointers - The number of Pointer objects created by default. In a mouse-only, or non-multi touch game, you can leave this as 1.
*/
this.inputActivePointers = GetValue(config, 'input.activePointers', 1);
/**
* @const {boolean} Phaser.Boot.Config#inputGamepad - [description]
* @const {integer} Phaser.Boot.Config#inputSmoothFactor - The smoothing factor to apply during Pointer movement. See {@link Phaser.Input.Pointer#smoothFactor}.
*/
this.inputSmoothFactor = GetValue(config, 'input.smoothFactor', 0);
/**
* @const {boolean} Phaser.Boot.Config#inputGamepad - Enable the Gamepad Plugin. This can be disabled in games that don't need gamepad input.
*/
this.inputGamepad = GetValue(config, 'input.gamepad', false);
/**
* @const {*} Phaser.Boot.Config#inputGamepadEventTarget - [description]
* @const {*} Phaser.Boot.Config#inputGamepadEventTarget - The DOM Target to listen for gamepad events on. Defaults to `window` if not specified.
*/
this.inputGamepadEventTarget = GetValue(config, 'input.gamepad.target', window);
/**
* @const {boolean} Phaser.Boot.Config#disableContextMenu - Set to `true` to disable context menu. Default value is `false`.
* @const {boolean} Phaser.Boot.Config#disableContextMenu - Set to `true` to disable the right-click context menu.
*/
this.disableContextMenu = GetValue(config, 'disableContextMenu', false);
/**
* @const {any} Phaser.Boot.Config#audio - [description]
* @const {AudioConfig} Phaser.Boot.Config#audio - The Audio Configuration object.
*/
this.audio = GetValue(config, 'audio');
// If you do: { banner: false } it won't display any banner at all
/**
* @const {boolean} Phaser.Boot.Config#hideBanner - [description]
* @const {boolean} Phaser.Boot.Config#hideBanner - Don't write the banner line to the console.log.
*/
this.hideBanner = (GetValue(config, 'banner', null) === false);
/**
* @const {boolean} Phaser.Boot.Config#hidePhaser - [description]
* @const {boolean} Phaser.Boot.Config#hidePhaser - Omit Phaser's name and version from the banner.
*/
this.hidePhaser = GetValue(config, 'banner.hidePhaser', false);
/**
* @const {string} Phaser.Boot.Config#bannerTextColor - [description]
* @const {string} Phaser.Boot.Config#bannerTextColor - The color of the banner text.
*/
this.bannerTextColor = GetValue(config, 'banner.text', defaultBannerTextColor);
/**
* @const {string[]} Phaser.Boot.Config#bannerBackgroundColor - [description]
* @const {string[]} Phaser.Boot.Config#bannerBackgroundColor - The background colors of the banner.
*/
this.bannerBackgroundColor = GetValue(config, 'banner.background', defaultBannerColor);
@ -480,16 +508,8 @@ var Config = new Class({
this.hideBanner = true;
}
// Frame Rate config
// fps: {
// min: 10,
// target: 60,
// forceSetTimeOut: false,
// deltaHistory: 10
// }
/**
* @const {?FPSConfig} Phaser.Boot.Config#fps - [description]
* @const {?FPSConfig} Phaser.Boot.Config#fps - The Frame Rate Configuration object, as parsed by the Timestep class.
*/
this.fps = GetValue(config, 'fps', null);
@ -504,12 +524,12 @@ var Config = new Class({
this.autoResize = GetValue(renderConfig, 'autoResize', true);
/**
* @const {boolean} Phaser.Boot.Config#antialias - [description]
* @const {boolean} Phaser.Boot.Config#antialias - When set to `true`, WebGL uses linear interpolation to draw scaled or rotated textures, giving a smooth appearance. When set to `false`, WebGL uses nearest-neighbor interpolation, giving a crisper appearance. `false` also disables antialiasing of the game canvas itself, if the browser supports it, when the game canvas is scaled.
*/
this.antialias = GetValue(renderConfig, 'antialias', true);
/**
* @const {boolean} Phaser.Boot.Config#roundPixels - [description]
* @const {boolean} Phaser.Boot.Config#roundPixels - Draw texture-based Game Objects at only whole-integer positions. Game Objects without textures, like Graphics, ignore this property.
*/
this.roundPixels = GetValue(renderConfig, 'roundPixels', false);
@ -525,32 +545,27 @@ var Config = new Class({
}
/**
* @const {boolean} Phaser.Boot.Config#transparent - [description]
* @const {boolean} Phaser.Boot.Config#transparent - Whether the game canvas will have a transparent background.
*/
this.transparent = GetValue(renderConfig, 'transparent', false);
/**
* @const {boolean} Phaser.Boot.Config#clearBeforeRender - [description]
* @const {boolean} Phaser.Boot.Config#clearBeforeRender - Whether the game canvas will be cleared between each rendering frame. You can disable this if you have a full-screen background image or game object.
*/
this.clearBeforeRender = GetValue(renderConfig, 'clearBeforeRender', true);
/**
* @const {boolean} Phaser.Boot.Config#premultipliedAlpha - [description]
* @const {boolean} Phaser.Boot.Config#premultipliedAlpha - In WebGL mode, sets the drawing buffer to contain colors with pre-multiplied alpha.
*/
this.premultipliedAlpha = GetValue(renderConfig, 'premultipliedAlpha', true);
/**
* @const {boolean} Phaser.Boot.Config#preserveDrawingBuffer - [description]
*/
this.preserveDrawingBuffer = GetValue(renderConfig, 'preserveDrawingBuffer', false);
/**
* @const {boolean} Phaser.Boot.Config#failIfMajorPerformanceCaveat - [description]
* @const {boolean} Phaser.Boot.Config#failIfMajorPerformanceCaveat - Let the browser abort creating a WebGL context if it judges performance would be unacceptable.
*/
this.failIfMajorPerformanceCaveat = GetValue(renderConfig, 'failIfMajorPerformanceCaveat', false);
/**
* @const {string} Phaser.Boot.Config#powerPreference - [description]
* @const {string} Phaser.Boot.Config#powerPreference - "high-performance", "low-power" or "default". A hint to the browser on how much device power the game might use.
*/
this.powerPreference = GetValue(renderConfig, 'powerPreference', 'default');
@ -567,7 +582,7 @@ var Config = new Class({
var bgc = GetValue(config, 'backgroundColor', 0);
/**
* @const {Phaser.Display.Color} Phaser.Boot.Config#backgroundColor - [description]
* @const {Phaser.Display.Color} Phaser.Boot.Config#backgroundColor - The background color of the game canvas. The default is black. This value is ignored if `transparent` is set to `true`.
*/
this.backgroundColor = ValueToColor(bgc);
@ -576,45 +591,33 @@ var Config = new Class({
this.backgroundColor.alpha = 0;
}
// Callbacks
/**
* @const {BootCallback} Phaser.Boot.Config#preBoot - [description]
* @const {BootCallback} Phaser.Boot.Config#preBoot - Called before Phaser boots. Useful for initializing anything not related to Phaser that Phaser may require while booting.
*/
this.preBoot = GetValue(config, 'callbacks.preBoot', NOOP);
/**
* @const {BootCallback} Phaser.Boot.Config#postBoot - [description]
* @const {BootCallback} Phaser.Boot.Config#postBoot - A function to run at the end of the boot sequence. At this point, all the game systems have started and plugins have been loaded.
*/
this.postBoot = GetValue(config, 'callbacks.postBoot', NOOP);
// Physics
// physics: {
// system: 'impact',
// setBounds: true,
// gravity: 0,
// cellSize: 64
// }
/**
* @const {object} Phaser.Boot.Config#physics - [description]
* @const {PhysicsConfig} Phaser.Boot.Config#physics - The Physics Configuration object.
*/
this.physics = GetValue(config, 'physics', {});
/**
* @const {boolean} Phaser.Boot.Config#defaultPhysicsSystem - [description]
* @const {(boolean|string)} Phaser.Boot.Config#defaultPhysicsSystem - The default physics system. It will be started for each scene. Either 'arcade', 'impact' or 'matter'.
*/
this.defaultPhysicsSystem = GetValue(this.physics, 'default', false);
// Loader Defaults
/**
* @const {string} Phaser.Boot.Config#loaderBaseURL - [description]
* @const {string} Phaser.Boot.Config#loaderBaseURL - A URL used to resolve paths given to the loader. Example: 'http://labs.phaser.io/assets/'.
*/
this.loaderBaseURL = GetValue(config, 'loader.baseURL', '');
/**
* @const {string} Phaser.Boot.Config#loaderPath - [description]
* @const {string} Phaser.Boot.Config#loaderPath - A URL path used to resolve relative paths given to the loader. Example: 'images/sprites/'.
*/
this.loaderPath = GetValue(config, 'loader.path', '');
@ -624,37 +627,35 @@ var Config = new Class({
this.loaderMaxParallelDownloads = GetValue(config, 'loader.maxParallelDownloads', 32);
/**
* @const {(string|undefined)} Phaser.Boot.Config#loaderCrossOrigin - [description]
* @const {(string|undefined)} Phaser.Boot.Config#loaderCrossOrigin - 'anonymous', 'use-credentials', or `undefined`. If you're not making cross-origin requests, leave this as `undefined`. See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes}.
*/
this.loaderCrossOrigin = GetValue(config, 'loader.crossOrigin', undefined);
/**
* @const {string} Phaser.Boot.Config#loaderResponseType - [description]
* @const {string} Phaser.Boot.Config#loaderResponseType - The response type of the XHR request, e.g. `blob`, `text`, etc.
*/
this.loaderResponseType = GetValue(config, 'loader.responseType', '');
/**
* @const {boolean} Phaser.Boot.Config#loaderAsync - [description]
* @const {boolean} Phaser.Boot.Config#loaderAsync - Should the XHR request use async or not?
*/
this.loaderAsync = GetValue(config, 'loader.async', true);
/**
* @const {string} Phaser.Boot.Config#loaderUser - [description]
* @const {string} Phaser.Boot.Config#loaderUser - Optional username for all XHR requests.
*/
this.loaderUser = GetValue(config, 'loader.user', '');
/**
* @const {string} Phaser.Boot.Config#loaderPassword - [description]
* @const {string} Phaser.Boot.Config#loaderPassword - Optional password for all XHR requests.
*/
this.loaderPassword = GetValue(config, 'loader.password', '');
/**
* @const {integer} Phaser.Boot.Config#loaderTimeout - [description]
* @const {integer} Phaser.Boot.Config#loaderTimeout - Optional XHR timeout value, in ms.
*/
this.loaderTimeout = GetValue(config, 'loader.timeout', 0);
// Plugins
/*
* Allows `plugins` property to either be an array, in which case it just replaces
* the default plugins like previously, or a config object.
@ -674,12 +675,12 @@ var Config = new Class({
*/
/**
* @const {any} Phaser.Boot.Config#installGlobalPlugins - [description]
* @const {any} Phaser.Boot.Config#installGlobalPlugins - An array of global plugins to be installed.
*/
this.installGlobalPlugins = [];
/**
* @const {any} Phaser.Boot.Config#installScenePlugins - [description]
* @const {any} Phaser.Boot.Config#installScenePlugins - An array of Scene level plugins to be installed.
*/
this.installScenePlugins = [];
@ -718,12 +719,12 @@ var Config = new Class({
var pngPrefix = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAg';
/**
* @const {string} Phaser.Boot.Config#defaultImage - [description]
* @const {string} Phaser.Boot.Config#defaultImage - A base64 encoded PNG that will be used as the default blank texture.
*/
this.defaultImage = GetValue(config, 'images.default', pngPrefix + 'AQMAAABJtOi3AAAAA1BMVEX///+nxBvIAAAAAXRSTlMAQObYZgAAABVJREFUeF7NwIEAAAAAgKD9qdeocAMAoAABm3DkcAAAAABJRU5ErkJggg==');
/**
* @const {string} Phaser.Boot.Config#missingImage - [description]
* @const {string} Phaser.Boot.Config#missingImage - A base64 encoded PNG that will be used as the default texture when a texture is assigned that is missing or not loaded.
*/
this.missingImage = GetValue(config, 'images.missing', pngPrefix + 'CAIAAAD8GO2jAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJ9JREFUeNq01ssOwyAMRFG46v//Mt1ESmgh+DFmE2GPOBARKb2NVjo+17PXLD8a1+pl5+A+wSgFygymWYHBb0FtsKhJDdZlncG2IzJ4ayoMDv20wTmSMzClEgbWYNTAkQ0Z+OJ+A/eWnAaR9+oxCF4Os0H8htsMUp+pwcgBBiMNnAwF8GqIgL2hAzaGFFgZauDPKABmowZ4GL369/0rwACp2yA/ttmvsQAAAABJRU5ErkJggg==');

View file

@ -23,10 +23,13 @@ var CreateRenderer = function (game)
{
var config = game.config;
// Game either requested Canvas,
// or requested AUTO or WEBGL but the browser doesn't support it, so fall back to Canvas
if ((config.customEnvironment || config.canvas) && config.renderType === CONST.AUTO)
{
throw new Error('Must set explicit renderType in custom environment');
}
if (config.renderType !== CONST.HEADLESS)
// Not a custom environment, didn't provide their own canvas and not headless, so determine the renderer:
if (!config.customEnvironment && !config.canvas && config.renderType !== CONST.HEADLESS)
{
if (config.renderType === CONST.CANVAS || (config.renderType !== CONST.CANVAS && !Features.webGL))
{
@ -58,12 +61,12 @@ var CreateRenderer = function (game)
{
game.canvas = config.canvas;
game.canvas.width = game.config.width;
game.canvas.height = game.config.height;
game.canvas.width = game.scale.canvasWidth;
game.canvas.height = game.scale.canvasHeight;
}
else
{
game.canvas = CanvasPool.create(game, config.width * config.resolution, config.height * config.resolution, config.renderType);
game.canvas = CanvasPool.create(game, game.scale.canvasWidth, game.scale.canvasHeight, config.renderType);
}
// Does the game config provide some canvas css styles to use?
@ -78,10 +81,6 @@ var CreateRenderer = function (game)
CanvasInterpolation.setCrisp(game.canvas);
}
// Zoomed?
game.canvas.style.width = (config.width * config.zoom).toString() + 'px';
game.canvas.style.height = (config.height * config.zoom).toString() + 'px';
if (config.renderType === CONST.HEADLESS)
{
// Nothing more to do here

View file

@ -19,6 +19,7 @@ var EventEmitter = require('eventemitter3');
var InputManager = require('../input/InputManager');
var PluginCache = require('../plugins/PluginCache');
var PluginManager = require('../plugins/PluginManager');
var ScaleManager = require('../dom/ScaleManager');
var SceneManager = require('../scene/SceneManager');
var SoundManagerCreator = require('../sound/SoundManagerCreator');
var TextureManager = require('../textures/TextureManager');
@ -225,6 +226,17 @@ var Game = new Class({
*/
this.device = Device;
/**
* An instance of the Scale Manager.
*
* The Scale Manager is a global system responsible for handling game scaling events.
*
* @name Phaser.Game#scale
* @type {Phaser.Boot.ScaleManager}
* @since 3.15.0
*/
this.scale = new ScaleManager(this, this.config);
/**
* An instance of the base Sound Manager.
*
@ -317,17 +329,6 @@ var Game = new Class({
*/
this.hasFocus = false;
/**
* Is the mouse pointer currently over the game canvas or not?
* This is modified by the VisibilityHandler.
*
* @name Phaser.Game#isOver
* @type {boolean}
* @readonly
* @since 3.10.0
*/
this.isOver = true;
// Wait for the DOM Ready event, then call boot.
DOMContentLoaded(this.boot.bind(this));
},
@ -363,6 +364,8 @@ var Game = new Class({
this.config.preBoot(this);
this.scale.preBoot();
CreateRenderer(this);
if (typeof EXPERIMENTAL)
@ -729,6 +732,34 @@ var Game = new Class({
this.events.emit('resize', width, height);
},
/**
* Returns the current game frame.
* When the game starts running, the frame is incremented every time Request Animation Frame, or Set Timeout, fires.
*
* @method Phaser.Game#getFrame
* @since 3.16.0
*
* @return {number} The current game frame.
*/
getFrame: function ()
{
return this.loop.frame;
},
/**
* Returns the current game timestamp.
* When the game starts running, the frame is incremented every time Request Animation Frame, or Set Timeout, fires.
*
* @method Phaser.Game#getTime
* @since 3.16.0
*
* @return {number} The current game timestamp.
*/
getTime: function ()
{
return this.loop.frame.time;
},
/**
* Game Destroy event.
*
@ -806,4 +837,8 @@ var Game = new Class({
});
/**
* "Computers are good at following instructions, but not at reading your mind." - Donald Knuth
*/
module.exports = Game;

View file

@ -445,13 +445,11 @@ var TimeStep = new Class({
*
* @method Phaser.Boot.TimeStep#step
* @since 3.0.0
*
*
* @param {number} time - The current time. Either a High Resolution Timer value if it comes from Request Animation Frame, or Date.now if using SetTimeout.
*/
step: function (time)
{
this.frame++;
var before = time - this.lastTime;
if (before < 0)
@ -561,6 +559,8 @@ var TimeStep = new Class({
// Shift time value over
this.lastTime = time;
this.frame++;
},
/**
@ -607,7 +607,7 @@ var TimeStep = new Class({
}
else if (seamless)
{
this.startTime += -this.lastTime + (this.lastTime = window.performance.now());
this.startTime += -this.lastTime + (this.lastTime + window.performance.now());
}
this.raf.start(this.step.bind(this), this.useRAF);

View file

@ -109,26 +109,6 @@ var VisibilityHandler = function (game)
if (window.focus && game.config.autoFocus)
{
window.focus();
game.canvas.addEventListener('mousedown', function ()
{
window.focus();
}, { passive: true });
}
if (game.canvas)
{
game.canvas.onmouseout = function ()
{
game.isOver = false;
eventEmitter.emit('mouseout');
};
game.canvas.onmouseover = function ()
{
game.isOver = true;
eventEmitter.emit('mouseover');
};
}
};

View file

@ -568,7 +568,7 @@ var BaseCamera = new Class({
* @param {number} y - The vertical coordinate to center on.
* @param {Phaser.Math.Vector2} [out] - A Vec2 to store the values in. If not given a new Vec2 is created.
*
* @return {Phaser.Math.Vector2} The scroll coordinates stored in the `x` abd `y` properties.
* @return {Phaser.Math.Vector2} The scroll coordinates stored in the `x` and `y` properties.
*/
getScroll: function (x, y, out)
{
@ -589,6 +589,60 @@ var BaseCamera = new Class({
return out;
},
/**
* Moves the Camera horizontally so that it is centered on the given x coordinate, bounds allowing.
* Calling this does not change the scrollY value.
*
* @method Phaser.Cameras.Scene2D.BaseCamera#centerOnX
* @since 3.16.0
*
* @param {number} x - The horizontal coordinate to center on.
*
* @return {Phaser.Cameras.Scene2D.BaseCamera} This Camera instance.
*/
centerOnX: function (x)
{
var originX = this.width * 0.5;
this.midPoint.x = x;
this.scrollX = x - originX;
if (this.useBounds)
{
this.scrollX = this.clampX(this.scrollX);
}
return this;
},
/**
* Moves the Camera vertically so that it is centered on the given y coordinate, bounds allowing.
* Calling this does not change the scrollX value.
*
* @method Phaser.Cameras.Scene2D.BaseCamera#centerOnY
* @since 3.16.0
*
* @param {number} y - The vertical coordinate to center on.
*
* @return {Phaser.Cameras.Scene2D.BaseCamera} This Camera instance.
*/
centerOnY: function (y)
{
var originY = this.height * 0.5;
this.midPoint.y = y;
this.scrollY = y - originY;
if (this.useBounds)
{
this.scrollY = this.clampY(this.scrollY);
}
return this;
},
/**
* Moves the Camera so that it is centered on the given coordinates, bounds allowing.
*
@ -602,19 +656,8 @@ var BaseCamera = new Class({
*/
centerOn: function (x, y)
{
var originX = this.width * 0.5;
var originY = this.height * 0.5;
this.midPoint.set(x, y);
this.scrollX = x - originX;
this.scrollY = y - originY;
if (this.useBounds)
{
this.scrollX = this.clampX(this.scrollX);
this.scrollY = this.clampY(this.scrollY);
}
this.centerOnX(x);
this.centerOnY(y);
return this;
},
@ -727,11 +770,12 @@ var BaseCamera = new Class({
var ty = (objectX * mvb + objectY * mvd + mvf);
var tw = ((objectX + objectW) * mva + (objectY + objectH) * mvc + mve);
var th = ((objectX + objectW) * mvb + (objectY + objectH) * mvd + mvf);
var cullW = cameraW + objectW;
var cullH = cameraH + objectH;
var cullTop = this.y;
var cullBottom = cullTop + cameraH;
var cullLeft = this.x;
var cullRight = cullLeft + cameraW;
if (tx > -objectW && ty > -objectH && tx < cullW && ty < cullH &&
tw > -objectW && th > -objectH && tw < cullW && th < cullH)
if ((tw > cullLeft && tx < cullRight) && (th > cullTop && ty < cullBottom))
{
culledObjects.push(object);
}
@ -1078,12 +1122,14 @@ var BaseCamera = new Class({
* @param {integer} y - The top-left y coordinate of the bounds.
* @param {integer} width - The width of the bounds, in pixels.
* @param {integer} height - The height of the bounds, in pixels.
* @param {boolean} [centerOn] - If `true` the Camera will automatically be centered on the new bounds.
* @param {boolean} [centerOn=false] - If `true` the Camera will automatically be centered on the new bounds.
*
* @return {Phaser.Cameras.Scene2D.BaseCamera} This Camera instance.
*/
setBounds: function (x, y, width, height, centerOn)
{
if (centerOn === undefined) { centerOn = false; }
this._bounds.setTo(x, y, width, height);
this.dirty = true;
@ -1102,6 +1148,31 @@ var BaseCamera = new Class({
return this;
},
/**
* Returns a rectangle containing the bounds of the Camera.
*
* If the Camera does not have any bounds the rectangle will be empty.
*
* The rectangle is a copy of the bounds, so is safe to modify.
*
* @method Phaser.Cameras.Scene2D.BaseCamera#getBounds
* @since 3.16.0
*
* @param {Phaser.Geom.Rectangle} [out] - An optional Rectangle to store the bounds in. If not given, a new Rectangle will be created.
*
* @return {Phaser.Geom.Rectangle} A rectangle containing the bounds of this Camera.
*/
getBounds: function (out)
{
if (out === undefined) { out = new Rectangle(); }
var source = this._bounds;
out.setTo(source.x, source.y, source.width, source.height);
return out;
},
/**
* Sets the name of this Camera.
* This value is for your own use and isn't used internally.
@ -1700,7 +1771,7 @@ var BaseCamera = new Class({
},
/**
* The x position of the center of the Camera's viewport, relative to the top-left of the game canvas.
* The horizontal position of the center of the Camera's viewport, relative to the left of the game canvas.
*
* @name Phaser.Cameras.Scene2D.BaseCamera#centerX
* @type {number}
@ -1717,7 +1788,7 @@ var BaseCamera = new Class({
},
/**
* The y position of the center of the Camera's viewport, relative to the top-left of the game canvas.
* The vertical position of the center of the Camera's viewport, relative to the top of the game canvas.
*
* @name Phaser.Cameras.Scene2D.BaseCamera#centerY
* @type {number}

View file

@ -222,7 +222,7 @@ var CameraManager = new Class({
* By default Cameras are transparent and will render anything that they can see based on their `scrollX`
* and `scrollY` values. Game Objects can be set to be ignored by a Camera by using the `Camera.ignore` method.
*
* The Camera will have its `roundPixels` propery set to whatever `CameraManager.roundPixels` is. You can change
* The Camera will have its `roundPixels` property set to whatever `CameraManager.roundPixels` is. You can change
* it after creation if required.
*
* See the Camera class documentation for more details.
@ -271,7 +271,7 @@ var CameraManager = new Class({
*
* The Camera should either be a `Phaser.Cameras.Scene2D.Camera` instance, or a class that extends from it.
*
* The Camera will have its `roundPixels` propery set to whatever `CameraManager.roundPixels` is. You can change
* The Camera will have its `roundPixels` property set to whatever `CameraManager.roundPixels` is. You can change
* it after addition if required.
*
* The Camera will be assigned an ID, which is used for Game Object exclusion and then added to the

View file

@ -270,8 +270,8 @@ var Shake = new Class({
if (this.camera.roundPixels)
{
this._offsetX |= 0;
this._offsetY |= 0;
this._offsetX = Math.round(this._offsetX);
this._offsetY = Math.round(this._offsetY);
}
}
else

View file

@ -7,13 +7,6 @@
var Class = require('../../utils/Class');
var GetValue = require('../../utils/object/GetValue');
// var camControl = new CameraControl({
// camera: this.cameras.main,
// left: cursors.left,
// right: cursors.right,
// speed: float OR { x: 0, y: 0 }
// })
/**
* @typedef {object} FixedKeyControlConfig
*
@ -30,14 +23,29 @@ var GetValue = require('../../utils/object/GetValue');
/**
* @classdesc
* [description]
* A Fixed Key Camera Control.
*
* This allows you to control the movement and zoom of a camera using the defined keys.
*
* ```javascript
* var camControl = new FixedKeyControl({
* camera: this.cameras.main,
* left: cursors.left,
* right: cursors.right,
* speed: float OR { x: 0, y: 0 }
* });
* ```
*
* Movement is precise and has no 'smoothing' applied to it.
*
* You must call the `update` method of this controller every frame.
*
* @class FixedKeyControl
* @memberof Phaser.Cameras.Controls
* @constructor
* @since 3.0.0
*
* @param {FixedKeyControlConfig} config - [description]
* @param {FixedKeyControlConfig} config - The Fixed Key Control configuration object.
*/
var FixedKeyControl = new Class({
@ -159,7 +167,7 @@ var FixedKeyControl = new Class({
}
/**
* [description]
* Internal property to track the current zoom level.
*
* @name Phaser.Cameras.Controls.FixedKeyControl#_zoom
* @type {number}
@ -227,7 +235,9 @@ var FixedKeyControl = new Class({
},
/**
* [description]
* Applies the results of pressing the control keys to the Camera.
*
* You must call this every step, it is not called automatically.
*
* @method Phaser.Cameras.Controls.FixedKeyControl#update
* @since 3.0.0

View file

@ -7,20 +7,6 @@
var Class = require('../../utils/Class');
var GetValue = require('../../utils/object/GetValue');
// var controlConfig = {
// camera: this.cameras.main,
// left: cursors.left,
// right: cursors.right,
// up: cursors.up,
// down: cursors.down,
// zoomIn: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q),
// zoomOut: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E),
// zoomSpeed: 0.02,
// acceleration: 0.06,
// drag: 0.0005,
// maxSpeed: 1.0
// };
/**
* @typedef {object} SmoothedKeyControlConfig
*
@ -38,14 +24,36 @@ var GetValue = require('../../utils/object/GetValue');
/**
* @classdesc
* [description]
* A Smoothed Key Camera Control.
*
* This allows you to control the movement and zoom of a camera using the defined keys.
* Unlike the Fixed Camera Control you can also provide physics values for acceleration, drag and maxSpeed for smoothing effects.
*
* ```javascript
*
* var controlConfig = {
* camera: this.cameras.main,
* left: cursors.left,
* right: cursors.right,
* up: cursors.up,
* down: cursors.down,
* zoomIn: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q),
* zoomOut: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E),
* zoomSpeed: 0.02,
* acceleration: 0.06,
* drag: 0.0005,
* maxSpeed: 1.0
* };
* ```
*
* You must call the `update` method of this controller every frame.
*
* @class SmoothedKeyControl
* @memberof Phaser.Cameras.Controls
* @constructor
* @since 3.0.0
*
* @param {SmoothedKeyControlConfig} config - [description]
* @param {SmoothedKeyControlConfig} config - The Smoothed Key Control configuration object.
*/
var SmoothedKeyControl = new Class({
@ -233,7 +241,7 @@ var SmoothedKeyControl = new Class({
}
/**
* [description]
* Internal property to track the speed of the control.
*
* @name Phaser.Cameras.Controls.SmoothedKeyControl#_speedX
* @type {number}
@ -244,7 +252,7 @@ var SmoothedKeyControl = new Class({
this._speedX = 0;
/**
* [description]
* Internal property to track the speed of the control.
*
* @name Phaser.Cameras.Controls.SmoothedKeyControl#_speedY
* @type {number}
@ -255,7 +263,7 @@ var SmoothedKeyControl = new Class({
this._speedY = 0;
/**
* [description]
* Internal property to track the zoom of the control.
*
* @name Phaser.Cameras.Controls.SmoothedKeyControl#_zoom
* @type {number}
@ -323,12 +331,14 @@ var SmoothedKeyControl = new Class({
},
/**
* [description]
* Applies the results of pressing the control keys to the Camera.
*
* You must call this every step, it is not called automatically.
*
* @method Phaser.Cameras.Controls.SmoothedKeyControl#update
* @since 3.0.0
*
* @param {number} delta - The delta time, in ms, elapsed since the last frame.
* @param {number} delta - The delta time in ms since the last frame. This is a smoothed and capped value based on the FPS rate.
*/
update: function (delta)
{

View file

@ -20,7 +20,7 @@ var CONST = {
* @type {string}
* @since 3.0.0
*/
VERSION: '3.15.1',
VERSION: '3.16.0 Beta 4',
BlendModes: require('./renderer/BlendModes'),

View file

@ -16,7 +16,7 @@ var tmpVec2 = new Vector2();
/**
* @classdesc
* [description]
* A LineCurve is a "curve" comprising exactly two points (a line segment).
*
* @class Line
* @extends Phaser.Curves.Curve
@ -24,8 +24,8 @@ var tmpVec2 = new Vector2();
* @constructor
* @since 3.0.0
*
* @param {(Phaser.Math.Vector2|number[])} p0 - [description]
* @param {Phaser.Math.Vector2} [p1] - [description]
* @param {(Phaser.Math.Vector2|number[])} p0 - The first endpoint.
* @param {Phaser.Math.Vector2} [p1] - The second endpoint.
*/
var LineCurve = new Class({
@ -45,7 +45,7 @@ var LineCurve = new Class({
}
/**
* [description]
* The first endpoint.
*
* @name Phaser.Curves.Line#p0
* @type {Phaser.Math.Vector2}
@ -54,7 +54,7 @@ var LineCurve = new Class({
this.p0 = p0;
/**
* [description]
* The second endpoint.
*
* @name Phaser.Curves.Line#p1
* @type {Phaser.Math.Vector2}
@ -102,14 +102,14 @@ var LineCurve = new Class({
},
/**
* [description]
* Gets the resolution of the line.
*
* @method Phaser.Curves.Line#getResolution
* @since 3.0.0
*
* @param {number} [divisions=1] - [description]
* @param {number} [divisions=1] - The number of divisions to consider.
*
* @return {number} [description]
* @return {number} The resolution. Equal to the number of divisions.
*/
getResolution: function (divisions)
{
@ -148,7 +148,7 @@ var LineCurve = new Class({
// Line curve is linear, so we can overwrite default getPointAt
/**
* [description]
* Gets a point at a given position on the line.
*
* @method Phaser.Curves.Line#getPointAt
* @since 3.0.0
@ -166,14 +166,14 @@ var LineCurve = new Class({
},
/**
* [description]
* Gets the slope of the line as a unit vector.
*
* @method Phaser.Curves.Line#getTangent
* @since 3.0.0
*
* @generic {Phaser.Math.Vector2} O - [out,$return]
*
* @return {Phaser.Math.Vector2} [description]
* @return {Phaser.Math.Vector2} The tangent vector.
*/
getTangent: function ()
{
@ -208,7 +208,7 @@ var LineCurve = new Class({
},
/**
* [description]
* Gets a JSON representation of the line.
*
* @method Phaser.Curves.Line#toJSON
* @since 3.0.0
@ -229,14 +229,14 @@ var LineCurve = new Class({
});
/**
* [description]
* Configures this line from a JSON representation.
*
* @function Phaser.Curves.Line.fromJSON
* @since 3.0.0
*
* @param {JSONCurve} data - The JSON object containing this curve data.
*
* @return {Phaser.Curves.Line} [description]
* @return {Phaser.Curves.Line} A new LineCurve object.
*/
LineCurve.fromJSON = function (data)
{

View file

@ -9,15 +9,15 @@ var Vector2 = require('../../math/Vector2');
/**
* @classdesc
* [description]
* A MoveTo Curve is a very simple curve consisting of only a single point. Its intended use is to move the ending point in a Path.
*
* @class MoveTo
* @memberof Phaser.Curves
* @constructor
* @since 3.0.0
*
* @param {number} [x] - [description]
* @param {number} [y] - [description]
* @param {number} [x] - `x` pixel coordinate.
* @param {number} [y] - `y` pixel coordinate.
*/
var MoveTo = new Class({
@ -28,7 +28,7 @@ var MoveTo = new Class({
// Skip length calcs in paths
/**
* [description]
* Denotes that this Curve does not influence the bounds, points, and drawing of its parent Path. Must be `false` or some methods in the parent Path will throw errors.
*
* @name Phaser.Curves.MoveTo#active
* @type {boolean}
@ -38,7 +38,7 @@ var MoveTo = new Class({
this.active = false;
/**
* [description]
* The lone point which this curve consists of.
*
* @name Phaser.Curves.MoveTo#p0
* @type {Phaser.Math.Vector2}
@ -68,17 +68,17 @@ var MoveTo = new Class({
},
/**
* [description]
* Retrieves the point at given position in the curve. This will always return this curve's only point.
*
* @method Phaser.Curves.MoveTo#getPointAt
* @since 3.0.0
*
* @generic {Phaser.Math.Vector2} O - [out,$return]
*
* @param {number} u - [description]
* @param {Phaser.Math.Vector2} [out] - [description]
* @param {number} u - The position in the path to retrieve, between 0 and 1. Not used.
* @param {Phaser.Math.Vector2} [out] - An optional vector in which to store the point.
*
* @return {Phaser.Math.Vector2} [description]
* @return {Phaser.Math.Vector2} The modified `out` vector, or a new `Vector2` if none was provided.
*/
getPointAt: function (u, out)
{
@ -112,12 +112,12 @@ var MoveTo = new Class({
},
/**
* [description]
* Converts this curve into a JSON-serializable object.
*
* @method Phaser.Curves.MoveTo#toJSON
* @since 3.0.0
*
* @return {JSONCurve} [description]
* @return {JSONCurve} A primitive object with the curve's type and only point.
*/
toJSON: function ()
{

View file

@ -21,23 +21,25 @@ var Vector2 = require('../../math/Vector2');
* @typedef {object} JSONPath
*
* @property {string} type - The of the curve.
* @property {number} x - [description]
* @property {number} y - [description]
* @property {number} x - The X coordinate of the curve's starting point.
* @property {number} y - The Y coordinate of the path's starting point.
* @property {boolean} autoClose - The path is auto closed.
* @property {JSONCurve[]} curves - The list of the curves
*/
/**
* @classdesc
* [description]
* A Path combines multiple Curves into one continuous compound curve. It does not matter how many Curves are in the Path or what type they are.
*
* A Curve in a Path does not have to start where the previous Curve ends - that is to say, a Path does not have to be an uninterrupted curve. Only the order of the Curves influences the actual points on the Path.
*
* @class Path
* @memberof Phaser.Curves
* @constructor
* @since 3.0.0
*
* @param {number} [x=0] - [description]
* @param {number} [y=0] - [description]
* @param {number} [x=0] - The X coordinate of the Path's starting point or a {@link JSONPath}.
* @param {number} [y=0] - The Y coordinate of the Path's starting point.
*/
var Path = new Class({
@ -49,7 +51,8 @@ var Path = new Class({
if (y === undefined) { y = 0; }
/**
* [description]
* The name of this Path.
* Empty by default and never populated by Phaser, this is left for developers to use.
*
* @name Phaser.Curves.Path#name
* @type {string}
@ -59,7 +62,7 @@ var Path = new Class({
this.name = '';
/**
* [description]
* The list of Curves which make up this Path.
*
* @name Phaser.Curves.Path#curves
* @type {Phaser.Curves.Curve[]}
@ -69,7 +72,9 @@ var Path = new Class({
this.curves = [];
/**
* [description]
* The cached length of each Curve in the Path.
*
* Used internally by {@link #getCurveLengths}.
*
* @name Phaser.Curves.Path#cacheLengths
* @type {number[]}
@ -89,7 +94,9 @@ var Path = new Class({
this.autoClose = false;
/**
* [description]
* The starting point of the Path.
*
* This is not necessarily equivalent to the starting point of the first Curve in the Path. In an empty Path, it's also treated as the ending point.
*
* @name Phaser.Curves.Path#startPoint
* @type {Phaser.Math.Vector2}
@ -98,7 +105,7 @@ var Path = new Class({
this.startPoint = new Vector2();
/**
* [description]
* A temporary vector used to avoid object creation when adding a Curve to the Path.
*
* @name Phaser.Curves.Path#_tmpVec2A
* @type {Phaser.Math.Vector2}
@ -108,7 +115,7 @@ var Path = new Class({
this._tmpVec2A = new Vector2();
/**
* [description]
* A temporary vector used to avoid object creation when adding a Curve to the Path.
*
* @name Phaser.Curves.Path#_tmpVec2B
* @type {Phaser.Math.Vector2}
@ -128,14 +135,16 @@ var Path = new Class({
},
/**
* [description]
* Appends a Curve to the end of the Path.
*
* The Curve does not have to start where the Path ends or, for an empty Path, at its defined starting point.
*
* @method Phaser.Curves.Path#add
* @since 3.0.0
*
* @param {Phaser.Curves.Curve} curve - [description]
* @param {Phaser.Curves.Curve} curve - The Curve to append.
*
* @return {Phaser.Curves.Path} [description]
* @return {Phaser.Curves.Path} This Path object.
*/
add: function (curve)
{
@ -145,16 +154,16 @@ var Path = new Class({
},
/**
* [description]
* Creates a circular Ellipse Curve positioned at the end of the Path.
*
* @method Phaser.Curves.Path#circleTo
* @since 3.0.0
*
* @param {number} radius - [description]
* @param {boolean} [clockwise=false] - [description]
* @param {number} [rotation=0] - [description]
* @param {number} radius - The radius of the circle.
* @param {boolean} [clockwise=false] - `true` to create a clockwise circle as opposed to a counter-clockwise circle.
* @param {number} [rotation=0] - The rotation of the circle in degrees.
*
* @return {Phaser.Curves.Path} [description]
* @return {Phaser.Curves.Path} This Path object.
*/
circleTo: function (radius, clockwise, rotation)
{
@ -164,12 +173,16 @@ var Path = new Class({
},
/**
* [description]
* Ensures that the Path is closed.
*
* A closed Path starts and ends at the same point. If the Path is not closed, a straight Line Curve will be created from the ending point directly to the starting point. During the check, the actual starting point of the Path, i.e. the starting point of the first Curve, will be used as opposed to the Path's defined {@link startPoint}, which could differ.
*
* Calling this method on an empty Path will result in an error.
*
* @method Phaser.Curves.Path#closePath
* @since 3.0.0
*
* @return {Phaser.Curves.Path} [description]
* @return {Phaser.Curves.Path} This Path object.
*/
closePath: function ()
{
@ -199,7 +212,7 @@ var Path = new Class({
* @param {number} [control2X] - The x coordinate of the second control point. Not used if vec2s are provided as the first 3 arguments.
* @param {number} [control2Y] - The y coordinate of the second control point. Not used if vec2s are provided as the first 3 arguments.
*
* @return {Phaser.Curves.Path} [description]
* @return {Phaser.Curves.Path} This Path object.
*/
cubicBezierTo: function (x, y, control1X, control1Y, control2X, control2Y)
{
@ -228,17 +241,17 @@ var Path = new Class({
// Creates a quadratic bezier curve starting at the previous end point and ending at p2, using p1 as a control point
/**
* [description]
* Creates a Quadratic Bezier Curve starting at the ending point of the Path.
*
* @method Phaser.Curves.Path#quadraticBezierTo
* @since 3.2.0
*
* @param {(number|Phaser.Math.Vector2[])} x - [description]
* @param {number} [y] - [description]
* @param {number} [controlX] - [description]
* @param {number} [controlY] - [description]
* @param {(number|Phaser.Math.Vector2[])} x - The X coordinate of the second control point or, if it's a `Vector2`, the first control point.
* @param {number} [y] - The Y coordinate of the second control point or, if `x` is a `Vector2`, the second control point.
* @param {number} [controlX] - If `x` is not a `Vector2`, the X coordinate of the first control point.
* @param {number} [controlY] - If `x` is not a `Vector2`, the Y coordinate of the first control point.
*
* @return {Phaser.Curves.Path} [description]
* @return {Phaser.Curves.Path} This Path object.
*/
quadraticBezierTo: function (x, y, controlX, controlY)
{
@ -262,17 +275,17 @@ var Path = new Class({
},
/**
* [description]
* Draws all Curves in the Path to a Graphics Game Object.
*
* @method Phaser.Curves.Path#draw
* @since 3.0.0
*
* @generic {Phaser.GameObjects.Graphics} G - [out,$return]
*
* @param {Phaser.GameObjects.Graphics} graphics - [description]
* @param {integer} [pointsTotal=32] - [description]
* @param {Phaser.GameObjects.Graphics} graphics - The Graphics Game Object to draw to.
* @param {integer} [pointsTotal=32] - The number of points to draw for each Curve. Higher numbers result in a smoother curve but require more processing.
*
* @return {Phaser.GameObjects.Graphics} [description]
* @return {Phaser.GameObjects.Graphics} The Graphics object which was drawn to.
*/
draw: function (graphics, pointsTotal)
{
@ -297,14 +310,14 @@ var Path = new Class({
* @method Phaser.Curves.Path#ellipseTo
* @since 3.0.0
*
* @param {number} xRadius - [description]
* @param {number} yRadius - [description]
* @param {number} startAngle - [description]
* @param {number} endAngle - [description]
* @param {boolean} clockwise - [description]
* @param {number} rotation - [description]
* @param {number} xRadius - The horizontal radius of the ellipse.
* @param {number} yRadius - The vertical radius of the ellipse.
* @param {number} startAngle - The start angle of the ellipse, in degrees.
* @param {number} endAngle - The end angle of the ellipse, in degrees.
* @param {boolean} clockwise - Whether the ellipse should be rotated clockwise (`true`) or counter-clockwise (`false`).
* @param {number} rotation - The rotation of the ellipse, in degrees.
*
* @return {Phaser.Curves.Path} [description]
* @return {Phaser.Curves.Path} This Path object.
*/
ellipseTo: function (xRadius, yRadius, startAngle, endAngle, clockwise, rotation)
{
@ -324,14 +337,16 @@ var Path = new Class({
},
/**
* [description]
* Creates a Path from a Path Configuration object.
*
* The provided object should be a {@link JSONPath}, as returned by {@link #toJSON}. Providing a malformed object may cause errors.
*
* @method Phaser.Curves.Path#fromJSON
* @since 3.0.0
*
* @param {object} data - [description]
* @param {object} data - The JSON object containing the Path data.
*
* @return {Phaser.Curves.Path} [description]
* @return {Phaser.Curves.Path} This Path object.
*/
fromJSON: function (data)
{
@ -376,17 +391,17 @@ var Path = new Class({
},
/**
* [description]
* Returns a Rectangle with a position and size matching the bounds of this Path.
*
* @method Phaser.Curves.Path#getBounds
* @since 3.0.0
*
* @generic {Phaser.Math.Vector2} O - [out,$return]
*
* @param {Phaser.Geom.Rectangle} [out] - [description]
* @param {integer} [accuracy=16] - [description]
* @param {Phaser.Geom.Rectangle} [out] - The Rectangle to store the bounds in.
* @param {integer} [accuracy=16] - The accuracy of the bounds calculations. Higher values are more accurate at the cost of calculation speed.
*
* @return {Phaser.Geom.Rectangle} [description]
* @return {Phaser.Geom.Rectangle} The modified `out` Rectangle, or a new Rectangle if none was provided.
*/
getBounds: function (out, accuracy)
{
@ -425,12 +440,14 @@ var Path = new Class({
},
/**
* [description]
* Returns an array containing the length of the Path at the end of each Curve.
*
* The result of this method will be cached to avoid recalculating it in subsequent calls. The cache is only invalidated when the {@link #curves} array changes in length, leading to potential inaccuracies if a Curve in the Path is changed, or if a Curve is removed and another is added in its place.
*
* @method Phaser.Curves.Path#getCurveLengths
* @since 3.0.0
*
* @return {number[]} [description]
* @return {number[]} An array containing the length of the Path at the end of each one of its Curves.
*/
getCurveLengths: function ()
{
@ -460,16 +477,18 @@ var Path = new Class({
},
/**
* [description]
* Returns the ending point of the Path.
*
* A Path's ending point is equivalent to the ending point of the last Curve in the Path. For an empty Path, the ending point is at the Path's defined {@link #startPoint}.
*
* @method Phaser.Curves.Path#getEndPoint
* @since 3.0.0
*
* @generic {Phaser.Math.Vector2} O - [out,$return]
*
* @param {Phaser.Math.Vector2} [out] - [description]
* @param {Phaser.Math.Vector2} [out] - The object to store the point in.
*
* @return {Phaser.Math.Vector2} [description]
* @return {Phaser.Math.Vector2} The modified `out` object, or a new Vector2 if none was provided.
*/
getEndPoint: function (out)
{
@ -488,12 +507,14 @@ var Path = new Class({
},
/**
* [description]
* Returns the total length of the Path.
*
* @see {@link #getCurveLengths}
*
* @method Phaser.Curves.Path#getLength
* @since 3.0.0
*
* @return {number} [description]
* @return {number} The total length of the Path.
*/
getLength: function ()
{
@ -512,17 +533,19 @@ var Path = new Class({
// 4. Return curve.getPointAt(t')
/**
* [description]
* Calculates the coordinates of the point at the given normalized location (between 0 and 1) on the Path.
*
* The location is relative to the entire Path, not to an individual Curve. A location of 0.5 is always in the middle of the Path and is thus an equal distance away from both its starting and ending points. In a Path with one Curve, it would be in the middle of the Curve; in a Path with two Curves, it could be anywhere on either one of them depending on their lengths.
*
* @method Phaser.Curves.Path#getPoint
* @since 3.0.0
*
* @generic {Phaser.Math.Vector2} O - [out,$return]
*
* @param {number} t - [description]
* @param {Phaser.Math.Vector2} [out] - [description]
* @param {number} t - The location of the point to return, between 0 and 1.
* @param {Phaser.Math.Vector2} [out] - The object in which to store the calculated point.
*
* @return {?Phaser.Math.Vector2} [description]
* @return {?Phaser.Math.Vector2} The modified `out` object, or a new `Vector2` if none was provided.
*/
getPoint: function (t, out)
{
@ -553,7 +576,9 @@ var Path = new Class({
},
/**
* [description]
* Returns the defined starting point of the Path.
*
* This is not necessarily equal to the starting point of the first Curve if it differs from {@link startPoint}.
*
* @method Phaser.Curves.Path#getPoints
* @since 3.0.0
@ -626,12 +651,12 @@ var Path = new Class({
},
/**
* [description]
* Creates a straight Line Curve from the ending point of the Path to the given coordinates.
*
* @method Phaser.Curves.Path#getSpacedPoints
* @since 3.0.0
*
* @param {integer} [divisions=40] - [description]
* @param {integer} [divisions=40] - The X coordinate of the line's ending point, or the line's ending point as a `Vector2`.
*
* @return {Phaser.Math.Vector2[]} [description]
*/

View file

@ -38,7 +38,7 @@ var CanvasPool = function ()
* @param {integer} [canvasType=Phaser.CANVAS] - The type of the Canvas. Either `Phaser.CANVAS` or `Phaser.WEBGL`.
* @param {boolean} [selfParent=false] - Use the generated Canvas element as the parent?
*
* @return {HTMLCanvasElement} [description]
* @return {HTMLCanvasElement} The canvas element that was created or pulled from the pool
*/
var create = function (parent, width, height, canvasType, selfParent)
{
@ -98,7 +98,7 @@ var CanvasPool = function ()
* @param {integer} [width=1] - The width of the Canvas.
* @param {integer} [height=1] - The height of the Canvas.
*
* @return {HTMLCanvasElement} [description]
* @return {HTMLCanvasElement} The created canvas.
*/
var create2D = function (parent, width, height)
{
@ -115,7 +115,7 @@ var CanvasPool = function ()
* @param {integer} [width=1] - The width of the Canvas.
* @param {integer} [height=1] - The height of the Canvas.
*
* @return {HTMLCanvasElement} [description]
* @return {HTMLCanvasElement} The created WebGL canvas.
*/
var createWebGL = function (parent, width, height)
{
@ -130,7 +130,7 @@ var CanvasPool = function ()
*
* @param {integer} [canvasType=Phaser.CANVAS] - The type of the Canvas. Either `Phaser.CANVAS` or `Phaser.WEBGL`.
*
* @return {HTMLCanvasElement} [description]
* @return {HTMLCanvasElement} The first free canvas, or `null` if a WebGL canvas was requested or if the pool doesn't have free canvases.
*/
var first = function (canvasType)
{
@ -161,7 +161,7 @@ var CanvasPool = function ()
* @function Phaser.Display.Canvas.CanvasPool.remove
* @since 3.0.0
*
* @param {*} parent - [description]
* @param {*} parent - The canvas or the parent of the canvas to free.
*/
var remove = function (parent)
{
@ -185,7 +185,7 @@ var CanvasPool = function ()
* @function Phaser.Display.Canvas.CanvasPool.total
* @since 3.0.0
*
* @return {integer} [description]
* @return {integer} The number of used canvases.
*/
var total = function ()
{
@ -208,7 +208,7 @@ var CanvasPool = function ()
* @function Phaser.Display.Canvas.CanvasPool.free
* @since 3.0.0
*
* @return {integer} [description]
* @return {integer} The number of free canvases.
*/
var free = function ()
{

View file

@ -19,9 +19,9 @@ var Smoothing = function ()
* @function Phaser.Display.Canvas.Smoothing.getPrefix
* @since 3.0.0
*
* @param {(CanvasRenderingContext2D|WebGLRenderingContext)} context - [description]
* @param {(CanvasRenderingContext2D|WebGLRenderingContext)} context - The canvas context to check.
*
* @return {string} [description]
* @return {string} The name of the property on the context which controls image smoothing (either `imageSmoothingEnabled` or a vendor-prefixed version thereof), or `null` if not supported.
*/
var getPrefix = function (context)
{
@ -50,9 +50,9 @@ var Smoothing = function ()
* @function Phaser.Display.Canvas.Smoothing.enable
* @since 3.0.0
*
* @param {(CanvasRenderingContext2D|WebGLRenderingContext)} context - [description]
* @param {(CanvasRenderingContext2D|WebGLRenderingContext)} context - The context on which to enable smoothing.
*
* @return {(CanvasRenderingContext2D|WebGLRenderingContext)} [description]
* @return {(CanvasRenderingContext2D|WebGLRenderingContext)} The provided context.
*/
var enable = function (context)
{
@ -79,9 +79,9 @@ var Smoothing = function ()
* @function Phaser.Display.Canvas.Smoothing.disable
* @since 3.0.0
*
* @param {(CanvasRenderingContext2D|WebGLRenderingContext)} context - [description]
* @param {(CanvasRenderingContext2D|WebGLRenderingContext)} context - The context on which to disable smoothing.
*
* @return {(CanvasRenderingContext2D|WebGLRenderingContext)} [description]
* @return {(CanvasRenderingContext2D|WebGLRenderingContext)} The provided context.
*/
var disable = function (context)
{
@ -105,9 +105,9 @@ var Smoothing = function ()
* @function Phaser.Display.Canvas.Smoothing.isEnabled
* @since 3.0.0
*
* @param {(CanvasRenderingContext2D|WebGLRenderingContext)} context - [description]
* @param {(CanvasRenderingContext2D|WebGLRenderingContext)} context - The context to check.
*
* @return {?boolean} [description]
* @return {?boolean} `true` if smoothing is enabled on the context, otherwise `false`. `null` if not supported.
*/
var isEnabled = function (context)
{

View file

@ -8,14 +8,22 @@ var Class = require('../../utils/Class');
/**
* @classdesc
* [description]
* A Bitmap Mask combines the alpha (opacity) of a masked pixel with the alpha of another pixel. Unlike the Geometry Mask, which is a clipping path, a Bitmask Mask behaves like an alpha mask, not a clipping path. It is only available when using the WebGL Renderer.
*
* A Bitmap Mask can use any Game Object to determine the alpha of each pixel of the masked Game Object(s). For any given point of a masked Game Object's texture, the pixel's alpha will be multiplied by the alpha of the pixel at the same position in the Bitmap Mask's Game Object. The color of the pixel from the Bitmap Mask doesn't matter.
*
* For example, if a pure blue pixel with an alpha of 0.95 is masked with a pure red pixel with an alpha of 0.5, the resulting pixel will be pure blue with an alpha of 0.475. Naturally, this means that a pixel in the mask with an alpha of 0 will hide the corresponding pixel in all masked Game Objects. A pixel with an alpha of 1 in the masked Game Object will receive the same alpha as the corresponding pixel in the mask.
*
* The Bitmap Mask's location matches the location of its Game Object, not the location of the masked objects. Moving or transforming the underlying Game Object will change the mask (and affect the visibility of any masked objects), whereas moving or transforming a masked object will not affect the mask.
*
* The Bitmap Mask will not render its Game Object by itself. If the Game Object is not in a Scene's display list, it will only be used for the mask and its full texture will not be directly visible. Adding the underlying Game Object to a Scene will not cause any problems - it will render as a normal Game Object and will also serve as a mask.
*
* @class BitmapMask
* @memberof Phaser.Display.Masks
* @constructor
* @since 3.0.0
*
* @param {Phaser.Scene} scene - [description]
* @param {Phaser.Scene} scene - The Scene which this Bitmap Mask will be used in.
* @param {Phaser.GameObjects.GameObject} renderable - A renderable Game Object that uses a texture, such as a Sprite.
*/
var BitmapMask = new Class({
@ -45,7 +53,7 @@ var BitmapMask = new Class({
this.bitmapMask = renderable;
/**
* [description]
* The texture used for the mask's framebuffer.
*
* @name Phaser.Display.Masks.BitmapMask#maskTexture
* @type {WebGLTexture}
@ -55,7 +63,7 @@ var BitmapMask = new Class({
this.maskTexture = null;
/**
* [description]
* The texture used for the main framebuffer.
*
* @name Phaser.Display.Masks.BitmapMask#mainTexture
* @type {WebGLTexture}
@ -65,7 +73,7 @@ var BitmapMask = new Class({
this.mainTexture = null;
/**
* [description]
* Whether the Bitmap Mask is dirty and needs to be updated.
*
* @name Phaser.Display.Masks.BitmapMask#dirty
* @type {boolean}
@ -75,7 +83,7 @@ var BitmapMask = new Class({
this.dirty = true;
/**
* [description]
* The framebuffer to which a masked Game Object is rendered.
*
* @name Phaser.Display.Masks.BitmapMask#mainFramebuffer
* @type {WebGLFramebuffer}
@ -84,7 +92,7 @@ var BitmapMask = new Class({
this.mainFramebuffer = null;
/**
* [description]
* The framebuffer to which the Bitmap Mask's masking Game Object is rendered.
*
* @name Phaser.Display.Masks.BitmapMask#maskFramebuffer
* @type {WebGLFramebuffer}
@ -93,7 +101,9 @@ var BitmapMask = new Class({
this.maskFramebuffer = null;
/**
* [description]
* Whether to invert the mask's alpha.
*
* If `true`, the alpha of the masking pixel will be inverted before it's multiplied with the masked pixel. Essentially, this means that a masked area will be visible only if the corresponding area in the mask is invisible.
*
* @name Phaser.Display.Masks.BitmapMask#invertAlpha
* @type {boolean}
@ -134,7 +144,7 @@ var BitmapMask = new Class({
},
/**
* [description]
* Sets a new masking Game Object for the Bitmap Mask.
*
* @method Phaser.Display.Masks.BitmapMask#setBitmap
* @since 3.0.0
@ -147,13 +157,15 @@ var BitmapMask = new Class({
},
/**
* [description]
* Prepares the WebGL Renderer to render a Game Object with this mask applied.
*
* This renders the masking Game Object to the mask framebuffer and switches to the main framebuffer so that the masked Game Object will be rendered to it instead of being rendered directly to the frame.
*
* @method Phaser.Display.Masks.BitmapMask#preRenderWebGL
* @since 3.0.0
*
* @param {(Phaser.Renderer.Canvas.CanvasRenderer|Phaser.Renderer.WebGL.WebGLRenderer)} renderer - [description]
* @param {Phaser.GameObjects.GameObject} maskedObject - [description]
* @param {(Phaser.Renderer.Canvas.CanvasRenderer|Phaser.Renderer.WebGL.WebGLRenderer)} renderer - The WebGL Renderer to prepare.
* @param {Phaser.GameObjects.GameObject} maskedObject - The masked Game Object which will be drawn.
* @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera to render to.
*/
preRenderWebGL: function (renderer, maskedObject, camera)
@ -162,12 +174,14 @@ var BitmapMask = new Class({
},
/**
* [description]
* Finalizes rendering of a masked Game Object.
*
* This resets the previously bound framebuffer and switches the WebGL Renderer to the Bitmap Mask Pipeline, which uses a special fragment shader to apply the masking effect.
*
* @method Phaser.Display.Masks.BitmapMask#postRenderWebGL
* @since 3.0.0
*
* @param {(Phaser.Renderer.Canvas.CanvasRenderer|Phaser.Renderer.WebGL.WebGLRenderer)} renderer - [description]
* @param {(Phaser.Renderer.Canvas.CanvasRenderer|Phaser.Renderer.WebGL.WebGLRenderer)} renderer - The WebGL Renderer to clean up.
*/
postRenderWebGL: function (renderer)
{
@ -175,13 +189,13 @@ var BitmapMask = new Class({
},
/**
* [description]
* This is a NOOP method. Bitmap Masks are not supported by the Canvas Renderer.
*
* @method Phaser.Display.Masks.BitmapMask#preRenderCanvas
* @since 3.0.0
*
* @param {(Phaser.Renderer.Canvas.CanvasRenderer|Phaser.Renderer.WebGL.WebGLRenderer)} renderer - [description]
* @param {Phaser.GameObjects.GameObject} mask - [description]
* @param {(Phaser.Renderer.Canvas.CanvasRenderer|Phaser.Renderer.WebGL.WebGLRenderer)} renderer - The Canvas Renderer which would be rendered to.
* @param {Phaser.GameObjects.GameObject} mask - The masked Game Object which would be rendered.
* @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera to render to.
*/
preRenderCanvas: function ()
@ -190,12 +204,12 @@ var BitmapMask = new Class({
},
/**
* [description]
* This is a NOOP method. Bitmap Masks are not supported by the Canvas Renderer.
*
* @method Phaser.Display.Masks.BitmapMask#postRenderCanvas
* @since 3.0.0
*
* @param {(Phaser.Renderer.Canvas.CanvasRenderer|Phaser.Renderer.WebGL.WebGLRenderer)} renderer - [description]
* @param {(Phaser.Renderer.Canvas.CanvasRenderer|Phaser.Renderer.WebGL.WebGLRenderer)} renderer - The Canvas Renderer which would be rendered to.
*/
postRenderCanvas: function ()
{

26
src/dom/Calibrate.js Normal file
View file

@ -0,0 +1,26 @@
/**
* @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 Calibrate = function (coords, cushion)
{
if (cushion === undefined) { cushion = 0; }
var output = {
width: 0,
height: 0,
left: 0,
right: 0,
top: 0,
bottom: 0
};
output.width = (output.right = coords.right + cushion) - (output.left = coords.left - cushion);
output.height = (output.bottom = coords.bottom + cushion) - (output.top = coords.top - cushion);
return output;
};
module.exports = Calibrate;

12
src/dom/ClientHeight.js Normal file
View file

@ -0,0 +1,12 @@
/**
* @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 ClientHeight = function ()
{
return Math.max(window.innerHeight, document.documentElement.clientHeight);
};
module.exports = ClientHeight;

12
src/dom/ClientWidth.js Normal file
View file

@ -0,0 +1,12 @@
/**
* @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 ClientWidth = function ()
{
return Math.max(window.innerWidth, document.documentElement.clientWidth);
};
module.exports = ClientWidth;

41
src/dom/DocumentBounds.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}
*/
var Class = require('../utils/Class');
var Rectangle = require('../geom/rectangle/Rectangle');
var DocumentBounds = new Class({
Extends: Rectangle,
initialize:
function DocumentBounds ()
{
Rectangle.call(this);
},
width: {
get: function ()
{
var d = document.documentElement;
return Math.max(d.clientWidth, d.offsetWidth, d.scrollWidth);
}
},
height: {
get: function ()
{
var d = document.documentElement;
return Math.max(d.clientHeight, d.offsetHeight, d.scrollHeight);
}
}
});
module.exports = new DocumentBounds();

30
src/dom/GetAspectRatio.js Normal file
View file

@ -0,0 +1,30 @@
/**
* @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 GetBounds = require('./GetBounds');
var VisualBounds = require('./VisualBounds');
var GetAspectRatio = function (object)
{
object = (object === null) ? VisualBounds : (object.nodeType === 1) ? GetBounds(object) : object;
var w = object.width;
var h = object.height;
if (typeof w === 'function')
{
w = w.call(object);
}
if (typeof h === 'function')
{
h = h.call(object);
}
return w / h;
};
module.exports = GetAspectRatio;

25
src/dom/GetBounds.js Normal file
View file

@ -0,0 +1,25 @@
/**
* @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 Calibrate = require('./Calibrate');
var GetBounds = function (element, cushion)
{
if (cushion === undefined) { cushion = 0; }
element = (element && !element.nodeType) ? element[0] : element;
if (!element || element.nodeType !== 1)
{
return false;
}
else
{
return Calibrate(element.getBoundingClientRect(), cushion);
}
};
module.exports = GetBounds;

28
src/dom/GetOffset.js Normal file
View file

@ -0,0 +1,28 @@
/**
* @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 Vec2 = require('../math/Vector2');
var VisualBounds = require('./VisualBounds');
var GetOffset = function (element, point)
{
if (point === undefined) { point = new Vec2(); }
var box = element.getBoundingClientRect();
var scrollTop = VisualBounds.y;
var scrollLeft = VisualBounds.x;
var clientTop = document.documentElement.clientTop;
var clientLeft = document.documentElement.clientLeft;
point.x = box.left + scrollLeft - clientLeft;
point.y = box.top + scrollTop - clientTop;
return point;
};
module.exports = GetOffset;

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 VisualBounds = require('./VisualBounds');
var GetScreenOrientation = function (primaryFallback)
{
var screen = window.screen;
var orientation = screen.orientation || screen.mozOrientation || screen.msOrientation;
if (orientation && typeof orientation.type === 'string')
{
// Screen Orientation API specification
return orientation.type;
}
else if (typeof orientation === 'string')
{
// moz / ms-orientation are strings
return orientation;
}
var PORTRAIT = 'portrait-primary';
var LANDSCAPE = 'landscape-primary';
if (primaryFallback === 'screen')
{
return (screen.height > screen.width) ? PORTRAIT : LANDSCAPE;
}
else if (primaryFallback === 'viewport')
{
return (VisualBounds.height > VisualBounds.width) ? PORTRAIT : LANDSCAPE;
}
else if (primaryFallback === 'window.orientation' && typeof window.orientation === 'number')
{
// This may change by device based on "natural" orientation.
return (window.orientation === 0 || window.orientation === 180) ? PORTRAIT : LANDSCAPE;
}
else if (window.matchMedia)
{
if (window.matchMedia('(orientation: portrait)').matches)
{
return PORTRAIT;
}
else if (window.matchMedia('(orientation: landscape)').matches)
{
return LANDSCAPE;
}
}
return (VisualBounds.height > VisualBounds.width) ? PORTRAIT : LANDSCAPE;
};
module.exports = GetScreenOrientation;

View file

@ -0,0 +1,17 @@
/**
* @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 GetBounds = require('./GetBounds');
var LayoutBounds = require('./LayoutBounds');
var InLayoutViewport = function (element, cushion)
{
var r = GetBounds(element, cushion);
return !!r && r.bottom >= 0 && r.right >= 0 && r.top <= LayoutBounds.width && r.left <= LayoutBounds.height;
};
module.exports = InLayoutViewport;

56
src/dom/LayoutBounds.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 Class = require('../utils/Class');
var ClientHeight = require('./ClientHeight');
var ClientWidth = require('./ClientWidth');
var Rectangle = require('../geom/rectangle/Rectangle');
var LayoutBounds = new Class({
Extends: Rectangle,
initialize:
function LayoutBounds ()
{
Rectangle.call(this);
},
init: function (isDesktop)
{
if (isDesktop)
{
Object.defineProperty(this, 'width', { get: ClientWidth });
Object.defineProperty(this, 'height', { get: ClientHeight });
}
else
{
Object.defineProperty(this, 'width', {
get: function ()
{
var a = document.documentElement.clientWidth;
var b = window.innerWidth;
return a < b ? b : a; // max
}
});
Object.defineProperty(this, 'height', {
get: function ()
{
var a = document.documentElement.clientHeight;
var b = window.innerHeight;
return a < b ? b : a; // max
}
});
}
}
});
module.exports = new LayoutBounds();

View file

@ -92,16 +92,19 @@ var RequestAnimationFrame = new Class({
* @type {FrameRequestCallback}
* @since 3.0.0
*/
this.step = function step (timestamp)
this.step = function step ()
{
// Because we cannot trust the time passed to this callback from the browser and need it kept in sync with event times
var timestamp = window.performance.now();
// DOMHighResTimeStamp
_this.lastTime = _this.tick;
_this.tick = timestamp;
_this.timeOutID = window.requestAnimationFrame(step);
_this.callback(timestamp);
_this.timeOutID = window.requestAnimationFrame(step);
};
/**
@ -122,9 +125,9 @@ var RequestAnimationFrame = new Class({
_this.tick = d;
_this.timeOutID = window.setTimeout(stepTimeout, delay);
_this.callback(d);
_this.timeOutID = window.setTimeout(stepTimeout, delay);
};
},

387
src/dom/ScaleManager.js Normal file
View file

@ -0,0 +1,387 @@
/**
* @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 Class = require('../utils/Class');
var CONST = require('./const');
var NOOP = require('../utils/NOOP');
var Rectangle = require('../geom/rectangle/Rectangle');
var Size = require('../structs/Size');
var SnapFloor = require('../math/snap/SnapFloor');
var Vec2 = require('../math/Vector2');
/**
* @classdesc
* TODO
*
* @class ScaleManager
* @memberof Phaser.DOM
* @constructor
* @since 3.15.0
*
* @param {Phaser.Game} game - A reference to the Phaser.Game instance.
* @param {any} config
*/
var ScaleManager = new Class({
initialize:
function ScaleManager (game)
{
/**
* A reference to the Phaser.Game instance.
*
* @name Phaser.DOM.ScaleManager#game
* @type {Phaser.Game}
* @readonly
* @since 3.15.0
*/
this.game = game;
this.scaleMode = 0;
// The base game size, as requested in the game config
this.gameSize = new Size();
// The canvas size, which is the base game size * zoom * resolution
this.canvasSize = new Size();
// this.width = 0;
// this.height = 0;
// this.canvasWidth = 0;
// this.canvasHeight = 0;
this.resolution = 1;
this.zoom = 1;
// The actual displayed canvas size (after refactoring in CSS depending on the scale mode, parent, etc)
this.displaySize = new Size();
// this.displayWidth = 0;
// this.displayHeight = 0;
// The scale factor between the base game size and the displayed size
this.scale = new Vec2(1);
this.parent;
this.parentIsWindow;
this.parentScale = new Vec2(1);
this.parentBounds = new Rectangle();
this.minSize = new Vec2();
this.maxSize = new Vec2();
this.trackParent = false;
this.canExpandParent = false;
this.allowFullScreen = false;
this.snap = new Vec2(1, 1);
this.listeners = {
orientationChange: NOOP,
windowResize: NOOP,
fullScreenChange: NOOP,
fullScreenError: NOOP
};
},
preBoot: function ()
{
// Parse the config to get the scaling values we need
// console.log('preBoot');
this.setParent(this.game.config.parent);
this.parseConfig(this.game.config);
this.game.events.once('boot', this.boot, this);
},
boot: function ()
{
// console.log('boot');
this.setScaleMode(this.scaleMode);
this.game.events.on('prestep', this.step, this);
},
parseConfig: function (config)
{
var width = config.width;
var height = config.height;
var resolution = config.resolution;
var scaleMode = config.scaleMode;
var zoom = config.zoom;
if (typeof width === 'string')
{
this.parentScale.x = parseInt(width, 10) / 100;
width = this.parentBounds.width * this.parentScale.x;
}
if (typeof height === 'string')
{
this.parentScale.y = parseInt(height, 10) / 100;
height = this.parentBounds.height * this.parentScale.y;
}
this.width = width;
this.height = height;
this.canvasWidth = (width * zoom) * resolution;
this.canvasHeight = (height * zoom) * resolution;
this.resolution = resolution;
this.zoom = zoom;
this.canExpandParent = config.expandParent;
this.scaleMode = scaleMode;
// console.log(config);
this.minSize.set(config.minWidth, config.minHeight);
this.maxSize.set(config.maxWidth, config.maxHeight);
},
setScaleMode: function (scaleMode)
{
this.scaleMode = scaleMode;
if (scaleMode === CONST.EXACT)
{
return;
}
var canvas = this.game.canvas;
var gameStyle = canvas.style;
var parent = this.parent;
var parentStyle = parent.style;
switch (scaleMode)
{
case CONST.FILL:
gameStyle.objectFit = 'fill';
gameStyle.width = '100%';
gameStyle.height = '100%';
if (this.canExpandParent)
{
parentStyle.height = '100%';
if (this.parentIsWindow)
{
document.getElementsByTagName('html')[0].style.height = '100%';
}
}
break;
case CONST.CONTAIN:
gameStyle.objectFit = 'contain';
gameStyle.width = '100%';
gameStyle.height = '100%';
if (this.canExpandParent)
{
parentStyle.height = '100%';
if (this.parentIsWindow)
{
document.getElementsByTagName('html')[0].style.height = '100%';
}
}
break;
}
var min = this.minSize;
var max = this.maxSize;
if (min.x > 0)
{
gameStyle.minWidth = min.x.toString() + 'px';
}
if (min.y > 0)
{
gameStyle.minHeight = min.y.toString() + 'px';
}
if (max.x > 0)
{
gameStyle.maxWidth = max.x.toString() + 'px';
}
if (max.y > 0)
{
gameStyle.maxHeight = max.y.toString() + 'px';
}
},
setParent: function (parent)
{
var target;
if (parent !== '')
{
if (typeof parent === 'string')
{
// Hopefully an element ID
target = document.getElementById(parent);
}
else if (parent && parent.nodeType === 1)
{
// Quick test for a HTMLElement
target = parent;
}
}
// Fallback to the document body. Covers an invalid ID and a non HTMLElement object.
if (!target)
{
// Use the full window
this.parent = document.body;
this.parentIsWindow = true;
}
else
{
this.parent = target;
this.parentIsWindow = false;
}
this.getParentBounds();
},
getParentBounds: function ()
{
var DOMRect = this.parent.getBoundingClientRect();
this.parentBounds.setSize(DOMRect.width, DOMRect.height);
},
startListeners: function ()
{
var _this = this;
var listeners = this.listeners;
listeners.orientationChange = function (event)
{
return _this.onOrientationChange(event);
};
listeners.windowResize = function (event)
{
return _this.onWindowResize(event);
};
window.addEventListener('orientationchange', listeners.orientationChange, false);
window.addEventListener('resize', listeners.windowResize, false);
if (this.allowFullScreen)
{
listeners.fullScreenChange = function (event)
{
return _this.onFullScreenChange(event);
};
listeners.fullScreenError = function (event)
{
return _this.onFullScreenError(event);
};
var vendors = [ 'webkit', 'moz', '' ];
vendors.forEach(function (prefix)
{
document.addEventListener(prefix + 'fullscreenchange', listeners.fullScreenChange, false);
document.addEventListener(prefix + 'fullscreenerror', listeners.fullScreenError, false);
});
// MS Specific
document.addEventListener('MSFullscreenChange', listeners.fullScreenChange, false);
document.addEventListener('MSFullscreenError', listeners.fullScreenError, false);
}
},
getInnerHeight: function ()
{
// Based on code by @tylerjpeterson
if (!this.game.device.os.iOS)
{
return window.innerHeight;
}
var axis = Math.abs(window.orientation);
var size = { w: 0, h: 0 };
var ruler = document.createElement('div');
ruler.setAttribute('style', 'position: fixed; height: 100vh; width: 0; top: 0');
document.documentElement.appendChild(ruler);
size.w = (axis === 90) ? ruler.offsetHeight : window.innerWidth;
size.h = (axis === 90) ? window.innerWidth : ruler.offsetHeight;
document.documentElement.removeChild(ruler);
ruler = null;
if (Math.abs(window.orientation) !== 90)
{
return size.h;
}
else
{
return size.w;
}
},
step: function ()
{
// canvas.clientWidth and clientHeight = canvas size when scaled with 100% object-fit, ignoring borders, margin, etc
},
stopListeners: function ()
{
var listeners = this.listeners;
window.removeEventListener('orientationchange', listeners.orientationChange, false);
window.removeEventListener('resize', listeners.windowResize, false);
var vendors = [ 'webkit', 'moz', '' ];
vendors.forEach(function (prefix)
{
document.removeEventListener(prefix + 'fullscreenchange', listeners.fullScreenChange, false);
document.removeEventListener(prefix + 'fullscreenerror', listeners.fullScreenError, false);
});
// MS Specific
document.removeEventListener('MSFullscreenChange', listeners.fullScreenChange, false);
document.removeEventListener('MSFullscreenError', listeners.fullScreenError, false);
},
destroy: function ()
{
}
});
module.exports = ScaleManager;

62
src/dom/VisualBounds.js Normal file
View file

@ -0,0 +1,62 @@
/**
* @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 Class = require('../utils/Class');
var ClientHeight = require('./ClientHeight');
var ClientWidth = require('./ClientWidth');
var Rectangle = require('../geom/rectangle/Rectangle');
// All target browsers should support page[XY]Offset.
var ScrollX = (window && ('pageXOffset' in window)) ? function () { return window.pageXOffset; } : function () { return document.documentElement.scrollLeft; };
var ScrollY = (window && ('pageYOffset' in window)) ? function () { return window.pageYOffset; } : function () { return document.documentElement.scrollTop; };
var VisualBounds = new Class({
Extends: Rectangle,
initialize:
function VisualBounds ()
{
Rectangle.call(this);
},
x: {
get: ScrollX
},
y: {
get: ScrollY
},
init: function (isDesktop)
{
if (isDesktop)
{
Object.defineProperty(this, 'width', { get: ClientWidth });
Object.defineProperty(this, 'height', { get: ClientHeight });
}
else
{
Object.defineProperty(this, 'width', {
get: function ()
{
return window.innerWidth;
}
});
Object.defineProperty(this, 'height', {
get: function ()
{
return window.innerHeight;
}
});
}
}
});
module.exports = new VisualBounds();

1447
src/dom/_ScaleManager.js Normal file

File diff suppressed because it is too large Load diff

51
src/dom/const.js Normal file
View file

@ -0,0 +1,51 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Phaser ScaleManager Modes.
*
* @name Phaser.DOM.ScaleModes
* @enum {integer}
* @memberof Phaser
* @readonly
* @since 3.15.0
*/
module.exports = {
/**
*
*
* @name Phaser.DOM.EXACT
* @since 3.15.0
*/
EXACT: 0,
/**
*
*
* @name Phaser.DOM.FILL
* @since 3.15.0
*/
FILL: 1,
/**
*
*
* @name Phaser.DOM.CONTAIN
* @since 3.15.0
*/
CONTAIN: 2,
/**
*
*
* @name Phaser.DOM.RESIZE
* @since 3.15.0
*/
RESIZE: 3
};

View file

@ -4,6 +4,9 @@
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var Extend = require('../utils/object/Extend');
var ScaleModes = require('./const');
/**
* @namespace Phaser.DOM
*/
@ -11,11 +14,26 @@
var Dom = {
AddToDOM: require('./AddToDOM'),
Calibrate: require('./Calibrate'),
ClientHeight: require('./ClientHeight'),
ClientWidth: require('./ClientWidth'),
DocumentBounds: require('./DocumentBounds'),
DOMContentLoaded: require('./DOMContentLoaded'),
GetAspectRatio: require('./GetAspectRatio'),
GetBounds: require('./GetBounds'),
GetOffset: require('./GetOffset'),
GetScreenOrientation: require('./GetScreenOrientation'),
InLayoutViewport: require('./InLayoutViewport'),
ParseXML: require('./ParseXML'),
RemoveFromDOM: require('./RemoveFromDOM'),
RequestAnimationFrame: require('./RequestAnimationFrame')
RequestAnimationFrame: require('./RequestAnimationFrame'),
ScaleManager: require('./ScaleManager'),
VisualBounds: require('./VisualBounds'),
ScaleModes: ScaleModes
};
Dom = Extend(false, Dom, ScaleModes);
module.exports = Dom;

View file

@ -138,46 +138,8 @@ var DisplayList = new Class({
},
/**
* Given an array of Game Objects, sort the array and return it, so that
* the objects are in index order with the lowest at the bottom.
*
* @method Phaser.GameObjects.DisplayList#sortGameObjects
* @since 3.0.0
*
* @param {Phaser.GameObjects.GameObject[]} gameObjects - The array of Game Objects to sort.
*
* @return {array} The sorted array of Game Objects.
*/
sortGameObjects: function (gameObjects)
{
if (gameObjects === undefined) { gameObjects = this.list; }
this.scene.sys.depthSort();
return gameObjects.sort(this.sortIndexHandler.bind(this));
},
/**
* Get the top-most Game Object in the given array of Game Objects, after sorting it.
*
* Note that the given array is sorted in place, even though it isn't returned directly it will still be updated.
*
* @method Phaser.GameObjects.DisplayList#getTopGameObject
* @since 3.0.0
*
* @param {Phaser.GameObjects.GameObject[]} gameObjects - The array of Game Objects.
*
* @return {Phaser.GameObjects.GameObject} The top-most Game Object in the array of Game Objects.
*/
getTopGameObject: function (gameObjects)
{
this.sortGameObjects(gameObjects);
return gameObjects[gameObjects.length - 1];
},
/**
* All members of the group.
* Returns an array which contains all objects currently on the Display List.
* This is a reference to the main list array, not a copy of it, so be careful not to modify it.
*
* @method Phaser.GameObjects.DisplayList#getChildren
* @since 3.12.0

View file

@ -55,6 +55,22 @@ var GameObject = new Class({
*/
this.type = type;
/**
* The current state of this Game Object.
*
* Phaser itself will never modify this value, although plugins may do so.
*
* Use this property to track the state of a Game Object during its lifetime. For example, it could move from
* a state of 'moving', to 'attacking', to 'dead'. The state value should be an integer (ideally mapped to a constant
* in your game code), or a string. These are recommended to keep it light and simple, with fast comparisons.
* If you need to store complex data about your Game Object, look at using the Data Component instead.
*
* @name Phaser.GameObjects.GameObject#state
* @type {{integer|string}}
* @since 3.16.0
*/
this.state = 0;
/**
* The parent Container of this Game Object, if it has one.
*
@ -211,6 +227,30 @@ var GameObject = new Class({
return this;
},
/**
* Sets the current state of this Game Object.
*
* Phaser itself will never modify the State of a Game Object, although plugins may do so.
*
* For example, a Game Object could change from a state of 'moving', to 'attacking', to 'dead'.
* The state value should typically be an integer (ideally mapped to a constant
* in your game code), but could also be a string. It is recommended to keep it light and simple.
* If you need to store complex data about your Game Object, look at using the Data Component instead.
*
* @method Phaser.GameObjects.GameObject#setState
* @since 3.16.0
*
* @param {(integer|string)} value - The state of the Game Object.
*
* @return {this} This GameObject.
*/
setState: function (value)
{
this.state = value;
return this;
},
/**
* Adds a Data Manager component to this Game Object.
*
@ -454,7 +494,7 @@ var GameObject = new Class({
*/
willRender: function (camera)
{
return !(GameObject.RENDER_MASK !== this.renderFlags || (this.cameraFilter > 0 && (this.cameraFilter & camera.id)));
return !(GameObject.RENDER_MASK !== this.renderFlags || (this.cameraFilter !== 0 && (this.cameraFilter & camera.id)));
},
/**
@ -515,8 +555,9 @@ var GameObject = new Class({
* Game Object Pool instead of destroying it, as destroyed objects cannot be resurrected.
*
* @method Phaser.GameObjects.GameObject#destroy
* @fires Phaser.GameObjects.GameObject#destroyEvent
* @since 3.0.0
*
*
* @param {boolean} [fromScene=false] - Is this Game Object being destroyed as the result of a Scene shutdown?
*/
destroy: function (fromScene)
@ -591,3 +632,8 @@ var GameObject = new Class({
GameObject.RENDER_MASK = 15;
module.exports = GameObject;
/**
* The Game Object will be destroyed.
* @event Phaser.GameObjects.GameObject#destroyEvent
*/

View file

@ -11,7 +11,8 @@ var Render = require('./DynamicBitmapTextRender');
/**
* @typedef {object} DisplayCallbackConfig
*
* @property {{topLeft:number, topRight:number, bottomLeft:number, bottomRight:number}} tint - The tint of the character being rendered.
* @property {Phaser.GameObjects.DynamicBitmapText} parent - The Dynamic Bitmap Text object that owns this character being rendered.
* @property {{topLeft:number, topRight:number, bottomLeft:number, bottomRight:number}} tint - The tint of the character being rendered. Always zero in Canvas.
* @property {number} index - The index of the character being rendered.
* @property {number} charCode - The character code of the character being rendered.
* @property {number} x - The x position of the character being rendered.
@ -149,6 +150,7 @@ var DynamicBitmapText = new Class({
* @since 3.11.0
*/
this.callbackData = {
parent: this,
color: 0,
tint: {
topLeft: 0,

View file

@ -36,6 +36,7 @@ var DynamicBitmapTextCanvasRenderer = function (renderer, src, interpolationPerc
var textureFrame = src.frame;
var displayCallback = src.displayCallback;
var callbackData = src.callbackData;
var cameraScrollX = camera.scrollX * src.scrollFactorX;
var cameraScrollY = camera.scrollY * src.scrollFactorY;
@ -61,7 +62,6 @@ var DynamicBitmapTextCanvasRenderer = function (renderer, src, interpolationPerc
var lastGlyph = null;
var lastCharCode = 0;
// var ctx = renderer.currentContext;
var image = src.frame.source.image;
var textureX = textureFrame.cutX;
@ -72,7 +72,6 @@ var DynamicBitmapTextCanvasRenderer = function (renderer, src, interpolationPerc
if (src.cropWidth > 0 && src.cropHeight > 0)
{
ctx.save();
ctx.beginPath();
ctx.rect(0, 0, src.cropWidth, src.cropHeight);
ctx.clip();
@ -121,7 +120,15 @@ var DynamicBitmapTextCanvasRenderer = function (renderer, src, interpolationPerc
if (displayCallback)
{
var output = displayCallback({ tint: { topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0 }, index: index, charCode: charCode, x: x, y: y, scale: scale, rotation: 0, data: glyph.data });
callbackData.index = index;
callbackData.charCode = charCode;
callbackData.x = x;
callbackData.y = y;
callbackData.scale = scale;
callbackData.rotation = rotation;
callbackData.data = glyph.data;
var output = displayCallback(callbackData);
x = output.x;
y = output.y;
@ -137,8 +144,8 @@ var DynamicBitmapTextCanvasRenderer = function (renderer, src, interpolationPerc
if (camera.roundPixels)
{
x |= 0;
y |= 0;
x = Math.round(x);
y = Math.round(y);
}
ctx.save();
@ -159,11 +166,7 @@ var DynamicBitmapTextCanvasRenderer = function (renderer, src, interpolationPerc
lastCharCode = charCode;
}
if (src.cropWidth > 0 && src.cropHeight > 0)
{
ctx.restore();
}
// Restore the context saved in SetTransform
ctx.restore();
};

View file

@ -273,20 +273,20 @@ var DynamicBitmapTextWebGLRenderer = function (renderer, src, interpolationPerce
if (roundPixels)
{
tx0 |= 0;
ty0 |= 0;
tx0 = Math.round(tx0);
ty0 = Math.round(ty0);
tx1 |= 0;
ty1 |= 0;
tx1 = Math.round(tx1);
ty1 = Math.round(ty1);
tx2 |= 0;
ty2 |= 0;
tx2 = Math.round(tx2);
ty2 = Math.round(ty2);
tx3 |= 0;
ty3 |= 0;
tx3 = Math.round(tx3);
ty3 = Math.round(ty3);
}
pipeline.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect);
pipeline.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect, texture, 0);
}
if (crop)

View file

@ -68,12 +68,12 @@ var Render = require('./BitmapTextRender');
*
* To create a BitmapText data files you need a 3rd party app such as:
*
* BMFont (Windows, free): http://www.angelcode.com/products/bmfont/
* Glyph Designer (OS X, commercial): http://www.71squared.com/en/glyphdesigner
* Littera (Web-based, free): http://kvazars.com/littera/
* BMFont (Windows, free): {@link http://www.angelcode.com/products/bmfont/|http://www.angelcode.com/products/bmfont/}
* Glyph Designer (OS X, commercial): {@link http://www.71squared.com/en/glyphdesigner|http://www.71squared.com/en/glyphdesigner}
* Littera (Web-based, free): {@link http://kvazars.com/littera/|http://kvazars.com/littera/}
*
* For most use cases it is recommended to use XML. If you wish to use JSON, the formatting should be equal to the result of
* converting a valid XML file through the popular X2JS library. An online tool for conversion can be found here: http://codebeautify.org/xmltojson
* converting a valid XML file through the popular X2JS library. An online tool for conversion can be found here: {@link http://codebeautify.org/xmltojson|http://codebeautify.org/xmltojson}
*
* @class BitmapText
* @extends Phaser.GameObjects.GameObject

View file

@ -148,8 +148,8 @@ var BitmapTextCanvasRenderer = function (renderer, src, interpolationPercentage,
if (roundPixels)
{
x |= 0;
y |= 0;
x = Math.round(x);
y = Math.round(y);
}
ctx.save();

View file

@ -203,20 +203,20 @@ var BitmapTextWebGLRenderer = function (renderer, src, interpolationPercentage,
if (roundPixels)
{
tx0 |= 0;
ty0 |= 0;
tx0 = Math.round(tx0);
ty0 = Math.round(ty0);
tx1 |= 0;
ty1 |= 0;
tx1 = Math.round(tx1);
ty1 = Math.round(ty1);
tx2 |= 0;
ty2 |= 0;
tx2 = Math.round(tx2);
ty2 = Math.round(ty2);
tx3 |= 0;
ty3 |= 0;
tx3 = Math.round(tx3);
ty3 = Math.round(ty3);
}
pipeline.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect);
pipeline.batchQuad(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, u0, v0, u1, v1, tintTL, tintTR, tintBL, tintBR, tintEffect, texture, 0);
}
};

View file

@ -78,8 +78,8 @@ var BlitterCanvasRenderer = function (renderer, src, interpolationPercentage, ca
{
if (roundPixels)
{
dx |= 0;
dy |= 0;
dx = Math.round(dx);
dy = Math.round(dy);
}
ctx.drawImage(

View file

@ -106,15 +106,15 @@ var BlitterWebGLRenderer = function (renderer, src, interpolationPercentage, cam
if (roundPixels)
{
tx0 |= 0;
ty0 |= 0;
tx0 = Math.round(tx0);
ty0 = Math.round(ty0);
tx1 |= 0;
ty1 |= 0;
tx1 = Math.round(tx1);
ty1 = Math.round(ty1);
}
// TL x/y, BL x/y, BR x/y, TR x/y
if (pipeline.batchQuad(tx0, ty0, tx0, ty1, tx1, ty1, tx1, ty0, frame.u0, frame.v0, frame.u1, frame.v1, tint, tint, tint, tint, tintEffect))
if (pipeline.batchQuad(tx0, ty0, tx0, ty1, tx1, ty1, tx1, ty0, frame.u0, frame.v0, frame.u1, frame.v1, tint, tint, tint, tint, tintEffect, frame.glTexture, 0))
{
prevTextureSourceIndex = -1;
}

View file

@ -4,12 +4,18 @@
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var BaseAnimation = require('../../animations/Animation');
var Class = require('../../utils/Class');
/**
* This event is dispatched when an animation starts playing.
*
* Listen for it on the Game Object: `sprite.on('animationstart', listener)`
*
* You can also listen for a specific animation by appending a hyphen and its key to the event name. For example,
* if you have an animation called `explode`, you can listen for `sprite.on('animationstart-explode', listener)`.
*
* You can also listen for the `start` event from the Animation itself: `animation.on('start', listener)`.
*
* @event Phaser.GameObjects.Components.Animation#onStartEvent
* @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation.
@ -21,6 +27,11 @@ var Class = require('../../utils/Class');
* This event is dispatched when an animation restarts.
*
* Listen for it on the Game Object: `sprite.on('animationrestart', listener)`
*
* You can also listen for a specific animation by appending a hyphen and its key to the event name. For example,
* if you have an animation called `explode`, you can listen for `sprite.on('animationrestart-explode', listener)`.
*
* You can also listen for the `restart` event from the Animation itself: `animation.on('restart', listener)`.
*
* @event Phaser.GameObjects.Components.Animation#onRestartEvent
* @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation.
@ -32,6 +43,9 @@ var Class = require('../../utils/Class');
* This event is dispatched when an animation repeats.
*
* Listen for it on the Game Object: `sprite.on('animationrepeat', listener)`
*
* You can also listen for a specific animation by appending a hyphen and its key to the event name. For example,
* if you have an animation called `explode`, you can listen for `sprite.on('animationrepeat-explode', listener)`.
*
* @event Phaser.GameObjects.Components.Animation#onRepeatEvent
* @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation.
@ -45,6 +59,9 @@ var Class = require('../../utils/Class');
* based on the animation frame rate and other factors like timeScale and delay.
*
* Listen for it on the Game Object: `sprite.on('animationupdate', listener)`
*
* You can also listen for a specific animation by appending a hyphen and its key to the event name. For example,
* if you have an animation called `explode`, you can listen for `sprite.on('animationupdate-explode', listener)`.
*
* @event Phaser.GameObjects.Components.Animation#onUpdateEvent
* @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation.
@ -56,6 +73,11 @@ var Class = require('../../utils/Class');
* This event is dispatched when an animation completes playing, either naturally or via Animation.stop.
*
* Listen for it on the Game Object: `sprite.on('animationcomplete', listener)`
*
* You can also listen for a specific animation by appending a hyphen and its key to the event name. For example,
* if you have an animation called `explode`, you can listen for `sprite.on('animationcomplete-explode', listener)`.
*
* You can also listen for the `complete` event from the Animation itself: `animation.on('complete', listener)`.
*
* @event Phaser.GameObjects.Components.Animation#onCompleteEvent
* @param {Phaser.Animations.Animation} animation - Reference to the currently playing animation.
@ -132,6 +154,16 @@ var Animation = new Class({
*/
this.currentFrame = null;
/**
* The key of the next Animation to be loaded into this Animation Controller when the current animation completes.
*
* @name Phaser.GameObjects.Components.Animation#nextAnim
* @type {?string}
* @default null
* @since 3.16.0
*/
this.nextAnim = null;
/**
* Time scale factor.
*
@ -339,6 +371,37 @@ var Animation = new Class({
this._pendingStopValue;
},
/**
* Sets an animation to be played immediately after the current one completes.
*
* The current animation must enter a 'completed' state for this to happen, i.e. finish all of its repeats, delays, etc, or have the `stop` method called directly on it.
*
* An animation set to repeat forever will never enter a completed state.
*
* You can chain a new animation at any point, including before the current one starts playing, during it, or when it ends (via its `animationcomplete` callback).
* Chained animations are specific to a Game Object, meaning different Game Objects can have different chained animations without impacting the global animation they're playing.
*
* Call this method with no arguments to reset the chained animation.
*
* @method Phaser.GameObjects.Components.Animation#chain
* @since 3.16.0
*
* @param {(string|Phaser.Animations.Animation)} [key] - The string-based key of the animation to play next, as defined previously in the Animation Manager. Or an Animation instance.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
chain: function (key)
{
if (key instanceof BaseAnimation)
{
key = key.key;
}
this.nextAnim = key;
return this.parent;
},
/**
* Sets the amount of time, in milliseconds, that the animation will be delayed before starting playback.
*
@ -508,13 +571,15 @@ var Animation = new Class({
},
/**
* Plays an Animation on the Game Object that owns this Animation Component.
* Plays an Animation on a Game Object that has the Animation component, such as a Sprite.
*
* Animations are stored in the global Animation Manager and are referenced by a unique string-based key.
*
* @method Phaser.GameObjects.Components.Animation#play
* @fires Phaser.GameObjects.Components.Animation#onStartEvent
* @since 3.0.0
*
* @param {string} key - The string-based key of the animation to play, as defined previously in the Animation Manager.
* @param {(string|Phaser.Animations.Animation)} key - The string-based key of the animation to play, as defined previously in the Animation Manager. Or an Animation instance.
* @param {boolean} [ignoreIfPlaying=false] - If an animation is already playing then ignore this call.
* @param {integer} [startFrame=0] - Optionally start the animation playing from this frame index.
*
@ -525,6 +590,11 @@ var Animation = new Class({
if (ignoreIfPlaying === undefined) { ignoreIfPlaying = false; }
if (startFrame === undefined) { startFrame = 0; }
if (key instanceof BaseAnimation)
{
key = key.key;
}
if (ignoreIfPlaying && this.isPlaying && this.currentAnim.key === key)
{
return this.parent;
@ -543,7 +613,7 @@ var Animation = new Class({
* @fires Phaser.GameObjects.Components.Animation#onStartEvent
* @since 3.12.0
*
* @param {string} key - The string-based key of the animation to play, as defined previously in the Animation Manager.
* @param {(string|Phaser.Animations.Animation)} key - The string-based key of the animation to play, as defined previously in the Animation Manager. Or an Animation instance.
* @param {boolean} [ignoreIfPlaying=false] - If an animation is already playing then ignore this call.
* @param {integer} [startFrame=0] - Optionally start the animation playing from this frame index.
*
@ -554,6 +624,11 @@ var Animation = new Class({
if (ignoreIfPlaying === undefined) { ignoreIfPlaying = false; }
if (startFrame === undefined) { startFrame = 0; }
if (key instanceof BaseAnimation)
{
key = key.key;
}
if (ignoreIfPlaying && this.isPlaying && this.currentAnim.key === key)
{
return this.parent;
@ -566,8 +641,7 @@ var Animation = new Class({
},
/**
* Load an Animation and fires 'onStartEvent' event,
* extracted from 'play' method
* Load an Animation and fires 'onStartEvent' event, extracted from 'play' method.
*
* @method Phaser.GameObjects.Components.Animation#_startAnimation
* @fires Phaser.GameObjects.Components.Animation#onStartEvent
@ -598,26 +672,33 @@ var Animation = new Class({
gameObject.visible = true;
}
gameObject.emit('animationstart', this.currentAnim, this.currentFrame, gameObject);
var frame = this.currentFrame;
anim.emit('start', anim, frame);
gameObject.emit('animationstart-' + key, anim, frame, gameObject);
gameObject.emit('animationstart', anim, frame, gameObject);
return gameObject;
},
/**
* Reverse an Animation that is already playing on the Game Object.
* Reverse the Animation that is already playing on the Game Object.
*
* @method Phaser.GameObjects.Components.Animation#reverse
* @since 3.12.0
*
* @param {string} key - The string-based key of the animation to play, as defined previously in the Animation Manager.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
reverse: function (key)
reverse: function ()
{
if (!this.isPlaying || this.currentAnim.key !== key) { return this.parent; }
this._reverse = !this._reverse;
this.forward = !this.forward;
if (this.isPlaying)
{
this._reverse = !this._reverse;
this.forward = !this.forward;
}
return this.parent;
},
@ -774,7 +855,9 @@ var Animation = new Class({
{
if (includeDelay === undefined) { includeDelay = false; }
this.currentAnim.getFirstTick(this, includeDelay);
var anim = this.currentAnim;
anim.getFirstTick(this, includeDelay);
this.forward = true;
this.isPlaying = true;
@ -782,17 +865,26 @@ var Animation = new Class({
this._paused = false;
// Set frame
this.updateFrame(this.currentAnim.frames[0]);
this.updateFrame(anim.frames[0]);
var gameObject = this.parent;
var frame = this.currentFrame;
gameObject.emit('animationrestart', this.currentAnim, this.currentFrame, gameObject);
anim.emit('restart', anim, frame);
gameObject.emit('animationrestart-' + anim.key, anim, frame, gameObject);
gameObject.emit('animationrestart', anim, frame, gameObject);
return this.parent;
},
/**
* Immediately stops the current animation from playing and dispatches the `animationcomplete` event.
*
* If no animation is set, no event will be dispatched.
*
* If there is another animation queued (via the `chain` method) then it will start playing immediately.
*
* @method Phaser.GameObjects.Components.Animation#stop
* @fires Phaser.GameObjects.Components.Animation#onCompleteEvent
@ -807,8 +899,26 @@ var Animation = new Class({
this.isPlaying = false;
var gameObject = this.parent;
var anim = this.currentAnim;
var frame = this.currentFrame;
gameObject.emit('animationcomplete', this.currentAnim, this.currentFrame, gameObject);
if (anim)
{
anim.emit('complete', anim, frame);
gameObject.emit('animationcomplete-' + anim.key, anim, frame, gameObject);
gameObject.emit('animationcomplete', anim, frame, gameObject);
}
if (this.nextAnim)
{
var key = this.nextAnim;
this.nextAnim = null;
this.play(key);
}
return gameObject;
},
@ -856,7 +966,7 @@ var Animation = new Class({
* @fires Phaser.GameObjects.Components.Animation#onCompleteEvent
* @since 3.4.0
*
* @param {Phaser.Animations.AnimationFrame} delay - The frame to check before stopping this animation.
* @param {Phaser.Animations.AnimationFrame} frame - The frame to check before stopping this animation.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/
@ -1010,6 +1120,8 @@ var Animation = new Class({
var anim = this.currentAnim;
gameObject.emit('animationupdate-' + anim.key, anim, animationFrame, gameObject);
gameObject.emit('animationupdate', anim, animationFrame, gameObject);
if (this._pendingStop === 3 && this._pendingStopValue === animationFrame)
@ -1019,6 +1131,50 @@ var Animation = new Class({
}
},
/**
* Advances the animation to the next frame, regardless of the time or animation state.
* If the animation is set to repeat, or yoyo, this will still take effect.
*
* Calling this does not change the direction of the animation. I.e. if it was currently
* playing in reverse, calling this method doesn't then change the direction to forwards.
*
* @method Phaser.GameObjects.Components.Animation#nextFrame
* @since 3.16.0
*
* @return {Phaser.GameObjects.GameObject} The Game Object this Animation Component belongs to.
*/
nextFrame: function ()
{
if (this.currentAnim)
{
this.currentAnim.nextFrame(this);
}
return this.parent;
},
/**
* Advances the animation to the previous frame, regardless of the time or animation state.
* If the animation is set to repeat, or yoyo, this will still take effect.
*
* Calling this does not change the direction of the animation. I.e. if it was currently
* playing in forwards, calling this method doesn't then change the direction to backwards.
*
* @method Phaser.GameObjects.Components.Animation#previousFrame
* @since 3.16.0
*
* @return {Phaser.GameObjects.GameObject} The Game Object this Animation Component belongs to.
*/
previousFrame: function ()
{
if (this.currentAnim)
{
this.currentAnim.previousFrame(this);
}
return this.parent;
},
/**
* Sets if the current Animation will yoyo when it reaches the end.
* A yoyo'ing animation will play through consecutively, and then reverse-play back to the start again.

View file

@ -37,6 +37,7 @@ var BlendMode = {
* * ADD
* * MULTIPLY
* * SCREEN
* * ERASE
*
* Canvas has more available depending on browser support.
*
@ -85,6 +86,7 @@ var BlendMode = {
* * ADD
* * MULTIPLY
* * SCREEN
* * ERASE (only works when rendering to a framebuffer, like a Render Texture)
*
* Canvas has more available depending on browser support.
*
@ -92,7 +94,7 @@ var BlendMode = {
*
* Blend modes have different effects under Canvas and WebGL, and from browser to browser, depending
* on support. Blend Modes also cause a WebGL batch flush should it encounter a new blend mode. For these
* reasons try to be careful about the construction of your Scene and the frequency of which blend modes
* reasons try to be careful about the construction of your Scene and the frequency in which blend modes
* are used.
*
* @method Phaser.GameObjects.Components.BlendMode#setBlendMode

View file

@ -727,7 +727,11 @@ var TransformMatrix = new Class({
},
/**
* Decompose this Matrix into its translation, scale and rotation values.
* Decompose this Matrix into its translation, scale and rotation values using QR decomposition.
*
* The result must be applied in the following order to reproduce the current matrix:
*
* translate -> rotate -> scale
*
* @method Phaser.GameObjects.Components.TransformMatrix#decomposeMatrix
* @since 3.0.0
@ -750,21 +754,33 @@ var TransformMatrix = new Class({
var c = matrix[2];
var d = matrix[3];
var a2 = a * a;
var b2 = b * b;
var c2 = c * c;
var d2 = d * d;
var sx = Math.sqrt(a2 + c2);
var sy = Math.sqrt(b2 + d2);
var determ = a * d - b * c;
decomposedMatrix.translateX = matrix[4];
decomposedMatrix.translateY = matrix[5];
decomposedMatrix.scaleX = sx;
decomposedMatrix.scaleY = sy;
if (a || b)
{
var r = Math.sqrt(a * a + b * b);
decomposedMatrix.rotation = Math.acos(a / sx) * (Math.atan(-c / a) < 0 ? -1 : 1);
decomposedMatrix.rotation = (b > 0) ? Math.acos(a / r) : -Math.acos(a / r);
decomposedMatrix.scaleX = r;
decomposedMatrix.scaleY = determ / r;
}
else if (c || d)
{
var s = Math.sqrt(c * c + d * d);
decomposedMatrix.rotation = Math.PI * 0.5 - (d > 0 ? Math.acos(-c / s) : -Math.acos(c / s));
decomposedMatrix.scaleX = determ / s;
decomposedMatrix.scaleY = s;
}
else
{
decomposedMatrix.rotation = 0;
decomposedMatrix.scaleX = 0;
decomposedMatrix.scaleY = 0;
}
return decomposedMatrix;
},

View file

@ -25,7 +25,7 @@ var DOMElementCSSRenderer = function (renderer, src, interpolationPercentage, ca
{
var node = src.node;
if (!node || GameObject.RENDER_MASK !== src.renderFlags || (src.cameraFilter > 0 && (src.cameraFilter & camera.id)))
if (!node || GameObject.RENDER_MASK !== src.renderFlags || (src.cameraFilter !== 0 && (src.cameraFilter & camera.id)))
{
if (node)
{

78
src/gameobjects/extern/Extern.js vendored Normal file
View file

@ -0,0 +1,78 @@
/**
* @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 Class = require('../../utils/Class');
var Components = require('../components');
var GameObject = require('../GameObject');
var ExternRender = require('./ExternRender');
/**
* @classdesc
* An Extern Game Object.
*
* @class Extern
* @extends Phaser.GameObjects.GameObject
* @memberof Phaser.GameObjects
* @constructor
* @since 3.16.0
*
* @extends Phaser.GameObjects.Components.Alpha
* @extends Phaser.GameObjects.Components.BlendMode
* @extends Phaser.GameObjects.Components.Depth
* @extends Phaser.GameObjects.Components.Flip
* @extends Phaser.GameObjects.Components.Origin
* @extends Phaser.GameObjects.Components.ScaleMode
* @extends Phaser.GameObjects.Components.ScrollFactor
* @extends Phaser.GameObjects.Components.Size
* @extends Phaser.GameObjects.Components.Texture
* @extends Phaser.GameObjects.Components.Tint
* @extends Phaser.GameObjects.Components.Transform
* @extends Phaser.GameObjects.Components.Visible
*
* @param {Phaser.Scene} scene - The Scene to which this Game Object belongs. A Game Object can only belong to one Scene at a time.
*/
var Extern = new Class({
Extends: GameObject,
Mixins: [
Components.Alpha,
Components.BlendMode,
Components.Depth,
Components.Flip,
Components.Origin,
Components.ScaleMode,
Components.ScrollFactor,
Components.Size,
Components.Texture,
Components.Tint,
Components.Transform,
Components.Visible,
ExternRender
],
initialize:
function Extern (scene)
{
GameObject.call(this, scene, 'Extern');
},
preUpdate: function ()
{
// override this!
// Arguments: time, delta
},
render: function ()
{
// override this!
// Arguments: renderer, camera, calcMatrix
}
});
module.exports = Extern;

View file

41
src/gameobjects/extern/ExternFactory.js vendored 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}
*/
var Extern = require('./Extern');
var GameObjectFactory = require('../GameObjectFactory');
/**
* Creates a new Extern Game Object and adds it to the Scene.
*
* Note: This method will only be available if the Extern Game Object has been built into Phaser.
*
* @method Phaser.GameObjects.GameObjectFactory#extern
* @since 3.16.0
*
* @param {number} x - The horizontal position of this Game Object in the world.
* @param {number} y - The vertical position of this Game Object in the world.
* @param {string} texture - The key of the Texture this Game Object will use to render with, as stored in the Texture Manager.
* @param {(string|integer)} [frame] - An optional frame from the Texture this Game Object is rendering with.
*
* @return {Phaser.GameObjects.Extern} The Game Object that was created.
*/
GameObjectFactory.register('extern', function ()
{
var extern = new Extern(this.scene);
this.displayList.add(extern);
this.updateList.add(extern);
return extern;
});
// When registering a factory function 'this' refers to the GameObjectFactory context.
//
// There are several properties available to use:
//
// this.scene - a reference to the Scene that owns the GameObjectFactory
// this.displayList - a reference to the Display List the Scene owns
// this.updateList - a reference to the Update List the Scene owns

25
src/gameobjects/extern/ExternRender.js vendored Normal file
View file

@ -0,0 +1,25 @@
/**
* @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 renderWebGL = require('../../utils/NOOP');
var renderCanvas = require('../../utils/NOOP');
if (typeof WEBGL_RENDERER)
{
renderWebGL = require('./ExternWebGLRenderer');
}
if (typeof CANVAS_RENDERER)
{
renderCanvas = require('./ExternCanvasRenderer');
}
module.exports = {
renderWebGL: renderWebGL,
renderCanvas: renderCanvas
};

View file

@ -0,0 +1,63 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Renders this Game Object with the WebGL Renderer to the given Camera.
* The object will not render if any of its renderFlags are set or it is being actively filtered out by the Camera.
* This method should not be called directly. It is a utility function of the Render module.
*
* @method Phaser.GameObjects.Extern#renderWebGL
* @since 3.16.0
* @private
*
* @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - A reference to the current active WebGL renderer.
* @param {Phaser.GameObjects.Extern} src - The Game Object being rendered in this call.
* @param {number} interpolationPercentage - Reserved for future use and custom pipelines.
* @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera that is rendering the Game Object.
* @param {Phaser.GameObjects.Components.TransformMatrix} parentMatrix - This transform matrix is defined if the game object is nested
*/
var ExternWebGLRenderer = function (renderer, src, interpolationPercentage, camera, parentMatrix)
{
var pipeline = renderer.currentPipeline;
renderer.clearPipeline();
var camMatrix = renderer._tempMatrix1;
var spriteMatrix = renderer._tempMatrix2;
var calcMatrix = renderer._tempMatrix3;
spriteMatrix.applyITRS(src.x, src.y, src.rotation, src.scaleX, src.scaleY);
camMatrix.copyFrom(camera.matrix);
if (parentMatrix)
{
// Multiply the camera by the parent matrix
camMatrix.multiplyWithOffset(parentMatrix, -camera.scrollX * src.scrollFactorX, -camera.scrollY * src.scrollFactorY);
// Undo the camera scroll
spriteMatrix.e = src.x;
spriteMatrix.f = src.y;
// Multiply by the Sprite matrix, store result in calcMatrix
camMatrix.multiply(spriteMatrix, calcMatrix);
}
else
{
spriteMatrix.e -= camera.scrollX * src.scrollFactorX;
spriteMatrix.f -= camera.scrollY * src.scrollFactorY;
// Multiply by the Sprite matrix, store result in calcMatrix
camMatrix.multiply(spriteMatrix, calcMatrix);
}
// Callback
src.render.call(src, renderer, camera, calcMatrix);
renderer.rebindPipeline(pipeline);
};
module.exports = ExternWebGLRenderer;

View file

@ -506,6 +506,26 @@ var Graphics = new Class({
return this;
},
/**
* Fill the current path.
*
* This is an alias for `Graphics.fillPath` and does the same thing.
* It was added to match the CanvasRenderingContext 2D API.
*
* @method Phaser.GameObjects.Graphics#fill
* @since 3.16.0
*
* @return {Phaser.GameObjects.Graphics} This Game Object.
*/
fill: function ()
{
this.commandBuffer.push(
Commands.FILL_PATH
);
return this;
},
/**
* Stroke the current path.
*
@ -523,6 +543,26 @@ var Graphics = new Class({
return this;
},
/**
* Stroke the current path.
*
* This is an alias for `Graphics.strokePath` and does the same thing.
* It was added to match the CanvasRenderingContext 2D API.
*
* @method Phaser.GameObjects.Graphics#stroke
* @since 3.16.0
*
* @return {Phaser.GameObjects.Graphics} This Game Object.
*/
stroke: function ()
{
this.commandBuffer.push(
Commands.STROKE_PATH
);
return this;
},
/**
* Fill the given circle.
*
@ -1005,15 +1045,15 @@ var Graphics = new Class({
},
/**
* [description]
* Draw a line from the current drawing position to the given position with a specific width and color.
*
* @method Phaser.GameObjects.Graphics#lineFxTo
* @since 3.0.0
*
* @param {number} x - [description]
* @param {number} y - [description]
* @param {number} width - [description]
* @param {number} rgb - [description]
* @param {number} x - The x coordinate to draw the line to.
* @param {number} y - The y coordinate to draw the line to.
* @param {number} width - The width of the stroke.
* @param {number} rgb - The color of the stroke.
*
* @return {Phaser.GameObjects.Graphics} This Game Object.
*/
@ -1028,15 +1068,15 @@ var Graphics = new Class({
},
/**
* [description]
* Move the current drawing position to the given position and change the pen width and color.
*
* @method Phaser.GameObjects.Graphics#moveFxTo
* @since 3.0.0
*
* @param {number} x - [description]
* @param {number} y - [description]
* @param {number} width - [description]
* @param {number} rgb - [description]
* @param {number} x - The x coordinate to move to.
* @param {number} y - The y coordinate to move to.
* @param {number} width - The new stroke width.
* @param {number} rgb - The new stroke color.
*
* @return {Phaser.GameObjects.Graphics} This Game Object.
*/

View file

@ -45,8 +45,6 @@ var GraphicsCanvasRenderer = function (renderer, src, interpolationPercentage, c
var green = 0;
var blue = 0;
ctx.save();
// Reset any currently active paths
ctx.beginPath();
@ -239,6 +237,7 @@ var GraphicsCanvasRenderer = function (renderer, src, interpolationPercentage, c
}
}
// Restore the context saved in SetTransform
ctx.restore();
};

View file

@ -28,7 +28,7 @@ var Sprite = require('../sprite/Sprite');
/**
* @typedef {object} GroupConfig
*
* @property {?object} [classType=Sprite] - Sets {@link Phaser.GameObjects.Group#classType}.
* @property {?GroupClassTypeConstructor} [classType=Sprite] - Sets {@link Phaser.GameObjects.Group#classType}.
* @property {?boolean} [active=true] - Sets {@link Phaser.GameObjects.Group#active}.
* @property {?number} [maxSize=-1] - Sets {@link Phaser.GameObjects.Group#maxSize}.
* @property {?string} [defaultKey=null] - Sets {@link Phaser.GameObjects.Group#defaultKey}.
@ -52,7 +52,7 @@ var Sprite = require('../sprite/Sprite');
*
* `key` is required. {@link Phaser.GameObjects.Group#defaultKey} is not used.
*
* @property {?object} [classType] - The class of each new Game Object.
* @property {?GroupClassTypeConstructor} [classType] - The class of each new Game Object.
* @property {string} [key] - The texture key of each new Game Object.
* @property {?(string|integer)} [frame=null] - The texture frame of each new Game Object.
* @property {?boolean} [visible=true] - The visible state of each new Game Object.
@ -93,6 +93,18 @@ var Sprite = require('../sprite/Sprite');
* @see Phaser.Utils.Array.Range
*/
/**
* A constructor function (class) that can be assigned to `classType`.
* @callback GroupClassTypeConstructor
* @param {Phaser.Scene} scene - The Scene to which this Game Object belongs. A Game Object can only belong to one Scene at a time.
* @param {number} x - The horizontal position of this Game Object in the world.
* @param {number} y - The vertical position of this Game Object in the world.
* @param {string} texture - The key of the Texture this Game Object will use to render with, as stored in the Texture Manager.
* @param {(string|integer)} [frame] - An optional frame from the Texture this Game Object is rendering with.
*
* @see Phaser.GameObjects.Group#classType
*/
/**
* @classdesc A Group is a way for you to create, manipulate, or recycle similar Game Objects.
*
@ -185,7 +197,7 @@ var Group = new Class({
* The class to create new group members from.
*
* @name Phaser.GameObjects.Group#classType
* @type {object}
* @type {GroupClassTypeConstructor}
* @since 3.0.0
* @default Phaser.GameObjects.Sprite
*/

View file

@ -15,7 +15,7 @@ var Group = require('./Group');
* @method Phaser.GameObjects.GameObjectCreator#group
* @since 3.0.0
*
* @param {GroupConfig} config - The configuration object this Game Object will use to create itself.
* @param {GroupConfig|GroupCreateConfig} config - The configuration object this Game Object will use to create itself.
*
* @return {Phaser.GameObjects.Group} The Game Object that was created.
*/

View file

@ -16,7 +16,7 @@ var GameObjectFactory = require('../GameObjectFactory');
* @since 3.0.0
*
* @param {(Phaser.GameObjects.GameObject[]|GroupConfig|GroupConfig[])} [children] - Game Objects to add to this Group; or the `config` argument.
* @param {GroupConfig} [config] - A Group Configuration object.
* @param {GroupConfig|GroupCreateConfig} [config] - A Group Configuration object.
*
* @return {Phaser.GameObjects.Group} The Game Object that was created.
*/

View file

@ -24,6 +24,7 @@ var GameObjects = {
Blitter: require('./blitter/Blitter'),
Container: require('./container/Container'),
DynamicBitmapText: require('./bitmaptext/dynamic/DynamicBitmapText'),
Extern: require('./extern/Extern.js'),
Graphics: require('./graphics/Graphics.js'),
Group: require('./group/Group'),
Image: require('./image/Image'),
@ -57,6 +58,7 @@ var GameObjects = {
Blitter: require('./blitter/BlitterFactory'),
Container: require('./container/ContainerFactory'),
DynamicBitmapText: require('./bitmaptext/dynamic/DynamicBitmapTextFactory'),
Extern: require('./extern/ExternFactory'),
Graphics: require('./graphics/GraphicsFactory'),
Group: require('./group/GroupFactory'),
Image: require('./image/ImageFactory'),

View file

@ -20,13 +20,10 @@ var MeshRender = require('./MeshRender');
* @webglOnly
* @since 3.0.0
*
* @extends Phaser.GameObjects.Components.Alpha
* @extends Phaser.GameObjects.Components.BlendMode
* @extends Phaser.GameObjects.Components.Depth
* @extends Phaser.GameObjects.Components.Flip
* @extends Phaser.GameObjects.Components.GetBounds
* @extends Phaser.GameObjects.Components.Mask
* @extends Phaser.GameObjects.Components.Origin
* @extends Phaser.GameObjects.Components.Pipeline
* @extends Phaser.GameObjects.Components.ScaleMode
* @extends Phaser.GameObjects.Components.Size
@ -50,13 +47,10 @@ var Mesh = new Class({
Extends: GameObject,
Mixins: [
Components.Alpha,
Components.BlendMode,
Components.Depth,
Components.Flip,
Components.GetBounds,
Components.Mask,
Components.Origin,
Components.Pipeline,
Components.ScaleMode,
Components.Size,
@ -157,7 +151,6 @@ var Mesh = new Class({
this.setTexture(texture, frame);
this.setPosition(x, y);
this.setSizeToFrame();
this.setOrigin();
this.initPipeline();
}

View file

@ -67,7 +67,7 @@ var MeshWebGLRenderer = function (renderer, src, interpolationPercentage, camera
var meshVerticesLength = vertices.length;
var vertexCount = Math.floor(meshVerticesLength * 0.5);
if (pipeline.vertexCount + vertexCount >= pipeline.vertexCapacity)
if (pipeline.vertexCount + vertexCount > pipeline.vertexCapacity)
{
pipeline.flush();
}
@ -92,8 +92,8 @@ var MeshWebGLRenderer = function (renderer, src, interpolationPercentage, camera
if (camera.roundPixels)
{
tx |= 0;
ty |= 0;
tx = Math.round(tx);
ty = Math.round(ty);
}
vertexViewF32[++vertexOffset] = tx;

View file

@ -78,14 +78,14 @@ var Wrap = require('../../math/Wrap');
/**
* @typedef {object} EmitterOpCustomEmitConfig
*
* @property {EmitterOpOnEmitCallback} onEmit - [description]
* @property {EmitterOpOnEmitCallback} onEmit - A callback that is invoked each time the emitter emits a particle.
*/
/**
* @typedef {object} EmitterOpCustomUpdateConfig
*
* @property {EmitterOpOnEmitCallback} [onEmit] - [description]
* @property {EmitterOpOnUpdateCallback} onUpdate - [description]
* @property {EmitterOpOnEmitCallback} [onEmit] - A callback that is invoked each time the emitter emits a particle.
* @property {EmitterOpOnUpdateCallback} onUpdate - A callback that is invoked each time the emitter updates.
*/
/**

View file

@ -12,14 +12,18 @@ var GetFastValue = require('../../utils/object/GetFastValue');
*
* @property {number} [x=0] - The x coordinate of the Gravity Well, in world space.
* @property {number} [y=0] - The y coordinate of the Gravity Well, in world space.
* @property {number} [power=0] - The power of the Gravity Well.
* @property {number} [epsilon=100] - [description]
* @property {number} [power=0] - The strength of the gravity force - larger numbers produce a stronger force.
* @property {number} [epsilon=100] - The minimum distance for which the gravity force is calculated.
* @property {number} [gravity=50] - The gravitational force of this Gravity Well.
*/
/**
* @classdesc
* [description]
* The GravityWell action applies a force on the particle to draw it towards, or repel it from, a single point.
*
* The force applied is inversely proportional to the square of the distance from the particle to the point, in accordance with Newton's law of gravity.
*
* This simulates the effect of gravity over large distances (as between planets, for example).
*
* @class GravityWell
* @memberof Phaser.GameObjects.Particles
@ -28,8 +32,8 @@ var GetFastValue = require('../../utils/object/GetFastValue');
*
* @param {(number|GravityWellConfig)} [x=0] - The x coordinate of the Gravity Well, in world space.
* @param {number} [y=0] - The y coordinate of the Gravity Well, in world space.
* @param {number} [power=0] - The power of the Gravity Well.
* @param {number} [epsilon=100] - [description]
* @param {number} [power=0] - The strength of the gravity force - larger numbers produce a stronger force.
* @param {number} [epsilon=100] - The minimum distance for which the gravity force is calculated.
* @param {number} [gravity=50] - The gravitational force of this Gravity Well.
*/
var GravityWell = new Class({
@ -118,7 +122,7 @@ var GravityWell = new Class({
this._epsilon = 0;
/**
* The power of the Gravity Well.
* The strength of the gravity force - larger numbers produce a stronger force.
*
* @name Phaser.GameObjects.Particles.GravityWell#power
* @type {number}
@ -127,7 +131,7 @@ var GravityWell = new Class({
this.power = power;
/**
* [description]
* The minimum distance for which the gravity force is calculated.
*
* @name Phaser.GameObjects.Particles.GravityWell#epsilon
* @type {number}

View file

@ -47,16 +47,6 @@ var Particle = new Class({
*/
this.frame = null;
/**
* The position of this Particle within its Emitter's particle pool.
*
* @name Phaser.GameObjects.Particles.Particle#index
* @type {number}
* @default 0
* @since 3.0.0
*/
this.index = 0;
/**
* The x coordinate of this Particle.
*
@ -276,6 +266,18 @@ var Particle = new Class({
return (this.lifeCurrent > 0);
},
/**
* Resets the position of this particle back to zero.
*
* @method Phaser.GameObjects.Particles.Particle#resetPosition
* @since 3.16.0
*/
resetPosition: function ()
{
this.x = 0;
this.y = 0;
},
/**
* Starts this Particle from the given coordinates.
*
@ -382,8 +384,6 @@ var Particle = new Class({
this.alpha = emitter.alpha.onEmit(this, 'alpha');
this.tint = emitter.tint.onEmit(this, 'tint');
this.index = emitter.alive.length;
},
/**

View file

@ -2012,13 +2012,9 @@ var ParticleEmitter = new Class({
for (var i = 0; i < count; i++)
{
var particle;
var particle = dead.pop();
if (dead.length > 0)
{
particle = dead.pop();
}
else
if (!particle)
{
particle = new this.particleClass(this);
}
@ -2073,47 +2069,49 @@ var ParticleEmitter = new Class({
var processors = this.manager.getProcessors();
var particles = this.alive;
var dead = this.dead;
var i = 0;
var rip = [];
var length = particles.length;
for (var index = 0; index < length; index++)
for (i = 0; i < length; i++)
{
var particle = particles[index];
var particle = particles[i];
// update returns `true` if the particle is now dead (lifeStep < 0)
// update returns `true` if the particle is now dead (lifeCurrent <= 0)
if (particle.update(delta, step, processors))
{
// Moves the dead particle to the end of the particles array (ready for splicing out later)
var last = particles[length - 1];
particles[length - 1] = particle;
particles[index] = last;
index -= 1;
length -= 1;
rip.push({ index: i, particle: particle });
}
}
// Move dead particles to the dead array
var deadLength = particles.length - length;
length = rip.length;
if (deadLength > 0)
if (length > 0)
{
var rip = particles.splice(particles.length - deadLength, deadLength);
var deathCallback = this.deathCallback;
var deathCallbackScope = this.deathCallbackScope;
if (deathCallback)
for (i = length - 1; i >= 0; i--)
{
for (var i = 0; i < rip.length; i++)
var entry = rip[i];
// Remove from particles array
particles.splice(entry.index, 1);
// Add to dead array
dead.push(entry.particle);
// Callback
if (deathCallback)
{
deathCallback.call(deathCallbackScope, rip[i]);
deathCallback.call(deathCallbackScope, entry.particle);
}
entry.particle.resetPosition();
}
this.dead.concat(rip);
StableSort.inplace(particles, this.indexSortCallback);
}
if (!this.on)
@ -2153,22 +2151,6 @@ var ParticleEmitter = new Class({
depthSortCallback: function (a, b)
{
return a.y - b.y;
},
/**
* Calculates the difference of two particles, for sorting them by index.
*
* @method Phaser.GameObjects.Particles.ParticleEmitter#indexSortCallback
* @since 3.0.0
*
* @param {object} a - The first particle.
* @param {object} b - The second particle.
*
* @return {integer} The difference of a and b's `index` properties.
*/
indexSortCallback: function (a, b)
{
return a.index - b.index;
}
});

View file

@ -99,8 +99,8 @@ var ParticleManagerCanvasRenderer = function (renderer, emitterManager, interpol
if (roundPixels)
{
x |= 0;
y |= 0;
x = Math.round(x);
y = Math.round(y);
}
ctx.drawImage(frame.source.image, cd.x, cd.y, cd.width, cd.height, x, y, cd.width, cd.height);

Some files were not shown because too many files have changed in this diff Show more