Logo

dev-resources.site

for different kinds of informations.

Promisifying Phaser

Published at
5/9/2020
Categories
phaser
gamedev
devdiary
showdev
Author
pincfloit
Categories
4 categories in total
phaser
open
gamedev
open
devdiary
open
showdev
open
Author
9 person written this
pincfloit
open
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!

Featured ones: