5
votes

I'm a bit confused about loading and playing sound effects. My game is setup in different states, first the Preloader state makes sure all images and sounds are loaded. The GameState is the main game, this state is re-started for each next level. There are different levels but the state is the same, it just changes a _levelIndex variable and uses the same state.

The GameState adds the needed audio to the game in the .create() function, and this create-function is called every time the GameState is started. See code below

mygame.Preloader.prototype = {
    preload: function(){

        this.loadingbar_bg = this.add.sprite(80, 512, "loadingbar_bg");
        this.loadingbar_fill = this.add.sprite(80, 512, "loadingbar_fill");
        this.load.setPreloadSprite(this.loadingbar_fill);

        // load sounds
        this.load.audio("button", ["snd/button.mp3", "snd/button.ogg"]);
        this.load.audio("punch",  ["snd/punch.mp3",  "snd/punch.ogg"]);
        this.load.audio("coin",   ["snd/coin.mp3",   "snd/coin.ogg"]);
    },
    create: function() {
        this.state.start("MainGame");
    },
};

mygame.GameState.prototype = {

    create: function() {
        this.stage.backgroundColor = "#f0f";
        // etc.

        // sound effects
        this.sound1 = this.game.add.audio("button");
        this.sound2 = this.game.add.audio("punch");
        this.sound3 = this.game.add.audio("coin");
        //etc.
    },

    update: function() {
        if (hitFace) {
            this.sound2.play();
            hitFace = false;
        };
    },

    doNextLevel: function() {
        this.sound1.play();
        this._levelIndex++; // next level
        this.state.start("MainGame"); // restart this state
    },
    //etc.
};

The problem is that when I play the punch sound a couple of times in a row a couple of seconds apart, the console gives this warning (which Phaser raises in code here)

Phaser.Sound: Audio source already exists

This warning appears even when the GameState is started for the first time.

I suspect that it has to do with decoding the mp3 and ogg sounds. Do I have to decode the sound samples every time the player starts (or restarts) a level i.e. restart the GameState? In other words, if the GameState will be .create() each time a level is (re)started and the audio samples are added using game.add.audio, will the decoded samples from the previous level be destroyed and have to be reloaded/decoded each time? That seems wasteful, what is the best way to do this? So my questions are:

  1. What does this message "Audio source already exists" mean ? Or should I ignore it?
  2. if I want to use sounds in a state, do I have to re-add them every time the state is started and .create() is called ?
  3. also somewhat related, if I want to use the same sound sample in multiple different States (menu, game, options etc.) do I have to do game.add.audio() for the same sound for each state?
1
Did you solve your problem with some answer?SirPeople

1 Answers

2
votes

Well, as far as I can see you code seems to be doing things right. So I will try to answer your questions with the knowledge I have:

1. What does this message "Audio source already exists" mean ? Or should I ignore it?

The message means that there is already an instance of that sound playing as you can see in the place where it is raised:

if (this._sound && ***!this.allowMultiple***)
    {
        console.warn('Phaser.Sound: Audio source already exists');

        // this._disconnectSource();
    }

It will throw this error if the sound you are trying to play is already being played by Phaser.Sound and if is not allowMultiple... There it is the quid of the issue. AllowMultiple from source code:

/**
* @property {boolean} allowMultiple - This will allow you to have multiple instances of this Sound playing at once. This is only useful when running under Web Audio, and we recommend you implement a local pooling system to not flood the sound channels.
* @default
*/
this.allowMultiple = false;

So basically is complaining that you are trying to spawn several instances of a sound that is not being allow multiple times. You shouldnt ignore it, but instead use the right flags.

Questions 2 and 3:

You shouldnt have re-add the resource, since thats why you load in the engine the source of audio, to can be reused through all the levels. Nor you have to do it for all the states.

In order to reuse an Sound in multiple states, you should be able to add the audio or any game object in the global scope and access it (Here I found someone trying to do what you ask in the question) Other ways will be to add this resources as an attribute to the game object, so you dont contaminate the global scope but only the Game object context. But I believe that is better strategy to add this audios in different states and manage their deletion/creation in the states. Mainly because JS is evil* and mutability may play a bad card on you

*Not that evil

To resolve this warning: Simply use the flag allowMultiple (created in here), eg:

    this.sound1 = this.game.add.audio("button") // allowMultiple is false by default
    this.sound2 = this.game.add.audio("punch");
    // Allow multiple instances running at the same time for sound2
    this.sound2.allowMultiple = true;
    this.sound3 = this.game.add.audio("coin");
    // Allow multiple instances running at the same time for sound3
    this.sound3.allowMultiple = true;