Skip to main content

Handling Music and Sound Effects In Your Games

Initiative 

While developing Treva's Adventure I had to figure out a way to handle multiple music tracks and sound effects in a clean manner or suffer horribly.  What was going to help me achieve a simple solution was taking all the different sounds and centralizing them in a single class in order to black box them.  Any other code trying to play a sound wouldn't even know the sound file's name.  All code trying to play a music track would reference a enum that defines all the track names.

Defining The Class

Creating The Enum

When I first started defining types in my enumeration,  I was naming the types to be exactly like the file name.  For a scary sound effect I had found a file named "ghost breath".  So around my code would be scattered lines like SoundManager.Play(SoundEffectType.GhostBreath);  This was fine until I found a sound that better fit the situation it was being used in,  and decided to use "ghost breath" for a different situation like a enemy screeching.  To incorporate the new sound effect required going through every place SoundEffectType.GhostBreath is referenced and change it.  The moral of the story is make enum type names ambiguous to the files name.  Name the sound effect as being in the situation your planning to use it in.  So instead of SoundEffectType.GhostBreath, I would instead call SoundEffectType.SpookPlayer.  So advantages are:
  • If you wanted to change the SpookPlayer sound effect,  you would go into the SoundManager class and have it reference a different file, Instead of sifting through thousands of lines of code trying to find the 6 places you said GhostBreath.
  • Other programmers coming behind you coding will have a better idea of what your trying to achieve when you say  SpookPlayer instead of GhostBreath.

Static

Music and sound effects are present through out the game.  They are present in your GUI when the player clicks a button.  Casting a fire ball needs to be heard so the player feels the significance of what they just did.  Without background music the game just feels empty. In conclusion It's not a bad idea to create your SoundManager class and it's methods as static. I originally attempted using a singleton method, but typing SoundManager.GetInstance().Play(SoundEffect.GhostBreath) got very old very quickly with as frequent I was calling it.

Methods

Now that all your sound effects are black boxed behind one class, you can easily adjust the volume for ALL sound effects ever played by calling just one method.  Have methods such as SetSound(), GetSound(), and Mute(), Pause() (might not be suited for sound effects), as well as Play().

Two Classes (At least)

This is only a suggestion.  I've found it easier to break up music tracks and and sound effects into two different classes for a few reasons.  Sound Effects don't really need a pause button like a music track does. When you pause the music,  you don't want it interfering with button clicking sounds.  Yes, you could create separate methods like playSoundEffect() and playSoundTrack().  Then you can create separate methods for each like getSoundEffectVolume() getSoundTrackVolume(), and this way works.  All that starts to happen is your AudioManager Class becomes pretty clustered with many methods with similar names and the eye strains begin.  So my suggestion is to create a AudioManager abstract class, and create your classes extending from that.  Some example classes would be MusicManager, GUISoundManager, SoundEffectManager, and 3DSoundEffectManager.   

Some tips in Unity

Storing and Loading Sounds

Keep them under a folder named "Resources/Audio".  Unity has a Resources class that you can load data from any folder named Resources so you can load a file with just Resources.Load().  Depending on what your using the sound for, you need to change how the sound is imported.  If the audio is small and is being used for something like a button click, then you should have the file Decompress on Load.  If the file is a music track then you should have the load type to steam from disk. You can read more here.

Sound Effects In Scene (3D vs 2D)

Unity imports sounds as either 3D or 2D.  3D sounds are positioned in the scene and if the camera(or wherever the audio listener is) is not near the Audio Source when it's playing, then is won't pick up on it, which is not optimal in some cases.  When calling Play() on a 3d sound, your going to need a second parameter that will take into account for position in the scene.  Another thought to ponder when writing these Audio Managing classes is whether or not you want to be able to be playing multiple sound effects if you want.  Usually with things like GUI sound effects, it's not needed to play multiple sounds at once.  Though with 3D sounds, your probably going to need multiple sounds playing at once, thus multiple AudioSources.  The sample code at the end of the post allows for as many audio sources at once, but does not delete the audio sources after the code is done playing.  If your using my code, I suggest creating a script that you call to self destruct after the audio is done playing.

Don't Destroy On Load

In games I usually hear music tracks constantly being played. In boss fights to loading screens your constantly hearing music, and never two tracks at once.  Unity has a method that allows GameObjects to not be deleted when you load different scenes.  So by using that you only have to instantiate the AudioSource once.
    static GameObject soundObjectInstance = null;   
    static AudioSource GetAudioSource(){   
       //if it's null, build the object   
       if(soundObjectInstance == null){
         soundObjectInstance = new GameObject("Music Track Audio");   
         soundObjectInstance.AddComponent<AudioSource>();
         DontDestroyOnLoad(soundObjectInstance);
       }   
       return soundObjectInstance.GetComponent<AudioSource>();   
    }  

Sample Code..

