For some reason as soon as I change scenes from the scene that my sliders are in, they no longer adjust sound or anything like that. I cannot figure out why, the code is pretty straight forward, most I got from a tutorial and it worked nothing like that project did. If anyone can find anything that it might be in the script, I would really appreciate it.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class AudioManager : MonoBehaviour
{
private static readonly string FirstPlay = "FirstPlay";
private static readonly string BackgroundPref = "BackgroundPref";
private static readonly string SoundEffectsPref = "SoundEffectsPref";
private int firstPlayInt;
public Slider backgroundSlider, soundEffectsSlider;
private float backgroundFloat, soundEffectsFloat;
public AudioSource backgroundAudio;
public AudioSource[] soundEffectsAudio;
void Start()
{
backgroundFloat = 1;
soundEffectsFloat = 1;
backgroundSlider.value = PlayerPrefs.GetFloat("BackGroundSliderValue", backgroundFloat);
soundEffectsSlider.value = PlayerPrefs.GetFloat("SoundFXSliderValue", soundEffectsFloat);
firstPlayInt = PlayerPrefs.GetInt(FirstPlay);
DontDestroyOnLoad(gameObject);
if (firstPlayInt == 0)
{
backgroundFloat = 1f;
soundEffectsFloat = 1f;
backgroundSlider.value = backgroundFloat;
soundEffectsSlider.value = soundEffectsFloat;
PlayerPrefs.SetFloat(BackgroundPref, backgroundFloat);
PlayerPrefs.SetFloat(SoundEffectsPref, soundEffectsFloat);
PlayerPrefs.SetInt(FirstPlay, -1);
}
else
{
backgroundFloat= PlayerPrefs.GetFloat(BackgroundPref);
backgroundSlider.value = backgroundFloat;
soundEffectsSlider.value = soundEffectsFloat;
soundEffectsFloat= PlayerPrefs.GetFloat(SoundEffectsPref);
}
}
public void SaveSoundSettings()
{
PlayerPrefs.SetFloat(BackgroundPref, backgroundSlider.value);
PlayerPrefs.SetFloat(SoundEffectsPref, soundEffectsSlider.value);
PlayerPrefs.SetFloat("BackgroundSliderValue", backgroundSlider.value);
backgroundSlider.value = PlayerPrefs.GetFloat("BackgroundSliderValue", 0);
PlayerPrefs.SetFloat("SoundFXSliderValue", soundEffectsSlider.value);
soundEffectsSlider.value = PlayerPrefs.GetFloat("SoundFXSliderValue", 0);
}
private void OnApplicationPause(bool inFocus)
{
if (!inFocus)
{
SaveSoundSettings();
}
}
public void UpdateSound()
{
backgroundAudio.volume = backgroundSlider.value;
PlayerPrefs.SetFloat("BackgroundSliderValue", backgroundSlider.value);
backgroundSlider.value = PlayerPrefs.GetFloat("BackgroundSliderValue", 0);
PlayerPrefs.SetFloat("SoundFXSliderValue", soundEffectsSlider.value);
soundEffectsSlider.value = PlayerPrefs.GetFloat("SoundFXSliderValue", 0);
for (int i = 0; i < soundEffectsAudio.Length; i++)
{
soundEffectsAudio[i].volume = soundEffectsSlider.value;
}
}
}
When is UpdateSound() called? Does this script unload when you load a new scene, or does it stay loaded? Are there any errors in the console?
What is the purpose of this code? It looks like you set the PlayerPrefs variable based on the slider value, but then you immediately read that value back and set the slider. Does the second line do anything?
To MelvMay, the sliders stop working after I change scenes and come back, and so the second line loads in a player prefs value for the background slider even though I have tried saving the heck out the settings in different ways in this script with player prefs which is what you see, because it was not working and so I kind of overloaded the cause but there is not difference before and after. I do not know if the script unloads, I would think it does not. But, I have tried DontDestroyOnLoad(this); in awake and start and it does not do anything other than on awake in forced my background music slider to zero strangely.
Ok, I see that you have DontDestroyOnLoad in Start. When you leave this scene and come back, do you see two instances of this Game Object in your hierarchy? When the scene loads again, it will recreate the same game object and you’ll have duplicates unless you clean them up. But before dealing with that, I’m not even sure if you need this script to have DontDestroyOnLoad.
When is UpdateSound() called? What is backgroundAudio? This is not defined in the posted script. (Edit: sorry, I see this defined as an AudioSource).
So I looked in the console and it says that AudioSource has been destroyed but I am still trying to access it as soon as I try and change the slider.
Here is the BG music, but it is also disabling the sound effects from being adjusted again after a new scene loads.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BGMusic : MonoBehaviour
{
// Start is called before the first frame update
private static BGMusic musicManagerInstance;
void Awake()
{
DontDestroyOnLoad(this);
if (musicManagerInstance == null)
{
musicManagerInstance = this;
}
else
{
Destroy(gameObject);
}
}
}
Update sound is called or is supposed to be called whenever the slider is adjusted, but it stops calling after a new scene loads and the script somehow becomes disabled. The background Audio was to put a little slot in the UI for the audio source to fit in, it worked for the guy I saw do it on the tutorial, but it could be out of date it seems. I forgot to add, I do see two instances of the script that the slider value adjustments are on.
Are the AudioSources for the backgroundAudio and soundEffectsAudio on the same object as the AudioManager script? Do the sliders only exist in the scene that contains AudioManager, or are they somehow accessible from other scenes?
It’s hard to give specific answers here without more information about how your game objects are managed in your scenes. I will just give some general advice.
DontDestroyOnLoad only preserves that game object and its children. If that game object contains references to anything else in the scene, those references will be lost when the scene unloads. I’m not sure if two different DontDestroyOnLoad objects can maintain references to each other, I have never tried.
Similarly, if any object in your scene has a reference to a DontDestroyOnLoad object, when the scene reloads it will not have access to the object that was preserved. In your example, it is possible that a new copy of AudioManager is being created when the scene loads and this gets a reference to a new copy of backgroundAudio, but then BGMusic destroys that copy.
It will likely be more convenient to work with an Audio Mixer rather than controlling the volume of each AudioSource individually. The Audio Mixer will be persistent in all scenes, so setting the volume in one scene will apply for all scenes.
I noticed that in the second copy of AudioManager it is missing the AudioSource from the audio source slot, but one has it and I get a compilation report that nothing is there that the slider is trying to access. I resets my slider values each time a scene starts also which is possibly part of the problem. I noticed that if I changed my BGMusic script up so that it did not destroy, there was always something there for the slider to adjust. But, two pieces of music would be playing over each other if the slider did not take down the volume. So it points to something, I am not sure exactly what though, the slider values should not be resetting with each scene load. I do not understand it.
Because your AudioManager is pointing to objects that have been destroyed when the scene they’re in is unloaded. These references don’t get restored when the scene is loaded again; because it’s a new instance of everything.
Just have the values to a scriptable object, and have anything that cares about sound settings read off said scriptable object. If it’s all basic data types it can just be written to disk with JSONUtility as well.
And the UI that changes the settings should be completely separate from the audio-manager itself. Too much mixed responsibility.
Yeah, that was a good idea, but I tried that and it still does the same thing. Something is killing the script function on scene load. I noticed also that the JSON file that saves never changes from 1.0 when I adjust the slider. Nothing is really saving as well. It is such a simple thing or it use to be and nothing that makes any sense is working. Here is what I did for the JSON:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
public class AudioManager : MonoBehaviour
{
private static readonly string FirstPlay = "FirstPlay";
private static readonly string BackgroundPref = "BackgroundPref";
private static readonly string SoundEffectsPref = "SoundEffectsPref";
private int firstPlayInt;
public Slider backgroundSlider, soundEffectsSlider;
private float backgroundFloat, soundEffectsFloat;
public AudioSource backgroundAudio;
public AudioSource[] soundEffectsAudio;
private static AudioManager AudioManagerInstance;
void Start()
{
string json = File.ReadAllText(Application.dataPath + "/SliderValue.json");
SliderJSON sliderJson = JsonUtility.FromJson<SliderJSON>(json);
backgroundFloat = sliderJson.JsonSlider;
firstPlayInt = PlayerPrefs.GetInt(FirstPlay);
if (firstPlayInt == 0)
{
backgroundFloat = 1f;
soundEffectsFloat = 1f;
backgroundSlider.value = backgroundFloat;
soundEffectsSlider.value = soundEffectsFloat;
PlayerPrefs.SetFloat(BackgroundPref, backgroundFloat);
PlayerPrefs.SetFloat(SoundEffectsPref, soundEffectsFloat);
PlayerPrefs.SetInt(FirstPlay, -1);
}
else
{
backgroundFloat= PlayerPrefs.GetFloat(BackgroundPref);
backgroundSlider.value = backgroundFloat;
soundEffectsSlider.value = soundEffectsFloat;
soundEffectsFloat= PlayerPrefs.GetFloat(SoundEffectsPref);
}
}
public void SaveSoundSettings()
{
SliderJSON sliderJson = new SliderJSON();
sliderJson.JsonSlider = backgroundFloat;
string json1 = JsonUtility.ToJson(sliderJson, true);
File.WriteAllText(Application.dataPath + "/SliderValue.json", json1);
PlayerPrefs.SetFloat(BackgroundPref, backgroundSlider.value);
PlayerPrefs.SetFloat(SoundEffectsPref, soundEffectsSlider.value);
}
private void OnApplicationPause(bool inFocus)
{
if (!inFocus)
{
SaveSoundSettings();
}
}
public void UpdateSound()
{
backgroundAudio.volume = backgroundSlider.value;
SaveSoundSettings();
for (int i = 0; i < soundEffectsAudio.Length; i++)
{
soundEffectsAudio[i].volume = soundEffectsSlider.value;
}
}
}
Yeah, I misunderstood you. But, I had better luck switching to an audio mixer like Dstears suggested. I just have to get it to save the place of the slider now. So, it is heading in the right direction. Thank you everyone.
Okay, so I got it to work with an audio mixer and then added what I had learned from the original script in their method of using player prefs with this final script here.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;
public class VolumeSettings : MonoBehaviour
{
[SerializeField] private AudioMixer Mixer;
[SerializeField] private Slider musicSlider;
[SerializeField] private float volumeValue;
private int firstPlayInt;
private static readonly string FirstPlay = "FirstPlay";
private static readonly string BackgroundPref = "BackgroundPref";
private const string MIXER_MUSIC = "MusicVolume";
private void Awake()
{
musicSlider.onValueChanged.AddListener(SetMusicVolume);
firstPlayInt = PlayerPrefs.GetInt(FirstPlay);
if (firstPlayInt == 0)
{
volumeValue = 1f;
musicSlider.value = volumeValue;
PlayerPrefs.SetFloat(BackgroundPref, volumeValue);
PlayerPrefs.SetInt(FirstPlay, -1);
}
else
{
volumeValue= PlayerPrefs.GetFloat(BackgroundPref);
musicSlider.value = volumeValue;
}
}
public void SetMusicVolume(float value)
{
Mixer.SetFloat(MIXER_MUSIC, Mathf.Log10(value) * 20);
float volumeValue = musicSlider.value;
PlayerPrefs.SetFloat(BackgroundPref, musicSlider.value);
}
}
Then, of course the background music player script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewAM : MonoBehaviour
{
public static NewAM instance;
private void Awake()
{
if (instance == null )
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
}