There are at least two ways to add sound effects in Unity. The first, somewhat more obvious way is to use the Audio Source component. Like any other component, the Audio Source component is added to an object in the Inspector.
The first field is the Audio Clip field. You can drag and drop the Audio Clip directly into this field. If you only have one sound effect you intend to use for the game object, this most certainly makes sense. However, you don’t have to populate this field now. You can instead assign it programmatically during game run. This is especially helpful if you need to switch between various sound effects.
As with any component, there are a variety of settings that allow you to refine how the audio clip will be managed. Two of immediate use, however, are the “Play On Awake” and “Loop” checkboxes. Loop does exactly what it says and continuously replays the assigned audio clip. We used this setting for our background music. The Play On Awake plays as soon as the game object this Audio Source is attached to is made active. This can be very useful for things like laser fire, explosions, etc. Then, as soon as the game object is triggered, the sound effect goes off immediately, with no additional programming. However, if the game object is going to be around for a while, such as an enemy ship or asteroid, then you will want this to be unchecked so you can invoke it based on some other action.
The code for this is straight forward.
AudioSource myAudio = GetComponent<AudioSource>();
if (myAudio == null) { Debug.LogError("Audio Source is NULL"); }
else { myAudio.Play(); }
There is just a teensy-weensy little problem with this process though. Often times, the sound effect we need occurs because a game object is destroyed or collected. This means, before the sound can be played, the object is destroyed. When that happens, there is a bit of additional trickery needed. When we call the Destroy()
method we put a delay long enough for the sound clip to play. Of course, we want the object to appear to be destroyed immediately and obviously no longer interact with other game objects. So, what we have to do is hide the game object instead.
Collider2D myCollider = GetComponent<Collider2D>();
Renderer myRenderer = GetComponent<Renderer>();
if (myCollider == null) { Debug.LogError("Collider is NULL"); }
else { myCollider.enabled = false; }
if (myRenderer == null) { Debug.LogError("Renderer is NULL"); }
else { myRenderer.enabled = false; }
Destroy(this, 2.4f);
When we disable the Renderer, the game object disappears from the screen. However, it is still there, so we also disable the Collider to ensure it does not interact with anything else. We then destroy the game object after the time (in seconds) indicated by the second argument to the Destroy()
method.
There is a second way to do this as well, though it has its own quirks. Instead of adding an AudioSource component, you can invoke AudioSource directly using the PlayClipAtPoint()
method which will automatically create an AudioSource object, then dispose of it immediately. The code above can then be replaced with the following.
[SerializeField] private AudioClip myAudioClip;
AudioSource.PlayClipAtPoint(myAudioClip, transform.position, 1f);
Destroy(this.gameObject);
The first argument for the PlayClipAtPoint()
is the audio clip asset to be played. The second is the position in world space to play the sound, in this case, the position of the game object being destroyed. The last argument is a volume control from zero to one, one being the loudest. Using this method allows us to immediately destroy the calling game object, because the AudioSource is attached to the world space, rather than the game object itself.
The quirk in this method is the second argument to the PlayClipAtPoint()
method. Initially, it would seem sensible to play the sound effect at the position of the game object. In some instances, this may be exactly what you want. In other cases, say a 2D space shooter or platformer, this will likely have the undesirable side effect of making the sound effect vary in volume, including being too soft to hear. The reason for this is because this method takes into account the distance from the main camera. The farther away it is, the softer the sound.
The fix, at least in my case, is to reset the position of the sound effect to be in the same place as the main camera. Making our code above this, instead.
[SerializeField] private AudioClip myAudioClip;
AudioSource.PlayClipAtPoint(myAudioClip, Camera.main.transform.position, 1f);
Destroy(this.gameObject);
If you search the vast inter-web, you may well find some fairly elaborate formulas for the second argument instead. Depending on exactly what you want, those may be more suitable. In my case however, I just wanted the sound effect to be the same volume as all the others. Thus, positioning the sound to be right on top of the main camera was the simplest, most convenient location to place it.
So, crank up the sound and game on!