@vpmedia/phaser 1.114.0 → 1.116.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.
Files changed (171) hide show
  1. package/dist/index.js +400 -377
  2. package/dist/index.js.map +1 -1
  3. package/dist/phaser/core/animation_manager.d.ts +2 -1
  4. package/dist/phaser/core/animation_manager.d.ts.map +1 -1
  5. package/dist/phaser/core/array_set.d.ts +1 -1
  6. package/dist/phaser/core/array_set.d.ts.map +1 -1
  7. package/dist/phaser/core/cache.d.ts +1 -1
  8. package/dist/phaser/core/cache.d.ts.map +1 -1
  9. package/dist/phaser/core/factory.d.ts +1 -1
  10. package/dist/phaser/core/factory.d.ts.map +1 -1
  11. package/dist/phaser/core/game.d.ts +2 -0
  12. package/dist/phaser/core/game.d.ts.map +1 -1
  13. package/dist/phaser/core/input.d.ts +5 -5
  14. package/dist/phaser/core/input.d.ts.map +1 -1
  15. package/dist/phaser/core/input_event.d.ts +35 -0
  16. package/dist/phaser/core/input_event.d.ts.map +1 -0
  17. package/dist/phaser/core/input_handler.d.ts +2 -2
  18. package/dist/phaser/core/input_handler.d.ts.map +1 -1
  19. package/dist/phaser/core/input_mouse.d.ts +27 -26
  20. package/dist/phaser/core/input_mouse.d.ts.map +1 -1
  21. package/dist/phaser/core/input_mspointer.d.ts +16 -15
  22. package/dist/phaser/core/input_mspointer.d.ts.map +1 -1
  23. package/dist/phaser/core/input_pointer.d.ts +9 -8
  24. package/dist/phaser/core/input_pointer.d.ts.map +1 -1
  25. package/dist/phaser/core/input_touch.d.ts +18 -17
  26. package/dist/phaser/core/input_touch.d.ts.map +1 -1
  27. package/dist/phaser/core/loader.d.ts +64 -30
  28. package/dist/phaser/core/loader.d.ts.map +1 -1
  29. package/dist/phaser/core/scale_manager.d.ts +1 -1
  30. package/dist/phaser/core/scale_manager.d.ts.map +1 -1
  31. package/dist/phaser/core/scene_manager.d.ts +14 -4
  32. package/dist/phaser/core/scene_manager.d.ts.map +1 -1
  33. package/dist/phaser/core/signal.d.ts +8 -8
  34. package/dist/phaser/core/signal.d.ts.map +1 -1
  35. package/dist/phaser/core/signal_binding.d.ts +2 -2
  36. package/dist/phaser/core/signal_binding.d.ts.map +1 -1
  37. package/dist/phaser/core/sound.d.ts +1 -1
  38. package/dist/phaser/core/sound.d.ts.map +1 -1
  39. package/dist/phaser/core/sound_manager.d.ts +3 -3
  40. package/dist/phaser/core/sound_manager.d.ts.map +1 -1
  41. package/dist/phaser/core/sound_sprite.d.ts +1 -1
  42. package/dist/phaser/core/sound_sprite.d.ts.map +1 -1
  43. package/dist/phaser/core/timer.d.ts +5 -5
  44. package/dist/phaser/core/timer.d.ts.map +1 -1
  45. package/dist/phaser/core/timer_event.d.ts +2 -2
  46. package/dist/phaser/core/timer_event.d.ts.map +1 -1
  47. package/dist/phaser/core/tween.d.ts +4 -4
  48. package/dist/phaser/core/tween.d.ts.map +1 -1
  49. package/dist/phaser/core/tween_data.d.ts +2 -1
  50. package/dist/phaser/core/tween_data.d.ts.map +1 -1
  51. package/dist/phaser/core/tween_manager.d.ts +1 -1
  52. package/dist/phaser/core/tween_manager.d.ts.map +1 -1
  53. package/dist/phaser/display/button.d.ts +1 -1
  54. package/dist/phaser/display/button.d.ts.map +1 -1
  55. package/dist/phaser/display/canvas/buffer.d.ts +3 -3
  56. package/dist/phaser/display/canvas/buffer.d.ts.map +1 -1
  57. package/dist/phaser/display/canvas/graphics.d.ts +2 -2
  58. package/dist/phaser/display/canvas/graphics.d.ts.map +1 -1
  59. package/dist/phaser/display/canvas/masker.d.ts +5 -2
  60. package/dist/phaser/display/canvas/masker.d.ts.map +1 -1
  61. package/dist/phaser/display/canvas/renderer.d.ts +6 -5
  62. package/dist/phaser/display/canvas/renderer.d.ts.map +1 -1
  63. package/dist/phaser/display/canvas/tinter.d.ts +2 -1
  64. package/dist/phaser/display/canvas/tinter.d.ts.map +1 -1
  65. package/dist/phaser/display/canvas/util.d.ts +11 -4
  66. package/dist/phaser/display/canvas/util.d.ts.map +1 -1
  67. package/dist/phaser/display/display_object.d.ts +4 -3
  68. package/dist/phaser/display/display_object.d.ts.map +1 -1
  69. package/dist/phaser/display/graphics.d.ts +47 -27
  70. package/dist/phaser/display/graphics.d.ts.map +1 -1
  71. package/dist/phaser/display/graphics_data.d.ts +20 -11
  72. package/dist/phaser/display/graphics_data.d.ts.map +1 -1
  73. package/dist/phaser/display/image.d.ts +4 -3
  74. package/dist/phaser/display/image.d.ts.map +1 -1
  75. package/dist/phaser/display/render_session.d.ts +44 -0
  76. package/dist/phaser/display/render_session.d.ts.map +1 -0
  77. package/dist/phaser/display/sprite_util.d.ts +4 -3
  78. package/dist/phaser/display/sprite_util.d.ts.map +1 -1
  79. package/dist/phaser/display/text.d.ts +64 -30
  80. package/dist/phaser/display/text.d.ts.map +1 -1
  81. package/dist/phaser/display/webgl/base_texture.d.ts +3 -3
  82. package/dist/phaser/display/webgl/base_texture.d.ts.map +1 -1
  83. package/dist/phaser/display/webgl/earcut.d.ts +25 -25
  84. package/dist/phaser/display/webgl/earcut.d.ts.map +1 -1
  85. package/dist/phaser/display/webgl/earcut_node.d.ts +2 -2
  86. package/dist/phaser/display/webgl/earcut_node.d.ts.map +1 -1
  87. package/dist/phaser/display/webgl/fast_sprite_batch.d.ts +3 -2
  88. package/dist/phaser/display/webgl/fast_sprite_batch.d.ts.map +1 -1
  89. package/dist/phaser/display/webgl/filter_manager.d.ts +1 -1
  90. package/dist/phaser/display/webgl/filter_manager.d.ts.map +1 -1
  91. package/dist/phaser/display/webgl/graphics.d.ts +2 -1
  92. package/dist/phaser/display/webgl/graphics.d.ts.map +1 -1
  93. package/dist/phaser/display/webgl/graphics_data.d.ts +9 -9
  94. package/dist/phaser/display/webgl/graphics_data.d.ts.map +1 -1
  95. package/dist/phaser/display/webgl/mask_manager.d.ts +3 -2
  96. package/dist/phaser/display/webgl/mask_manager.d.ts.map +1 -1
  97. package/dist/phaser/display/webgl/render_texture.d.ts +3 -3
  98. package/dist/phaser/display/webgl/render_texture.d.ts.map +1 -1
  99. package/dist/phaser/display/webgl/renderer.d.ts +5 -4
  100. package/dist/phaser/display/webgl/renderer.d.ts.map +1 -1
  101. package/dist/phaser/display/webgl/shader/normal.d.ts +3 -1
  102. package/dist/phaser/display/webgl/shader/normal.d.ts.map +1 -1
  103. package/dist/phaser/display/webgl/shader_manager.d.ts +10 -4
  104. package/dist/phaser/display/webgl/shader_manager.d.ts.map +1 -1
  105. package/dist/phaser/display/webgl/sprite_batch.d.ts +4 -3
  106. package/dist/phaser/display/webgl/sprite_batch.d.ts.map +1 -1
  107. package/dist/phaser/display/webgl/stencil_manager.d.ts +4 -3
  108. package/dist/phaser/display/webgl/stencil_manager.d.ts.map +1 -1
  109. package/dist/phaser/display/webgl/texture.d.ts +6 -6
  110. package/dist/phaser/display/webgl/texture.d.ts.map +1 -1
  111. package/package.json +1 -1
  112. package/src/phaser/core/animation_manager.ts +2 -2
  113. package/src/phaser/core/array_set.ts +1 -1
  114. package/src/phaser/core/cache.ts +1 -1
  115. package/src/phaser/core/callback_context.test.ts +70 -0
  116. package/src/phaser/core/factory.ts +1 -1
  117. package/src/phaser/core/game.ts +2 -0
  118. package/src/phaser/core/input.ts +7 -6
  119. package/src/phaser/core/input_event.ts +34 -0
  120. package/src/phaser/core/input_handler.ts +2 -11
  121. package/src/phaser/core/input_mouse.ts +53 -36
  122. package/src/phaser/core/input_mspointer.ts +54 -29
  123. package/src/phaser/core/input_pointer.test.ts +149 -0
  124. package/src/phaser/core/input_pointer.ts +20 -21
  125. package/src/phaser/core/input_touch.ts +48 -31
  126. package/src/phaser/core/loader.test.ts +139 -0
  127. package/src/phaser/core/loader.ts +146 -83
  128. package/src/phaser/core/scale_manager.ts +1 -1
  129. package/src/phaser/core/scene_manager.ts +16 -8
  130. package/src/phaser/core/signal.ts +8 -8
  131. package/src/phaser/core/signal_binding.ts +2 -2
  132. package/src/phaser/core/sound.ts +4 -4
  133. package/src/phaser/core/sound_manager.ts +17 -19
  134. package/src/phaser/core/sound_sprite.ts +2 -2
  135. package/src/phaser/core/timer.ts +6 -6
  136. package/src/phaser/core/timer_event.ts +2 -2
  137. package/src/phaser/core/tween.ts +6 -6
  138. package/src/phaser/core/tween_data.ts +2 -1
  139. package/src/phaser/core/tween_manager.ts +1 -1
  140. package/src/phaser/display/button.ts +1 -1
  141. package/src/phaser/display/canvas/buffer.ts +3 -3
  142. package/src/phaser/display/canvas/graphics.ts +24 -20
  143. package/src/phaser/display/canvas/masker.ts +5 -2
  144. package/src/phaser/display/canvas/renderer.ts +10 -11
  145. package/src/phaser/display/canvas/tinter.ts +4 -3
  146. package/src/phaser/display/canvas/util.ts +15 -5
  147. package/src/phaser/display/display_object.ts +6 -5
  148. package/src/phaser/display/graphics.test.ts +122 -0
  149. package/src/phaser/display/graphics.ts +73 -64
  150. package/src/phaser/display/graphics_data.ts +22 -12
  151. package/src/phaser/display/image.ts +4 -3
  152. package/src/phaser/display/render_session.ts +45 -0
  153. package/src/phaser/display/sprite_util.ts +10 -8
  154. package/src/phaser/display/text.test.ts +27 -1
  155. package/src/phaser/display/text.ts +181 -117
  156. package/src/phaser/display/webgl/base_texture.ts +3 -3
  157. package/src/phaser/display/webgl/earcut.test.ts +132 -0
  158. package/src/phaser/display/webgl/earcut.ts +84 -74
  159. package/src/phaser/display/webgl/earcut_node.ts +5 -5
  160. package/src/phaser/display/webgl/fast_sprite_batch.ts +4 -4
  161. package/src/phaser/display/webgl/filter_manager.ts +1 -1
  162. package/src/phaser/display/webgl/graphics.ts +26 -17
  163. package/src/phaser/display/webgl/graphics_data.ts +9 -9
  164. package/src/phaser/display/webgl/mask_manager.ts +3 -2
  165. package/src/phaser/display/webgl/render_texture.ts +3 -3
  166. package/src/phaser/display/webgl/renderer.ts +7 -6
  167. package/src/phaser/display/webgl/shader/normal.ts +23 -6
  168. package/src/phaser/display/webgl/shader_manager.ts +15 -6
  169. package/src/phaser/display/webgl/sprite_batch.ts +4 -3
  170. package/src/phaser/display/webgl/stencil_manager.ts +10 -3
  171. package/src/phaser/display/webgl/texture.ts +6 -6