So here is some of the code I wrote for the game some 6 months ago.  With your own experience and after reading this  post you can easily improve it.  Feel free to use it as you please.  Any questions or suggestions are always welcomed.
 using UnityEngine;  
 using System.Collections;  
 public enum SoundEffectTypes{  
      OnButtonUp,  
      NotificationPopUp,  
      NotificationClose,  
      SpellCast,  
      BoulderExplosion,  
      Screech,  
      Hit  
 }  
 public static class SoundEffects  {  
      public static void Play(SoundEffectTypes effectToPlay){  
           GetAudioSource().clip = GetSoundEffect(effectToPlay);  
           GetAudioSource().Play();  
      }  
      public static GameObject PlayInWorld(SoundEffectTypes effectToPlay, Vector3 positionToPlayAt){  
           soundObjectInstance = new GameObject("Sound Effect Object");  
           soundObjectInstance.transform.position = positionToPlayAt;  
           soundObjectInstance.AddComponent<AudioSource>();  
           soundObjectInstance.GetComponent<AudioSource>().clip = GetSoundEffect(effectToPlay);  
           soundObjectInstance.GetComponent<AudioSource>().Play();  
           soundObjectInstance.GetComponent<AudioSource>().loop = false;  
           soundObjectInstance.GetComponent<AudioSource>().priority = 1;  
           return soundObjectInstance;  
      }  
      static GameObject soundObjectInstance = null;  
      static AudioSource GetAudioSource(){  
           //if it's null, build the object  
           if(soundObjectInstance == null){  
                soundObjectInstance = new GameObject("Sound Effect Object");  
                soundObjectInstance.AddComponent<AudioSource>();  
           }  
           return soundObjectInstance.GetComponent<AudioSource>();  
      }  
      public static void SetVolume(float newVolume){  
           GetAudioSource().volume = newVolume;  
      }  
      public static float GetCurrentVolume(){  
           return GetAudioSource().volume;  
      }  
      static AudioClip GetSoundEffect(SoundEffectTypes effectToPlay){  
           switch(effectToPlay){  
                case SoundEffectTypes.OnButtonUp:  
                     return Resources.Load("MusicAndFx/ButtonUp") as AudioClip;  
                break;  
                case SoundEffectTypes.NotificationPopUp:  
                     return Resources.Load("MusicAndFx/NotificationPopUp") as AudioClip;  
                break;  
                case SoundEffectTypes.SpellCast:  
                     return Resources.Load("MusicAndFx/spellCasting") as AudioClip;  
                break;  
                case SoundEffectTypes.BoulderExplosion:  
                     return Resources.Load("MusicAndFx/BoulderHit") as AudioClip;  
                break;  
                case SoundEffectTypes.Screech:  
                     return Resources.Load("MusicAndFx/ghostbreath") as AudioClip;  
                break;  
                case SoundEffectTypes.Hit:  
                     return Resources.Load("MusicAndFx/hit24") as AudioClip;  
                break;  
           }  
           return null;  
      }  
 }  

Comments

Post a Comment

Popular posts from this blog

How To Make a Hellish Looking Sky Box

I came across this problem while constructing my scene of Hell in a little project I've been working on, and could not find a reasonable sky box on the web for what I want. Maybe I was not looking hard enough, but I ended up making nice substitute. If you think the sky box looks familiar, then your right. The Sky box I'm using is already packaged with Unity3D! To import the sky boxes Unity has made for you,  simply go to Assets>Import Package>Skyboxes.  The sky boxes will appear in your projects tab under a folder named "Standard Assets". To make this sky box, first you must find the folder containing all the sky box materials and open it up. In it will be a list of sky boxes for your disposal. To get this skybox, I decided to tweak the "StarryNight Skybox" (But the "MoonShine Skybox" looks pretty cool also!).  Select the sky box and view it under the inspector tab. Underneath the properties there will be a tint color variable allowin

Making A Laser Pointer

Want a frieking lazer pointer? BOOM. Attach a Line Renderer component to the object you have the script below attached to. (Component> Miscellaneous>Line Renderer) Code: function Update () { var lineRenderer : LineRenderer = GetComponent(LineRenderer); lineRenderer.useWorldSpace = false; lineRenderer.SetVertexCount(2); var hit : RaycastHit; Physics.Raycast(transform.position,transform.forward,hit); if(hit.collider){ lineRenderer.SetPosition(1,Vector3(0,0,hit.distance)); } else{ lineRenderer.SetPosition(1,Vector3(0,0,5000)); } } @script RequireComponent(LineRenderer) Thank  3dDude for the script. Original Source here .

How To Make A Gun Shot Sound (SFX On Unity 3D)

When it comes to audio in Unity, there are four components: Audio Clip , Audio Source , Audio Listener , and Audio Re-verb Zone . Audio Clips are the actual audio file imported into your game. Unity supports file formats: .aif, .wav, .mp3, and .ogg. When imported, you can compress them greatly, with the price of loosing some quality. You can do this by first selecting the audio clip, view it in the inspector. Under the Audio Importer component, you can switch the audio format from Native to the audio clip, to a compressed format applied by Unity. You can change how compressed the file is by dragging the bar at the bottom, then hitting apply. You can get plenty of free good SFX from a site called  freesound.org . All you have to do is create an account for free , and download all the sounds you want. I found a nice gun shot sound here . Simply download and load into your Project. Audio Source actually plays the audio clip in your scene. They are an component, so it mu