@vpmedia/phaser 1.0.1 → 1.0.3
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/README.md +20 -3
- package/dist/phaser.cjs +1 -1
- package/dist/phaser.cjs.LICENSE.txt +1 -1
- package/dist/phaser.cjs.map +1 -1
- package/dist/phaser.js +1 -1
- package/dist/phaser.js.LICENSE.txt +1 -1
- package/dist/phaser.js.map +1 -1
- package/package.json +23 -17
- package/src/index.js +142 -0
- package/src/phaser/core/animation.js +355 -0
- package/src/phaser/core/animation_manager.js +238 -0
- package/src/phaser/core/animation_parser.js +133 -0
- package/src/phaser/core/array_set.js +107 -0
- package/src/phaser/core/cache.js +558 -0
- package/src/phaser/core/const.js +106 -0
- package/src/phaser/core/device.js +67 -0
- package/src/phaser/core/device_util.js +388 -0
- package/src/phaser/core/dom.js +207 -0
- package/src/phaser/core/event_manager.js +243 -0
- package/src/phaser/core/factory.js +74 -0
- package/src/phaser/core/frame.js +75 -0
- package/src/phaser/core/frame_data.js +84 -0
- package/src/phaser/core/frame_util.js +33 -0
- package/src/phaser/core/game.js +412 -0
- package/src/phaser/core/input.js +401 -0
- package/src/phaser/core/input_button.js +102 -0
- package/src/phaser/core/input_handler.js +687 -0
- package/src/phaser/core/input_mouse.js +289 -0
- package/src/phaser/core/input_mspointer.js +197 -0
- package/src/phaser/core/input_pointer.js +427 -0
- package/src/phaser/core/input_touch.js +157 -0
- package/src/phaser/core/loader.js +1057 -0
- package/src/phaser/core/loader_parser.js +109 -0
- package/src/phaser/core/raf.js +46 -0
- package/src/phaser/core/raf_fb.js +75 -0
- package/src/phaser/core/raf_to.js +34 -0
- package/src/phaser/core/scale_manager.js +806 -0
- package/src/phaser/core/scene.js +65 -0
- package/src/phaser/core/scene_manager.js +309 -0
- package/src/phaser/core/signal.js +175 -0
- package/src/phaser/core/signal_binding.js +69 -0
- package/src/phaser/core/sound.js +538 -0
- package/src/phaser/core/sound_manager.js +364 -0
- package/src/phaser/core/stage.js +108 -0
- package/src/phaser/core/time.js +203 -0
- package/src/phaser/core/timer.js +276 -0
- package/src/phaser/core/timer_event.js +21 -0
- package/src/phaser/core/tween.js +329 -0
- package/src/phaser/core/tween_data.js +258 -0
- package/src/phaser/core/tween_easing.js +341 -0
- package/src/phaser/core/tween_manager.js +185 -0
- package/src/phaser/core/world.js +18 -0
- package/src/phaser/display/bitmap_text.js +322 -0
- package/src/phaser/display/button.js +194 -0
- package/src/phaser/display/canvas/buffer.js +36 -0
- package/src/phaser/display/canvas/graphics.js +227 -0
- package/src/phaser/display/canvas/masker.js +39 -0
- package/src/phaser/display/canvas/pool.js +126 -0
- package/src/phaser/display/canvas/renderer.js +123 -0
- package/src/phaser/display/canvas/tinter.js +144 -0
- package/src/phaser/display/canvas/util.js +159 -0
- package/src/phaser/display/display_object.js +597 -0
- package/src/phaser/display/graphics.js +723 -0
- package/src/phaser/display/graphics_data.js +27 -0
- package/src/phaser/display/graphics_data_util.js +15 -0
- package/src/phaser/display/group.js +227 -0
- package/src/phaser/display/image.js +288 -0
- package/src/phaser/display/sprite_batch.js +15 -0
- package/src/phaser/display/sprite_util.js +250 -0
- package/src/phaser/display/text.js +1089 -0
- package/src/phaser/display/webgl/abstract_filter.js +25 -0
- package/src/phaser/display/webgl/base_texture.js +68 -0
- package/src/phaser/display/webgl/blend_manager.js +35 -0
- package/src/phaser/display/webgl/earcut.js +662 -0
- package/src/phaser/display/webgl/earcut_node.js +28 -0
- package/src/phaser/display/webgl/fast_sprite_batch.js +242 -0
- package/src/phaser/display/webgl/filter_manager.js +46 -0
- package/src/phaser/display/webgl/filter_texture.js +61 -0
- package/src/phaser/display/webgl/graphics.js +624 -0
- package/src/phaser/display/webgl/graphics_data.js +42 -0
- package/src/phaser/display/webgl/mask_manager.js +36 -0
- package/src/phaser/display/webgl/render_texture.js +81 -0
- package/src/phaser/display/webgl/renderer.js +234 -0
- package/src/phaser/display/webgl/shader/complex.js +74 -0
- package/src/phaser/display/webgl/shader/fast.js +97 -0
- package/src/phaser/display/webgl/shader/normal.js +225 -0
- package/src/phaser/display/webgl/shader/primitive.js +72 -0
- package/src/phaser/display/webgl/shader/strip.js +77 -0
- package/src/phaser/display/webgl/shader_manager.js +89 -0
- package/src/phaser/display/webgl/sprite_batch.js +320 -0
- package/src/phaser/display/webgl/stencil_manager.js +170 -0
- package/src/phaser/display/webgl/texture.js +117 -0
- package/src/phaser/display/webgl/texture_util.js +34 -0
- package/src/phaser/display/webgl/util.js +78 -0
- package/src/phaser/geom/circle.js +186 -0
- package/src/phaser/geom/ellipse.js +65 -0
- package/src/phaser/geom/line.js +190 -0
- package/src/phaser/geom/matrix.js +147 -0
- package/src/phaser/geom/point.js +164 -0
- package/src/phaser/geom/polygon.js +140 -0
- package/src/phaser/geom/rectangle.js +306 -0
- package/src/phaser/geom/rounded_rectangle.js +36 -0
- package/src/phaser/geom/util/circle.js +122 -0
- package/src/phaser/geom/util/ellipse.js +34 -0
- package/src/phaser/geom/util/line.js +135 -0
- package/src/phaser/geom/util/matrix.js +53 -0
- package/src/phaser/geom/util/point.js +296 -0
- package/src/phaser/geom/util/polygon.js +28 -0
- package/src/phaser/geom/util/rectangle.js +229 -0
- package/src/phaser/geom/util/rounded_rectangle.js +32 -0
- package/src/phaser/util/math.js +297 -0
- package/src/phaser/util/string.js +32 -0
|
@@ -0,0 +1,1057 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Andras Csizmadia <andras@vpmedia.hu>
|
|
3
|
+
* @author Richard Davey <rich@photonstorm.com>
|
|
4
|
+
* @copyright Copyright (c) 2018-present Richard Davey, Photon Storm Ltd., Andras Csizmadia <andras@vpmedia.hu> (www.vpmedia.hu)
|
|
5
|
+
*/
|
|
6
|
+
import Signal from './signal';
|
|
7
|
+
import Rectangle from '../geom/rectangle';
|
|
8
|
+
import { canPlayAudio } from './device_util';
|
|
9
|
+
import { TEXTURE_ATLAS_JSON_ARRAY, TEXTURE_ATLAS_JSON_HASH, TEXTURE_ATLAS_XML_STARLING, TEXTURE_ATLAS_JSON_PYXEL } from './const';
|
|
10
|
+
|
|
11
|
+
export const TILED_JSON = 6;
|
|
12
|
+
export const TILEMAP_CSV = 7;
|
|
13
|
+
|
|
14
|
+
export default class {
|
|
15
|
+
|
|
16
|
+
constructor(game) {
|
|
17
|
+
this.game = game;
|
|
18
|
+
this.cache = game.cache;
|
|
19
|
+
this.resetLocked = false;
|
|
20
|
+
this.isLoading = false;
|
|
21
|
+
this.hasLoaded = false;
|
|
22
|
+
this.preloadSprite = null;
|
|
23
|
+
this.crossOrigin = false;
|
|
24
|
+
this.baseURL = '';
|
|
25
|
+
this.path = '';
|
|
26
|
+
this.headers = {
|
|
27
|
+
requestedWith: false,
|
|
28
|
+
json: 'application/json',
|
|
29
|
+
xml: 'application/xml',
|
|
30
|
+
};
|
|
31
|
+
this.onLoadStart = new Signal();
|
|
32
|
+
this.onLoadComplete = new Signal();
|
|
33
|
+
this.onPackComplete = new Signal();
|
|
34
|
+
this.onFileStart = new Signal();
|
|
35
|
+
this.onFileComplete = new Signal();
|
|
36
|
+
this.onFileError = new Signal();
|
|
37
|
+
this.useXDomainRequest = false;
|
|
38
|
+
this._warnedAboutXDomainRequest = false;
|
|
39
|
+
this.enableParallel = true;
|
|
40
|
+
this.maxParallelDownloads = 6;
|
|
41
|
+
this._withSyncPointDepth = 0;
|
|
42
|
+
this._fileList = [];
|
|
43
|
+
this._flightQueue = [];
|
|
44
|
+
this._processingHead = 0;
|
|
45
|
+
this._fileLoadStarted = false;
|
|
46
|
+
this._totalPackCount = 0;
|
|
47
|
+
this._totalFileCount = 0;
|
|
48
|
+
this._loadedPackCount = 0;
|
|
49
|
+
this._loadedFileCount = 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
setPreloadSprite(sprite, direction = 0) {
|
|
53
|
+
this.preloadSprite = {
|
|
54
|
+
sprite,
|
|
55
|
+
direction,
|
|
56
|
+
width: sprite.width,
|
|
57
|
+
height: sprite.height,
|
|
58
|
+
rect: null,
|
|
59
|
+
};
|
|
60
|
+
if (direction === 0) {
|
|
61
|
+
// Horizontal rect
|
|
62
|
+
this.preloadSprite.rect = new Rectangle(0, 0, 1, sprite.height);
|
|
63
|
+
} else {
|
|
64
|
+
// Vertical rect
|
|
65
|
+
this.preloadSprite.rect = new Rectangle(0, 0, sprite.width, 1);
|
|
66
|
+
}
|
|
67
|
+
sprite.crop(this.preloadSprite.rect);
|
|
68
|
+
sprite.visible = true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
resize() {
|
|
72
|
+
if (this.preloadSprite && this.preloadSprite.height !== this.preloadSprite.sprite.height) {
|
|
73
|
+
this.preloadSprite.rect.height = this.preloadSprite.sprite.height;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
checkKeyExists(type, key) {
|
|
78
|
+
return this.getAssetIndex(type, key) > -1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
getAssetIndex(type, key) {
|
|
82
|
+
let bestFound = -1;
|
|
83
|
+
for (let i = 0; i < this._fileList.length; i += 1) {
|
|
84
|
+
const file = this._fileList[i];
|
|
85
|
+
if (file.type === type && file.key === key) {
|
|
86
|
+
bestFound = i;
|
|
87
|
+
// An already loaded/loading file may be superceded.
|
|
88
|
+
if (!file.loaded && !file.loading) {
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return bestFound;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
getAsset(type, key) {
|
|
98
|
+
const fileIndex = this.getAssetIndex(type, key);
|
|
99
|
+
if (fileIndex > -1) {
|
|
100
|
+
return { index: fileIndex, file: this._fileList[fileIndex] };
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
reset(hard, clearEvents = false) {
|
|
106
|
+
if (this.resetLocked) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (hard) {
|
|
110
|
+
this.preloadSprite = null;
|
|
111
|
+
}
|
|
112
|
+
this.isLoading = false;
|
|
113
|
+
this._processingHead = 0;
|
|
114
|
+
this._fileList.length = 0;
|
|
115
|
+
this._flightQueue.length = 0;
|
|
116
|
+
this._fileLoadStarted = false;
|
|
117
|
+
this._totalFileCount = 0;
|
|
118
|
+
this._totalPackCount = 0;
|
|
119
|
+
this._loadedPackCount = 0;
|
|
120
|
+
this._loadedFileCount = 0;
|
|
121
|
+
if (clearEvents) {
|
|
122
|
+
this.onLoadStart.removeAll();
|
|
123
|
+
this.onLoadComplete.removeAll();
|
|
124
|
+
this.onPackComplete.removeAll();
|
|
125
|
+
this.onFileStart.removeAll();
|
|
126
|
+
this.onFileComplete.removeAll();
|
|
127
|
+
this.onFileError.removeAll();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
addToFileList(type, key = '', url = null, properties = null, overwrite = false, extension = null) {
|
|
132
|
+
if (key === undefined || key === '') {
|
|
133
|
+
console.warn('Loader: Invalid or no key given of type ' + type);
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
if (url === undefined || url === null) {
|
|
137
|
+
if (extension) {
|
|
138
|
+
url = key + extension;
|
|
139
|
+
} else {
|
|
140
|
+
console.warn('Loader: No URL given for file type: ' + type + ' key: ' + key);
|
|
141
|
+
return this;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const file = {
|
|
145
|
+
type,
|
|
146
|
+
key,
|
|
147
|
+
path: this.path,
|
|
148
|
+
url,
|
|
149
|
+
syncPoint: this._withSyncPointDepth > 0,
|
|
150
|
+
data: null,
|
|
151
|
+
loading: false,
|
|
152
|
+
loaded: false,
|
|
153
|
+
error: false,
|
|
154
|
+
};
|
|
155
|
+
if (properties) {
|
|
156
|
+
const keys = Object.keys(properties);
|
|
157
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
158
|
+
const prop = keys[i];
|
|
159
|
+
file[prop] = properties[prop];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const fileIndex = this.getAssetIndex(type, key);
|
|
163
|
+
if (overwrite && fileIndex > -1) {
|
|
164
|
+
const currentFile = this._fileList[fileIndex];
|
|
165
|
+
if (!currentFile.loading && !currentFile.loaded) {
|
|
166
|
+
this._fileList[fileIndex] = file;
|
|
167
|
+
} else {
|
|
168
|
+
this._fileList.push(file);
|
|
169
|
+
this._totalFileCount += 1;
|
|
170
|
+
}
|
|
171
|
+
} else if (fileIndex === -1) {
|
|
172
|
+
this._fileList.push(file);
|
|
173
|
+
this._totalFileCount += 1;
|
|
174
|
+
}
|
|
175
|
+
return this;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
replaceInFileList(type, key, url, properties) {
|
|
179
|
+
return this.addToFileList(type, key, url, properties, true);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
pack(key, url, data, callbackContext) {
|
|
183
|
+
const pack = {
|
|
184
|
+
type: 'packfile',
|
|
185
|
+
key: key,
|
|
186
|
+
url: url,
|
|
187
|
+
path: this.path,
|
|
188
|
+
syncPoint: true,
|
|
189
|
+
data: null,
|
|
190
|
+
loading: false,
|
|
191
|
+
loaded: false,
|
|
192
|
+
error: false,
|
|
193
|
+
callbackContext: callbackContext
|
|
194
|
+
};
|
|
195
|
+
if (data) {
|
|
196
|
+
if (typeof data === 'string') {
|
|
197
|
+
data = JSON.parse(data);
|
|
198
|
+
}
|
|
199
|
+
pack.data = data || {};
|
|
200
|
+
pack.loaded = true;
|
|
201
|
+
}
|
|
202
|
+
for (let i = 0; i < this._fileList.length + 1; i += 1) {
|
|
203
|
+
const file = this._fileList[i];
|
|
204
|
+
if (!file || (!file.loaded && !file.loading && file.type !== 'packfile')) {
|
|
205
|
+
this._fileList.splice(i, 0, pack);
|
|
206
|
+
this._totalPackCount += 1;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return this;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
image(key, url, overwrite) {
|
|
214
|
+
return this.addToFileList('image', key, url, undefined, overwrite, '.png');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
images(keys, urls) {
|
|
218
|
+
if (Array.isArray(urls)) {
|
|
219
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
220
|
+
this.image(keys[i], urls[i]);
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
224
|
+
this.image(keys[i]);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return this;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
text(key, url, overwrite) {
|
|
231
|
+
return this.addToFileList('text', key, url, undefined, overwrite, '.txt');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
json(key, url, overwrite) {
|
|
235
|
+
return this.addToFileList('json', key, url, undefined, overwrite, '.json');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
shader(key, url, overwrite) {
|
|
239
|
+
return this.addToFileList('shader', key, url, undefined, overwrite, '.frag');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
xml(key, url, overwrite) {
|
|
243
|
+
return this.addToFileList('xml', key, url, undefined, overwrite, '.xml');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
script(key, url, callback = false, callbackContext = this) {
|
|
247
|
+
return this.addToFileList('script', key, url, { syncPoint: true, callback, callbackContext }, false, '.js');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
binary(key, url, callback = false, callbackContext = this) {
|
|
251
|
+
return this.addToFileList('binary', key, url, { callback, callbackContext }, false, '.bin');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
spritesheet(key, url, frameWidth, frameHeight, frameMax = -1, margin = 0, spacing = 0) {
|
|
255
|
+
return this.addToFileList('spritesheet', key, url, { frameWidth, frameHeight, frameMax, margin, spacing }, false, '.png');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
audio(key, urls, autoDecode = true) {
|
|
259
|
+
if (this.game.sound.noAudio) {
|
|
260
|
+
return this;
|
|
261
|
+
}
|
|
262
|
+
if (typeof urls === 'string') {
|
|
263
|
+
urls = [urls];
|
|
264
|
+
}
|
|
265
|
+
return this.addToFileList('audio', key, urls, { buffer: null, autoDecode });
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
audioSprite(key, urls, jsonURL, jsonData, autoDecode = true) {
|
|
269
|
+
if (this.game.sound.noAudio) {
|
|
270
|
+
return this;
|
|
271
|
+
}
|
|
272
|
+
this.audio(key, urls, autoDecode);
|
|
273
|
+
if (jsonURL) {
|
|
274
|
+
this.json(key + '-audioatlas', jsonURL);
|
|
275
|
+
} else if (jsonData) {
|
|
276
|
+
if (typeof jsonData === 'string') {
|
|
277
|
+
jsonData = JSON.parse(jsonData);
|
|
278
|
+
}
|
|
279
|
+
this.cache.addJSON(key + '-audioatlas', '', jsonData);
|
|
280
|
+
}
|
|
281
|
+
return this;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
video() {
|
|
285
|
+
// TODO
|
|
286
|
+
console.warn('loader.video() is not implemented');
|
|
287
|
+
return this;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
tilemap() {
|
|
291
|
+
// TODO
|
|
292
|
+
console.warn('loader.tilemap() is not implemented');
|
|
293
|
+
return this;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
bitmapFont(key, textureURL = null, atlasURL = null, atlasData = null, xSpacing = 0, ySpacing = 0) {
|
|
297
|
+
if (textureURL === undefined || textureURL === null) {
|
|
298
|
+
textureURL = key + '.png';
|
|
299
|
+
}
|
|
300
|
+
if (atlasURL === null && atlasData === null) {
|
|
301
|
+
atlasURL = key + '.xml';
|
|
302
|
+
}
|
|
303
|
+
// A URL to a json/xml atlas has been given
|
|
304
|
+
if (atlasURL) {
|
|
305
|
+
this.addToFileList('bitmapfont', key, textureURL, { atlasURL, xSpacing, ySpacing });
|
|
306
|
+
} else if (typeof atlasData === 'string') {
|
|
307
|
+
// A stringified xml/json atlas has been given
|
|
308
|
+
let json = null;
|
|
309
|
+
let xml = null;
|
|
310
|
+
try {
|
|
311
|
+
json = JSON.parse(atlasData);
|
|
312
|
+
} catch (e) {
|
|
313
|
+
xml = this.parseXml(atlasData);
|
|
314
|
+
}
|
|
315
|
+
if (!xml && !json) {
|
|
316
|
+
throw new Error('Loader. Invalid Bitmap Font atlas given');
|
|
317
|
+
}
|
|
318
|
+
this.addToFileList('bitmapfont', key, textureURL, { atlasURL: null, atlasData: json || xml, atlasType: (json ? 'json' : 'xml'), xSpacing, ySpacing });
|
|
319
|
+
}
|
|
320
|
+
return this;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
atlasJSONArray(key, textureURL, atlasURL, atlasData) {
|
|
324
|
+
return this.atlas(key, textureURL, atlasURL, atlasData, TEXTURE_ATLAS_JSON_ARRAY);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
atlasJSONHash(key, textureURL, atlasURL, atlasData) {
|
|
328
|
+
return this.atlas(key, textureURL, atlasURL, atlasData, TEXTURE_ATLAS_JSON_HASH);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
atlasXML() {
|
|
332
|
+
// TODO
|
|
333
|
+
console.warn('loader.atlasXML() is not implemented');
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
atlas(key, textureURL, atlasURL = null, atlasData = null, format = TEXTURE_ATLAS_JSON_ARRAY) {
|
|
337
|
+
if (textureURL === undefined || textureURL === null) {
|
|
338
|
+
textureURL = key + '.png';
|
|
339
|
+
}
|
|
340
|
+
if (!atlasURL && !atlasData) {
|
|
341
|
+
if (format === TEXTURE_ATLAS_XML_STARLING) {
|
|
342
|
+
atlasURL = key + '.xml';
|
|
343
|
+
} else {
|
|
344
|
+
atlasURL = key + '.json';
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
// A URL to a json/xml file has been given
|
|
348
|
+
if (atlasURL) {
|
|
349
|
+
this.addToFileList('textureatlas', key, textureURL, { atlasURL, format });
|
|
350
|
+
} else {
|
|
351
|
+
switch (format) {
|
|
352
|
+
// A json string or object has been given
|
|
353
|
+
case TEXTURE_ATLAS_JSON_ARRAY:
|
|
354
|
+
if (typeof atlasData === 'string') {
|
|
355
|
+
atlasData = JSON.parse(atlasData);
|
|
356
|
+
}
|
|
357
|
+
break;
|
|
358
|
+
// An xml string or object has been given
|
|
359
|
+
case TEXTURE_ATLAS_XML_STARLING:
|
|
360
|
+
if (typeof atlasData === 'string') {
|
|
361
|
+
const xml = this.parseXml(atlasData);
|
|
362
|
+
if (!xml) {
|
|
363
|
+
throw new Error('Invalid Texture Atlas XML given');
|
|
364
|
+
}
|
|
365
|
+
atlasData = xml;
|
|
366
|
+
}
|
|
367
|
+
break;
|
|
368
|
+
default:
|
|
369
|
+
// pass
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
this.addToFileList('textureatlas', key, textureURL, { atlasURL: null, atlasData, format });
|
|
373
|
+
}
|
|
374
|
+
return this;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
withSyncPoint(callback, callbackContext) {
|
|
378
|
+
this._withSyncPointDepth += 1;
|
|
379
|
+
try {
|
|
380
|
+
callback.call(callbackContext || this, this);
|
|
381
|
+
} finally {
|
|
382
|
+
this._withSyncPointDepth -= 1;
|
|
383
|
+
}
|
|
384
|
+
return this;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
addSyncPoint(type, key) {
|
|
388
|
+
const asset = this.getAsset(type, key);
|
|
389
|
+
if (asset) {
|
|
390
|
+
asset.file.syncPoint = true;
|
|
391
|
+
}
|
|
392
|
+
return this;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
removeFile(type, key) {
|
|
396
|
+
const asset = this.getAsset(type, key);
|
|
397
|
+
if (asset) {
|
|
398
|
+
if (!asset.loaded && !asset.loading) {
|
|
399
|
+
this._fileList.splice(asset.index, 1);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
removeAll() {
|
|
405
|
+
this._fileList.length = 0;
|
|
406
|
+
this._flightQueue.length = 0;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
start() {
|
|
410
|
+
if (this.isLoading) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
this.hasLoaded = false;
|
|
414
|
+
this.isLoading = true;
|
|
415
|
+
this.updateProgress();
|
|
416
|
+
this.processLoadQueue();
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
processLoadQueue() {
|
|
420
|
+
if (!this.isLoading) {
|
|
421
|
+
console.warn('Loader - active loading canceled / reset');
|
|
422
|
+
this.finishedLoading(true);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
// Empty the flight queue as applicable
|
|
426
|
+
for (let i = 0; i < this._flightQueue.length; i += 1) {
|
|
427
|
+
const file = this._flightQueue[i];
|
|
428
|
+
if (file.loaded || file.error) {
|
|
429
|
+
this._flightQueue.splice(i, 1);
|
|
430
|
+
i -= 1;
|
|
431
|
+
file.loading = false;
|
|
432
|
+
file.requestUrl = null;
|
|
433
|
+
file.requestObject = null;
|
|
434
|
+
if (file.error) {
|
|
435
|
+
this.onFileError.dispatch(file.key, file);
|
|
436
|
+
}
|
|
437
|
+
if (file.type !== 'packfile') {
|
|
438
|
+
this._loadedFileCount += 1;
|
|
439
|
+
this.onFileComplete.dispatch(this.progress, file.key, !file.error, this._loadedFileCount, this._totalFileCount);
|
|
440
|
+
} else if (file.type === 'packfile' && file.error) {
|
|
441
|
+
// Non-error pack files are handled when processing the file queue
|
|
442
|
+
this._loadedPackCount += 1;
|
|
443
|
+
this.onPackComplete.dispatch(file.key, !file.error, this._loadedPackCount, this._totalPackCount);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// When true further non-pack file downloads are suppressed
|
|
448
|
+
let syncblock = false;
|
|
449
|
+
const inflightLimit = this.enableParallel ? Math.max(1, this.maxParallelDownloads) : 1;
|
|
450
|
+
for (let i = this._processingHead; i < this._fileList.length; i += 1) {
|
|
451
|
+
const file = this._fileList[i];
|
|
452
|
+
// Pack is fetched (ie. has data) and is currently at the start of the process queue.
|
|
453
|
+
if (file.type === 'packfile' && !file.error && file.loaded && i === this._processingHead) {
|
|
454
|
+
// Processing the pack / adds more files
|
|
455
|
+
this.processPack(file);
|
|
456
|
+
this._loadedPackCount += 1;
|
|
457
|
+
this.onPackComplete.dispatch(file.key, !file.error, this._loadedPackCount, this._totalPackCount);
|
|
458
|
+
}
|
|
459
|
+
if (file.loaded || file.error) {
|
|
460
|
+
// Item at the start of file list finished, can skip it in future
|
|
461
|
+
if (i === this._processingHead) {
|
|
462
|
+
this._processingHead = i + 1;
|
|
463
|
+
}
|
|
464
|
+
} else if (!file.loading && this._flightQueue.length < inflightLimit) {
|
|
465
|
+
// -> not loaded/failed, not loading
|
|
466
|
+
if (file.type === 'packfile' && !file.data) {
|
|
467
|
+
// Fetches the pack data: the pack is processed above as it reaches queue-start.
|
|
468
|
+
// (Packs do not trigger onLoadStart or onFileStart.)
|
|
469
|
+
this._flightQueue.push(file);
|
|
470
|
+
file.loading = true;
|
|
471
|
+
this.loadFile(file);
|
|
472
|
+
} else if (!syncblock) {
|
|
473
|
+
if (!this._fileLoadStarted) {
|
|
474
|
+
this._fileLoadStarted = true;
|
|
475
|
+
this.onLoadStart.dispatch();
|
|
476
|
+
}
|
|
477
|
+
this._flightQueue.push(file);
|
|
478
|
+
file.loading = true;
|
|
479
|
+
this.onFileStart.dispatch(this.progress, file.key, file.url);
|
|
480
|
+
this.loadFile(file);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (!file.loaded && file.syncPoint) {
|
|
484
|
+
syncblock = true;
|
|
485
|
+
}
|
|
486
|
+
// Stop looking if queue full - or if syncblocked and there are no more packs.
|
|
487
|
+
// (As only packs can be loaded around a syncblock)
|
|
488
|
+
if (this._flightQueue.length >= inflightLimit || (syncblock && this._loadedPackCount === this._totalPackCount)) {
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
this.updateProgress();
|
|
493
|
+
// True when all items in the queue have been advanced over
|
|
494
|
+
// (There should be no inflight items as they are complete - loaded/error.)
|
|
495
|
+
if (this._processingHead >= this._fileList.length) {
|
|
496
|
+
this.finishedLoading();
|
|
497
|
+
} else if (!this._flightQueue.length) {
|
|
498
|
+
// Flight queue is empty but file list is not done being processed.
|
|
499
|
+
// This indicates a critical internal error with no known recovery.
|
|
500
|
+
console.warn('Loader - aborting: processing queue empty, loading may have stalled');
|
|
501
|
+
const _this = this;
|
|
502
|
+
setTimeout(() => {
|
|
503
|
+
_this.finishedLoading(true);
|
|
504
|
+
}, 2000);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
finishedLoading(abnormal) {
|
|
509
|
+
if (this.hasLoaded) {
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
this.hasLoaded = true;
|
|
513
|
+
this.isLoading = false;
|
|
514
|
+
// If there were no files make sure to trigger the event anyway, for consistency
|
|
515
|
+
if (!abnormal && !this._fileLoadStarted) {
|
|
516
|
+
this._fileLoadStarted = true;
|
|
517
|
+
this.onLoadStart.dispatch();
|
|
518
|
+
}
|
|
519
|
+
// https://github.com/photonstorm/phaser-ce/pull/54/
|
|
520
|
+
this.reset();
|
|
521
|
+
this.onLoadComplete.dispatch();
|
|
522
|
+
this.game.state.loadComplete();
|
|
523
|
+
// https://github.com/photonstorm/phaser-ce/pull/54/
|
|
524
|
+
// this.reset();
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
asyncComplete(file, errorMessage = '') {
|
|
528
|
+
file.loaded = true;
|
|
529
|
+
file.error = !!errorMessage;
|
|
530
|
+
if (errorMessage) {
|
|
531
|
+
file.errorMessage = errorMessage;
|
|
532
|
+
console.warn(file, errorMessage);
|
|
533
|
+
}
|
|
534
|
+
this.processLoadQueue();
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
processPack(pack) {
|
|
538
|
+
const packData = pack.data[pack.key];
|
|
539
|
+
if (!packData) {
|
|
540
|
+
console.warn('Missing loader pack key', pack.key);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
for (let i = 0; i < packData.length; i += 1) {
|
|
544
|
+
const file = packData[i];
|
|
545
|
+
switch (file.type) {
|
|
546
|
+
case "image":
|
|
547
|
+
this.image(file.key, file.url, file.overwrite);
|
|
548
|
+
break;
|
|
549
|
+
case "text":
|
|
550
|
+
this.text(file.key, file.url, file.overwrite);
|
|
551
|
+
break;
|
|
552
|
+
case "json":
|
|
553
|
+
this.json(file.key, file.url, file.overwrite);
|
|
554
|
+
break;
|
|
555
|
+
case "xml":
|
|
556
|
+
this.xml(file.key, file.url, file.overwrite);
|
|
557
|
+
break;
|
|
558
|
+
case "script":
|
|
559
|
+
this.script(file.key, file.url, file.callback, pack.callbackContext || this);
|
|
560
|
+
break;
|
|
561
|
+
case "binary":
|
|
562
|
+
this.binary(file.key, file.url, file.callback, pack.callbackContext || this);
|
|
563
|
+
break;
|
|
564
|
+
case "spritesheet":
|
|
565
|
+
this.spritesheet(file.key, file.url, file.frameWidth, file.frameHeight, file.frameMax, file.margin, file.spacing);
|
|
566
|
+
break;
|
|
567
|
+
case "video":
|
|
568
|
+
this.video(file.key, file.urls);
|
|
569
|
+
break;
|
|
570
|
+
case "audio":
|
|
571
|
+
this.audio(file.key, file.urls, file.autoDecode);
|
|
572
|
+
break;
|
|
573
|
+
case "audiosprite":
|
|
574
|
+
this.audioSprite(file.key, file.urls, file.jsonURL, file.jsonData, file.autoDecode);
|
|
575
|
+
break;
|
|
576
|
+
case "tilemap":
|
|
577
|
+
// TODO
|
|
578
|
+
// this.tilemap(file.key, file.url, file.data, Phaser.Tilemap[file.format]);
|
|
579
|
+
break;
|
|
580
|
+
case "physics":
|
|
581
|
+
// TODO
|
|
582
|
+
// this.physics(file.key, file.url, file.data, Phaser.Loader[file.format]);
|
|
583
|
+
break;
|
|
584
|
+
case "bitmapFont":
|
|
585
|
+
this.bitmapFont(file.key, file.textureURL, file.atlasURL, file.atlasData, file.xSpacing, file.ySpacing);
|
|
586
|
+
break;
|
|
587
|
+
case "atlasJSONArray":
|
|
588
|
+
this.atlasJSONArray(file.key, file.textureURL, file.atlasURL, file.atlasData);
|
|
589
|
+
break;
|
|
590
|
+
case "atlasJSONHash":
|
|
591
|
+
this.atlasJSONHash(file.key, file.textureURL, file.atlasURL, file.atlasData);
|
|
592
|
+
break;
|
|
593
|
+
case "atlasXML":
|
|
594
|
+
this.atlasXML(file.key, file.textureURL, file.atlasURL, file.atlasData);
|
|
595
|
+
break;
|
|
596
|
+
case "atlas":
|
|
597
|
+
this.atlas(file.key, file.textureURL, file.atlasURL, file.atlasData, file.format === 'TEXTURE_ATLAS_JSON_HASH' ? TEXTURE_ATLAS_JSON_HASH : TEXTURE_ATLAS_JSON_ARRAY);
|
|
598
|
+
break;
|
|
599
|
+
case "shader":
|
|
600
|
+
this.shader(file.key, file.url, file.overwrite);
|
|
601
|
+
break;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
transformUrl(url, file) {
|
|
607
|
+
if (!url) {
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
if (url.match(/^(?:blob:|data:|http:\/\/|https:\/\/|\/\/)/)) {
|
|
611
|
+
return url;
|
|
612
|
+
}
|
|
613
|
+
return this.baseURL + file.path + url;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
loadFile(file) {
|
|
617
|
+
switch (file.type) {
|
|
618
|
+
case 'packfile':
|
|
619
|
+
this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.fileComplete);
|
|
620
|
+
break;
|
|
621
|
+
case 'image':
|
|
622
|
+
case 'spritesheet':
|
|
623
|
+
case 'textureatlas':
|
|
624
|
+
case 'bitmapfont':
|
|
625
|
+
this.loadImageTag(file);
|
|
626
|
+
break;
|
|
627
|
+
case 'audio':
|
|
628
|
+
file.url = this.getAudioURL(file.url);
|
|
629
|
+
if (file.url) {
|
|
630
|
+
// WebAudio or Audio Tag?
|
|
631
|
+
if (this.game.sound.usingWebAudio) {
|
|
632
|
+
this.xhrLoad(file, this.transformUrl(file.url, file), 'arraybuffer', this.fileComplete);
|
|
633
|
+
} else if (this.game.sound.usingAudioTag) {
|
|
634
|
+
this.loadAudioTag(file);
|
|
635
|
+
}
|
|
636
|
+
} else {
|
|
637
|
+
this.fileError(file, null, 'No supported audio URL specified or device does not have audio playback support');
|
|
638
|
+
}
|
|
639
|
+
break;
|
|
640
|
+
case 'video':
|
|
641
|
+
file.url = this.getVideoURL(file.url);
|
|
642
|
+
if (file.url) {
|
|
643
|
+
if (file.asBlob) {
|
|
644
|
+
this.xhrLoad(file, this.transformUrl(file.url, file), 'blob', this.fileComplete);
|
|
645
|
+
} else {
|
|
646
|
+
this.loadVideoTag(file);
|
|
647
|
+
}
|
|
648
|
+
} else {
|
|
649
|
+
this.fileError(file, null, 'No supported video URL specified or device does not have video playback support');
|
|
650
|
+
}
|
|
651
|
+
break;
|
|
652
|
+
case 'json':
|
|
653
|
+
this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.jsonLoadComplete);
|
|
654
|
+
break;
|
|
655
|
+
case 'xml':
|
|
656
|
+
this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.xmlLoadComplete);
|
|
657
|
+
break;
|
|
658
|
+
case 'tilemap':
|
|
659
|
+
if (file.format === TILED_JSON) {
|
|
660
|
+
this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.jsonLoadComplete);
|
|
661
|
+
} else if (file.format === TILEMAP_CSV) {
|
|
662
|
+
this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.csvLoadComplete);
|
|
663
|
+
} else {
|
|
664
|
+
this.asyncComplete(file, 'invalid Tilemap format: ' + file.format);
|
|
665
|
+
}
|
|
666
|
+
break;
|
|
667
|
+
case 'text':
|
|
668
|
+
case 'script':
|
|
669
|
+
case 'shader':
|
|
670
|
+
case 'physics':
|
|
671
|
+
this.xhrLoad(file, this.transformUrl(file.url, file), 'text', this.fileComplete);
|
|
672
|
+
break;
|
|
673
|
+
case 'binary':
|
|
674
|
+
this.xhrLoad(file, this.transformUrl(file.url, file), 'arraybuffer', this.fileComplete);
|
|
675
|
+
break;
|
|
676
|
+
default:
|
|
677
|
+
// pass
|
|
678
|
+
break;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
loadImageTag(file) {
|
|
683
|
+
const _this = this;
|
|
684
|
+
file.data = new Image();
|
|
685
|
+
file.data.name = file.key;
|
|
686
|
+
if (this.crossOrigin) {
|
|
687
|
+
file.data.crossOrigin = this.crossOrigin;
|
|
688
|
+
}
|
|
689
|
+
file.data.onload = () => {
|
|
690
|
+
if (file.data.onload) {
|
|
691
|
+
file.data.onload = null;
|
|
692
|
+
file.data.onerror = null;
|
|
693
|
+
_this.fileComplete(file);
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
file.data.onerror = () => {
|
|
697
|
+
if (file.data.onload) {
|
|
698
|
+
file.data.onload = null;
|
|
699
|
+
file.data.onerror = null;
|
|
700
|
+
_this.fileError(file);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
file.data.src = this.transformUrl(file.url, file);
|
|
704
|
+
// Image is immediately-available/cached
|
|
705
|
+
// Special Firefox magic, exclude from cached reload
|
|
706
|
+
// More info here: https://github.com/photonstorm/phaser/issues/2534
|
|
707
|
+
if (!this.game.device.firefox && file.data.complete && file.data.width && file.data.height) {
|
|
708
|
+
file.data.onload = null;
|
|
709
|
+
file.data.onerror = null;
|
|
710
|
+
this.fileComplete(file);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
loadVideoTag() {
|
|
715
|
+
// TODO
|
|
716
|
+
console.warn('loader.loadVideoTag() is not implemented');
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
loadAudioTag(file) {
|
|
720
|
+
const scope = this;
|
|
721
|
+
if (this.game.sound.touchLocked) {
|
|
722
|
+
// If audio is locked we can't do this yet, so need to queue this load request. Bum.
|
|
723
|
+
file.data = new Audio();
|
|
724
|
+
file.data.name = file.key;
|
|
725
|
+
file.data.preload = 'auto';
|
|
726
|
+
file.data.src = this.transformUrl(file.url, file);
|
|
727
|
+
this.fileComplete(file);
|
|
728
|
+
} else {
|
|
729
|
+
file.data = new Audio();
|
|
730
|
+
file.data.name = file.key;
|
|
731
|
+
const playThroughEvent = () => {
|
|
732
|
+
file.data.removeEventListener('canplaythrough', playThroughEvent, false);
|
|
733
|
+
file.data.onerror = null;
|
|
734
|
+
scope.fileComplete(file);
|
|
735
|
+
};
|
|
736
|
+
file.data.onerror = () => {
|
|
737
|
+
file.data.removeEventListener('canplaythrough', playThroughEvent, false);
|
|
738
|
+
file.data.onerror = null;
|
|
739
|
+
scope.fileError(file);
|
|
740
|
+
};
|
|
741
|
+
file.data.preload = 'auto';
|
|
742
|
+
file.data.src = this.transformUrl(file.url, file);
|
|
743
|
+
file.data.addEventListener('canplaythrough', playThroughEvent, false);
|
|
744
|
+
file.data.load();
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
xhrLoad(file, url, type, onload, onerror) {
|
|
749
|
+
const xhr = new XMLHttpRequest();
|
|
750
|
+
xhr.open('GET', url, true);
|
|
751
|
+
xhr.responseType = type;
|
|
752
|
+
if (this.headers.requestedWith !== false) {
|
|
753
|
+
xhr.setRequestHeader('X-Requested-With', this.headers.requestedWith);
|
|
754
|
+
}
|
|
755
|
+
if (this.headers[file.type]) {
|
|
756
|
+
xhr.setRequestHeader('Accept', this.headers[file.type]);
|
|
757
|
+
}
|
|
758
|
+
onerror = onerror || this.fileError;
|
|
759
|
+
const scope = this;
|
|
760
|
+
xhr.onload = () => {
|
|
761
|
+
try {
|
|
762
|
+
if (xhr.readyState === 4 && xhr.status >= 400 && xhr.status <= 599) { // Handle HTTP status codes of 4xx and 5xx as errors, even if xhr.onerror was not called.
|
|
763
|
+
return onerror.call(scope, file, xhr);
|
|
764
|
+
}
|
|
765
|
+
return onload.call(scope, file, xhr);
|
|
766
|
+
} catch (e) {
|
|
767
|
+
// If this was the last file in the queue and an error is thrown in the create method
|
|
768
|
+
// then it's caught here, so be sure we don't carry on processing it
|
|
769
|
+
if (!scope.hasLoaded) {
|
|
770
|
+
scope.asyncComplete(file, e.message || 'Exception');
|
|
771
|
+
} else {
|
|
772
|
+
console.error(e);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
return null;
|
|
776
|
+
};
|
|
777
|
+
xhr.onerror = () => {
|
|
778
|
+
try {
|
|
779
|
+
return onerror.call(scope, file, xhr);
|
|
780
|
+
} catch (e) {
|
|
781
|
+
if (!scope.hasLoaded) {
|
|
782
|
+
scope.asyncComplete(file, e.message || 'Exception');
|
|
783
|
+
} else {
|
|
784
|
+
console.error(e);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
return null;
|
|
788
|
+
};
|
|
789
|
+
file.requestObject = xhr;
|
|
790
|
+
file.requestUrl = url;
|
|
791
|
+
xhr.send();
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
xhrLoadWithXDR() {
|
|
795
|
+
// TODO
|
|
796
|
+
console.warn('loader.xhrLoadWithXDR() is not implemented');
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
getAudioURL(urls) {
|
|
800
|
+
if (this.game.sound.noAudio) {
|
|
801
|
+
return null;
|
|
802
|
+
}
|
|
803
|
+
for (let i = 0; i < urls.length; i += 1) {
|
|
804
|
+
let url = urls[i];
|
|
805
|
+
let audioType = null;
|
|
806
|
+
if (url.uri) {
|
|
807
|
+
// {uri: .., type: ..} pair
|
|
808
|
+
audioType = url.type;
|
|
809
|
+
url = url.uri;
|
|
810
|
+
if (canPlayAudio(this.game.device, audioType)) {
|
|
811
|
+
return url;
|
|
812
|
+
}
|
|
813
|
+
} else {
|
|
814
|
+
// Assume direct-data URI can be played if not in a paired form; select immediately
|
|
815
|
+
if (url.indexOf('blob:') === 0 || url.indexOf('data:') === 0) {
|
|
816
|
+
return url;
|
|
817
|
+
}
|
|
818
|
+
if (url.indexOf('?') >= 0) {
|
|
819
|
+
// Remove query from URL
|
|
820
|
+
url = url.substr(0, url.indexOf('?'));
|
|
821
|
+
}
|
|
822
|
+
const extension = url.substr((Math.max(0, url.lastIndexOf('.')) || Infinity) + 1);
|
|
823
|
+
audioType = extension.toLowerCase();
|
|
824
|
+
if (canPlayAudio(this.game.device, audioType)) {
|
|
825
|
+
return urls[i];
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
return null;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
fileError(file, xhr, reason) {
|
|
833
|
+
const url = file.requestUrl || this.transformUrl(file.url, file);
|
|
834
|
+
let message = 'error loading asset from URL ' + url;
|
|
835
|
+
if (!reason && xhr) {
|
|
836
|
+
reason = xhr.status;
|
|
837
|
+
}
|
|
838
|
+
if (reason) {
|
|
839
|
+
message = message + ' (' + reason + ')';
|
|
840
|
+
}
|
|
841
|
+
this.asyncComplete(file, message);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
fileComplete(file, xhr) {
|
|
845
|
+
let loadNext = true;
|
|
846
|
+
switch (file.type) {
|
|
847
|
+
case 'packfile':
|
|
848
|
+
// Pack data must never be false-ish after it is fetched without error
|
|
849
|
+
file.data = JSON.parse(xhr.responseText) || {};
|
|
850
|
+
break;
|
|
851
|
+
case 'image':
|
|
852
|
+
this.cache.addImage(file.key, file.url, file.data);
|
|
853
|
+
break;
|
|
854
|
+
case 'spritesheet':
|
|
855
|
+
this.cache.addSpriteSheet(file.key, file.url, file.data, file.frameWidth, file.frameHeight, file.frameMax, file.margin, file.spacing);
|
|
856
|
+
break;
|
|
857
|
+
case 'textureatlas':
|
|
858
|
+
if (file.atlasURL == null) {
|
|
859
|
+
this.cache.addTextureAtlas(file.key, file.url, file.data, file.atlasData, file.format);
|
|
860
|
+
} else {
|
|
861
|
+
// Load the JSON or XML before carrying on with the next file
|
|
862
|
+
loadNext = false;
|
|
863
|
+
if (file.format === TEXTURE_ATLAS_JSON_ARRAY || file.format === TEXTURE_ATLAS_JSON_HASH || file.format === TEXTURE_ATLAS_JSON_PYXEL) {
|
|
864
|
+
this.xhrLoad(file, this.transformUrl(file.atlasURL, file), 'text', this.jsonLoadComplete);
|
|
865
|
+
} else if (file.format === TEXTURE_ATLAS_XML_STARLING) {
|
|
866
|
+
this.xhrLoad(file, this.transformUrl(file.atlasURL, file), 'text', this.xmlLoadComplete);
|
|
867
|
+
} else {
|
|
868
|
+
throw new Error('Invalid Texture Atlas format: ' + file.format);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
break;
|
|
872
|
+
case 'bitmapfont':
|
|
873
|
+
if (!file.atlasURL) {
|
|
874
|
+
this.cache.addBitmapFont(file.key, file.url, file.data, file.atlasData, file.atlasType, file.xSpacing, file.ySpacing);
|
|
875
|
+
} else {
|
|
876
|
+
// Load the XML before carrying on with the next file
|
|
877
|
+
loadNext = false;
|
|
878
|
+
this.xhrLoad(file, this.transformUrl(file.atlasURL, file), 'text', (bitmapFontFile, bitmapFontXhr) => {
|
|
879
|
+
let json;
|
|
880
|
+
try {
|
|
881
|
+
// Try to parse as JSON, if it fails, then it's hopefully XML
|
|
882
|
+
json = JSON.parse(bitmapFontXhr.responseText);
|
|
883
|
+
} catch (e) {
|
|
884
|
+
// pass
|
|
885
|
+
}
|
|
886
|
+
if (json) {
|
|
887
|
+
bitmapFontFile.atlasType = 'json';
|
|
888
|
+
this.jsonLoadComplete(bitmapFontFile, bitmapFontXhr);
|
|
889
|
+
} else {
|
|
890
|
+
bitmapFontFile.atlasType = 'xml';
|
|
891
|
+
this.xmlLoadComplete(bitmapFontFile, bitmapFontXhr);
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
break;
|
|
896
|
+
case 'video':
|
|
897
|
+
if (file.asBlob) {
|
|
898
|
+
try {
|
|
899
|
+
file.data = xhr.response;
|
|
900
|
+
} catch (e) {
|
|
901
|
+
throw new Error('Unable to parse video file as Blob: ' + file.key);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
this.cache.addVideo(file.key, file.url, file.data, file.asBlob);
|
|
905
|
+
break;
|
|
906
|
+
case 'audio':
|
|
907
|
+
if (this.game.sound.usingWebAudio) {
|
|
908
|
+
file.data = xhr.response;
|
|
909
|
+
this.cache.addSound(file.key, file.url, file.data, true, false);
|
|
910
|
+
if (file.autoDecode) {
|
|
911
|
+
this.game.sound.decode(file.key);
|
|
912
|
+
}
|
|
913
|
+
} else {
|
|
914
|
+
this.cache.addSound(file.key, file.url, file.data, false, true);
|
|
915
|
+
}
|
|
916
|
+
break;
|
|
917
|
+
case 'text':
|
|
918
|
+
file.data = xhr.responseText;
|
|
919
|
+
this.cache.addText(file.key, file.url, file.data);
|
|
920
|
+
break;
|
|
921
|
+
case 'shader':
|
|
922
|
+
file.data = xhr.responseText;
|
|
923
|
+
this.cache.addShader(file.key, file.url, file.data);
|
|
924
|
+
break;
|
|
925
|
+
case 'physics':
|
|
926
|
+
this.cache.addPhysicsData(file.key, file.url, JSON.parse(xhr.responseText), file.format);
|
|
927
|
+
break;
|
|
928
|
+
case 'script':
|
|
929
|
+
file.data = document.createElement('script');
|
|
930
|
+
file.data.language = 'javascript';
|
|
931
|
+
file.data.type = 'text/javascript';
|
|
932
|
+
file.data.defer = false;
|
|
933
|
+
file.data.text = xhr.responseText;
|
|
934
|
+
document.head.appendChild(file.data);
|
|
935
|
+
if (file.callback) {
|
|
936
|
+
file.data = file.callback.call(file.callbackContext, file.key, xhr.responseText);
|
|
937
|
+
}
|
|
938
|
+
break;
|
|
939
|
+
case 'binary':
|
|
940
|
+
if (file.callback) {
|
|
941
|
+
file.data = file.callback.call(file.callbackContext, file.key, xhr.response);
|
|
942
|
+
} else {
|
|
943
|
+
file.data = xhr.response;
|
|
944
|
+
}
|
|
945
|
+
this.cache.addBinary(file.key, file.data);
|
|
946
|
+
break;
|
|
947
|
+
default:
|
|
948
|
+
// pass
|
|
949
|
+
break;
|
|
950
|
+
}
|
|
951
|
+
if (loadNext) {
|
|
952
|
+
this.asyncComplete(file);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
jsonLoadComplete(file, xhr) {
|
|
957
|
+
const data = JSON.parse(xhr.responseText);
|
|
958
|
+
if (file.type === 'tilemap') {
|
|
959
|
+
this.cache.addTilemap(file.key, file.url, data, file.format);
|
|
960
|
+
} else if (file.type === 'bitmapfont') {
|
|
961
|
+
this.cache.addBitmapFont(file.key, file.url, file.data, data, file.atlasType, file.xSpacing, file.ySpacing);
|
|
962
|
+
} else if (file.type === 'json') {
|
|
963
|
+
this.cache.addJSON(file.key, file.url, data);
|
|
964
|
+
} else {
|
|
965
|
+
this.cache.addTextureAtlas(file.key, file.url, file.data, data, file.format);
|
|
966
|
+
}
|
|
967
|
+
this.asyncComplete(file);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
csvLoadComplete() {
|
|
971
|
+
// TODO
|
|
972
|
+
console.warn('loader.csvLoadComplete() is not implemented');
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
xmlLoadComplete(file, xhr) {
|
|
976
|
+
// Always try parsing the content as XML, regardless of actually response type
|
|
977
|
+
const data = xhr.responseText;
|
|
978
|
+
const xml = this.parseXml(data);
|
|
979
|
+
if (!xml) {
|
|
980
|
+
const responseType = xhr.responseType || xhr.contentType; // contentType for MS-XDomainRequest
|
|
981
|
+
console.warn('Loader - ' + file.key + ': invalid XML (' + responseType + ')');
|
|
982
|
+
this.asyncComplete(file, 'invalid XML');
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
if (file.type === 'bitmapfont') {
|
|
986
|
+
this.cache.addBitmapFont(file.key, file.url, file.data, xml, file.atlasType, file.xSpacing, file.ySpacing);
|
|
987
|
+
} else if (file.type === 'textureatlas') {
|
|
988
|
+
this.cache.addTextureAtlas(file.key, file.url, file.data, xml, file.format);
|
|
989
|
+
} else if (file.type === 'xml') {
|
|
990
|
+
this.cache.addXML(file.key, file.url, xml);
|
|
991
|
+
}
|
|
992
|
+
this.asyncComplete(file);
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
parseXml(data) {
|
|
996
|
+
let xml = null;
|
|
997
|
+
try {
|
|
998
|
+
if (window.DOMParser) {
|
|
999
|
+
const domparser = new DOMParser();
|
|
1000
|
+
xml = domparser.parseFromString(data, 'text/xml');
|
|
1001
|
+
} else {
|
|
1002
|
+
xml = new window.ActiveXObject('Microsoft.XMLDOM');
|
|
1003
|
+
// Why is this 'false'?
|
|
1004
|
+
xml.async = 'false';
|
|
1005
|
+
xml.loadXML(data);
|
|
1006
|
+
}
|
|
1007
|
+
} catch (e) {
|
|
1008
|
+
xml = null;
|
|
1009
|
+
}
|
|
1010
|
+
if (!xml || !xml.documentElement || xml.getElementsByTagName('parsererror').length) {
|
|
1011
|
+
return null;
|
|
1012
|
+
}
|
|
1013
|
+
return xml;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
updateProgress() {
|
|
1017
|
+
if (this.preloadSprite) {
|
|
1018
|
+
if (this.preloadSprite.direction === 0) {
|
|
1019
|
+
this.preloadSprite.rect.width = Math.floor((this.preloadSprite.width / 100) * this.progress);
|
|
1020
|
+
} else {
|
|
1021
|
+
this.preloadSprite.rect.height = Math.floor((this.preloadSprite.height / 100) * this.progress);
|
|
1022
|
+
}
|
|
1023
|
+
if (this.preloadSprite.sprite) {
|
|
1024
|
+
this.preloadSprite.sprite.updateCrop();
|
|
1025
|
+
} else {
|
|
1026
|
+
// We seem to have lost our sprite - maybe it was destroyed?
|
|
1027
|
+
this.preloadSprite = null;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
totalLoadedFiles() {
|
|
1033
|
+
return this._loadedFileCount;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
totalQueuedFiles() {
|
|
1037
|
+
return this._totalFileCount - this._loadedFileCount;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
totalLoadedPacks() {
|
|
1041
|
+
return this._totalPackCount;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
totalQueuedPacks() {
|
|
1045
|
+
return this._totalPackCount - this._loadedPackCount;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
get progressFloat() {
|
|
1049
|
+
const progress = (this._loadedFileCount / this._totalFileCount) * 100;
|
|
1050
|
+
return Math.max(0, Math.min(100, progress || 0));
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
get progress() {
|
|
1054
|
+
return Math.round(this.progressFloat);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
}
|