DEV Community

loading...
Cover image for Promisifying Phaser

Promisifying Phaser

pincfloit profile image Núria ・2 min read

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)

pic
Editor guide
Collapse
jeffjadulco profile image
Jeff Jadulco

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