2
\$\begingroup\$

I have a game built in Unity. The game plays music continuously, which can be muted on button press on the scene. This works fine using the below code:

MuteButton.cs

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class MuteButton : MonoBehaviour {
    public GameObject audioObject;
    private AudioSource audioSource;

    void Start()
    {
        Button b = gameObject.GetComponent<Button>();
        b.onClick.AddListener(Pause);
    }

    void Pause() {
        Debug.Log("mute toggle");

        audioSource = audioObject.GetComponent<AudioSource>();
        if(!audioSource.isPlaying) {
            audioSource.Play();
        } else {
            audioSource.Pause();
        }
    }
}

However, when the player loses the game restarts by reloading the scene, using this code:

public void Restart()
{
    SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}

In order to keep the music running I have attached the following script to my music game object:

using UnityEngine;
using System.Collections;

public class Music : MonoBehaviour {
    static Music instance;
    void Start() {
        if(instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else if (instance != this)
        {
            Destroy(gameObject);
        }
    }
}

All working fine up until now. Once the scene is reloaded when the user tries to mute the music I get the following:

MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object.

I understand that the error is that I'm trying to mute a now non-existent game object, but how can I pause the music if this is the case?

\$\endgroup\$
0

2 Answers 2

4
\$\begingroup\$

Add to your music class a method like this:

public static Music GetInstance() {
    // Optionally, you can create an instance here
    // if one isn't already present in the scene.
    return instance;
}

Then when you want to toggle the music, instead of referencing an object saved in a member variable, ask the music class which instance is current:

var currentMusic = Music.GetInstance();

Now you can play/pause this active instance.

\$\endgroup\$
4
\$\begingroup\$

The solution by DMGregory is a quick and dirty solution which works well for a single audio source. But in a more complex game you might have multiple audio sources which function as background music. You might also have other groups of audio sources you want to mute together. In that case you might want to use the cleaner solution using the Audio Mixer system and Audio Mixer Snapshots.

  1. Create a second audio mixer "Music".
  2. Assign that master audio group of that mixer to the Output of your background music Audio Source. It should now still work as normal.
  3. Create two snapshots in the Music audio mixer. One with the master volume on normal volume and one with the master volume off.
  4. Create two variables in your MuteButton script, public AudioMixerSnapshot musicOn; and public AudioMixerSnapshot musicOff;.
  5. Assign the two snapshots to these variables.
  6. You can now switch between the muted and the unmuted state with musicOff.TransitionTo(0.0f) and musicOn.TransitionTo(0.0f) respectively (0.0f is the time in seconds the transition should take. You can smoothly fade the music in and out by using a larger value).
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .