Volume settings persistant between scenes.

Hello
This is kind of a dumb one. I have a volume settings menu so the player can change the volume of things with sliders. Pretty standard stuff. My issue is it no longer saves volume data between scenes. If I set the sliders to something in the main menu then start a level, the sliders and audio levels in the settings menu return to default. This used to work properly, I had to upgrade to Unity version 2022.3.4f1 for something and that didn't break anything (it's a pretty simple game) but now it appears it broke the PlayerPrefs? I just need the volume settings to be saved and loaded like they used to be.

I tried a few things like ensuring it doesn't destroy on scene change but that just makes the sliders disconnect from the audio manager completely. It's a tad annoying, not game breaking, but still annoying.

Here is the script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;

public class AudioManager : MonoBehaviour
{
    public AudioMixer audioMixer; // Reference to the Audio Mixer in your project

    public Slider musicSlider;
    public Slider fxSlider;
    public Slider masterSlider; // Controls both music and FX

    private const string MusicVolumeParameter = "Music";
    private const string FXVolumeParameter = "FX";

    private void Start()
    {
        LoadAudioSettings(); // Load saved audio settings when the game starts
    }

    public void SetMusicVolume(float volume)
    {
        audioMixer.SetFloat(MusicVolumeParameter, ConvertToDecibels(volume));
        SaveAudioSettings();
    }

    public void SetFXVolume(float volume)
    {
        audioMixer.SetFloat(FXVolumeParameter, ConvertToDecibels(volume));
        SaveAudioSettings();
    }

    public void SetMasterVolume(float volume)
    {
        audioMixer.SetFloat("Master", ConvertToDecibels(volume));
        SaveAudioSettings();
    }

    private void LoadAudioSettings()
    {
        if (PlayerPrefs.HasKey(MusicVolumeParameter))
        {
            float musicVolume = PlayerPrefs.GetFloat(MusicVolumeParameter);
            musicSlider.value = musicVolume;
            SetMusicVolume(musicVolume);
        }

        if (PlayerPrefs.HasKey(FXVolumeParameter))
        {
            float fxVolume = PlayerPrefs.GetFloat(FXVolumeParameter);
            fxSlider.value = fxVolume;
            SetFXVolume(fxVolume);
        }

        if (PlayerPrefs.HasKey("Master")) // Use the correct key for master volume
        {
            float masterVolume = PlayerPrefs.GetFloat("Master");
            masterSlider.value = masterVolume;
            SetMasterVolume(masterVolume);
        }
    }

    private void SaveAudioSettings()
    {
        PlayerPrefs.SetFloat(MusicVolumeParameter, musicSlider.value);
        PlayerPrefs.SetFloat(FXVolumeParameter, fxSlider.value);
        PlayerPrefs.SetFloat("Master", masterSlider.value); // Use the correct key for master volume
        PlayerPrefs.Save();
    }

    private float ConvertToDecibels(float volume)
    {
        return Mathf.Log10(volume) * 20f;
    }
}

I think the best way to handle long living objects/managers/singletons is to have the all loaded in a scene, and then load/unload your other scenes additively. This way you will have this kind of "universe" scene that will never stop to exist and won't have to deal lifetimes.

The second best thing would be to use ScriptableObject, that are objects persisting across scenes and even sessions! You could have a AudioOptions SO with all your configs, and it shall keep on living. Keep in mind that all value changes will persist, whether you tweak it in the editor or in the game.

The odd thing is it used to work. I have tried making the audio manager persistent so it isn't destroyed. However When I do that it completely separates the audio sliders from the audio mixer making them not only not carry over the levels, but make the sliders not work at all. It should work with PlayerPrefs but for some reason it's just not.

Oh, fixed it. I just reworked the script so it was going for the audio manager and not the sliders.

1 Like

If this manages a bunch of UI stuff, then it probably should not be persistent.

But the advice of using a scriptable object is sound. Separate the UI from the data. Make it something you can visualise. Then you can write it to disk as well. I'd avoid player prefs as much as you can.