Assets

Why Resources

When building games you may have assets you want to load from an external file, like sound, art, etc.

Resources must be loaded before they can be used with a Loader

Creating Loader for Resources

When calling Engine.start, you can optionally pass an asset Loader. This loader will contain a reference to any "loadables" you want to load.

const loader = new ex.Loader([
  /* add Loadables here */
])

Loadables are different kinds of assets such as image, sounds, and generic resources.

Anytime you call game.start(loader), the game will pause and the engine will load assets. This means that you do not have to load every asset at once! Instead you may want to call game.start(loader) initially with core assets and then again when initializing a Scene.

Images with the ImageSource Resource

Excalibur supports .png, .jpg, .gif, and .bmp image sources with partial support for .svg

  • .png and .svg will be completely lossless formats. For pixel art type games we recommend .png
  • .jpg and .gif are lossy formats, useful to optimize for download size.
  • .bmp are the biggest
  • base64 useful if you don't want to pay the loading time cost of your images at the expense of larger source download
    • data:image/png;base64,BASE64DATA...
const game = new Engine({...});
const spriteSheetImage = new ImageSource('./my/spritesheet.png');

const loader = new Loader([spriteSheetImage]);
await game.start([loader]);

const spriteSheet = SpriteSheet.fromImageSource({
  image: spriteFontImage,
  grid: {
    rows: 5,
    columns: 2,
    spriteWidth: 32, // pixels
    spriteHeight: 32 // pixels
  }
});

Audio with the Sound Resource

Excalibur supports any audio the browser supports like .wav, .mp3, and .ogg. Due to mixed browser support you may wish to specificy a list of source files and codecs,the order of the files specifies order of preference (we recommend mp3, wav).

Major Browser support table documented on MDN

Pass an instance of Sound to a Loader to preload it. Once a sound is loaded, you can play it. You can pass an argument from 0.0 - 1.0 into play in order to play the sound at that volume.

const game = new Engine({...});
const sound = new Sound('./path/to/my.mp3', './path/to/fallback.wav');

const loader = new Loader([sound]);
await game.start([loader]);

sound.play(0.5);

Generic Resources

Sometimes you may have some other type of file you'd like to load, perhaps some data stored in a text file, json, or perhaps some binary data.

Excalibur supports a generic Resource to load arbitrary data.

const game = new Engine({...});
const text = new Resource<string>('./path/to/my/data.txt', 'text');
const json = new Resource<MyJsonShapeType>('./path/to/my/json.json', 'json');

const loader = new Loader([text, json]);
await game.start([loader]);

console.log(text.data);
console.log(json.data);

See the examples or API documentation for Sound for additional features available such as looping, volume setting, and more.

Other Resources

Using a web server

The asset loader only works with a web server since it loads assets with XHR. That means you cannot use the loader whenrunning an HTML file locally from the file-system (e.g. a file:// protocol URL will not work). The browser throws errors that will prevent you from loading assets.

The fastest way to serve a folder of files is by using the serve NPM package.

# Serve the current directory
npx serve .

# Serve a folder
npx serve ./dist

If you are developing a game using Excalibur with Webpack, Parcel, or another bundler, these typically already come with dev servers for running your game. See Excalibur project templates for templates you can start from that use these tools.

Relative vs. absolute paths

Given this directory structure:

/root
  src/
    game.js
  assets/
    textures/
      map.png
  index.html

And you serve from the root directory like this:

> cd root
> npx serve .

Now serving on http://localhost:3000/

The path to your assets doesn't matter as much because both absolute and relative paths will work:

  • /assets/textures/map.png => HTTP 200 OK
  • assets/textures/map.png => HTTP 200 OK

But if you are serving under a sub-directory, like http://localhost:3000/root/index.html then the format of your paths matter:

  • /assets/textures/map.png => HTTP 404 Not Found
  • assets/textures/map.png => HTTP 200 OK

The first path will fail to load as the absolute asset path would now be /root/assets and not /assets. Use a relative path to load assets relative to the HTML file serving your game.

Setting the base for a page

In your HTML file(s), to set the base for any absolute paths like the example above, you can use the base tag:

<!DOCTYPE html>
<html>
  <head>
    <!-- Set the base for all absolute URLs -->
    <base href="/root" />
  </head>
  <body>
    <!-- The browser will now properly resolve /root/game.js -->
    <script src="/game.js"></script>
  </body>
</html>

This can be accessed programmatically using document.baseUri to resolve absolute paths in JavaScript.

This is a good approach to use when hosting your game at a sub-directory, such as publishing to GitHub Pages.