- Home /
Audio Manager
Hello everyone.
In my game, I let the user change the volume of audio.
I already have a volume slider working perfectly, but only for one sound (menu background music).
I want the sliders (I have one for BGM and one for SFX) to control all the sounds and music in the game.
Whats the best way to approach this?
Thanks!
Answer by Chronos-L · Mar 20, 2013 at 01:44 AM
Read this first ( 1 master volume in game )
ou can control the master volume via AudioListener.volume, and you can pause audio using AudioListener.pause.
However, if you want to have 2 master volume for BGM and SFX respectively, you will have to do the manual work ( in the segment after this one ).
For 2 or more master volume in game
se a singleton AudioManager to control all the sound in your game. You need to add all existing AudioSource to the AudioManager in Start()
, I will recommend using a dynamic collection to store the reference to the AudioSource, so you can add in sounds (SFX) that is generated in runtime.
From this singleton AudioManager, you will be able to control volumes.
Follow Up
Base File
Here's is a skeleton for the audio manager. You use this by attaching this to a emtpyObject/camera. I am reusing sample codes from alucardj's example.
public class AudioManager : MonoBehaviour
{
private static AudioManager instance;
void Awake()
{
if (instance != null && instance != this)
{
Destroy( this.gameObject );
return;
}
else
{
instance = this;
}
//DontDestroyOnLoad( this.gameObject );
}
public static AudioManager GetInstance()
{
return instance;
}
}
The codes in the Awake()
ensures that there will be only one AudioManager
object in one scene. DontDestroyOnLoad()
is used for this purpose, you can choose whether you want to keep it or not.
Master Volume
o achieve a master volume control, you need to add in a masterVolumeBGM
in the AudioManager
.
public class AudioManager : MonoBehaviour {
public float masterVolumeBGM;
....
}
Then, in your GUI script, you will do something like this:
// Just call the instance as a class-variable, no need to assign
// the audioManager in the inspector
AudioManage am = AudioManager.GetInstance();
float newVolume = GUILayout.HorizontalSlider (am.masterVolumeBGM , 0.0, 2.0);
if( newVolume != am.masterVolumeBGM ) { //The volume have changed
am.masterVolumeBGM = newVolume;
//Call a function to update audio's volume for BGM
}
Update Master Volume
n the AudioManager
, you just need to use a simple loops to updates all the audioSource
controlled by the AudioManager
public class AudioManager : MonoBehaviour {
...
public void UpdateBGMVolume() {
//Update volume of all audio source in scene
}
}
Problems to tackle
owever, this is not fully completed yet. You still have a few more problems to solve:
All audio access: You need to search for all audioSource in the scene on
Awake()
and store their reference in aCollections
, so you can control all of them later. Since you are using SFX, it is very likely that you willinstantiate
new audio in-game, you will need to use a dynamic collections. You can add the SFX to the AudioManager via something like this:AudioManager.GetInstance().Add( instantiatedAudioSource )
Base Volume: You need to know the base volume of the
audioSource
to calculate the finalized volume. However, you cannot useaudioSource.volume
straight away, or else the calculation will becomeaudioSource.volume = audioSource.volume * masterVolume
; once you did this, the original volume is gone for good. You will need to store the starting volume of the audioSource.Dynamic Sound: When you use SFX, oftentimes, you will
Destroy
it when you are done. However, when a SFX is destroyed, the reference inaudioManager
will becomenull
. You will need to periodically clean up thecollections
in youraudioManager
Final Words
his might seems like a lot of work, but I can assure you that once you are done with it, you will have something very valuable, and you can reuse it over and over again in other game projects.
What do you mean by "singleton Audio$$anonymous$$anager"?
Check my answer here : http://answers.unity3d.com/questions/375227/music-continued-in-the-all-level.html
Ok, I get what singleton means, but how should the manager be constructed?
Do you $$anonymous$$d expending your idea please?
@dorpe, read the link provided by alucardj, it is very informative.
To explain it briefly here, singleton
design means in any given time, there will be only one instance of this class.
We can refer the instance of this class via a static variable/function. This makes it very powerful, we can access this object and call its functions from any script by Audio$$anonymous$$anager.GetInstance().DoSomething()
.
A manager-type class is very suitable to be implemented as singleton
, because you only need/have one manager object to control things in the game.
If you are still not 100% sure of what to do, I will be more than happy to provide a skeleton for you to work on. But not now, it is quite late now for my time zone, I am not in the mental state to write a skeleton class.
Do read on the link before you proceed any further in singleton
design.
Let's build an example for your case, you can use a GUI.slider to control a masterVolume
in the Audio$$anonymous$$anager.GetInstance()
. Then, you can call a funtion like Audio$$anonymous$$anager.GetInstance().UpdateSound()
, in UpdateSound()
, you use the masterVolume
to affect the volume of all the audioSource
controlled by the audio$$anonymous$$anager.
@alucardj, thanks a lot for providing the link. I have wrote a singleton
game manager a while back(to pause-play, control UI, control audio, spawn enemy etc), so I know for sure that a singleton
audio manager will work.
@dorpe, I will get back to you in 10 hours. I really need some sleep now. Thanks a lot for your understanding.