Skip to content

Loading assets

samme edited this page Feb 2, 2023 · 23 revisions

Strategy

  • Load assets before using them
  • Load shared assets in a "boot" or "preload" scene and any non-shared assets in the scene they will be used in
  • Use a scene payload to load small assets before the scene preload() callback, if needed
  • For special cases, run the scene loader manually and access the newly loaded assets in event callbacks

Assets

There are many types, and you can read about all of them.

Assets need to be loaded before you can use them, but once loaded, they are available everywhere. It doesn't matter which loader or scene loaded them. Once loaded they are in the Texture Manager (this.textures) or the asset caches (this.cache).

Use unique keys (names) for assets.

Where to load assets

In a single-scene game, you'll load assets in that scene, naturally.

In a multi-scene game, it's convenient to load shared assets in a "boot" or "preloader" scene and then start the other scenes afterwards. Any non-shared assets can be loaded in the scene that uses them, and removed if necessary when that scene shuts down.

The loader

Each scene has a loader plugin, this.load, for loading assets.

Adding files to the loader

All the "load" methods queue a file by key (name) and URL.

this.load.image('treasure', 'treasure.png');

Each method also has an object config format:

this.load.image({ key: 'treasure', url: 'treasure.png' });

As a shortcut, passing key only sets the url as well, using a default extension (by asset type):

// `url` will be 'treasure.png'
this.load.image('treasure');

If you don't care for the key/URL distinction, you can pass:

this.load.image({ key: 'treasure.png', extension: '' });

Then the asset key and URL are identical.

The loader will not add assets with duplicate keys (per asset type) at all:

this.load.image('sky', 'sky1.png');
// OOPS:
this.load.image('sky', 'sky2.png');
// 'sky1.png' will be loaded and stored as 'sky'.
// 'sky2.png' will not be added or loaded.

Some key exceptions:

  • For some asset types (script(), sometimes pack()), you won't use the key again to retrieve anything.
  • For plugin(), sceneFile(), and scenePlugin(), key must be the global class name of the plugin or scene.

Each "load" method can take an array, so there is no need to loop:

this.load.image([ 'conch', 'treasure', 'trident' ]);

this.load.spritesheet([
  { key: 'mermaid', url: 'mermaid.png', frameConfig: { frameWidth: 16, frameHeight: 16 } },
  { key: 'merman', url: 'merman', frameConfig: { frameWidth: 16, frameHeight: 16 } }
]);

Thus you could write your own manifest pretty easily:

const files = {
  animation: [/* … */],
  audio: [/* … */],
  image: [/* … */],
  spritesheet: [/* … */],
};

this.load.animation(files.animation);
this.load.audio(files.audio);
this.load.image(files.images);
this.load.spritesheet(files.spritesheet};

A File Pack could do as well:

this.load.pack('pack1', {
  section1: {
    files: [
      { type: 'image', key: 'conch', url: 'conch.png' },
      { type: 'spritesheet', key: 'mermaid', url: 'mermaid.png', frameConfig: {/* … */} }
    ]
  }
});

A File Pack needs at least one named section. If you're loading all the pack assets at once, it doesn't really matter what the names are. The docs describe a method for downloading pack sections separately, but if you want to do this it seems more practical to use load.json() followed by load.pack().

You can add assets to the load queue while the loader is running:

this.load.json('level1');
this.load.on('filecomplete-json-level1', (key, type, data) => {
  this.load.image(data.images);
  this.load.spritesheet(data.spritesheets);
});

load.multiatlas(), load.pack(), and load.spine() work this way.

preload()

Most of the time you will load assets in a scene preload() method.

When preload() returns, the loader starts automatically only if it has any files queued, then create() is called only after loading finishes.

If no files are queued when preload() returns, the loader doesn't start or complete and create() is called immediately.

Scene payload

A scene payload lets you load assets right when the scene starts. The scene waits for the payload to download completely before it continues.

The pack object structure is the same as the files portion of a pack file section.

const sceneConfig = {
  pack: {
    files: [
      { type: 'json', key: 'settings', url: 'settings.json' },
      { type: 'image', key: 'bar', url: 'bar.png' }
    ]
  },
  init: function () {
    this.game.registry.merge(this.cache.json.get('settings'));
  },
  preload: function () {
    const loadingBar = this.add.image(0, 0, 'bar');
    // …
  }
};

It's best for small assets you want to use right away, before create().

Background loading

To load assets outside of preload(), you add files as usual, listen for completion events, and then start the loader yourself.

this.load
  .image(['conch', 'treasure', 'trident'])
  .once('complete', () => {
    // All files complete
  })
  .start();

It's fine if two processes both "start" the loader. If it's already running, the start call is ignored.

button1.once('pointerdown', () => {
  this.load
    .video('macaque')
    .once('filecomplete-video-macaque', () => {
      this.add.video(0, 0, 'macaque');
    })
    .start();
});

button2.once('pointerdown', () => {
  this.load
    .video('macaw')
    .once('filecomplete-video-macaw', () => {
      this.add.video(0, 0, 'macaw');
    })
    .start();
});

Other scenes should listen for "add" events from the game caches or Texture Manager:

this.cache.audio.on('add', (cache, key) => {
  if (key === 'music') {
    this.sound.play('music');
  }
});

this.textures.on('addtexture', (key) => {
  if (key === 'map') {
    this.add.image(0, 0, 'map');
  }
});

Removing assets

You can remove assets to save memory. Remove any game objects or scene objects (e.g., Sounds) using these assets first!

Remove textures from the Texture Manager:

this.textures.remove('conch');

and other assets from their respective caches:

this.cache.audio.remove('chime');
this.cache.json.remove('settings');

Removing assets to reuse their keys for different assets is usually a bad idea.

Clone this wiki locally