This commit is contained in:
Richard Davey 2024-02-14 22:34:22 +00:00
commit 61a8fda08c
9 changed files with 196 additions and 18 deletions

View file

@ -21,10 +21,20 @@ The Phaser LoaderPlugin and related classes have been updated so that they now w
* The `SpineGameObject.setAlpha` method has had its 2nd parameter removed. This fixes needless slot look-ups during rendering when a Spine Game Object is inside a regular Container. If you need to set slot alpha, use the new `setSlotAlpha` method instead. Fix #6571 (thanks @spayton)
* The `SpineFile.onFileComplete` handler was running a regular expression against `file.src` instead of `file.url`, sometimes leading to double paths in the atlas paths on loading. Fix #6642 (thanks @rez23)
# Input Updates
The Phaser Input and related classes have been updated to be more consistent with each Game Object.
* If you enable a Game Object for Input Debugging, the debug shape will no longer be rendered if the Game Object itself is not visible. Fix #6364 (thanks @orjandh)
* `Mesh` based Game Objects now can use an input config with the `setInteractive` method, which supports the options `draggable`, `dropzone`, `cursor` and `userHandCursor`. Fix #6510 #6652 (thanks @Baegus @Neppord)
* The touch event handler `onTouchEndWindow` now stops pointer events when clicking through DOM elements to input. Fix #6697 (thanks @laineus)
* The `Input.InputPlugin` method `disable` which is called by `GameObjects.GameObject#disableInteractive` keeps its temp hit box value which stops propagation to interactive Game Objects in another scene. Fix #6601 (thanks @UnaiNeuronUp)
* Using `setInteractive` and `removeInteractive` methods of a Game Object outside of the game loop would cause an error in which `Input.InputManager#resetCursor` would lose input context. Fix #6387 (thanks @TomorrowToday)
# Updates
* The `TweenChainBuilder` was incorrectly setting the `persist` flag on the Chain to `true`, which goes against what the documentation says. It now correctly sets it to `false`. This means if you previously had a Tween Chain that was persisting, it will no longer do so, so add the property to regain the feature.
* The `dropped` argument has now been adeded to the documentation for the `DRAG_END` and `GAMEOBJECT_DRAG_END` events. (thanks @samme)
* The `dropped` argument has now been added to the documentation for the `DRAG_END` and `GAMEOBJECT_DRAG_END` events. (thanks @samme)
* `Container.onChildDestroyed` is a new internal method used to destroy Container children. Previously, if you destroyed a Game Object in an exclusive Container, the game object would (momentarily) move onto the Scene display list and emit an ADDED_TO_SCENE event. Also, if you added a Sprite to a non-exclusive Container and stopped the Scene, you would get a TypeError (evaluating 'this.anims.destroy'). This happened because the fromChild argument in the DESTROY event was misinterpreted as destroyChild in the Container's remove(), and the Container was calling the Sprite's destroy() again. (thanks @samme)
* The `Text` and `TileSprite` Game Objects now place their textures into the global `TextureManager` and a `_textureKey` private string property has been added which contains a UUID to reference that texture.
* The `Tilemaps.Components.WeightedRandomize` method now uses the Phaser `Math.RND.frac` method with a seed instead of the `Math.Random` static method. (thanks @jorbascrumps)
@ -34,15 +44,13 @@ The Phaser LoaderPlugin and related classes have been updated so that they now w
* The `Renderer.Canvas` and `Renderer.WebGL` will now only be included in the build file if the corresponding feature flags `CANVAS_RENDERER` and/or `WEBGL_RENDERER` are set to `true`. For Canvas only builds this saves a lot of space in the build. (thanks @samme)
* You can now specify an `autoResize` boolean in the `RenderTargetConfig` which is passed to the Render Targets when they are created by a pipeline.
* The `UtilityPipeline` now sets `autoResize` to `true` in its Render Target Config, so that the global `fullFrame` and `halfFrame` Render Targets will automatically resize if the renderer changes.
* `Actions.PlaceOnLine` now has an added `ease` parameter which accepts a string from the EaseMap or a custom ease function to allow for different distrubutions along a line. (thanks @sB3p)
* If you enable a Game Object for Input Debugging, the debug shape will no longer be rendered if the Game Object itself is not visible. Fix #6364 (thanks @orjandh)
* `Actions.PlaceOnLine` now has an added `ease` parameter which accepts a string from the EaseMap or a custom ease function to allow for different distributions along a line. (thanks @sB3p)
* The `XHRLoader` will now listen for `ontimeout` and if triggered it will hand over to the `File.onError` handler. This prevents the Loader from stalling if a file times out. Fix #6472 (thanks @343dev)
* `LightPipeline.currentNormalMap` was incorrectly documented as being a property of `WebGLRenderer`.
* `Mesh` based Game Objects now can use an input config with the `setInteractive` method, which supports the options `draggable`, `dropzone`, `cursor` and `userHandCursor`. Fix #6510 #6652 (thanks @Baegus @Neppord)
* `Video` Game Objects now emit a `metadata` event, which emits once the video metadata is available.
# Bug Fixes
* The `InputManager.onTouchMove` function has been fixed so it now correctly handles touch events on pages that have scrolled horizontally or vertically and shifted the viewport. Fix #6489 (thanks @somechris @hyewonjo)
* `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)
@ -50,15 +58,14 @@ The Phaser LoaderPlugin and related classes have been updated so that they now w
* 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)
* `WebGLRenderer.getCompressedTextures` can now identify BPTC and RGTC support correctly. These were previously skipped.
* The `BloomFX` and `BlurFX` and any custom pipeline that relies on using the `UtilityPipeline` full or half frame targets will now correctly draw even after the renderer size changes. Fix #6677 (thanks @Nerodon)
* The `PostFXPipeline.postBatch` method will now skip `onDraw` if the pipeline hasn't booted, introducing an artificial frame skip. This should potentially fix glitch errors on mobile devices where Post FX would appear corrupted for a single frame. Fix #6681 (thanks @moufmouf @tongliang999)
* The `Matter.Body` function `scale` has been updated so if the Body originally had an `inertia` of `Infinity` this will be restored at the end of the call. This happens if you set a Matter Body to have fixed rotation. Fix #6369 (thanks @sushovande)
* Modified the `RandomDataGenerator.weightedPick` method to avoid sampling past the last element. Fix #6701 (thanks @jameskirkwood)
* The touch event handler `onTouchEndWindow` now stops pointer events when clicking through DOM elements to input. Fix #6697 (thanks @laineus)
* The `Physics.Matter.Factory` method `pointerConstraint` no longer returns an error when it can't find the camera. Fix #6684 (thanks @spritus)
* The `Physics.Arcade.StaticBody` method `reset` now re-applies `offset` values. Fix #6729 (thanks @samme)
* The `Input.InputPlugin` method `disable` which is called by `GameObjects.GameObject#disableInteractive` keeps its temp hit box value which stops propagation to interactive Game Objects in another scene. Fix #6601 (thanks @UnaiNeuronUp)
* Using `setInteractive` and `removeInteractive` methods of a Game Object outside of the game loop would cause an error in which `Input.InputManager#resetCursor` would lose input context. Fix #6387 (thanks @TomorrowToday)
* The `Video` Game Object now has a starting texture, which stops errors with accessing `frame` before the video loads the first frame. Fix #6475 (thanks @rexrainbow @JoeSiu)
* The `Device.Browser.safari` regular expression has been strenghtened so it now captures versions with double or triple periods in. Previously it would fail for `Version/17.2.1` due to the minor value (thanks watcher)
## Examples, Documentation, Beta Testing and TypeScript