@@ -8,16 +8,48 @@ import { Signal } from './signal.js';
8
8
 
9
9
  const TEXTURE_ATLAS_JSON_HASH = 1;
10
10
 
11
+ /** An audio source, either a plain URL or a URL paired with its format. */
12
+ export type AudioSource = string | { uri: string; type?: string };
13
+
11
14
  /**
12
- * Describes a file entry managed by the Loader.
15
+ * A queued or in-flight load. The core fields are set for every file; the rest are supplied by the
16
+ * per-type helpers (image, audio, atlas, bitmap font) as extra properties.
13
17
  */
14
- export interface LoaderFile {
15
- key: string;
18
+ export type LoaderFile = {
16
19
  type: string;
17
- url: string;
20
+ key: string;
21
+ path: string;
22
+ url: string | AudioSource[];
23
+ syncPoint: boolean;
24
+ data: any;
25
+ loading: boolean;
26
+ loaded: boolean;
18
27
  error: boolean;
19
- errorMessage: string;
20
- }
28
+ errorMessage?: string;
29
+ requestObject?: XMLHttpRequest | HTMLImageElement | HTMLAudioElement | null;
30
+ requestUrl?: string | null;
31
+ numRetry?: number;
32
+ overwrite?: boolean;
33
+ format?: unknown;
34
+ urls?: string[] | string;
35
+ autoDecode?: boolean;
36
+ buffer?: unknown;
37
+ atlasURL?: string | null;
38
+ atlasData?: unknown;
39
+ atlasType?: string;
40
+ textureURL?: string | null;
41
+ jsonURL?: string | null;
42
+ jsonData?: unknown;
43
+ audioURL?: string;
44
+ fontDataURL?: string;
45
+ frameWidth?: number;
46
+ frameHeight?: number;
47
+ frameMax?: number;
48
+ margin?: number;
49
+ spacing?: number;
50
+ xSpacing?: number;
51
+ ySpacing?: number;
52
+ };
21
53
 
