Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ben Richards 2024-02-21 11:49:15 +13:00
commit 60176e4b39
16 changed files with 175 additions and 42 deletions

View file

@ -4,6 +4,8 @@
* Phaser now performs a [WebGL Context Restore](WebGLContextRestore.md) to keep the game running after losing WebGL context. This affects many parts of the rendering system, but everything should work just the same unless you're doing something very technical. See the link for more details.
* The Scale Manager has a new scale mode called `EXPAND`. This is inspired by the Expand mode in Godot: "Keep aspect ratio when stretching the screen, but keep neither the base width nor height. Depending on the screen aspect ratio, the viewport will either be larger in the horizontal direction (if the screen is wider than the base size) or in the vertical direction (if the screen is taller than the original size)" (thanks @rexrainbow)
* The `Tilemap.createFromTiles` method has been updated. It will now copy the following properties, if set in the Tile, to the Sprites it creates: `rotation`, `flipX`, `flipY`, `alpha`, `visible` and `tint`. If these properties are declared in the `spriteConfig` passed to the method, those will be used instead, otherwise the Tile values are used. Fix #6711 (thanks @Nerodon)
* The `Tilemap.createFromTiles` method has a new property called `useSpriteSheet`. If this is set to `true` and you have loaded the tileset as a sprite sheet (not an image), then it will set the Sprite key and frame to match the sprite texture and tile index. Also, if you have not specified an `origin` in the spriteConfig, it will adjust the sprite positions by half the tile size, to position them accurately on the map.
# New Feature - Base64 Loader
@ -60,13 +62,16 @@ The Phaser Input and related classes have been updated to be more consistent wit
* The `Curves.Path` methods `lineTo` and `moveTo` now support `Types.Math.Vector2Like` as the first parameter. Fix #6557 (thanks @wayfu)
* The `BitmapText.setFont` method will now set the texture, size and alignment even if the same font key has been given as is already in use. Fix #6740 (thanks @AlvaroNeuronup)
* `WebGLPipeline.resizeUniform` is a new property that is defined in the `WebGLPipelineConfig`. This is a string that defines a `uResolution` property, or similar, within the pipeline shader. If the WebGL Renderer resizes, this uniform will now be updated automatically as part of the pipeline resize method. It has been added to both the Multi and Mobile pipelines as default. This fixes issues where the pipelines were rendering with old resolution values, causing graphical glitches in mostly pixel-art games. Fix #6674 #6678 (thanks @Nerodon @LazeKer)
* `WebAudioSound` will now set `hasEnded = false` as part of `stopAndRemoveBufferSource`, after the source has been stopped and disconnected. This should prevent it from being left in a `true` state if the source `onended` callback fired late, after the sound had been re-played. Fix #6657 (thanks @Demeno)
* The `ScaleManager.orientationChange` event listener will now directly refresh the Scale Manager internals. This fixes an issue where the orientation change event would fire after the window resize event, causing the Scale Manager to incorrectly report the new orientation on Chrome on iOS. Fix #6484 (thanks @spayton)
# Bug Fixes
* `Factory.staticBody` had the wrong return type in the docs/TS defs. Fix #6693 (thanks @ddhaiby)
* The `Time.Timeline` class didn't show as extending the Event Emitter, or have `config` as an optional argument in the docs / TS defs. Fix #6673 (thanks @ghclark2)
* The `Animations.AnimationFrame` member `duration` is now the complete duration of the frame, which is a breaking change. Before this `Animations.AnimationState#msPerFrame` was combined with `Animations.AnimationFrame#duration` which wasn't intuitive. The fix to remove `Animations.AnimationState#msPerFrame` from `Animations.AnimationFrame#duration` has been removed from the `Animations.AnimationManager` method `createFromAseprite` because of this clarification. Fix #6712 (thanks @Nerodon @TomMalitz)
* The `NineSlice` Game Object method `setSize` now recalculates its origin by calling the `updateDisplayOrigin` method. (thanks @dhashvir)
* The `NineSlice` Game Object method `setSize` now recalculates its origin by calling the `updateDisplayOrigin` method. Fix #6713 (thanks @dhashvir)
* The `NineSlice` Game Object method no longer defaults origin to `0.5`. Fix #6655 (thanks @michalfialadev)
* When a `Layer` Game Object is destroyed, i.e. from changing or restarting a Scene, it will no longer cause an error when trying to destroy the children on its display list. Fix #6675 (thanks @crockergd @gm0nk)
* `DynamicTexture` will now automatically call `setSize(width, height)` for both WebGL and Canvas. Previously it only did it for WebGL. This fixes an issue where DynamicTextures in Canvas mode would have a width and height of -1. Fix #6682 (thanks @samme)
* `DynamicTexture.setSize` will now check to see if the `glTexture` bound to the current frame is stale, and if so, destroy it before binding the one from the Render Target. This fixes an issue where constantly destroying and creating Dynamic Textures would cause a memory leak in WebGL. Fix #6669 (thanks @DavidTalevski)
@ -93,13 +98,16 @@ The Phaser Input and related classes have been updated to be more consistent wit
My thanks to the following for helping with the Phaser 3 Examples, Beta Testing, Docs, and TypeScript definitions, either by reporting errors, fixing them, or helping author the docs:
@AlvaroEstradaDev
@stevenwithaph
@paxperscientiam
@samme
@actionmoon
@rafael-lua
@AlvaroEstradaDev
@Byvire
@yaustar
@Creepypoke
@Flashfyre
@orcomarcio
@paxperscientiam
@michalfialadev
@rafael-lua
@samme
@Stan-Stani
@stevenwithaph
@yaustar