View file

@ -0,0 +1,21 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2013-2023 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
/**
* The Video Game Object Metadata Event.
*
* This event is dispatched when a Video has access to the metadata.
*
* Listen for it from a Video Game Object instance using `Video.on('metadata', listener)`.
*
* @event Phaser.GameObjects.Events#VIDEO_METADATA
* @type {string}
* @since 3.80.0
*
* @param {Phaser.GameObjects.Video} video - The Video Game Object which fired the event.
* @param {DOMException|string} event - The native DOM event the browser raised during playback.
*/
module.exports = 'metadata';

View file

@ -18,6 +18,7 @@ module.exports = {
VIDEO_ERROR: require('./VIDEO_ERROR_EVENT'),
VIDEO_LOCKED: require('./VIDEO_LOCKED_EVENT'),
VIDEO_LOOP: require('./VIDEO_LOOP_EVENT'),
VIDEO_METADATA: require('./VIDEO_METADATA_EVENT'),
VIDEO_PLAY: require('./VIDEO_PLAY_EVENT'),
VIDEO_PLAYING: require('./VIDEO_PLAYING_EVENT'),
VIDEO_SEEKED: require('./VIDEO_SEEKED_EVENT'),

View file

@ -389,6 +389,16 @@ var Video = new Class({
*/
this._loadCallbackHandler = this.loadErrorHandler.bind(this);
/**
* The locally bound callback handler specifically for the loadedmetadata event.
*
* @name Phaser.GameObjects.Video#_metadataCallbackHandler
* @type {function}
* @private
* @since 3.80.0
*/
this._metadataCallbackHandler = this.metadataHandler.bind(this);
/**
* The internal crop data object, as used by `setCrop` and passed to the `Frame.setCropUVs` method.
*
@ -777,8 +787,6 @@ var Video = new Class({
video.src = url;
}
this.addLoadEventHandlers();
this.retry = 0;
this.video = video;
@ -786,6 +794,12 @@ var Video = new Class({
video.load();
this.addLoadEventHandlers();
var texture = this.scene.sys.textures.get(this._key);
this.setTexture(texture);
return this;
},
@ -1004,6 +1018,7 @@ var Video = new Class({
{
video.addEventListener('error', this._loadCallbackHandler);
video.addEventListener('abort', this._loadCallbackHandler);
video.addEventListener('loadedmetadata', this._metadataCallbackHandler);
}
},
@ -1454,6 +1469,32 @@ var Video = new Class({
this.emit(Events.VIDEO_ERROR, this, event);
},
/**
* This internal method is called automatically when the video metadata is available.
*
* @method Phaser.GameObjects.Video#metadataHandler
* @fires Phaser.GameObjects.Events#VIDEO_METADATA
* @since 3.80.0
*
* @param {Event} event - The loadedmetadata Event.
*/
metadataHandler: function (event)
{
var video = this.video;
if (this.scaleX !== 1)
{
this.scaleX = this.displayWidth / video.videoWidth;
}
if (this.scaleY !== 1)
{
this.scaleY = this.displayHeight / video.videoHeight;
}
this.emit(Events.VIDEO_METADATA, this, event);
},
/**
* This internal method is called automatically if the video stalls, for whatever reason.
*

View file

@ -2130,6 +2130,8 @@ var InputPlugin = new Class({
* The hit area callback is the function that takes an `x` and `y` coordinate and returns a boolean if
* those values fall within the area of the shape or not. All of the Phaser geometry objects provide this,
* such as `Phaser.Geom.Rectangle.Contains`.
*
* A hit area callback can be supplied to the `hitArea` parameter without using the `hitAreaCallback` parameter.
*
* @method Phaser.Input.InputPlugin#setHitArea
* @since 3.0.0
@ -2192,6 +2194,11 @@ var InputPlugin = new Class({
customHitArea = false;
}
}
else if (typeof hitArea === 'function' && !hitAreaCallback)
{
hitAreaCallback = hitArea;
hitArea = {};
}
for (var i = 0; i < gameObjects.length; i++)
{

View file

@ -1344,10 +1344,11 @@ var WebGLRenderer = new Class({
{
var extString = 'WEBGL_compressed_texture_';
var wkExtString = 'WEBKIT_' + extString;
var extEXTString = 'EXT_texture_compression_';
var hasExt = function (gl, format)
{
var results = gl.getExtension(extString + format) || gl.getExtension(wkExtString + format);
var results = gl.getExtension(extString + format) || gl.getExtension(wkExtString + format) || gl.getExtension(extEXTString + format);
if (results)
{

View file

@ -77,6 +77,11 @@ var Events = require('./events');
* timeline.play();
* ```
*
* The Timeline can also be looped with the repeat method:
* ```js
* timeline.repeat().play();
* ```
*
* There are lots of options available to you via the configuration object. See the
* {@link Phaser.Types.Time.TimelineEventConfig} typedef for more details.
*
@ -151,8 +156,8 @@ var Timeline = new Class({
*
* A Timeline is considered complete when all of its events have been run.
*
* If you wish to restart a Timeline after it has completed, you can do so
* by calling the `Timeline.restart` method.
* If you wish to reset a Timeline after it has completed, you can do so
* by calling the `Timeline.reset` method.
*
* You can also use the `Timeline.stop` method to stop a running Timeline,
* at any point, without resetting it.
@ -177,6 +182,28 @@ var Timeline = new Class({
*/
this.totalComplete = 0;
/**
* The number of times this timeline should loop.
*
* If this value is -1 or any negative number this Timeline will not stop.
*
* @name Phaser.Time.Timeline#loop
* @type {number}
* @since 3.80.0
*/
this.loop = 0;
/**
* The number of times this Timeline has looped.
*
* This value is incremented each loop if looping is enabled.
*
* @name Phaser.Time.Timeline#iteration
* @type {number}
* @since 3.80.0
*/
this.iteration = 0;
/**
* An array of all the Timeline Events.
*
@ -229,6 +256,8 @@ var Timeline = new Class({
* If the `TimelineEvent.event` property is set then the Timeline emits that event.
*
* If the `TimelineEvent.run` property is set then the Timeline invokes that method.
*
* If the `TimelineEvent.loop` property is set then the Timeline invokes that method when repeated.
*
* If the `TimelineEvent.target` property is set then the Timeline invokes the `run` method on that target.
*
@ -313,10 +342,20 @@ var Timeline = new Class({
event.run.call(target);
}
if (event.loop && event.repeat)
{
event.loop.call(target);
}
if (event.stop)
{
this.stop();
}
if (this.iteration)
{
event.repeat++;
}
}
}
@ -336,7 +375,16 @@ var Timeline = new Class({
// It may be greater than the length if events have been removed
if (this.totalComplete >= events.length)
{
this.complete = true;
if (this.loop !== 0 && (this.loop === -1 || this.loop > this.iteration))
{
this.iteration++;
this.reset(true);
}
else
{
this.complete = true;
}
}
if (this.complete)
@ -399,6 +447,34 @@ var Timeline = new Class({
return this;
},
/**
* Repeats this Timeline.
*
* If the value for `amount` is positive, the Timeline will repeat that many additional times.
* For example a value of 1 will actually run this Timeline twice.
*
* Depending on the value given, `false` is 0 and `true`, undefined and negative numbers are infinite.
*
* If this Timeline had any events set to `once` that have already been removed,
* they will **not** be repeated each loop.
*
* @method Phaser.Time.Timeline#repeat
* @since 3.80.0
*
* @param {number|boolean} [amount=-1] - Amount of times to repeat, if `true` or negative it will be infinite.
*
* @return {this} This Timeline instance.
*/
repeat: function (amount)
{
if (amount === undefined || amount === true) { amount = -1; }
if (amount === false) { amount = 0; }
this.loop = amount;
return this;
},
/**
* Resumes this Timeline from a paused state.
*
@ -451,16 +527,30 @@ var Timeline = new Class({
*
* @method Phaser.Time.Timeline#reset
* @since 3.60.0
*
*
* @param {boolean} [loop=false] - Set to true if you do not want to reset the loop counters.
*
* @return {this} This Timeline instance.
*/
reset: function ()
reset: function (loop)
{
if (loop === undefined) { loop = false; }
this.elapsed = 0;
if (!loop)
{
this.iteration = 0;
}
for (var i = 0; i < this.events.length; i++)
{
this.events[i].complete = false;
if (!loop)
{
this.events[i].repeat = 0;
}
}
return this.play(false);
@ -528,8 +618,10 @@ var Timeline = new Class({
events.push({
complete: false,
time: startTime,
repeat: 0,
if: GetFastValue(entry, 'if', null),
run: GetFastValue(entry, 'run', null),
loop: GetFastValue(entry, 'loop', null),
event: GetFastValue(entry, 'event', null),
target: GetFastValue(entry, 'target', null),
set: GetFastValue(entry, 'set', null),
@ -696,6 +788,11 @@ var Timeline = new Class({
* timeline.play();
* ```
*
* The Timeline can also be looped with the repeat method:
* ```js
* timeline.repeat().play();
* ```
*
* There are lots of options available to you via the configuration object. See the
* {@link Phaser.Types.Time.TimelineEventConfig} typedef for more details.
*

View file

@ -5,8 +5,10 @@
* @property {boolean} complete - Has this event completed yet?
* @property {boolean} once - Is this a once only event?
* @property {number} time - The time (in elapsed ms) at which this event will fire.
* @property {function} [repeat=0] - The amount of times this Event has repeated.
* @property {function} [if=null] - User-land callback which will be called if set. If it returns `true` then this event run all of its actions, otherwise it will be skipped.
* @property {function} [run=null] - User-land callback which will be called when the Event fires.
* @property {function} [loop=null] - User-land callback which will be called when the Event loops.
* @property {Phaser.Types.Tweens.TweenBuilderConfig|Phaser.Types.Tweens.TweenChainBuilderConfig|Phaser.Tweens.Tween|Phaser.Tweens.TweenChain} [tween=null] - Tween configuration object which will be used to create a Tween when the Event fires if set.
* @property {object} [set=null] - Object containing properties to set on the `target` when the Event fires if set.
* @property {string|object} [sound=null] - Sound configuration object which will be used to create a Sound when the Event fires if set.

View file

@ -3,9 +3,10 @@
* @since 3.60.0
*
* @property {number} [at=0] - The time (in ms) at which the Event will fire. The Timeline starts at 0.
* @property {number} [in] - If the Timeline is already running, this is the time (in ms) at which the Event will fire based on its current elapsed value. If set, overrides the `at` property.
* @property {number} [from] - Fire this event 'from' milliseconds after the previous event in the Timeline. If set it overrides the `at` and `in` properties.
* @property {number} [in] - If the Timeline is running, this is the time (in ms) at which the Event will fire based on its current elapsed value. If set it will override the `at` property.
* @property {number} [from] - Fire this event 'from' milliseconds after the previous event in the Timeline. If set it will override the `at` and `in` properties.
* @property {function} [run] - A function which will be called when the Event fires.
* @property {function} [loop] - A function which will be called when the Event loops, this does not get called if the `repeat` method is not used or on first iteration.
* @property {string} [event] - Optional string-based event name to emit when the Event fires. The event is emitted from the Timeline instance.
* @property {*} [target] - The scope (`this` object) with which to invoke the run `callback`, if set.
* @property {boolean} [once=false] - If set, the Event will be removed from the Timeline when it fires.