or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdaudio.mdfiles.mdgraphics.mdindex.mdinput.mdnetworking.mdpreloader.mdwebaudio.mdwidgets.md

preloader.mddocs/

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

}