Sponsored By

Music and Sound Effects in Unity

In this week's PuckMania dev blog, we share simple techniques used to load in audio clips for SFX and music in Unity, as well as manage their volume.

Marc Breaux, Blogger

October 21, 2014

8 Min Read
Game Developer logo in a gray background | Game Developer

After an intense bout of market research, I've come to the revolutionary conclusion that gamers like to have sound and music in their games.

About as simple as a settings menu can get... And a way to turn them off when they get irritated by them..

PuckMania is a simple, unassuming little game, so its audio needs are modest.  Just some background music playing in each scene, and some sound effects clips playing in response to certain in-game events.  We do not require any fancy spatial environmental sounds.

The good news for those of us who aren't terribly audio-inclined is that Unity makes playing audio a fairly painless affair.  But we still have to wrangle all of our audio clips, which may be from disparate sources, and worry about balancing their volume levels, and allowing the user to adjust and mute them to their heart's content.

There are loads of audio-related add-ons in the Unity Asset Store that can help manage more complex audio needs.  But we only care about volume control for a modest number of 2D clips, so we did the not-so-dirty work ourselves.

This week I'm going to share the simple techniques used to load in audio clips for SFX and music, as well as manage their volume.

SFX Audio Clips

The normal approach here would be to load in a series of audio clips from a Resources folder using Resources.Load.  Instead, we created objects containing AudioSources ahead of time.  This allows us to set the individual name, volume, and other audio settings of each clip independently with minimal coding.

We create a parent GameObject called SFX, and this object's children are GameObjects with AudioSource components.  Each of these GameObjects is named for the function it will serve (e.g. "PuckHitsPuck" or "GoalTriggered").  What I like about this approach is that you can easily assign a relative volume to each of the SFX child objects by setting the AudioSource volume of that object, sort of like a mixer.  These will be scaled by the SFX master volume later.

We store these AudioSources in a Dictionary so that we can refer to them by name:


        if (AudioSources == null)
        {
            AudioSources = new Dictionary<string, AudioSource>();

            AudioSource[] sources = gameObject.GetComponentsInChildren<AudioSource>();
            for (int i = 0; i < sources.Length; i++)
            {
                GameController.AudioSources[sources[i].gameObject.name] = sources[i];
                DontDestroyOnLoad(sources[i]);
            }
        }

AudioSource is declared as static in our master GameController, and other objects can easily access it:


public static Dictionary<string, AudioSource> AudioSources;

With this in place, you can play a SFX clip from just about anywhere:


AudioSources["PuckHitsPuck"].Play();

BGM Audio Clips

Unlike SFX, our music clips aren't going to stay the same across all levels in the project.  We're going to want to specify different clips for our background music AudioSource depending on which scene is loaded.  We do this by specifying a background music audio clip on the level object itself, along with a volume level for that clip. (More on this in Volume Management, below.)


        AudioSources["BackgroundMusic"] = transform.FindChild("BackgroundMusic").GetComponent<AudioSource>();
        AudioSources["BackgroundMusic"].clip = Level.BackgroundMusic;
        AudioSources["BackgroundMusic"].loop = true;
        _bgminitialvolume = Level.BGMVolume;
        SetBGMVolume(BGMVolume);
        AudioSources["BackgroundMusic"].ignoreListenerVolume = true;

In this case, the BGM AudioSource we're using is attached to a child object called "BackgroundMusic."

Our Level object exposes the clip as Level.BackgroundMusic and the volume as BGMVolume.  The .ignoreListenerVolume property will help us separate out the volume for SFX and BGM, as we'll see below.

Volume Management

Like most games, we want to separate out the adjustment of the background music and SFX.  We'll store the master volumes and mute flags in some simple public fields.  The private _bgminitialvolume sets the "base" volume level for the background music, which is loaded in on a per-level basis:


    public float BGMVolume;
    public float SFXVolume;
    public bool SFXMuted = false;
    public bool BGMMuted = false;
    private float _bgminitialvolume;

In a simple project like this, we have a single AudioListener component attached to the default camera.  To adjust the volume, simply set AudioListener.volume to a float between 0.0 and 1.0.

Normally, adjusting the volume in this way will affect all audio.  What we need is two volume controls, one for music and one for SFX.  Unity gives a way of accomplishing this for our music AudioSource with a property called ignoreListenerVolume.  With this set to true for the background music AudioSource, our listener volume will now affect only the SFX clips.

With this in place, we can set our SFX volume with:


    public void SetSFXVolume(float volume)
    {
        volume = Mathf.Clamp(volume, 0.0f, 1.0f);
        if (!SFXMuted)
        {
            AudioListener.volume = volume;
        }
        SFXVolume = volume;
    }

And our BGM volume with:


    public void SetBGMVolume(float volume)
    {
        volume = Mathf.Clamp(volume, 0.0f, 1.0f);
        if (!BGMMuted)
        {
            AudioSources["BackgroundMusic"].volume = _bgminitialvolume * volume;

        }
        BGMVolume = volume;
    }

SetBGMVolume is a little bit different.  When adjusting SFX volume, we're not adjusting any AudioSource volumes directly, so we don't have to worry about their base volume.

This isn't the case with the music - we have to adjust that audio source directly, so the initial base volume has to be taken into account.  As noted before, he audio clip and initial volume are specified on a per-level basis.

Conclusion

Audio is an important part of a fun and memorable game.  Unless you're making an old-school text adventure, you're going to have to plan for it.  Thankfully, a simple audio system that just works isn't too terribly hard to implement in a small project.  I hope that some of you can find these pointers helpful, and even expand upon them.  And as always, let me know if you'd like to share your improvements or suggestions.

Thanks for reading, and check us out on PuckMania!
-Marc

Orignally posted at http://www.puckmania.com/blog/music-and-sound-effects-in-unity/

Read more about:

Featured Blogs
Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like