22
54
  export class Loader {
23
55
  public game!: Game;
@@ -40,8 +72,8 @@ export class Loader {
40
72
  public onFileError!: Signal;
41
73
  public maxParallelDownloads!: number;
42
74
  public _withSyncPointDepth!: number;
43
- public _fileList!: any;
44
- public _flightQueue!: any;
75
+ public _fileList!: LoaderFile[];
76
+ public _flightQueue!: LoaderFile[];
45
77
  public _processingHead!: number;
46
78
  public _fileLoadStarted!: boolean;
47
79
  public _totalPackCount!: number;
@@ -139,7 +171,7 @@ export class Loader {
139
171
  public getAssetIndex(type: string, key: string) {
140
172
  let bestFound = -1;
141
173
  for (let i = 0; i < this._fileList.length; i += 1) {
142
- const file = this._fileList[i];
174
+ const file = this._fileList[i]!;
143
175
  if (file.type === type && file.key === key) {
144
176
  bestFound = i;
145
177
  // An already loaded/loading file may be superceded.
@@ -161,7 +193,7 @@ export class Loader {
161
193
  public getAsset(type: string, key: string) {
162
194
  const fileIndex = this.getAssetIndex(type, key);
163
195
  if (fileIndex > -1) {
164
- return { index: fileIndex, file: this._fileList[fileIndex] };
196
+ return { index: fileIndex, file: this._fileList[fileIndex]! };
165
197
  }
166
198
  return null;
167
199
  }
@@ -207,8 +239,8 @@ export class Loader {
207
239
  public addToFileList(
208
240
  type: string,
209
241
  key = '',
210
- url: string | null = null,
211
- properties: any | null = null,
242
+ url: string | AudioSource[] | null = null,
243
+ properties: Partial<LoaderFile> | null = null,
212
244
  overwrite = false,
213
245
  extension: string | null = null
214
246
  ) {
@@ -224,7 +256,7 @@ export class Loader {
224
256
  return this;
225
257
  }
226
258
  }
227
- const file: Record<string, unknown> = {
259
+ const file: LoaderFile = {
228
260
  type,
229
261
  key,
230
262
  path: this.path,
@@ -234,16 +266,11 @@ export class Loader {
234
266
  loading: false,
235
267
  loaded: false,
236
268
  error: false,
269
+ ...properties,
237
270
  };
238
- if (properties) {
239
- const extraProperties = properties as Record<string, unknown>;
240
- for (const prop of Object.keys(extraProperties)) {
241
- file[prop] = extraProperties[prop];
242
- }
243
- }
244
271
  const fileIndex = this.getAssetIndex(type, key);
245
272
  if (overwrite && fileIndex > -1) {
246
- const currentFile = this._fileList[fileIndex];
273
+ const currentFile = this._fileList[fileIndex]!;
247
274
  if (!currentFile.loading && !currentFile.loaded) {
248
275
  this._fileList[fileIndex] = file;
249
276
  } else {
@@ -265,7 +292,7 @@ export class Loader {
265
292
  * @param {object} properties - The new properties for the file.
266
293
  * @returns {Loader} This Loader instance for chaining.
267
294
  */
268
- public replaceInFileList(type: string, key: string, url: string, properties: any) {
295
+ public replaceInFileList(type: string, key: string, url: string, properties: Partial<LoaderFile>) {
269
296
  return this.addToFileList(type, key, url, properties, true);
270
297
  }
271
298
 
@@ -277,7 +304,7 @@ export class Loader {
277
304
  * @param {object} callbackContext - The context in which to call the callback.
278
305
  * @returns {Loader} This Loader instance for chaining.
279
306
  */
280
- public pack(key: string, url: string, data: any, callbackContext: any) {
307
+ public pack(key: string, url: string, data: unknown, callbackContext: unknown) {
281
308
  const pack = {
282
309
  type: 'packfile',
283
310
  key,
@@ -315,7 +342,7 @@ export class Loader {
315
342
  * @param {boolean} overwrite - Whether to overwrite an existing file with the same key.
316
343
  * @returns {Loader} This Loader instance for chaining.
317
344
  */
318
- public image(key: string, url?: any, overwrite = false) {
345
+ public image(key: string, url?: string, overwrite = false) {
319
346
  return this.addToFileList('image', key, url, undefined, overwrite, '.png');
320
347
  }
321
348
 
@@ -408,7 +435,7 @@ export class Loader {
408
435
  * @param {boolean} autoDecode - Whether to automatically decode the audio file.
409
436
  * @returns {Loader} This Loader instance for chaining.
410
437
  */
411
- public audio(key: string, urls: any, autoDecode = true) {
438
+ public audio(key: string, urls: string | string[], autoDecode = true) {
412
439
  if (this.game.sound.noAudio || this.game.device.noAudioFormat) {
413
440
  return this;
414
441
  }
@@ -427,7 +454,7 @@ export class Loader {
427
454
  * @param {boolean} autoDecode - Whether to automatically decode the audio file.
428
455
  * @returns {Loader} This Loader instance for chaining.
429
456
  */
430
- public audioSprite(key: string, urls: string, jsonURL: string, jsonData: any, autoDecode = true) {
457
+ public audioSprite(key: string, urls: string, jsonURL: string, jsonData: unknown, autoDecode = true) {
431
458
  if (this.game.sound.noAudio || this.game.device.noAudioFormat) {
432
459
  return this;
433
460
  }
@@ -458,7 +485,7 @@ export class Loader {
458
485
  key: string,
459
486
  textureURL: string | null = null,
460
487
  atlasURL: string | null = null,
461
- atlasData: any | null = null,
488
+ atlasData: unknown = null,
462
489
  xSpacing = 0,
463
490
  ySpacing = 0
464
491
  ) {
@@ -505,7 +532,7 @@ export class Loader {
505
532
  key: string,
506
533
  textureURL: string,
507
534
  atlasURL: string | null = null,
508
- atlasData: any | null = null,
535
+ atlasData: unknown = null,
509
536
  format: number = TEXTURE_ATLAS_JSON_HASH
510
537
  ) {
511
538
  textureURL ??= `${key}.png`;
@@ -527,7 +554,7 @@ export class Loader {
527
554
  * @param {object} callbackContext - The context in which to call the callback.
528
555
  * @returns {Loader} This Loader instance for chaining.
529
556
  */
530
- public withSyncPoint(callback: Function, callbackContext: any) {
557
+ public withSyncPoint(callback: Function, callbackContext: unknown) {
531
558
  this._withSyncPointDepth += 1;
532
559
  try {
533
560
  callback.call(callbackContext ?? this, this);
@@ -597,7 +624,7 @@ export class Loader {
597
624
  }
598
625
  // Empty the flight queue as applicable
599
626
  for (let i = 0; i < this._flightQueue.length; i += 1) {
600
- const file = this._flightQueue[i];
627
+ const file = this._flightQueue[i]!;
601
628
  if (file.loaded || file.error) {
602
629
  this._flightQueue.splice(i, 1);
603
630
  i -= 1;
@@ -627,7 +654,7 @@ export class Loader {
627
654
  let syncblock = false;
628
655
  const inflightLimit = this.maxParallelDownloads;
629
656
  for (let i = this._processingHead; i < this._fileList.length; i += 1) {
630
- const file = this._fileList[i];
657
+ const file = this._fileList[i]!;
631
658
  // Pack is fetched (ie. has data) and is currently at the start of the process queue.
632
659
  if (file.type === 'packfile' && !file.error && file.loaded && i === this._processingHead) {
633
660
  // Processing the pack / adds more files
@@ -712,7 +739,7 @@ export class Loader {
712
739
  * @param {object} file - The file to complete or mark as failed.
713
740
  * @param {string} errorMessage - An error message if the file failed to load.
714
741
  */
715
- public asyncComplete(file: any, errorMessage = '') {
742
+ public asyncComplete(file: LoaderFile, errorMessage = '') {
716
743
  file.loaded = true;
717
744
  file.error = Boolean(errorMessage);
718
745
  if (file.error) {
@@ -727,7 +754,7 @@ export class Loader {
727
754
  * Processes a pack file, adding its contained files to the loader.
728
755
  * @param {object} pack - The pack file object to process.
729
756
  */
730
- public processPack(pack: any) {
757
+ public processPack(pack: LoaderFile) {
731
758
  const packData = pack.data[pack.key];
732
759
  if (!packData) {
733
760
  this.game.logger.warn('Missing loader pack key', { key: pack.key });
@@ -801,7 +828,10 @@ export class Loader {
801
828
  * @param {object} file - The file object containing path information.
802
829
  * @returns {string} The transformed URL.
803
830
  */
804
- public transformUrl(url: any, file: any): any {
831
+ public transformUrl(url: string | AudioSource[] | null, file: LoaderFile): string | false {
832
+ if (typeof url !== 'string') {
833
+ return false;
834
+ }
805
835
  if (!url) {
806
836
  return false;
807
837
  }
@@ -815,7 +845,7 @@ export class Loader {
815
845
  * Loads a file using XMLHttpRequest, handling image files specially.
816
846
  * @param {object} file - The file object to load.
817
847
  */
818
- public loadFile(file: any) {
848
+ public loadFile(file: LoaderFile) {
819
849
  switch (file.type) {
820
850
  case 'packfile': {
821
851
  this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.fileComplete);
@@ -829,9 +859,10 @@ export class Loader {
829
859
  break;
830
860
  }
831
861
  case 'audio': {
832
- file.url = this.getAudioURL(file.url);
833
- if (file.url) {
834
- this.xhrLoad(file, this.transformUrl(file.url, file), 'arraybuffer', this.fileComplete);
862
+ const resolved = this.getAudioURL(file.url);
863
+ if (resolved) {
864
+ file.url = resolved;
865
+ this.xhrLoad(file, this.transformUrl(resolved, file), 'arraybuffer', this.fileComplete);
835
866
  } else if (this.game.sound.noAudio) {
836
867
  this.fileError(file, null, 'Device does not have audio playback support');
837
868
  } else if (this.game.device.noAudioFormat) {
@@ -864,7 +895,7 @@ export class Loader {
864
895
  * Loads an image file using the Image DOM element.
865
896
  * @param {object} file - The file object to load.
866
897
  */
867
- public loadImageTag(file: any) {
898
+ public loadImageTag(file: LoaderFile) {
868
899
  this.log('loadImageTag', file);
869
900
  const scope = this;
870
901
  file.data = new globalThis.Image();
@@ -902,7 +933,17 @@ export class Loader {
902
933
  * @param {Function} onload - The function to call when the file loads successfully.
903
934
  * @param {Function} onerror - The function to call if the file fails to load.
904
935
  */
905
- public xhrLoad(file: any, url: any, type: any, onload: Function, onerror: Function | null = null) {
936
+ public xhrLoad(
937
+ file: LoaderFile,
938
+ url: string | false,
939
+ type: XMLHttpRequestResponseType,
940
+ onload: Function,
941
+ onerror: Function | null = null
942
+ ) {
943
+ if (url === false) {
944
+ this.fileError(file, null, 'Could not resolve the file URL');
945
+ return;
946
+ }
906
947
  this.log('xhrLoad', file);
907
948
  const scope = this;
908
949
  const xhr = new XMLHttpRequest();
@@ -981,33 +1022,34 @@ export class Loader {
981
1022
  * @param {object[]} urls - The array of URLs to check for supported audio formats.
982
1023
  * @returns {string} The first URL with a supported audio format, or null if none found.
983
1024
  */
984
- public getAudioURL(urls: any[]) {
1025
+ public getAudioURL(urls: string | AudioSource[]) {
985
1026
  if (this.game.sound.noAudio || this.game.device.noAudioFormat) {
986
1027
  return null;
987
1028
  }
988
- for (let i = 0; i < urls.length; i += 1) {
989
- let url = urls[i];
1029
+ const candidates = typeof urls === 'string' ? [urls] : urls;
1030
+ for (let i = 0; i < candidates.length; i += 1) {
1031
+ const candidate = candidates[i]!;
1032
+ let url: string;
990
1033
  let audioType = null;
991
- if (url.uri) {
1034
+ if (typeof candidate !== 'string') {
992
1035
  // {uri: .., type: ..} pair
993
- audioType = url.type;
994
- url = url.uri;
1036
+ audioType = candidate.type ?? '';
1037
+ url = candidate.uri;
995
1038
  if (canPlayAudio(this.game.device, audioType)) {
996
1039
  return url;
997
1040
  }
998
1041
  } else {
1042
+ url = candidate;
999
1043
  // Assume direct-data URI can be played if not in a paired form; select immediately
1000
- if (url.indexOf('blob:') === 0 || url.indexOf('data:') === 0) {
1044
+ if (url.startsWith('blob:') || url.startsWith('data:')) {
1001
1045
  return url;
1002
1046
  }
1003
- if (url.includes('?')) {
1004
- // Remove query from URL
1005
- url = url.substr(0, url.indexOf('?'));
1006
- }
1007
- const extension = url.slice((Math.max(0, url.lastIndexOf('.')) || Infinity) + 1);
1047
+ // The query is only stripped to read the extension; the candidate is returned intact.
1048
+ const withoutQuery = url.includes('?') ? url.slice(0, url.indexOf('?')) : url;
1049
+ const extension = withoutQuery.slice((Math.max(0, withoutQuery.lastIndexOf('.')) || Infinity) + 1);
1008
1050
  audioType = extension.toLowerCase();
1009
1051
  if (canPlayAudio(this.game.device, audioType)) {
1010
- return urls[i];
1052
+ return candidate;
1011
1053
  }
1012
1054
  }
1013
1055
  }
@@ -1022,7 +1064,7 @@ export class Loader {
1022
1064
  * @param {XMLHttpRequest} xhr - The XMLHttpRequest object that failed.
1023
1065
  * @param {number | string} reason - The error code or message explaining the failure.
1024
1066
  */
1025
- public fileError(file: any, xhr: any | null = null, reason: any = 0) {
1067
+ public fileError(file: LoaderFile, xhr: XMLHttpRequest | null = null, reason: unknown = 0) {
1026
1068
  // const url = file.requestUrl || this.transformUrl(file.url, file);
1027
1069
  if (!reason && xhr) {
1028
1070
  reason = xhr.status;
@@ -1037,34 +1079,37 @@ export class Loader {
1037
1079
  * @param {XMLHttpRequest} xhr - TBD.
1038
1080
  * @throws {Error}
1039
1081
  */
1040
- public fileComplete(file: any, xhr?: any) {
1082
+ public fileComplete(file: LoaderFile, xhr?: XMLHttpRequest) {
1041
1083
  let loadNext = true;
1084
+ // By this point the audio candidate list has been resolved to a single URL.
1085
+ const url = typeof file.url === 'string' ? file.url : '';
1086
+ const response = xhr!;
1042
1087
  switch (file.type) {
1043
1088
  case 'packfile': {
1044
1089
  // Pack data must never be false-ish after it is fetched without error
1045
- file.data = JSON.parse(xhr.responseText) ?? {};
1090
+ file.data = JSON.parse(response.responseText) ?? {};
1046
1091
  break;
1047
1092
  }
1048
1093
  case 'image': {
1049
- this.cache.addImage(file.key, file.url, file.data);
1094
+ this.cache.addImage(file.key, url, file.data);
1050
1095
  break;
1051
1096
  }
1052
1097
  case 'spritesheet': {
1053
1098
  this.cache.addSpriteSheet(
1054
1099
  file.key,
1055
- file.url,
1100
+ url,
1056
1101
  file.data,
1057
- file.frameWidth,
1058
- file.frameHeight,
1059
- file.frameMax,
1060
- file.margin,
1061
- file.spacing
1102
+ file.frameWidth ?? 0,
1103
+ file.frameHeight ?? 0,
1104
+ file.frameMax ?? -1,
1105
+ file.margin ?? 0,
1106
+ file.spacing ?? 0
1062
1107
  );
1063
1108
  break;
1064
1109
  }
1065
1110
  case 'textureatlas': {
1066
1111
  if (file.atlasURL == null) {
1067
- this.cache.addTextureAtlas(file.key, file.url, file.data, file.atlasData);
1112
+ this.cache.addTextureAtlas(file.key, url, file.data, file.atlasData);
1068
1113
  } else {
1069
1114
  loadNext = false;
1070
1115
  if (file.format === TEXTURE_ATLAS_JSON_HASH) {
@@ -1079,12 +1124,12 @@ export class Loader {
1079
1124
  if (!file.atlasURL) {
1080
1125
  this.cache.addBitmapFont(
1081
1126
  file.key,
1082
- file.url,
1127
+ url,
1083
1128
  file.data,
1084
1129
  file.atlasData,
1085
- file.atlasType,
1086
- file.xSpacing,
1087
- file.ySpacing
1130
+ file.atlasType ?? 'xml',
1131
+ file.xSpacing ?? 0,
1132
+ file.ySpacing ?? 0
1088
1133
  );
1089
1134
  } else {
1090
1135
  // Load the XML before carrying on with the next file
@@ -1093,7 +1138,7 @@ export class Loader {
1093
1138
  file,
1094
1139
  this.transformUrl(file.atlasURL, file),
1095
1140
  'text',
1096
- (bitmapFontFile: Record<string, unknown>, bitmapFontXhr: XMLHttpRequest) => {
1141
+ (bitmapFontFile: LoaderFile, bitmapFontXhr: XMLHttpRequest) => {
1097
1142
  let json;
1098
1143
  try {
1099
1144
  // Try to parse as JSON, if it fails, then it's hopefully XML
@@ -1102,10 +1147,10 @@ export class Loader {
1102
1147
  // pass
1103
1148
  }
1104
1149
  if (json) {
1105
- bitmapFontFile['atlasType'] = 'json';
1150
+ bitmapFontFile.atlasType = 'json';
1106
1151
  this.jsonLoadComplete(bitmapFontFile, bitmapFontXhr);
1107
1152
  } else {
1108
- bitmapFontFile['atlasType'] = 'xml';
1153
+ bitmapFontFile.atlasType = 'xml';
1109
1154
  this.xmlLoadComplete(bitmapFontFile, bitmapFontXhr);
1110
1155
  }
1111
1156
  }
@@ -1114,16 +1159,16 @@ export class Loader {
1114
1159
  break;
1115
1160
  }
1116
1161
  case 'audio': {
1117
- file.data = xhr.response;
1118
- this.cache.addSound(file.key, file.url, file.data);
1162
+ file.data = response.response;
1163
+ this.cache.addSound(file.key, url, file.data);
1119
1164
  if (file.autoDecode) {
1120
1165
  this.game.sound.decode(file.key);
1121
1166
  }
1122
1167
  break;
1123
1168
  }
1124
1169
  case 'text': {
1125
- file.data = xhr.responseText;
1126
- this.cache.addText(file.key, file.url, file.data);
1170
+ file.data = response.responseText;
1171
+ this.cache.addText(file.key, url, file.data);
1127
1172
  break;
1128
1173
  }
1129
1174
  default: {
@@ -1141,14 +1186,23 @@ export class Loader {
1141
1186
  * @param {object} file - The file object that was loaded successfully.
1142
1187
  * @param {XMLHttpRequest} xhr - The XMLHttpRequest object containing the file data.
1143
1188
  */
1144
- public jsonLoadComplete(file: any, xhr: XMLHttpRequest) {
1189
+ public jsonLoadComplete(file: LoaderFile, xhr: XMLHttpRequest) {
1145
1190
  const data = JSON.parse(xhr.responseText);
1191
+ const url = typeof file.url === 'string' ? file.url : '';
1146
1192
  if (file.type === 'bitmapfont') {
1147
- this.cache.addBitmapFont(file.key, file.url, file.data, data, file.atlasType, file.xSpacing, file.ySpacing);
1193
+ this.cache.addBitmapFont(
1194
+ file.key,
1195
+ url,
1196
+ file.data,
1197
+ data,
1198
+ file.atlasType ?? 'json',
1199
+ file.xSpacing ?? 0,
1200
+ file.ySpacing ?? 0
1201
+ );
1148
1202
  } else if (file.type === 'json') {
1149
- this.cache.addJSON(file.key, file.url, data);
1203
+ this.cache.addJSON(file.key, url, data);
1150
1204
  } else {
1151
- this.cache.addTextureAtlas(file.key, file.url, file.data, data);
1205
+ this.cache.addTextureAtlas(file.key, url, file.data, data);
1152
1206
  }
1153
1207
  this.asyncComplete(file);
1154
1208
  }
@@ -1166,7 +1220,7 @@ export class Loader {
1166
1220
  * @param {object} file - The file object containing the JSON data.
1167
1221
  * @param {XMLHttpRequest} xhr - The XMLHttpRequest object containing the file data.
1168
1222
  */
1169
- public xmlLoadComplete(file: any, xhr: XMLHttpRequest) {
1223
+ public xmlLoadComplete(file: LoaderFile, xhr: XMLHttpRequest) {
1170
1224
  // Always try parsing the content as XML, regardless of actually response type
1171
1225
  const data = xhr.responseText;
1172
1226
  const xml = this.parseXml(data);
@@ -1176,12 +1230,21 @@ export class Loader {
1176
1230
  this.asyncComplete(file, 'invalid XML');
1177
1231
  return;
1178
1232
  }
1233
+ const url = typeof file.url === 'string' ? file.url : '';
1179
1234
  if (file.type === 'bitmapfont') {
1180
- this.cache.addBitmapFont(file.key, file.url, file.data, xml, file.atlasType, file.xSpacing, file.ySpacing);
1235
+ this.cache.addBitmapFont(
1236
+ file.key,
1237
+ url,
1238
+ file.data,
1239
+ xml,
1240
+ file.atlasType ?? 'xml',
1241
+ file.xSpacing ?? 0,
1242
+ file.ySpacing ?? 0
1243
+ );
1181
1244
  } else if (file.type === 'textureatlas') {
1182
- this.cache.addTextureAtlas(file.key, file.url, file.data, xml);
1245
+ this.cache.addTextureAtlas(file.key, url, file.data, xml);
1183
1246
  } else if (file.type === 'xml') {
1184
- this.cache.addXML(file.key, file.url, xml);
1247
+ this.cache.addXML(file.key, url, xml);
1185
1248
  }
1186
1249
  this.asyncComplete(file);
1187
1250
  }
@@ -1191,7 +1254,7 @@ export class Loader {
1191
1254
  * @param {object} data - The XML string data to parse.
1192
1255
  * @returns {Document} The parsed DOM Document, or null if parsing failed.
1193
1256
  */
1194
- public parseXml(data: any) {
1257
+ public parseXml(data: string) {
1195
1258
  let xml = null;
1196
1259
  try {
1197
1260
  if (globalThis.DOMParser) {
@@ -319,7 +319,7 @@ export class ScaleManager {
319
319
  * @param {Function} callback - TBD.
320
320
  * @param {object} context - TBD.
321
321
  */
322
- public setResizeCallback(callback: Function, context: any) {
322
+ public setResizeCallback(callback: Function, context: unknown) {
323
323
  this.onResize = callback;
324
324
  this.onResizeContext = context;
325
325
  }
@@ -1,8 +1,19 @@
1
1
  import type { Game } from './game.js';
2
2
  import { Scene } from './scene.js';
3
3
 
4
+ /** The lifecycle hooks a scene may implement; the manager binds whichever are present. */
5
+ export type SceneHooks = {
6
+ init?: (...args: unknown[]) => void;
7
+ preload?: () => void;
8
+ create?: () => void;
9
+ update?: () => void;
10
+ resize?: (width: number, height: number) => void;
11
+ pauseUpdate?: () => void;
12
+ shutdown?: () => void;
13
+ };
14
+
4
15
  export class SceneManager {
5
- public game!: any;
16
+ public game!: Game;
6
17
  public states!: any;
7
18
  public _pendingState!: any;
8
19
  public _clearWorld!: any;
@@ -17,7 +28,7 @@ export class SceneManager {
17
28
  public onResizeCallback!: any;
18
29
  public onPauseUpdateCallback!: any;
19
30
  public onShutDownCallback!: any;
20
- public callbackContext!: any;
31
+ public callbackContext!: SceneHooks;
21
32
  /**
22
33
  * Creates a new SceneManager instance.
23
34
  * @param {Game} game - The game instance this manager belongs to.
@@ -88,7 +99,6 @@ export class SceneManager {
88
99
  */
89
100
  public remove(key: string) {
90
101
  if (this.current === key) {
91
- this.callbackContext = null;
92
102
  this.onInitCallback = null;
93
103
  this.onShutDownCallback = null;
94
104
  this.onPreloadCallback = null;
@@ -107,7 +117,7 @@ export class SceneManager {
107
117
  * @param {boolean} clearCache - Whether to clear the cache before starting.
108
118
  * @param {...any} args - Additional arguments to pass to the state.
109
119
  */
110
- public start(key: string, clearWorld = true, clearCache = false, ...args: any[]) {
120
+ public start(key: string, clearWorld = true, clearCache = false, ...args: unknown[]) {
111
121
  if (this.checkState(key)) {
112
122
  // Place the state in the queue. It will be started the next time the game loop begins.
113
123
  this._pendingState = key;
@@ -125,7 +135,7 @@ export class SceneManager {
125
135
  * @param {boolean} clearCache - Whether to clear the cache before restarting.
126
136
  * @param {...any} args - Additional arguments to pass to the state.
127
137
  */
128
- public restart(clearWorld = true, clearCache = false, ...args: any[]) {
138
+ public restart(clearWorld = true, clearCache = false, ...args: unknown[]) {
129
139
  this._pendingState = this.current;
130
140
  this._clearWorld = clearWorld;
131
141
  this._clearCache = clearCache;
@@ -181,7 +191,7 @@ export class SceneManager {
181
191
  this.game.tweens.removeAll();
182
192
  this.game.input.reset(true);
183
193
  this.game.time.removeAll();
184
- this.game.scale.reset(this._clearWorld);
194
+ this.game.scale.reset();
185
195
  if (this._clearWorld) {
186
196
  this.game.world.destroy(true, true);
187
197
  if (this._clearCache) {
@@ -310,14 +320,12 @@ export class SceneManager {
310
320
  this._clearWorld = true;
311
321
  this._clearCache = true;
312
322
  this.clearCurrentState();
313
- this.callbackContext = null;
314
323
  this.onInitCallback = null;
315
324
  this.onShutDownCallback = null;
316
325
  this.onPreloadCallback = null;
317
326
  this.onCreateCallback = null;
318
327
  this.onUpdateCallback = null;
319
328
  this.onPauseUpdateCallback = null;
320
- this.game = null;
321
329
  this.states = {};
322
330
  this._pendingState = null;
323
331
  this.current = '';
@@ -40,7 +40,7 @@ export class Signal {
40
40
  public _registerListener(
41
41
  listener: Function,
42
42
  isOnce = false,
43
- listenerContext: any | null = null,
43
+ listenerContext: unknown | null = null,
44
44
  priority = 0,
45
45
  args: any = null
46
46
  ) {
@@ -86,7 +86,7 @@ export class Signal {
86
86
  * @param {object} context - The context of the listener.
87
87
  * @returns {number} The index of the listener in the bindings array, or -1 if not found.
88
88
  */
89
- public _indexOfListener(listener: Function, context: any | null = null) {
89
+ public _indexOfListener(listener: Function, context: unknown = null) {
90
90
  if (!this._bindings) {
91
91
  return -1;
92
92
  }
@@ -108,7 +108,7 @@ export class Signal {
108
108
  * @param {object} context - The context of the listener.
109
109
  * @returns {boolean} True if the listener is registered, false otherwise.
110
110
  */
111
- public has(listener: Function, context: any | null = null) {
111
+ public has(listener: Function, context: unknown = null) {
112
112
  return this._indexOfListener(listener, context) !== -1;
113
113
  }
114
114
 
@@ -120,7 +120,7 @@ export class Signal {
120
120
  * @param {...any} args - Additional arguments to pass to the listener.
121
121
  * @returns {SignalBinding} The binding for this listener.
122
122
  */
123
- public add(listener: Function, listenerContext: any | null = null, priority = 0, ...args: any[]) {
123
+ public add(listener: Function, listenerContext: unknown | null = null, priority = 0, ...args: unknown[]) {
124
124
  this.validateListener(listener, 'add');
125
125
  return this._registerListener(listener, false, listenerContext, priority, args);
126
126
  }
@@ -133,7 +133,7 @@ export class Signal {
133
133
  * @param {...any} args - Additional arguments to pass to the listener.
134
134
  * @returns {SignalBinding} The binding for this listener.
135
135
  */
136
- public addOnce(listener: Function, listenerContext: any | null = null, priority = 0, ...args: any[]) {
136
+ public addOnce(listener: Function, listenerContext: unknown | null = null, priority = 0, ...args: unknown[]) {
137
137
  this.validateListener(listener, 'addOnce');
138
138
  return this._registerListener(listener, true, listenerContext, priority, args);
139
139
  }
@@ -144,7 +144,7 @@ export class Signal {
144
144
  * @param {object} context - The context of the listener.
145
145
  * @returns {Function} The removed listener function.
146
146
  */
147
- public remove(listener: Function, context: any | null = null) {
147
+ public remove(listener: Function, context: unknown = null) {
148
148
  this.validateListener(listener, 'remove');
149
149
  const i = this._indexOfListener(listener, context);
150
150
  if (i !== -1 && this._bindings) {
@@ -159,7 +159,7 @@ export class Signal {
159
159
  * Remove all listeners from the signal, or only those in a specific context.
160
160
  * @param {object} context - The context to filter listeners by, or null to remove all.
161
161
  */
162
- public removeAll(context: any | null = null) {
162
+ public removeAll(context: unknown = null) {
163
163
  if (!this._bindings) {
164
164
  return;
165
165
  }
@@ -200,7 +200,7 @@ export class Signal {
200
200
  * Dispatch the signal to all registered listeners.
201
201
  * @param {...any} args - Arguments to pass to the listeners.
202
202
  */
203
- public dispatch(...args: any[]) {
203
+ public dispatch(...args: unknown[]) {
204
204
  if (!this.active || !this._bindings) {
205
205
  return;
206
206
  }