DEV Community

Cover image for Promisifying Phaser
Núria
Núria

Posted on

Promisifying Phaser

Working on web development, promises are a basic tool I use every day, and I feel that the old days when everybody used callbacks are long gone. Except when I'm working with Phaser!

For example, at the start of the game, I want to move the camera around so the player gets a sense of their surroundings, and then start playing the game. Phaser cameras have a pan method to do that, and this method receives a callback which is called on every update. In order to wait and call another method once the effect has finished, you need to check if the progress has reached 1:

create() {
  this.cameras.main.pan(
    this.survivor.x,
    this.survivor.y,
    4000,
    'Linear',
    false,
    (_, progress) => {
      if (progress === 1) {
        this.cameras.main.startFollow(this.survivor)
        this.play()
      }
    }
  )
}

This approach might be useful if I want to do something while the pan is running, but most of the time I want to wait until it's done, and it's a bit tedious to keep writing the callback, not to mention if you want to chain multiple effects: you easily run into callback hell.

So, I decided to turn this kind of Phaser methods into promises:

cameraPan(x: number, y: number, time = 1000) {
  return new Promise((resolve) => {
    this.cameras.main.pan(x, y, time, 'Linear', false, (_, progress) => {
      if (progress === 1) {
        resolve()
      }
    })
  })
}

This way, thanks to async/await, the previous code looks much simpler and easier to understand:

async create() {
  await this.cameraPan(this.survivor.x, this.survivor.y, 4000)
  this.cameras.main.startFollow(this.survivor)
  this.start()
}

The improvement is even more obvious when you are using several camera effects, tweens, and other methods that would require callbacks. Imagine how this code would look without await:

async endScene() {
  this.cameras.main.stopFollow()
  await this.cameraFade('fadeIn')
  await this.cameraPan(0, 0, 4000)
  await this.createDialog("How strange to see northern lights so far down south.")
  await this.cameraPan(this.survivor.x, this.survivor.y, 4000)
  await this.cameraFade('fadeOut', 2000)
}

You can still use the original Phaser method at certain points when you need more control over the progress, but I've found this is a quick and easy way to make your Phaser games a bit more readable. Hope it helped!

Discussion (1)

Collapse
jeffjadulco profile image
Jeff Jadulco

Great! This also makes the game feel smoother because there will be fewer hiccups :)