Smooth Switching scenes

Hi everyone,

I’m developing a Phaser 3 game on the AirConsole plattform.
You can actually try it out right now on the AirConsole Simulator if you authenticate with your google account.

The structure of the game is as follows:

class FindItScene extends Phaser.Scene
class MainMenu extends FindItScene
class PauseScreen extends FindItScene
class Guessing extends FindItScene

As I’m reusing a lot of assets in every scene (background, ui elements), this enables me to stay DRY.
Every Scene calls super.preload() and super.create() before doing the elements that are specific to that scene.

Phaser gets initiated as follows:

var config = {
    type: Phaser.AUTO,
    scale: {
        mode: Phaser.Scale.NONE,
        parent: 'body',
        width: "100%",
        height: "100%",
        autoCenter: Phaser.Scale.NO_CENTER,
    },
    scene: [MainMenu, Guessing, TimeScreen, EndOfGame, PauseScreen]
};

// store the game object in the document so its available from everywhere
document.game = new Phaser.Game(config);

AirConsole listens for input from controllers (these are mobile devices) and reports these events.
When these events get triggered, I need to switch scenes from outside of Phaser.

I solved this currently by adding and EventListener to the FindItScene class in its create method:

create(){
    // listen for sceneChange by AirConsole
    this.events.once("sceneChange", this.handleSceneChange, this);
}

handleSceneChange(args) {
    this.scene.start(args.targetScene);
}

So when an AirConsole event comes in that triggers a scene change, I emit the event on the currently active scene:

document.game.scene.getScenes(true)[0].events.emit("sceneChange", {targetScene: targetScene});

Now what i’ve found is that with that approach, there is always a short black screen between each scenes. I could just use a background behind the canvas, but I’m seriously wondering why this would even happen, since, as I understand it, switching scenes just sleeps them, and all the assets should be cached and ready. I’ve also noticed that using launch avoids the black screen, because the old scene just remains behind the new scene, but stacking scenes above each other doesn’t feel correct either.

What is the best approach to having a consistent background image between all Phaser Scenes?

:wave:

How/where are you adding the background images to a scene?

1 Like

preloading and creating in FindItScene:

export default class FindItScene extends Phaser.Scene {

preload() {
(…)
this.load.svg(“bg”, “assets/drawing-4.svg”);
(…)
}

create(){
(…)
this.bg = this.add.image(0, 0, “bg”).setScale(scale).setOrigin(0, 0);
(…)
}

And every child scene calls super.preload(); and super.create();

Once the “bg” texture is loaded scenes should do

this.bg = this.add.image(0, 0, “bg”).setScale(scale).setOrigin(0, 0);

in init(), not create(). You could add a BootScene that runs first and loads all the common assets.

Or you could add a BgScene that stays open at the back.

1 Like

Thanks. Putting it in init() doesn’t work on the first scene, but every other scene, and there is no more black background. I’m guessing the first time, init does not wait for the preload to finish.

Then again, if i just put it in both, it works everywhere. I should probably find a way to only add it in create the first time the MainMenu opens.

Is there a way to check if an image failed to add (the black square with the green line through it)?

Textures are global, so there’s no need to load the same image more than once. init() always runs before preload() and create().

You can check this.textures.exists('bg').

1 Like

Yeah I’m not trying to load it twice. It’s just that the initial scene fails to add it, if its only in init. Every other scene change after that is fine.

Unfortunately, when adding fails:
image
this.textures.exists(‘bg’) still evaluates to true :frowning:

init() runs before preload() or create(). During the first scene init() no textures have been loaded, so you can’t use the “bg” texture yet there.

A pattern for this is

class BootScene extends Phaser.Scene {
  preload () {
    // Load common assets
  }
  
  create () {
    this.scene.start('otherScene');
  }
}

class OtherScene extends Phaser.Scene {
  init () {
    // Add game objects w/ common assets
  }
  
  preload () {
    // Load assets for this scene only
  }
  
  create () {
    // Add the other game objects
  }
}
1 Like