Phaser and same button sounds in multiple scenes, code organisation question

I’m working on a game with 3 separate scenes Menu, Tutorial and Game (and I may add more later). So the general structure of the project is like so:

- PreloaderScene
- MainMenuScene
- TutorialScene
- GameScene

Each scene has buttons to navigate menus and to change between scenes. When pressed these buttons should play the same sound effect in each scene. Also, in the main menu there is a Sound ON/OFF option. When the player has selected OFF it shouldn’t play the sounds in any scene.

At the moment, I’m loading all the needed sound effects per scene, like so:

// in game scene .create()
this._button_start = this.sound.add('gui_forward');
this._button_back = this.sound.add('gui_back');
this._explosion = this.sound.add('explosion');
// etc

It’s similar for the MainMenu and Tutorial scenes, but doesn’t this load the same audio multiple times? Also when a sound should be played (button, powerup, explosion etc.) I need to check the Sound=OFF option in each scene.

I’ve already got a global Settings object that is global/shared so it’s used by all scenes. So now I’m thinking it might be better to also create a global/shared sound object that handles all the playing of sound effecs, so then I can load the audio and check the Sound=OFF setting in just one place.

I guess my question is:

  • What are the best practices for Phaser3 and loading/playing sound effects with separate scenes?

It’s fine to use sound.add() that way, and probably best. You’re downloading each sound only once, in PreloaderScene, I assume. You can do

this._button_start.destroy();

to clean up when shutting down the scene, if that happens.

If the sound toggle is global, you can do

this.sound.mute = true;

etc.

Hi, just migrating from Phasaer 2 to Phaser 3 and making the first game in it. I am also finding my way how to handle sounds in convenient way.

Here is approach I am now implementing:
1] AudioSprites - all sounds in the game are in single audiosprite. All sounds are single asset with single load request:

this.load.audioSprite("Sfx", "sound/Sfx.json");

… notice, that I load only .json file and not any .ogg/m4a/mp3… It is because Sfx.json has the right format with all files in resources property (be careful about paths!) and Phaser will read it and load the right file:

{
  "resources": [
    "sound\\Sfx.ogg",
    "sound\\Sfx.m4a"
  ],
  
  "spritemap": {
    "truck": {
      "start": 0,
      "end": 2.940702947845805,
      "loop": false
    },
    "click": {
      "start": 4,
      "end": 4.108684807256235,
      "loop": false
    },
        :
        :
        :
  }
}

2] Sound manager is global for game, not specific to single scene. You can add audiosprite like this and access it in any scene:

const sfx = this.sound.addAudioSprite("Sfx");

… of course, you have to keep the reference somewhere. With single reference, you can play any of the sounds inside audiosprite like this:

sfx.play("click");

3] now, the problem is that I can’t play single audiosprite multiple times - if you want to play “click” while “truck” is playing, it will stop the “truck” sound. Also, it would mean, that you need extra audiosprite for each button in your case, which would not be great.
To solve this, I am creating global object AudioUtils. It creates some number (8-10 should be enough, but it is possible to configure it) of audiosprite sounds (…addAudioSprite()) - lets call them slots => any of them can play any sound (because all sounds are in single audiosprite). When the game needs to play specific sound, I call AudioUtils.playSound(“click”). It then looks for free (not playing) slot, takes it, starts playing the sound and marks the time it started to play. If no slot is free I take the longest playing one.

4] … and yes, of course, you can check if sound is ON/OFF at single place with this.