0
# Asset Preloading
1
2
The GWT backend includes a comprehensive asset preloading system designed specifically for web deployment. The preloader downloads and caches all game assets before the application starts, ensuring smooth gameplay without loading delays.
3
4
## Core Preloader Classes
5
6
### Preloader { .api }
7
8
```java
9
public class Preloader {
10
// Preloader state information
11
public static class PreloaderState {
12
public long loaded; // Bytes loaded
13
public long total; // Total bytes to load
14
public boolean hasEnded; // Loading complete
15
16
public float getProgress();
17
public boolean isComplete();
18
}
19
20
// Preloader callback interface
21
public interface PreloaderCallback {
22
void update(PreloaderState state);
23
void error(String file);
24
}
25
26
// Constructor
27
public Preloader(String assetsFileLocation);
28
public Preloader();
29
30
// Preloading control
31
public void preload(String assetFileUrl, PreloaderCallback callback);
32
public PreloaderState update();
33
34
// Asset access after preloading
35
public boolean contains(String path);
36
public int length(String path);
37
public boolean isText(String path);
38
public boolean isAudio(String path);
39
public boolean isImage(String path);
40
public boolean isBinary(String path);
41
42
// Asset reading
43
public String getText(String path);
44
public byte[] getBinary(String path);
45
public ImageElement getImage(String path);
46
47
// Asset management
48
public void loadText(String url, AssetDownloader.AssetLoaderListener<String> assetLoaderListener);
49
public void loadBinary(String url, AssetDownloader.AssetLoaderListener<Blob> assetLoaderListener);
50
public void loadImage(String url, AssetDownloader.AssetLoaderListener<ImageElement> assetLoaderListener);
51
public void loadAudio(String url, AssetDownloader.AssetLoaderListener<Void> assetLoaderListener);
52
}
53
```
54
55
### AssetDownloader { .api }
56
57
```java
58
public class AssetDownloader {
59
// Asset loading interface
60
public interface AssetLoaderListener<T> {
61
void onProgress(double amount);
62
void onFailure();
63
void onSuccess(T result);
64
}
65
66
// Asset loading methods
67
public void load(Array<Asset> assets, LoaderCallback<AssetDownloader> callback);
68
public void loadText(String url, AssetLoaderListener<String> listener);
69
public void loadBinary(String url, AssetLoaderListener<Blob> listener);
70
public void loadImage(String url, AssetLoaderListener<ImageElement> listener);
71
public void loadAudio(String url, AssetLoaderListener<Void> listener);
72
73
// Asset information
74
public boolean contains(String path);
75
public boolean isText(String path);
76
public boolean isBinary(String path);
77
public boolean isAudio(String path);
78
public boolean isImage(String path);
79
80
// Asset access
81
public String getText(String path);
82
public ImageElement getImage(String path);
83
public Blob getBinary(String path);
84
}
85
```
86
87
### AssetFilter { .api }
88
89
```java
90
public interface AssetFilter {
91
boolean accept(String file, boolean isDirectory);
92
93
// Pre-defined filter types
94
AssetFilter IMAGE_FILTER = new AssetFilter() {
95
public boolean accept(String file, boolean isDirectory) {
96
return isDirectory || file.matches(".*\\.(png|jpg|jpeg|gif|bmp)$");
97
}
98
};
99
100
AssetFilter AUDIO_FILTER = new AssetFilter() {
101
public boolean accept(String file, boolean isDirectory) {
102
return isDirectory || file.matches(".*\\.(ogg|mp3|wav|m4a)$");
103
}
104
};
105
106
AssetFilter TEXT_FILTER = new AssetFilter() {
107
public boolean accept(String file, boolean isDirectory) {
108
return isDirectory || file.matches(".*\\.(txt|json|xml|csv)$");
109
}
110
};
111
}
112
```
113
114
### DefaultAssetFilter { .api }
115
116
```java
117
public class DefaultAssetFilter implements AssetFilter {
118
public boolean accept(String file, boolean isDirectory) {
119
if (isDirectory) return true;
120
121
// Accept common game asset formats
122
return file.matches(".*\\.(png|jpg|jpeg|gif|bmp|ogg|mp3|wav|m4a|txt|json|xml|fnt|pack|atlas)$");
123
}
124
}
125
```
126
127
### FileWrapper { .api }
128
129
```java
130
public class FileWrapper {
131
// File information
132
public String path;
133
public FileType type;
134
public long length;
135
public boolean isDirectory;
136
137
// File content access
138
public String read();
139
public String readString();
140
public byte[] readBytes();
141
public long length();
142
143
// Constructors
144
public FileWrapper(String path, FileType type);
145
public FileWrapper(String path, FileType type, long length, byte[] data);
146
}
147
```
148
149
## Preloader Integration
150
151
### Basic Preloader Setup
152
153
```java
154
public class MyGameGwt extends GwtApplication {
155
@Override
156
public GwtApplicationConfiguration getConfig() {
157
return new GwtApplicationConfiguration(800, 600);
158
}
159
160
@Override
161
public ApplicationListener createApplicationListener() {
162
return new MyGame();
163
}
164
165
@Override
166
public Preloader createPreloader() {
167
// Create preloader with assets list file
168
return new Preloader("assets.txt");
169
}
170
171
@Override
172
public PreloaderCallback getPreloaderCallback() {
173
return new PreloaderCallback() {
174
@Override
175
public void update(PreloaderState state) {
176
// Update loading progress display
177
float progress = state.getProgress();
178
updateLoadingScreen(progress);
179
180
System.out.println("Loading: " + (int)(progress * 100) + "%");
181
}
182
183
@Override
184
public void error(String file) {
185
System.err.println("Failed to load asset: " + file);
186
}
187
};
188
}
189
190
private void updateLoadingScreen(float progress) {
191
// Update your custom loading screen UI
192
// This runs before your ApplicationListener.create() is called
193
}
194
}
195
```
196
197
### Assets File Format
198
199
The `assets.txt` file lists all assets to be preloaded:
200
201
```
202
# Asset list for preloader
203
# Format: path:type:size (size is optional)
204
205
# Images
206
images/player.png:i
207
images/enemy.png:i
208
images/background.jpg:i
209
images/ui/button.png:i
210
211
# Audio files
212
audio/background.ogg:a
213
audio/jump.wav:a
214
audio/explosion.ogg:a
215
216
# Text/data files
217
data/levels.json:t
218
data/config.txt:t
219
fonts/arial.fnt:t
220
221
# Binary files
222
data/terrain.bin:b
223
224
# Type codes:
225
# i = image
226
# a = audio
227
# t = text
228
# b = binary
229
```
230
231
## Advanced Preloader Usage
232
233
### Custom Asset Filtering
234
235
```java
236
public class GameAssetGwt extends GwtApplication {
237
@Override
238
public Preloader createPreloader() {
239
return new Preloader() {
240
@Override
241
protected AssetFilter getAssetFilter() {
242
return new AssetFilter() {
243
@Override
244
public boolean accept(String file, boolean isDirectory) {
245
if (isDirectory) return true;
246
247
// Only preload essential assets
248
if (file.startsWith("essential/")) return true;
249
if (file.endsWith(".png") || file.endsWith(".jpg")) return true;
250
if (file.endsWith(".ogg") || file.endsWith(".wav")) return true;
251
if (file.endsWith(".json") || file.endsWith(".fnt")) return true;
252
253
return false;
254
}
255
};
256
}
257
};
258
}
259
}
260
```
261
262
### Progress Tracking with Custom UI
263
264
```java
265
public class LoadingScreenGwt extends GwtApplication {
266
private ProgressBar progressBar;
267
private Label statusLabel;
268
269
@Override
270
public PreloaderCallback getPreloaderCallback() {
271
return new PreloaderCallback() {
272
@Override
273
public void update(PreloaderState state) {
274
float progress = state.getProgress();
275
long loaded = state.loaded;
276
long total = state.total;
277
278
// Update progress bar
279
if (progressBar != null) {
280
progressBar.setValue(progress);
281
}
282
283
// Update status text
284
if (statusLabel != null) {
285
String status = String.format("Loading... %d/%d KB (%.1f%%)",
286
loaded / 1024, total / 1024, progress * 100);
287
statusLabel.setText(status);
288
}
289
290
// Custom loading stages
291
if (progress < 0.3f) {
292
setLoadingStatus("Loading textures...");
293
} else if (progress < 0.6f) {
294
setLoadingStatus("Loading audio...");
295
} else if (progress < 0.9f) {
296
setLoadingStatus("Loading data...");
297
} else {
298
setLoadingStatus("Initializing game...");
299
}
300
}
301
302
@Override
303
public void error(String file) {
304
System.err.println("Loading failed for: " + file);
305
setLoadingStatus("Error loading " + file);
306
}
307
};
308
}
309
310
private void setLoadingStatus(String status) {
311
System.out.println(status);
312
// Update your loading screen UI
313
}
314
}
315
```
316
317
### Asset Validation and Error Handling
318
319
```java
320
public class RobustPreloaderGwt extends GwtApplication {
321
private Set<String> failedAssets = new HashSet<>();
322
private int retryCount = 0;
323
private static final int MAX_RETRIES = 3;
324
325
@Override
326
public PreloaderCallback getPreloaderCallback() {
327
return new PreloaderCallback() {
328
@Override
329
public void update(PreloaderState state) {
330
if (state.hasEnded) {
331
if (!failedAssets.isEmpty() && retryCount < MAX_RETRIES) {
332
// Retry failed assets
333
retryCount++;
334
System.out.println("Retrying failed assets (attempt " + retryCount + ")");
335
retryFailedAssets();
336
} else {
337
// Proceed with missing assets or after max retries
338
proceedWithAvailableAssets();
339
}
340
}
341
}
342
343
@Override
344
public void error(String file) {
345
failedAssets.add(file);
346
System.err.println("Failed to load: " + file);
347
}
348
};
349
}
350
351
private void retryFailedAssets() {
352
// Create new preloader for failed assets only
353
Preloader retryPreloader = new Preloader();
354
for (String failedAsset : failedAssets) {
355
// Add failed assets to retry queue
356
// Implementation depends on your specific needs
357
}
358
}
359
360
private void proceedWithAvailableAssets() {
361
if (failedAssets.isEmpty()) {
362
System.out.println("All assets loaded successfully");
363
} else {
364
System.out.println("Proceeding with " + failedAssets.size() + " missing assets");
365
366
// Log missing assets for debugging
367
for (String missing : failedAssets) {
368
System.out.println("Missing: " + missing);
369
}
370
}
371
372
// Continue to game initialization
373
}
374
}
375
```
376
377
## Asset Management Best Practices
378
379
### Optimal Asset Organization
380
381
```java
382
// Organize assets for efficient preloading
383
public class AssetOrganizer {
384
385
// Group assets by loading priority
386
private static final String[] CRITICAL_ASSETS = {
387
"images/loading_bg.png", // Loading screen background
388
"images/progress_bar.png", // Progress bar graphics
389
"fonts/ui_font.fnt" // UI font
390
};
391
392
private static final String[] ESSENTIAL_ASSETS = {
393
"images/player.png",
394
"images/ui/buttons.pack",
395
"audio/ui_sounds.ogg"
396
};
397
398
private static final String[] GAMEPLAY_ASSETS = {
399
"images/enemies.pack",
400
"images/levels.pack",
401
"audio/music.ogg",
402
"data/levels.json"
403
};
404
405
public static void validateAssetStructure() {
406
// Verify critical assets are available
407
for (String asset : CRITICAL_ASSETS) {
408
if (!Gdx.files.internal(asset).exists()) {
409
throw new RuntimeException("Critical asset missing: " + asset);
410
}
411
}
412
413
// Check essential assets
414
int missingEssential = 0;
415
for (String asset : ESSENTIAL_ASSETS) {
416
if (!Gdx.files.internal(asset).exists()) {
417
System.err.println("Essential asset missing: " + asset);
418
missingEssential++;
419
}
420
}
421
422
if (missingEssential > 0) {
423
System.out.println("Warning: " + missingEssential + " essential assets missing");
424
}
425
}
426
}
427
```
428
429
### Asset Size Optimization
430
431
```java
432
public class AssetOptimizer {
433
private static final long MAX_TOTAL_SIZE = 50 * 1024 * 1024; // 50MB limit
434
private static final long MAX_SINGLE_FILE = 5 * 1024 * 1024; // 5MB per file
435
436
public static void analyzeAssetSizes() {
437
long totalSize = 0;
438
int oversizedFiles = 0;
439
440
String[] assetDirs = {"images/", "audio/", "data/"};
441
442
for (String dir : assetDirs) {
443
FileHandle dirHandle = Gdx.files.internal(dir);
444
if (dirHandle.exists() && dirHandle.isDirectory()) {
445
for (FileHandle file : dirHandle.list()) {
446
long fileSize = file.length();
447
totalSize += fileSize;
448
449
if (fileSize > MAX_SINGLE_FILE) {
450
System.out.println("Oversized file: " + file.path() +
451
" (" + (fileSize / 1024) + " KB)");
452
oversizedFiles++;
453
}
454
}
455
}
456
}
457
458
System.out.println("Total asset size: " + (totalSize / 1024 / 1024) + " MB");
459
System.out.println("Oversized files: " + oversizedFiles);
460
461
if (totalSize > MAX_TOTAL_SIZE) {
462
System.out.println("WARNING: Total assets exceed recommended size limit");
463
}
464
}
465
466
public static void generateOptimizedAssetsList() {
467
// Create optimized assets.txt based on file sizes and importance
468
StringBuilder assetsList = new StringBuilder();
469
assetsList.append("# Optimized assets list\n");
470
assetsList.append("# Generated automatically\n\n");
471
472
// Add critical assets first
473
assetsList.append("# Critical assets (loaded first)\n");
474
addAssetsToList(assetsList, "critical/", "i");
475
476
// Add essential assets
477
assetsList.append("\n# Essential gameplay assets\n");
478
addAssetsToList(assetsList, "essential/", "i");
479
480
// Add optional assets
481
assetsList.append("\n# Optional enhancement assets\n");
482
addAssetsToList(assetsList, "optional/", "i");
483
484
// Write to file
485
Gdx.files.local("generated_assets.txt").writeString(assetsList.toString(), false);
486
}
487
488
private static void addAssetsToList(StringBuilder list, String directory, String type) {
489
FileHandle dir = Gdx.files.internal(directory);
490
if (dir.exists() && dir.isDirectory()) {
491
for (FileHandle file : dir.list()) {
492
if (!file.isDirectory()) {
493
list.append(file.path()).append(":").append(type).append("\n");
494
}
495
}
496
}
497
}
498
}
499
```
500
501
### Lazy Loading Strategy
502
503
```java
504
// For very large games, implement lazy loading after initial preload
505
public class LazyAssetLoader {
506
private Map<String, Boolean> loadedChunks = new HashMap<>();
507
private AssetDownloader downloader = new AssetDownloader();
508
509
public void loadChunk(String chunkName, Runnable onComplete) {
510
if (loadedChunks.getOrDefault(chunkName, false)) {
511
// Chunk already loaded
512
if (onComplete != null) onComplete.run();
513
return;
514
}
515
516
String[] chunkAssets = getChunkAssets(chunkName);
517
loadAssetsBatch(chunkAssets, () -> {
518
loadedChunks.put(chunkName, true);
519
System.out.println("Chunk loaded: " + chunkName);
520
if (onComplete != null) onComplete.run();
521
});
522
}
523
524
private String[] getChunkAssets(String chunkName) {
525
switch (chunkName) {
526
case "level1":
527
return new String[]{"images/level1_bg.png", "audio/level1_music.ogg"};
528
case "level2":
529
return new String[]{"images/level2_bg.png", "audio/level2_music.ogg"};
530
case "powerups":
531
return new String[]{"images/powerups.pack", "audio/powerup_sfx.ogg"};
532
default:
533
return new String[0];
534
}
535
}
536
537
private void loadAssetsBatch(String[] assets, Runnable onComplete) {
538
// Implementation for batch loading assets after initial preload
539
// This would use HTTP requests to download additional assets
540
System.out.println("Loading " + assets.length + " additional assets...");
541
542
// Simulate async loading
543
Timer.schedule(new Timer.Task() {
544
@Override
545
public void run() {
546
if (onComplete != null) onComplete.run();
547
}
548
}, 1.0f); // 1 second delay simulation
549
}
550
}
551
```
552
553
## Web-Specific Preloader Considerations
554
555
### Browser Caching Integration
556
557
```java
558
// The preloader works with browser caching for optimal performance
559
public class CacheAwarePreloader extends Preloader {
560
public CacheAwarePreloader(String assetsFile) {
561
super(assetsFile);
562
563
// Assets are automatically cached by browser
564
// Subsequent loads will be much faster
565
// Use cache-busting for asset updates
566
}
567
568
// Generate cache-busting URLs for asset updates
569
private String addCacheBuster(String assetUrl, String version) {
570
return assetUrl + "?v=" + version;
571
}
572
}
573
```
574
575
### Memory Management
576
577
```java
578
// Preloader manages memory efficiently for web deployment
579
public class MemoryEfficientPreloader {
580
581
public static void optimizeForMemory() {
582
// The GWT preloader automatically:
583
// 1. Streams large files instead of loading entirely into memory
584
// 2. Compresses text assets
585
// 3. Uses efficient binary formats
586
// 4. Releases intermediate loading buffers
587
588
System.out.println("Preloader optimized for web memory constraints");
589
}
590
591
public static void monitorMemoryUsage() {
592
// Check available memory during preloading
593
long heapSize = Runtime.getRuntime().totalMemory();
594
long usedMemory = heapSize - Runtime.getRuntime().freeMemory();
595
596
System.out.println("Memory usage: " + (usedMemory / 1024 / 1024) + " MB");
597
598
if (usedMemory > heapSize * 0.8) {
599
System.out.println("WARNING: High memory usage during asset loading");
600
}
601
}
602
}