View file

@ -50,12 +50,14 @@ var Crop = {
* Cropping a Game Object does not change its size, dimensions, physics body or hit area, it just
* changes what is shown when rendered.
*
* The crop size as well as coordinates can not exceed the the size of the texture frame.
*
* The crop coordinates are relative to the texture frame, not the Game Object, meaning 0 x 0 is the top-left.
*
* Therefore, if you had a Game Object that had an 800x600 sized texture, and you wanted to show only the left
* half of it, you could call `setCrop(0, 0, 400, 600)`.
*
* It is also scaled to match the Game Object scale automatically. Therefore a crop rect of 100x50 would crop
* It is also scaled to match the Game Object scale automatically. Therefore a crop rectangle of 100x50 would crop
* an area of 200x100 when applied to a Game Object that had a scale factor of 2.
*
* You can either pass in numeric values directly, or you can provide a single Rectangle object as the first argument.
@ -68,10 +70,10 @@ var Crop = {
* @method Phaser.GameObjects.Components.Crop#setCrop
* @since 3.11.0
*
* @param {(number|Phaser.Geom.Rectangle)} [x] - The x coordinate to start the crop from. Or a Phaser.Geom.Rectangle object, in which case the rest of the arguments are ignored.
* @param {number} [y] - The y coordinate to start the crop from.
* @param {number} [width] - The width of the crop rectangle in pixels.
* @param {number} [height] - The height of the crop rectangle in pixels.
* @param {(number|Phaser.Geom.Rectangle)} [x] - The x coordinate to start the crop from. Cannot be negative or exceed the Frame width. Or a Phaser.Geom.Rectangle object, in which case the rest of the arguments are ignored.
* @param {number} [y] - The y coordinate to start the crop from. Cannot be negative or exceed the Frame height.
* @param {number} [width] - The width of the crop rectangle in pixels. Cannot exceed the Frame width.
* @param {number} [height] - The height of the crop rectangle in pixels. Cannot exceed the Frame height.
*
* @return {this} This Game Object instance.
*/

View file

@ -55,12 +55,14 @@ var TextureCrop = {
* Cropping a Game Object does not change its size, dimensions, physics body or hit area, it just
* changes what is shown when rendered.
*
* The crop size as well as coordinates can not exceed the the size of the texture frame.
*
* The crop coordinates are relative to the texture frame, not the Game Object, meaning 0 x 0 is the top-left.
*
* Therefore, if you had a Game Object that had an 800x600 sized texture, and you wanted to show only the left
* half of it, you could call `setCrop(0, 0, 400, 600)`.
*
* It is also scaled to match the Game Object scale automatically. Therefore a crop rect of 100x50 would crop
* It is also scaled to match the Game Object scale automatically. Therefore a crop rectangle of 100x50 would crop
* an area of 200x100 when applied to a Game Object that had a scale factor of 2.
*
* You can either pass in numeric values directly, or you can provide a single Rectangle object as the first argument.
@ -73,10 +75,10 @@ var TextureCrop = {
* @method Phaser.GameObjects.Components.TextureCrop#setCrop
* @since 3.11.0
*
* @param {(number|Phaser.Geom.Rectangle)} [x] - The x coordinate to start the crop from. Or a Phaser.Geom.Rectangle object, in which case the rest of the arguments are ignored.
* @param {number} [y] - The y coordinate to start the crop from.
* @param {number} [width] - The width of the crop rectangle in pixels.
* @param {number} [height] - The height of the crop rectangle in pixels.
* @param {(number|Phaser.Geom.Rectangle)} [x] - The x coordinate to start the crop from. Cannot be negative or exceed the Frame width. Or a Phaser.Geom.Rectangle object, in which case the rest of the arguments are ignored.
* @param {number} [y] - The y coordinate to start the crop from. Cannot be negative or exceed the Frame height.
* @param {number} [width] - The width of the crop rectangle in pixels. Cannot exceed the Frame width.
* @param {number} [height] - The height of the crop rectangle in pixels. Cannot exceed the Frame height.
*
* @return {this} This Game Object instance.
*/

View file

@ -65,6 +65,9 @@ var Vector4 = require('../../math/Vector4');
* entirely and clipped accordingly. DOM Elements respect camera scrolling and scrollFactor settings, but if you
* change the size of the camera so it no longer matches the size of the canvas, they won't be clipped accordingly.
*
* DOM Game Objects can be added to a Phaser Container, however you should only nest them **one level deep**.
* Any further down the chain and they will ignore all root container properties.
*
* Also, all DOM Elements are inserted into the same DOM Container, regardless of which Scene they are created in.
*
* Note that you should only have DOM Elements in a Scene with a _single_ Camera. If you require multiple cameras,

View file

@ -331,7 +331,7 @@ var NineSlice = new Class({
this.setSlices(width, height, leftWidth, rightWidth, topHeight, bottomHeight, false);
this.setOrigin(0.5, 0.5);
this.updateDisplayOrigin();
this.initPipeline();
this.initPostPipeline();

View file

@ -60,7 +60,7 @@
* @property {number|number[]|string|string[]|Phaser.Textures.Frame|Phaser.Textures.Frame[]|Phaser.Types.GameObjects.Particles.ParticleEmitterFrameConfig} [frame] - Sets {@link Phaser.GameObjects.Particles.ParticleEmitter#frames}.
* @property {string|Phaser.Textures.Texture} [texture] - Sets {@link Phaser.GameObjects.Particles.ParticleEmitter#texture}. Overrides any texture already set on the Emitter.
* @property {number} [reserve] - Creates specified number of inactive particles and adds them to this emitter's pool. {@link Phaser.GameObjects.Particles.ParticleEmitter#reserve}
* @property {number} [advance] - If you wish to 'fast forward' the emitter in time, set this value to a number representing the amount of ms the emitter should advance.
* @property {number} [advance] - If you wish to 'fast forward' the emitter in time, set this value to a number representing the amount of ms the emitter should advance. Doing so implicitly sets `emitting` to `true`.
* @property {number} [duration] - Limit the emitter to emit particles for a maximum of `duration` ms. Default to zero, meaning 'forever'.
* @property {number} [stopAfter] - Limit the emitter to emit this exact number of particles and then stop. Default to zero, meaning no limit.
* @property {Phaser.Types.GameObjects.Particles.ParticleSortCallback} [sortCallback] - A custom callback that sorts particles prior to rendering. Sets {@link Phaser.GameObjects.Particles.ParticleEmitter#sortCallback}.

View file

@ -486,6 +486,16 @@ var Body = new Class({
*/
this.onOverlap = false;
/**
* Whether the simulation emits an `bounce` event when this Body bounces.
*
* @name Phaser.Physics.Arcade.StaticBody#onBounce
* @type {boolean}
* @default false
* @since 3.80.0
*/
this.onBounce = false;
/**
* The absolute maximum velocity of this body, in pixels per second.
* The horizontal and vertical components are applied separately.
@ -1222,6 +1232,11 @@ var Body = new Class({
var blocked = this.blocked;
this.world.emit(Events.WORLD_BOUNDS, this, blocked.up, blocked.down, blocked.left, blocked.right);
if (this.onBounce && this.bounce.length())
{
this.emit(Events.BOUNCE, this);
}
}
},

View file

@ -295,6 +295,17 @@ var StaticBody = new Class({
*/
this.onOverlap = false;
/**
* Whether the simulation emits an `bounce` event when this StaticBody bounces.
* Always false for a Static Body. (Static Bodies never bounce and never trigger a `bounce` event.)
*
* @name Phaser.Physics.Arcade.StaticBody#onBounce
* @type {boolean}
* @default false
* @since 3.80.0
*/
this.onBounce = false;
/**
* The StaticBody's inertia, relative to a default unit (1). With `bounce`, this affects the exchange of momentum (velocities) during collisions.
*

View file

@ -1469,6 +1469,16 @@ var World = new Class({
else if (body1.onCollide || body2.onCollide)
{
this.emit(Events.COLLIDE, body1.gameObject, body2.gameObject, body1, body2);
if (body1.onBounce && body1.bounce.length())
{
this.emit(Events.BOUNCE, body1);
}
if (body2.onBounce && body2.bounce.length())
{
this.emit(Events.BOUNCE, body2);
}
}
}

View file

@ -0,0 +1,24 @@
/**
* @author Richard Davey <rich@phaser.io>
* @copyright 2013-2024 Phaser Studio Inc.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
/**
* The Arcade Physics World Bounce Event.
*
* This event is dispatched by an Arcade Physics World instance if a body collides with a body or world bounds
* _and_ it has its [onBounce]{@link Phaser.Physics.Arcade.Body#onBounce} property set to `true` while having
* a bounce magnitude above 0.
*
* It provides an alternative means to handling collide events rather than using the callback approach.
*
* Listen to it from a Scene using: `this.physics.world.on('bounce', listener)`.
*
* @event Phaser.Physics.Arcade.Events#BOUNCE
* @type {string}
* @since 3.80.0
*
* @param {Phaser.Physics.Arcade.Body} body - The Arcade Physics Body that bounced.
*/
module.exports = 'bounce';

View file

@ -10,6 +10,7 @@
module.exports = {
BOUNCE: require('./BOUNCE_EVENT'),
COLLIDE: require('./COLLIDE_EVENT'),
OVERLAP: require('./OVERLAP_EVENT'),
PAUSE: require('./PAUSE_EVENT'),

View file

@ -1511,6 +1511,8 @@ var ScaleManager = new Class({
_this._checkOrientation = true;
_this.dirty = true;
_this.refresh();
};
listeners.windowResize = function ()

View file

@ -444,13 +444,17 @@ var WebAudioSound = new Class({
{
if (this.source)
{
this.source.stop();
this.source.disconnect();
var tempSource = this.source;
this.source = null;
tempSource.stop();
tempSource.disconnect();
}
this.playTime = 0;
this.startTime = 0;
this.hasEnded = false;
this.stopAndRemoveLoopBufferSource();
},
@ -622,8 +626,6 @@ var WebAudioSound = new Class({
if (this.hasEnded)
{
this.hasEnded = false;
BaseSound.prototype.stop.call(this);
this.stopAndRemoveBufferSource();

View file

@ -485,6 +485,8 @@ var Frame = new Class({
* Takes a crop data object and, based on the rectangular region given, calculates the
* required UV coordinates in order to crop this Frame for WebGL and Canvas rendering.
*
* The crop size as well as coordinates can not exceed the the size of the frame.
*
* This is called directly by the Game Object Texture Components `setCrop` method.
* Please use that method to crop a Game Object.
*

View file

@ -198,8 +198,11 @@ var Tilemap = new Class({
/**
* Map specific properties as specified in Tiled.
*
* Depending on the version of Tiled and the JSON export used, this will be either
* an object or an array of objects. For Tiled 1.2.0+ maps, it will be an array.
*
* @name Phaser.Tilemaps.Tilemap#properties
* @type {object}
* @type {object|object[]}
* @since 3.0.0
*/
this.properties = mapData.properties;
@ -910,11 +913,27 @@ var Tilemap = new Class({
},
/**
* Creates a Sprite for every object matching the given tile indexes in the layer. You can
* Creates a Sprite for every tile matching the given tile indexes in the layer. You can
* optionally specify if each tile will be replaced with a new tile after the Sprite has been
* created. This is useful if you want to lay down special tiles in a level that are converted to
* created. Set this value to -1 if you want to just remove the tile after conversion.
*
* This is useful if you want to lay down special tiles in a level that are converted to
* Sprites, but want to replace the tile itself with a floor tile or similar once converted.
*
* The following features were added in Phaser v3.80:
*
* By default, Phaser Sprites have their origin set to 0.5 x 0.5. If you don't specify a new
* origin in the spriteConfig, then it will adjust the sprite positions by half the tile size,
* to position them accurately on the map.
*
* When the Sprite is created it will copy the following properties from the tile:
*
* 'rotation', 'flipX', 'flipY', 'alpha', 'visible' and 'tint'.
*
* The spriteConfig also has a special property called `useSpriteSheet`. If this is set to
* `true` and you have loaded the tileset as a sprite sheet (not an image), then it will
* set the Sprite key and frame to match the sprite texture and tile index.
*
* @method Phaser.Tilemaps.Tilemap#createFromTiles
* @since 3.0.0
*
@ -922,7 +941,7 @@ var Tilemap = new Class({
* @param {?(number|array)} replacements - The tile index, or array of indexes, to change a converted
* tile to. Set to `null` to leave the tiles unchanged. If an array is given, it is assumed to be a
* one-to-one mapping with the indexes array.
* @param {Phaser.Types.GameObjects.Sprite.SpriteConfig} spriteConfig - The config object to pass into the Sprite creator (i.e. scene.make.sprite).
* @param {Phaser.Types.GameObjects.Sprite.SpriteConfig} [spriteConfig] - The config object to pass into the Sprite creator (i.e. scene.make.sprite).
* @param {Phaser.Scene} [scene] - The Scene to create the Sprites within.
* @param {Phaser.Cameras.Scene2D.Camera} [camera] - The Camera to use when calculating the tile index from the world values.
* @param {(string|number|Phaser.Tilemaps.TilemapLayer)} [layer] - The tile layer to use. If not given the current layer is used.

View file

@ -4,6 +4,7 @@
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var DeepCopy = require('../../utils/object/DeepCopy');
var GetTilesWithin = require('./GetTilesWithin');
var ReplaceByIndex = require('./ReplaceByIndex');
@ -39,39 +40,70 @@ var CreateFromTiles = function (indexes, replacements, spriteConfig, scene, came
if (!scene) { scene = tilemapLayer.scene; }
if (!camera) { camera = scene.cameras.main; }
var tiles = GetTilesWithin(0, 0, layer.width, layer.height, null, layer);
var layerWidth = layer.width;
var layerHeight = layer.height;
var tiles = GetTilesWithin(0, 0, layerWidth, layerHeight, null, layer);
var sprites = [];
var i;
var mergeExtras = function (config, tile, properties)
{
for (var i = 0; i < properties.length; i++)
{
var property = properties[i];
if (!config.hasOwnProperty(property))
{
config[property] = tile[property];
}
}
};
for (i = 0; i < tiles.length; i++)
{
var tile = tiles[i];
var config = DeepCopy(spriteConfig);
if (indexes.indexOf(tile.index) !== -1)
{
var point = tilemapLayer.tileToWorldXY(tile.x, tile.y, undefined, camera,layer);
spriteConfig.x = point.x;
spriteConfig.y = point.y;
config.x = point.x;
config.y = point.y;
sprites.push(scene.make.sprite(spriteConfig));
mergeExtras(config, tile, [ 'rotation', 'flipX', 'flipY', 'alpha', 'visible', 'tint' ]);
if (!config.hasOwnProperty('origin'))
{
config.x += tile.width * 0.5;
config.y += tile.height * 0.5;
}
if (config.hasOwnProperty('useSpriteSheet'))
{
config.key = tile.tileset.image;
config.frame = tile.index - 1;
}
sprites.push(scene.make.sprite(config));
}
}
if (typeof replacements === 'number')
{
// Assume 1 replacement for all types of tile given
for (i = 0; i < indexes.length; i++)
{
ReplaceByIndex(indexes[i], replacements, 0, 0, layer.width, layer.height, layer);
}
}
else if (Array.isArray(replacements))
if (Array.isArray(replacements))
{
// Assume 1 to 1 mapping with indexes array
for (i = 0; i < indexes.length; i++)
{
ReplaceByIndex(indexes[i], replacements[i], 0, 0, layer.width, layer.height, layer);
ReplaceByIndex(indexes[i], replacements[i], 0, 0, layerWidth, layerHeight, layer);
}
}
else if (replacements !== null)
{
// Assume 1 replacement for all types of tile given
for (i = 0; i < indexes.length; i++)
{
ReplaceByIndex(indexes[i], replacements, 0, 0, layerWidth, layerHeight, layer);
}
}