Phaser: Loading assets in a saner way
Tags: gamedev, devlog, phaser, showdev
Published: 2020-04-19 08:46:35

It's been some time since I talked about the code of the game, so I thought I'd share some of the changes I've made to make my life easier, in the shape of short posts. Today's turn is…

## Loading Assets

As you may know, to add an asset to a Phaser scene, you need to call a load function with a `key` and the asset path as parameters. If the asset is a sprite, you also need to pass the frame width and height.

```js
this.load.spritesheet('enemy', `/images/enemy.png`, {
  frameWidth: 50,
  frameHeight: 160
})
```

As you can imagine, when you have a lot of sprites, the preloading of all the assets becomes very verbose, and if you use the same sprite in different scenes, having the width and height hardcoded is tiresome and a potential source of bugs (if you change the size of the sprite, it's likely you forget to update it everywhere).

So the first step to improve this is to move all this hardcoded data to a `constants.ts` file. We've solved an issue but it's still quite verbose. This is how a scene preload function looked like at a certain point:

```js
public preload() {
  this.load.audio(AUDIO.FIRE.KEY, `/sound/${AUDIO.FIRE.FILE}`)
  this.load.audio(AUDIO.STATIC.KEY, `/sound/${AUDIO.STATIC.FILE}`)
  this.load.audio(AUDIO.DROP.KEY, `/sound/${AUDIO.DROP.FILE}`)
  this.load.audio(AUDIO.BANG.KEY, `/sound/${AUDIO.BANG.FILE}`)
  this.load.image(
    IMAGES.BUILDING_BG.KEY,
    `/images/${IMAGES.BUILDING_BG.FILE}`
  )
  this.load.image(
    IMAGES.BUILDING_BG_2.KEY,
    `/images/${IMAGES.BUILDING_BG_2.FILE}`
  )
  this.load.image(IMAGES.FLOOR.KEY, `/images/${IMAGES.FLOOR.FILE}`)
  this.load.image(IMAGES.LADDER.KEY, `/images/${IMAGES.LADDER.FILE}`)
  this.load.image(IMAGES.BOXES.KEY, `/images/${IMAGES.BOXES.FILE}`)
  this.load.image(IMAGES.BUCKET.KEY, `/images/${IMAGES.BUCKET.FILE}`)
  this.load.image(IMAGES.WOOD.KEY, `/images/${IMAGES.WOOD.FILE}`)
  this.load.image(IMAGES.CLOTH.KEY, `/images/${IMAGES.CLOTH.FILE}`)
  this.load.image(IMAGES.DROP.KEY, `/images/${IMAGES.DROP.FILE}`)
  this.load.image(IMAGES.ROCK.KEY, `/images/${IMAGES.ROCK.FILE}`)
  this.load.image(IMAGES.METALBOX.KEY, `/images/${IMAGES.METALBOX.FILE}`)
  this.load.spritesheet(
    IMAGES.ANTENNA.KEY,
    `/images/${IMAGES.ANTENNA.FILE}`,
    {
      frameWidth: 160,
      frameHeight: 504
    }
  )
  this.load.spritesheet(
    IMAGES.FIREPIT.KEY,
    `/images/${IMAGES.FIREPIT.FILE}`,
    {
      frameWidth: 84,
      frameHeight: 60
    }
  )
}
```

I have a `BaseScene` with some common methods that all scenes inherit, to I created a `loadAudio`, `loadImage` and `loadSprite` functions there that receive the sprite constant as a parameter:

```js
public loadSprite(SPRITE: SpriteAsset) {
  this.load.spritesheet(SPRITE.KEY, `/images/${SPRITE.FILE}`, {
    frameWidth: SPRITE.WIDTH,
    frameHeight: SPRITE.HEIGHT
  })
}
```

So the preload function ended up looking like this. It's actually loading more assets than before, but it's way easier to read:

```js
public preload() {
  // Preload audio
  this.loadAudio(AUDIO.FIRE)
  this.loadAudio(AUDIO.STATIC)
  this.loadAudio(AUDIO.DROP)
  this.loadAudio(AUDIO.BANG)

  // Preload images
  this.loadImage(IMAGES.BUILDING_BG)
  this.loadImage(IMAGES.BUILDING_BG_2)
  this.loadImage(IMAGES.BUILDING_NIGHT_BG)
  this.loadImage(IMAGES.BUILDING_NIGHT_BG_2)
  this.loadImage(IMAGES.FLOOR)
  this.loadImage(IMAGES.WOOD)
  this.loadImage(IMAGES.CLOTH)
  this.loadImage(IMAGES.DROP)
  this.loadImage(IMAGES.ROCK)

  // Preload sprites
  this.loadSprite(SPRITES.METALBOX)
  this.loadSprite(SPRITES.LADDER)
  this.loadSprite(SPRITES.BUCKET)
  this.loadSprite(SPRITES.BOXES)
  this.loadSprite(SPRITES.ANTENNA)
  this.loadSprite(SPRITES.FIREPIT)
  this.loadSprite(SPRITES.BUGGY)
  this.loadSprite(SPRITES.STRANGER)
}
```

There's still room for improvement, for example I could have all the audio, images and sprites a scene needs in a constant, and load them all in a single call. But for now it's more than enough to make the code a bit more readable!