@vpmedia/phaser 1.123.0 → 1.125.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +635 -623
- package/dist/index.js.map +1 -1
- package/dist/phaser/core/animation.d.ts +3 -3
- package/dist/phaser/core/animation.d.ts.map +1 -1
- package/dist/phaser/core/animation_manager.d.ts.map +1 -1
- package/dist/phaser/core/animation_parser.d.ts +27 -2
- package/dist/phaser/core/animation_parser.d.ts.map +1 -1
- package/dist/phaser/core/array_set.d.ts +11 -11
- package/dist/phaser/core/array_set.d.ts.map +1 -1
- package/dist/phaser/core/cache.d.ts.map +1 -1
- package/dist/phaser/core/callback.d.ts.map +1 -1
- package/dist/phaser/core/dom.d.ts +125 -19
- package/dist/phaser/core/dom.d.ts.map +1 -1
- package/dist/phaser/core/factory.d.ts +3 -2
- package/dist/phaser/core/factory.d.ts.map +1 -1
- package/dist/phaser/core/frame_data.d.ts.map +1 -1
- package/dist/phaser/core/input.d.ts +3 -2
- package/dist/phaser/core/input.d.ts.map +1 -1
- package/dist/phaser/core/input_handler.d.ts.map +1 -1
- package/dist/phaser/core/input_mouse.d.ts +5 -1
- package/dist/phaser/core/input_mouse.d.ts.map +1 -1
- package/dist/phaser/core/input_pointer.d.ts +3 -3
- package/dist/phaser/core/input_pointer.d.ts.map +1 -1
- package/dist/phaser/core/input_touch.d.ts +8 -8
- package/dist/phaser/core/input_touch.d.ts.map +1 -1
- package/dist/phaser/core/loader.d.ts +11 -2
- package/dist/phaser/core/loader.d.ts.map +1 -1
- package/dist/phaser/core/loader_parser.d.ts +14 -1
- package/dist/phaser/core/loader_parser.d.ts.map +1 -1
- package/dist/phaser/core/raf.d.ts +1 -1
- package/dist/phaser/core/raf.d.ts.map +1 -1
- package/dist/phaser/core/scale_manager.d.ts.map +1 -1
- package/dist/phaser/core/scene_manager.d.ts.map +1 -1
- package/dist/phaser/core/signal.d.ts.map +1 -1
- package/dist/phaser/core/sound.d.ts.map +1 -1
- package/dist/phaser/core/sound_manager.d.ts +1 -1
- package/dist/phaser/core/sound_manager.d.ts.map +1 -1
- package/dist/phaser/core/stage.d.ts +16 -6
- package/dist/phaser/core/stage.d.ts.map +1 -1
- package/dist/phaser/core/time.d.ts.map +1 -1
- package/dist/phaser/core/timer.d.ts +1 -1
- package/dist/phaser/core/timer.d.ts.map +1 -1
- package/dist/phaser/core/tween.d.ts +13 -5
- package/dist/phaser/core/tween.d.ts.map +1 -1
- package/dist/phaser/core/tween_data.d.ts +9 -7
- package/dist/phaser/core/tween_data.d.ts.map +1 -1
- package/dist/phaser/core/tween_manager.d.ts.map +1 -1
- package/dist/phaser/display/button.d.ts +6 -5
- package/dist/phaser/display/button.d.ts.map +1 -1
- package/dist/phaser/display/canvas/buffer.d.ts +1 -1
- package/dist/phaser/display/canvas/buffer.d.ts.map +1 -1
- package/dist/phaser/display/canvas/masker.d.ts +1 -1
- package/dist/phaser/display/canvas/masker.d.ts.map +1 -1
- package/dist/phaser/display/canvas/pool.d.ts +2 -2
- package/dist/phaser/display/canvas/pool.d.ts.map +1 -1
- package/dist/phaser/display/canvas/renderer.d.ts +9 -8
- package/dist/phaser/display/canvas/renderer.d.ts.map +1 -1
- package/dist/phaser/display/display_object.d.ts +5 -3
- package/dist/phaser/display/display_object.d.ts.map +1 -1
- package/dist/phaser/display/graphics.d.ts +1 -1
- package/dist/phaser/display/graphics.d.ts.map +1 -1
- package/dist/phaser/display/group.d.ts +1 -1
- package/dist/phaser/display/group.d.ts.map +1 -1
- package/dist/phaser/display/image.d.ts +6 -5
- package/dist/phaser/display/image.d.ts.map +1 -1
- package/dist/phaser/display/sprite_util.d.ts +3 -2
- package/dist/phaser/display/sprite_util.d.ts.map +1 -1
- package/dist/phaser/display/text.d.ts +2 -16
- package/dist/phaser/display/text.d.ts.map +1 -1
- package/dist/phaser/display/webgl/abstract_filter.d.ts +14 -8
- package/dist/phaser/display/webgl/abstract_filter.d.ts.map +1 -1
- package/dist/phaser/display/webgl/blend_manager.d.ts +2 -3
- package/dist/phaser/display/webgl/blend_manager.d.ts.map +1 -1
- package/dist/phaser/display/webgl/earcut.d.ts.map +1 -1
- package/dist/phaser/display/webgl/fast_sprite_batch.d.ts +11 -5
- package/dist/phaser/display/webgl/fast_sprite_batch.d.ts.map +1 -1
- package/dist/phaser/display/webgl/filter_manager.d.ts +6 -4
- package/dist/phaser/display/webgl/filter_manager.d.ts.map +1 -1
- package/dist/phaser/display/webgl/filter_texture.d.ts +4 -4
- package/dist/phaser/display/webgl/filter_texture.d.ts.map +1 -1
- package/dist/phaser/display/webgl/graphics.d.ts +2 -2
- package/dist/phaser/display/webgl/graphics.d.ts.map +1 -1
- package/dist/phaser/display/webgl/mask_manager.d.ts +3 -2
- package/dist/phaser/display/webgl/mask_manager.d.ts.map +1 -1
- package/dist/phaser/display/webgl/render_texture.d.ts +11 -8
- package/dist/phaser/display/webgl/render_texture.d.ts.map +1 -1
- package/dist/phaser/display/webgl/renderer.d.ts +8 -4
- package/dist/phaser/display/webgl/renderer.d.ts.map +1 -1
- package/dist/phaser/display/webgl/shader/normal.d.ts +28 -3
- package/dist/phaser/display/webgl/shader/normal.d.ts.map +1 -1
- package/dist/phaser/display/webgl/sprite_batch.d.ts +6 -5
- package/dist/phaser/display/webgl/sprite_batch.d.ts.map +1 -1
- package/dist/phaser/display/webgl/stencil_manager.d.ts +3 -3
- package/dist/phaser/display/webgl/stencil_manager.d.ts.map +1 -1
- package/dist/phaser/display/webgl/texture.d.ts.map +1 -1
- package/dist/phaser/display/webgl/texture_util.d.ts +2 -2
- package/dist/phaser/display/webgl/texture_util.d.ts.map +1 -1
- package/dist/phaser/display/webgl/util.d.ts +1 -1
- package/dist/phaser/display/webgl/util.d.ts.map +1 -1
- package/dist/phaser/geom/circle.d.ts.map +1 -1
- package/dist/phaser/geom/line.d.ts +10 -1
- package/dist/phaser/geom/line.d.ts.map +1 -1
- package/dist/phaser/geom/rectangle.d.ts.map +1 -1
- package/dist/phaser/geom/util/circle.d.ts +2 -1
- package/dist/phaser/geom/util/circle.d.ts.map +1 -1
- package/dist/phaser/geom/util/point.d.ts +1 -1
- package/dist/phaser/geom/util/point.d.ts.map +1 -1
- package/dist/phaser/geom/util/rectangle.d.ts +1 -1
- package/dist/phaser/geom/util/rectangle.d.ts.map +1 -1
- package/dist/phaser/util/math.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/phaser/core/animation.ts +11 -11
- package/src/phaser/core/animation_manager.ts +12 -12
- package/src/phaser/core/animation_parser.ts +39 -37
- package/src/phaser/core/array_set.ts +28 -28
- package/src/phaser/core/cache.test.ts +33 -33
- package/src/phaser/core/cache.ts +7 -7
- package/src/phaser/core/callback.ts +1 -0
- package/src/phaser/core/callback_context.test.ts +8 -8
- package/src/phaser/core/device_util.ts +4 -4
- package/src/phaser/core/dom.ts +38 -24
- package/src/phaser/core/factory.ts +9 -2
- package/src/phaser/core/frame_data.test.ts +23 -23
- package/src/phaser/core/frame_data.ts +2 -5
- package/src/phaser/core/game.ts +12 -12
- package/src/phaser/core/input.ts +11 -10
- package/src/phaser/core/input_handler.test.ts +18 -18
- package/src/phaser/core/input_handler.ts +14 -14
- package/src/phaser/core/input_mouse.ts +13 -12
- package/src/phaser/core/input_pointer.test.ts +26 -26
- package/src/phaser/core/input_pointer.ts +4 -4
- package/src/phaser/core/input_touch.ts +8 -8
- package/src/phaser/core/loader.test.ts +26 -26
- package/src/phaser/core/loader.ts +63 -75
- package/src/phaser/core/loader_parser.test.ts +16 -16
- package/src/phaser/core/loader_parser.ts +16 -6
- package/src/phaser/core/raf.ts +1 -1
- package/src/phaser/core/registry.test.ts +6 -6
- package/src/phaser/core/scale_manager.ts +12 -11
- package/src/phaser/core/scene_manager.test.ts +30 -30
- package/src/phaser/core/scene_manager.ts +3 -3
- package/src/phaser/core/signal.test.ts +8 -8
- package/src/phaser/core/signal.ts +3 -3
- package/src/phaser/core/signal_dispatch.test.ts +30 -30
- package/src/phaser/core/sound.ts +45 -40
- package/src/phaser/core/sound_manager.ts +18 -22
- package/src/phaser/core/sound_sprite.ts +1 -1
- package/src/phaser/core/stage.ts +22 -12
- package/src/phaser/core/time.ts +1 -1
- package/src/phaser/core/timer.test.ts +47 -47
- package/src/phaser/core/timer.ts +2 -2
- package/src/phaser/core/tween.ts +34 -36
- package/src/phaser/core/tween_data.test.ts +119 -0
- package/src/phaser/core/tween_data.ts +54 -39
- package/src/phaser/core/tween_easing.test.ts +5 -5
- package/src/phaser/core/tween_manager.ts +2 -2
- package/src/phaser/display/bitmap_text.test.ts +30 -30
- package/src/phaser/display/bitmap_text.ts +3 -3
- package/src/phaser/display/button.ts +20 -18
- package/src/phaser/display/canvas/buffer.ts +2 -2
- package/src/phaser/display/canvas/graphics.ts +2 -2
- package/src/phaser/display/canvas/masker.ts +1 -1
- package/src/phaser/display/canvas/pool.test.ts +20 -20
- package/src/phaser/display/canvas/pool.ts +6 -6
- package/src/phaser/display/canvas/renderer.ts +18 -16
- package/src/phaser/display/canvas/tinter.ts +1 -1
- package/src/phaser/display/canvas/util.test.ts +25 -25
- package/src/phaser/display/canvas/util.ts +2 -2
- package/src/phaser/display/display_object.ts +16 -15
- package/src/phaser/display/graphics.test.ts +70 -20
- package/src/phaser/display/graphics.ts +46 -42
- package/src/phaser/display/group.ts +13 -12
- package/src/phaser/display/image.ts +35 -31
- package/src/phaser/display/sprite_util.ts +4 -3
- package/src/phaser/display/text.test.ts +28 -25
- package/src/phaser/display/text.ts +56 -62
- package/src/phaser/display/webgl/abstract_filter.ts +21 -11
- package/src/phaser/display/webgl/blend_manager.ts +4 -5
- package/src/phaser/display/webgl/earcut.test.ts +20 -20
- package/src/phaser/display/webgl/earcut.ts +46 -42
- package/src/phaser/display/webgl/fast_sprite_batch.ts +21 -16
- package/src/phaser/display/webgl/filter_manager.ts +7 -4
- package/src/phaser/display/webgl/filter_texture.ts +5 -5
- package/src/phaser/display/webgl/graphics.ts +3 -3
- package/src/phaser/display/webgl/mask_manager.ts +9 -14
- package/src/phaser/display/webgl/render_texture.ts +15 -14
- package/src/phaser/display/webgl/renderer.ts +10 -9
- package/src/phaser/display/webgl/shader/normal.ts +45 -35
- package/src/phaser/display/webgl/shader/shader.test.ts +24 -24
- package/src/phaser/display/webgl/shader_manager.test.ts +18 -18
- package/src/phaser/display/webgl/shader_manager.ts +1 -1
- package/src/phaser/display/webgl/sprite_batch.ts +10 -10
- package/src/phaser/display/webgl/stencil_manager.ts +4 -4
- package/src/phaser/display/webgl/texture.ts +2 -1
- package/src/phaser/display/webgl/texture_util.ts +2 -2
- package/src/phaser/display/webgl/util.ts +4 -4
- package/src/phaser/geom/circle.test.ts +38 -38
- package/src/phaser/geom/circle.ts +7 -7
- package/src/phaser/geom/ellipse.test.ts +12 -12
- package/src/phaser/geom/line.test.ts +15 -15
- package/src/phaser/geom/line.ts +5 -2
- package/src/phaser/geom/matrix.test.ts +31 -31
- package/src/phaser/geom/point.test.ts +31 -31
- package/src/phaser/geom/polygon.test.ts +27 -27
- package/src/phaser/geom/polygon.ts +2 -2
- package/src/phaser/geom/rectangle.test.ts +87 -87
- package/src/phaser/geom/rectangle.ts +12 -13
- package/src/phaser/geom/rounded_rectangle.test.ts +9 -9
- package/src/phaser/geom/util/circle.test.ts +5 -5
- package/src/phaser/geom/util/circle.ts +8 -11
- package/src/phaser/geom/util/ellipse.test.ts +2 -2
- package/src/phaser/geom/util/line.test.ts +2 -2
- package/src/phaser/geom/util/matrix.test.ts +4 -4
- package/src/phaser/geom/util/point.test.ts +2 -2
- package/src/phaser/geom/util/point.ts +6 -8
- package/src/phaser/geom/util/polygon.test.ts +2 -2
- package/src/phaser/geom/util/rectangle.test.ts +2 -2
- package/src/phaser/geom/util/rectangle.ts +1 -1
- package/src/phaser/geom/util/rounded_rectangle.test.ts +2 -2
- package/src/phaser/util/math.test.ts +41 -41
- package/src/phaser/util/math.ts +7 -5
package/src/phaser/core/tween.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { TweenData } from './tween_data.js';
|
|
|
6
6
|
import type { Game } from './game.js';
|
|
7
7
|
import type { TweenManager } from './tween_manager.js';
|
|
8
8
|
import type { AppliedCallback, Callback, EasingFunction, InterpolationFunction } from './callback.js';
|
|
9
|
+
import type { TweenValues } from './tween_data.js';
|
|
9
10
|
|
|
10
11
|
export class Tween {
|
|
11
12
|
public game!: Game;
|
|
@@ -23,7 +24,7 @@ export class Tween {
|
|
|
23
24
|
public onComplete!: Signal;
|
|
24
25
|
public isRunning!: boolean;
|
|
25
26
|
public current!: number;
|
|
26
|
-
public properties!:
|
|
27
|
+
public properties!: TweenValues;
|
|
27
28
|
public chainedTween!: Tween | null;
|
|
28
29
|
public isPaused!: boolean;
|
|
29
30
|
public _onUpdateCallback!: Callback | null;
|
|
@@ -92,7 +93,7 @@ export class Tween {
|
|
|
92
93
|
* @returns {Tween} This Tween object for chaining.
|
|
93
94
|
*/
|
|
94
95
|
public to(
|
|
95
|
-
properties:
|
|
96
|
+
properties: TweenValues,
|
|
96
97
|
duration = 1000,
|
|
97
98
|
ease: string | EasingFunction = 'Linear',
|
|
98
99
|
autoStart = false,
|
|
@@ -100,13 +101,11 @@ export class Tween {
|
|
|
100
101
|
repeat = 0,
|
|
101
102
|
yoyo = false
|
|
102
103
|
): this {
|
|
103
|
-
|
|
104
|
-
ease = this.manager.easeMap[ease]!;
|
|
105
|
-
}
|
|
104
|
+
const easing = this.resolveEasing(ease);
|
|
106
105
|
if (this.isRunning) {
|
|
107
106
|
return this;
|
|
108
107
|
}
|
|
109
|
-
this.timeline.push(new TweenData(this).to(properties, duration,
|
|
108
|
+
this.timeline.push(new TweenData(this).to(properties, duration, easing, delay, repeat, yoyo));
|
|
110
109
|
if (autoStart) {
|
|
111
110
|
this.start();
|
|
112
111
|
}
|
|
@@ -125,7 +124,7 @@ export class Tween {
|
|
|
125
124
|
* @returns {Tween} This Tween object for chaining.
|
|
126
125
|
*/
|
|
127
126
|
public from(
|
|
128
|
-
properties:
|
|
127
|
+
properties: TweenValues,
|
|
129
128
|
duration = 1000,
|
|
130
129
|
ease: string | EasingFunction = 'Linear',
|
|
131
130
|
autoStart = false,
|
|
@@ -133,14 +132,11 @@ export class Tween {
|
|
|
133
132
|
repeat = 0,
|
|
134
133
|
yoyo = false
|
|
135
134
|
): this {
|
|
136
|
-
if (typeof ease === 'string' && this.manager.easeMap[ease]) {
|
|
137
|
-
ease = this.manager.easeMap[ease]!;
|
|
138
|
-
}
|
|
139
135
|
if (this.isRunning) {
|
|
140
136
|
this.game.logger.warn('Tween.from cannot be called after Tween.start');
|
|
141
137
|
return this;
|
|
142
138
|
}
|
|
143
|
-
this.timeline.push(new TweenData(this).from(properties, duration, ease, delay, repeat, yoyo));
|
|
139
|
+
this.timeline.push(new TweenData(this).from(properties, duration, this.resolveEasing(ease), delay, repeat, yoyo));
|
|
144
140
|
if (autoStart) {
|
|
145
141
|
this.start();
|
|
146
142
|
}
|
|
@@ -161,12 +157,9 @@ export class Tween {
|
|
|
161
157
|
// Build our master property list with the starting values
|
|
162
158
|
const keys = Object.keys(tweenData.vEnd);
|
|
163
159
|
for (const property of keys) {
|
|
164
|
-
const targetProperties = this.target as unknown as Record<string, number>;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
// Ensures we're using numbers, not strings
|
|
168
|
-
this.properties[property] *= 1;
|
|
169
|
-
}
|
|
160
|
+
const targetProperties = this.target as unknown as Record<string, number | string | undefined>;
|
|
161
|
+
// Ensures we're using numbers, not strings
|
|
162
|
+
this.properties[property] = Number(targetProperties[property] ?? 0);
|
|
170
163
|
}
|
|
171
164
|
}
|
|
172
165
|
for (const tweenData of this.timeline) {
|
|
@@ -174,10 +167,7 @@ export class Tween {
|
|
|
174
167
|
}
|
|
175
168
|
this.manager.add(this);
|
|
176
169
|
this.isRunning = true;
|
|
177
|
-
|
|
178
|
-
index = 0;
|
|
179
|
-
}
|
|
180
|
-
this.current = index;
|
|
170
|
+
this.current = index < 0 || index > this.timeline.length - 1 ? 0 : index;
|
|
181
171
|
this.timeline[this.current]!.start();
|
|
182
172
|
return this;
|
|
183
173
|
}
|
|
@@ -209,7 +199,7 @@ export class Tween {
|
|
|
209
199
|
* @param {number} index - The index in the timeline to update.
|
|
210
200
|
* @returns {Tween} This Tween object for chaining.
|
|
211
201
|
*/
|
|
212
|
-
public updateTweenData(property: string, value:
|
|
202
|
+
public updateTweenData(property: string, value: unknown, index = 0): this {
|
|
213
203
|
if (this.timeline.length === 0) {
|
|
214
204
|
return this;
|
|
215
205
|
}
|
|
@@ -283,11 +273,21 @@ export class Tween {
|
|
|
283
273
|
* @param {number} index - The index in the timeline to apply easing to.
|
|
284
274
|
* @returns {Tween} This Tween object for chaining.
|
|
285
275
|
*/
|
|
286
|
-
public
|
|
287
|
-
if (typeof ease
|
|
288
|
-
|
|
276
|
+
public resolveEasing(ease: string | EasingFunction): EasingFunction {
|
|
277
|
+
if (typeof ease !== 'string') {
|
|
278
|
+
return ease;
|
|
289
279
|
}
|
|
290
|
-
return this.
|
|
280
|
+
return this.manager.easeMap[ease] ?? this.manager.easeMap['Linear']!;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Sets the easing function for a tween in the timeline.
|
|
285
|
+
* @param {string | Function} ease - The easing function or its name.
|
|
286
|
+
* @param {number} index - The index of the tween in the timeline.
|
|
287
|
+
* @returns {Tween} This Tween object for chaining.
|
|
288
|
+
*/
|
|
289
|
+
public easing(ease: string | EasingFunction, index: number): this {
|
|
290
|
+
return this.updateTweenData('easingFunction', this.resolveEasing(ease), index);
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
/**
|
|
@@ -401,7 +401,7 @@ export class Tween {
|
|
|
401
401
|
* @returns {boolean} True if the tween should continue running, false if it's complete.
|
|
402
402
|
*/
|
|
403
403
|
public update(time: number): boolean {
|
|
404
|
-
if (this.pendingDelete || !this.target) {
|
|
404
|
+
if (this.pendingDelete || !(this.target as TweenTarget | undefined)) {
|
|
405
405
|
return false;
|
|
406
406
|
}
|
|
407
407
|
if (this.isPaused) {
|
|
@@ -484,7 +484,7 @@ export class Tween {
|
|
|
484
484
|
* @param {object[]} data - The array to store the generated data in.
|
|
485
485
|
* @returns {object[]} The populated data array.
|
|
486
486
|
*/
|
|
487
|
-
public generateData(frameRate = 60, data:
|
|
487
|
+
public generateData(frameRate = 60, data: Record<string, number>[] = []): Record<string, number>[] | null {
|
|
488
488
|
if (this.game === null || this.target === null) {
|
|
489
489
|
return null;
|
|
490
490
|
}
|
|
@@ -493,21 +493,19 @@ export class Tween {
|
|
|
493
493
|
// Build our master property list with the starting values
|
|
494
494
|
const keys = Object.keys(tweenData.vEnd);
|
|
495
495
|
for (const property of keys) {
|
|
496
|
-
const targetProperties = this.target as unknown as Record<string, number>;
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
// Ensures we're using numbers, not strings
|
|
500
|
-
this.properties[property] *= 1;
|
|
501
|
-
}
|
|
496
|
+
const targetProperties = this.target as unknown as Record<string, number | string | undefined>;
|
|
497
|
+
// Ensures we're using numbers, not strings
|
|
498
|
+
this.properties[property] = Number(targetProperties[property] ?? 0);
|
|
502
499
|
}
|
|
503
500
|
}
|
|
504
501
|
for (const tweenData of this.timeline) {
|
|
505
502
|
tweenData.loadValues();
|
|
506
503
|
}
|
|
504
|
+
const frames = [...data];
|
|
507
505
|
for (const tweenData of this.timeline) {
|
|
508
|
-
|
|
506
|
+
frames.push(...tweenData.generateData(frameRate));
|
|
509
507
|
}
|
|
510
|
-
return
|
|
508
|
+
return frames;
|
|
511
509
|
}
|
|
512
510
|
|
|
513
511
|
/**
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { TWEEN_COMPLETE, TWEEN_RUNNING } from './const.js';
|
|
3
|
+
import { Signal } from './signal.js';
|
|
4
|
+
import { Tween } from './tween.js';
|
|
5
|
+
import { TweenManager } from './tween_manager.js';
|
|
6
|
+
import type { Game } from './game.js';
|
|
7
|
+
|
|
8
|
+
const createGame = (): Game =>
|
|
9
|
+
({
|
|
10
|
+
time: { time: 0, elapsedMS: 0 },
|
|
11
|
+
logger: { warn: (): void => undefined },
|
|
12
|
+
onPause: new Signal(),
|
|
13
|
+
onResume: new Signal(),
|
|
14
|
+
}) as unknown as Game;
|
|
15
|
+
|
|
16
|
+
const createTween = (target: Record<string, number>): { game: Game; tween: Tween } => {
|
|
17
|
+
const game = createGame();
|
|
18
|
+
const manager = new TweenManager(game);
|
|
19
|
+
return { game, tween: new Tween(target, game, manager) };
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const advance = (game: Game, tween: Tween, ms: number): void => {
|
|
23
|
+
game.time.time += ms;
|
|
24
|
+
game.time.elapsedMS = ms;
|
|
25
|
+
tween.update(game.time.time);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
describe('TweenData', (): void => {
|
|
29
|
+
describe('resolveEasing', (): void => {
|
|
30
|
+
it('takes a function as-is', (): void => {
|
|
31
|
+
const { tween } = createTween({ x: 0 });
|
|
32
|
+
const ease = (k: number): number => k * k;
|
|
33
|
+
expect(tween.resolveEasing(ease)).toBe(ease);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('looks a named curve up in the manager', (): void => {
|
|
37
|
+
const { tween } = createTween({ x: 0 });
|
|
38
|
+
expect(tween.resolveEasing('Quad.easeIn')).toBe(tween.manager.easeMap['Quad.easeIn']);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('falls back to linear for a name the manager does not know', (): void => {
|
|
42
|
+
const { tween } = createTween({ x: 0 });
|
|
43
|
+
expect(tween.resolveEasing('No.Such.Curve')).toBe(tween.manager.easeMap['Linear']);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('to', (): void => {
|
|
48
|
+
it('drives a numeric property from its start value to the end value', (): void => {
|
|
49
|
+
const target = { x: 0 };
|
|
50
|
+
const { game, tween } = createTween(target);
|
|
51
|
+
tween.to({ x: 100 }, 100, 'Linear', true);
|
|
52
|
+
advance(game, tween, 50);
|
|
53
|
+
expect(target.x).toBeCloseTo(50);
|
|
54
|
+
advance(game, tween, 50);
|
|
55
|
+
expect(target.x).toBeCloseTo(100);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('reads a relative end value against the start', (): void => {
|
|
59
|
+
const target = { x: 20 };
|
|
60
|
+
const { game, tween } = createTween(target);
|
|
61
|
+
tween.to({ x: '+10' }, 100, 'Linear', true);
|
|
62
|
+
advance(game, tween, 100);
|
|
63
|
+
expect(target.x).toBeCloseTo(30);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('interpolates through a list of waypoints', (): void => {
|
|
67
|
+
const target = { x: 0 };
|
|
68
|
+
const { game, tween } = createTween(target);
|
|
69
|
+
tween.to({ x: [0, 50, 100] }, 100, 'Linear', true);
|
|
70
|
+
advance(game, tween, 100);
|
|
71
|
+
expect(target.x).toBeCloseTo(100);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// An empty waypoint list has nothing to interpolate between, so the property goes to NaN.
|
|
75
|
+
it('survives an empty waypoint list', (): void => {
|
|
76
|
+
const target = { x: 7 };
|
|
77
|
+
const { game, tween } = createTween(target);
|
|
78
|
+
tween.to({ x: [] }, 100, 'Linear', true);
|
|
79
|
+
expect((): void => {
|
|
80
|
+
advance(game, tween, 100);
|
|
81
|
+
}).not.toThrow();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('reports the tween running until the duration has passed', (): void => {
|
|
85
|
+
const target = { x: 0 };
|
|
86
|
+
const { game, tween } = createTween(target);
|
|
87
|
+
tween.to({ x: 10 }, 100, 'Linear', true);
|
|
88
|
+
game.time.time += 50;
|
|
89
|
+
game.time.elapsedMS = 50;
|
|
90
|
+
expect(tween.timeline[0]?.update(game.time.time)).toBe(TWEEN_RUNNING);
|
|
91
|
+
game.time.time += 100;
|
|
92
|
+
game.time.elapsedMS = 100;
|
|
93
|
+
expect(tween.timeline[0]?.update(game.time.time)).toBe(TWEEN_COMPLETE);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('from', (): void => {
|
|
98
|
+
it('starts at the given value and lands on the target original', (): void => {
|
|
99
|
+
const target = { x: 100 };
|
|
100
|
+
const { game, tween } = createTween(target);
|
|
101
|
+
tween.from({ x: 0 }, 100, 'Linear', true);
|
|
102
|
+
advance(game, tween, 0);
|
|
103
|
+
expect(target.x).toBeCloseTo(0);
|
|
104
|
+
advance(game, tween, 100);
|
|
105
|
+
expect(target.x).toBeCloseTo(100);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('generateData', (): void => {
|
|
110
|
+
it('produces one frame of values per step', (): void => {
|
|
111
|
+
const { tween } = createTween({ x: 0 });
|
|
112
|
+
tween.to({ x: 100 }, 100, 'Linear');
|
|
113
|
+
tween.start();
|
|
114
|
+
const data = tween.generateData(10) ?? [];
|
|
115
|
+
expect(data.length).toBeGreaterThan(0);
|
|
116
|
+
expect(data.at(-1)?.['x']).toBeCloseTo(100);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|
|
@@ -2,15 +2,18 @@ import type { Game } from './game.js';
|
|
|
2
2
|
import * as MathUtils from '../util/math.js';
|
|
3
3
|
import { TWEEN_COMPLETE, TWEEN_LOOPED, TWEEN_PENDING, TWEEN_RUNNING } from './const.js';
|
|
4
4
|
import type { Tween } from './tween.js';
|
|
5
|
-
import type { InterpolationFunction } from './callback.js';
|
|
5
|
+
import type { EasingFunction, InterpolationFunction } from './callback.js';
|
|
6
|
+
|
|
7
|
+
/** The properties a tween drives, each holding either a single target or a list of waypoints. */
|
|
8
|
+
export type TweenValues = Record<string, number | number[] | string>;
|
|
6
9
|
|
|
7
10
|
export class TweenData {
|
|
8
11
|
public parent!: Tween;
|
|
9
12
|
public game!: Game;
|
|
10
|
-
public vStart!:
|
|
11
|
-
public vStartCache!:
|
|
12
|
-
public vEnd!:
|
|
13
|
-
public vEndCache!:
|
|
13
|
+
public vStart!: TweenValues;
|
|
14
|
+
public vStartCache!: TweenValues;
|
|
15
|
+
public vEnd!: TweenValues;
|
|
16
|
+
public vEndCache!: TweenValues;
|
|
14
17
|
public duration!: number;
|
|
15
18
|
public percent!: number;
|
|
16
19
|
public value!: number;
|
|
@@ -71,7 +74,14 @@ export class TweenData {
|
|
|
71
74
|
* @param {boolean} yoyo - Whether to reverse the tween on each repeat.
|
|
72
75
|
* @returns {TweenData} This TweenData object for chaining.
|
|
73
76
|
*/
|
|
74
|
-
public to(
|
|
77
|
+
public to(
|
|
78
|
+
properties: TweenValues,
|
|
79
|
+
duration: number,
|
|
80
|
+
ease: EasingFunction,
|
|
81
|
+
delay: number,
|
|
82
|
+
repeat: number,
|
|
83
|
+
yoyo: boolean
|
|
84
|
+
): this {
|
|
75
85
|
this.vEnd = properties;
|
|
76
86
|
this.duration = duration;
|
|
77
87
|
this.easingFunction = ease;
|
|
@@ -92,7 +102,14 @@ export class TweenData {
|
|
|
92
102
|
* @param {boolean} yoyo - Whether to reverse the tween on each repeat.
|
|
93
103
|
* @returns {TweenData} This TweenData object for chaining.
|
|
94
104
|
*/
|
|
95
|
-
public from(
|
|
105
|
+
public from(
|
|
106
|
+
properties: TweenValues,
|
|
107
|
+
duration: number,
|
|
108
|
+
ease: EasingFunction,
|
|
109
|
+
delay: number,
|
|
110
|
+
repeat: number,
|
|
111
|
+
yoyo: boolean
|
|
112
|
+
): this {
|
|
96
113
|
this.vEnd = properties;
|
|
97
114
|
this.duration = duration;
|
|
98
115
|
this.easingFunction = ease;
|
|
@@ -115,9 +132,9 @@ export class TweenData {
|
|
|
115
132
|
// Reverse them all and instant set them
|
|
116
133
|
const keys = Object.keys(this.vStartCache);
|
|
117
134
|
for (const property of keys) {
|
|
118
|
-
this.vStart[property] = this.vEndCache[property]
|
|
119
|
-
this.vEnd[property] = this.vStartCache[property]
|
|
120
|
-
(this.parent.target as unknown as Record<string,
|
|
135
|
+
this.vStart[property] = this.vEndCache[property]!;
|
|
136
|
+
this.vEnd[property] = this.vStartCache[property]!;
|
|
137
|
+
(this.parent.target as unknown as Record<string, unknown>)[property] = this.vStart[property];
|
|
121
138
|
}
|
|
122
139
|
}
|
|
123
140
|
this.value = 0;
|
|
@@ -134,29 +151,27 @@ export class TweenData {
|
|
|
134
151
|
const keys = Object.keys(this.parent.properties);
|
|
135
152
|
for (const property of keys) {
|
|
136
153
|
// Load the property from the parent object
|
|
137
|
-
|
|
154
|
+
const start = this.parent.properties[property]!;
|
|
155
|
+
this.vStart[property] = start;
|
|
138
156
|
// Check if an Array was provided as property value
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
// but we only want to do this once, if the Tween hasn't run before
|
|
145
|
-
this.vEnd[property] = [this.vStart[property], ...this.vEnd[property]];
|
|
146
|
-
}
|
|
157
|
+
const end = this.vEnd[property];
|
|
158
|
+
if (Array.isArray(end) && end.length > 0 && this.percent === 0) {
|
|
159
|
+
// Put the start value at the beginning of the array
|
|
160
|
+
// but we only want to do this once, if the Tween hasn't run before
|
|
161
|
+
this.vEnd[property] = [Number(start), ...end];
|
|
147
162
|
}
|
|
148
|
-
if (
|
|
149
|
-
|
|
163
|
+
if (end === undefined) {
|
|
164
|
+
// Null tween
|
|
165
|
+
this.vEnd[property] = start;
|
|
166
|
+
} else {
|
|
167
|
+
if (typeof end === 'string') {
|
|
150
168
|
// Parses relative end values with start as base (e.g.: +10, -3)
|
|
151
|
-
this.vEnd[property] =
|
|
169
|
+
this.vEnd[property] = Number(start) + Number(end);
|
|
152
170
|
}
|
|
153
|
-
this.parent.properties[property] = this.vEnd[property]
|
|
154
|
-
} else {
|
|
155
|
-
// Null tween
|
|
156
|
-
this.vEnd[property] = this.vStart[property];
|
|
171
|
+
this.parent.properties[property] = this.vEnd[property]!;
|
|
157
172
|
}
|
|
158
|
-
this.vStartCache[property] = this.vStart[property]
|
|
159
|
-
this.vEndCache[property] = this.vEnd[property]
|
|
173
|
+
this.vStartCache[property] = this.vStart[property]!;
|
|
174
|
+
this.vEndCache[property] = this.vEnd[property]!;
|
|
160
175
|
}
|
|
161
176
|
return this;
|
|
162
177
|
}
|
|
@@ -189,11 +204,11 @@ export class TweenData {
|
|
|
189
204
|
this.value = this.easingFunction(this.percent);
|
|
190
205
|
const keys = Object.keys(this.vEnd);
|
|
191
206
|
for (const property of keys) {
|
|
192
|
-
const start = this.vStart[property];
|
|
193
207
|
const end = this.vEnd[property];
|
|
194
|
-
(this.
|
|
208
|
+
const start = Number(this.vStart[property]);
|
|
209
|
+
(this.parent.target as unknown as Record<string, unknown>)[property] = Array.isArray(end)
|
|
195
210
|
? this.interpolationFunction.call(this.interpolationContext, end, this.value)
|
|
196
|
-
: start + (end - start) * this.value;
|
|
211
|
+
: start + (Number(end) - start) * this.value;
|
|
197
212
|
}
|
|
198
213
|
if ((!this.parent.reverse && this.percent === 1) || (this.parent.reverse && this.percent === 0)) {
|
|
199
214
|
return this.repeat();
|
|
@@ -224,11 +239,11 @@ export class TweenData {
|
|
|
224
239
|
const blob: Record<string, number> = {};
|
|
225
240
|
const keys = Object.keys(this.vEnd);
|
|
226
241
|
for (const property of keys) {
|
|
227
|
-
const start = this.vStart[property];
|
|
228
242
|
const end = this.vEnd[property];
|
|
243
|
+
const start = Number(this.vStart[property]);
|
|
229
244
|
blob[property] = Array.isArray(end)
|
|
230
245
|
? this.interpolationFunction(end, this.value)
|
|
231
|
-
: start + (end - start) * this.value;
|
|
246
|
+
: start + (Number(end) - start) * this.value;
|
|
232
247
|
}
|
|
233
248
|
data.push(blob);
|
|
234
249
|
if ((!this.parent.reverse && this.percent === 1) || (this.parent.reverse && this.percent === 0)) {
|
|
@@ -253,8 +268,8 @@ export class TweenData {
|
|
|
253
268
|
// Restore the properties
|
|
254
269
|
const keys = Object.keys(this.vStartCache);
|
|
255
270
|
for (const property of keys) {
|
|
256
|
-
this.vStart[property] = this.vStartCache[property]
|
|
257
|
-
this.vEnd[property] = this.vEndCache[property]
|
|
271
|
+
this.vStart[property] = this.vStartCache[property]!;
|
|
272
|
+
this.vEnd[property] = this.vEndCache[property]!;
|
|
258
273
|
}
|
|
259
274
|
this.inReverse = false;
|
|
260
275
|
return TWEEN_COMPLETE;
|
|
@@ -267,15 +282,15 @@ export class TweenData {
|
|
|
267
282
|
// If inReverse we're going from vEnd to vStartCache
|
|
268
283
|
const keys = Object.keys(this.vStartCache);
|
|
269
284
|
for (const property of keys) {
|
|
270
|
-
this.vStart[property] = this.vEndCache[property]
|
|
271
|
-
this.vEnd[property] = this.vStartCache[property]
|
|
285
|
+
this.vStart[property] = this.vEndCache[property]!;
|
|
286
|
+
this.vEnd[property] = this.vStartCache[property]!;
|
|
272
287
|
}
|
|
273
288
|
} else {
|
|
274
289
|
// If not inReverse we're just repopulating the cache again
|
|
275
290
|
const keys = Object.keys(this.vStartCache);
|
|
276
291
|
for (const property of keys) {
|
|
277
|
-
this.vStart[property] = this.vStartCache[property]
|
|
278
|
-
this.vEnd[property] = this.vEndCache[property]
|
|
292
|
+
this.vStart[property] = this.vStartCache[property]!;
|
|
293
|
+
this.vEnd[property] = this.vEndCache[property]!;
|
|
279
294
|
}
|
|
280
295
|
// -1 means repeat forever, otherwise decrement the repeatCounter
|
|
281
296
|
// We only decrement this counter if the tween isn't doing a yoyo, as that doesn't count towards the repeat total
|
|
@@ -82,22 +82,22 @@ const EXPECTED: Record<string, number[]> = {
|
|
|
82
82
|
],
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
-
describe('tween_easing', () => {
|
|
86
|
-
it.each(Object.keys(EXPECTED))('%s matches its reference curve', (name) => {
|
|
85
|
+
describe('tween_easing', (): void => {
|
|
86
|
+
it.each(Object.keys(EXPECTED))('%s matches its reference curve', (name): void => {
|
|
87
87
|
const fn = (Easing as unknown as Record<string, (k: number) => number>)[name]!;
|
|
88
|
-
const actual = SAMPLE_POINTS.map((k) => fn(k));
|
|
88
|
+
const actual = SAMPLE_POINTS.map((k): number => fn(k));
|
|
89
89
|
for (const [index, value] of actual.entries()) {
|
|
90
90
|
expect(value).toBeCloseTo(EXPECTED[name]![index]!, 12);
|
|
91
91
|
}
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
-
it.each(Object.keys(EXPECTED))('%s is anchored at both ends', (name) => {
|
|
94
|
+
it.each(Object.keys(EXPECTED))('%s is anchored at both ends', (name): void => {
|
|
95
95
|
const fn = (Easing as unknown as Record<string, (k: number) => number>)[name]!;
|
|
96
96
|
expect(fn(0)).toBeCloseTo(0, 12);
|
|
97
97
|
expect(fn(1)).toBeCloseTo(1, 12);
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
-
it.each(Object.keys(EXPECTED))('%s does not mutate beyond its return value', (name) => {
|
|
100
|
+
it.each(Object.keys(EXPECTED))('%s does not mutate beyond its return value', (name): void => {
|
|
101
101
|
const fn = (Easing as unknown as Record<string, (k: number) => number>)[name]!;
|
|
102
102
|
for (const k of SAMPLE_POINTS) {
|
|
103
103
|
expect(fn(k)).toBe(fn(k));
|
|
@@ -106,7 +106,7 @@ export class TweenManager {
|
|
|
106
106
|
* Get all tweens managed by this manager.
|
|
107
107
|
* @returns {Tween[]} An array of all active tweens.
|
|
108
108
|
*/
|
|
109
|
-
public getAll() {
|
|
109
|
+
public getAll(): Tween[] {
|
|
110
110
|
return this._tweens;
|
|
111
111
|
}
|
|
112
112
|
|
|
@@ -128,7 +128,7 @@ export class TweenManager {
|
|
|
128
128
|
*/
|
|
129
129
|
public removeFrom(obj: TweenTarget, children: object[] | null = null): void {
|
|
130
130
|
if (Array.isArray(obj)) {
|
|
131
|
-
for (const entry of obj) {
|
|
131
|
+
for (const entry of obj as object[]) {
|
|
132
132
|
this.removeFrom(entry);
|
|
133
133
|
}
|
|
134
134
|
return;
|