Home

Awesome

SoundManager component for Unity3D

With modulation ranges, AudioSource pooling, playing at world coordinates, and even playing while following a Transform

Version information: Tested in Unity 2018.3, requires scripting runtime set to '.Net 4.x equivalent' (uses C# 7 features)

My take on a light-weight sound manager for Unity3D. Admittedly I haven't looked into any implementations on the Asset Store, etc., because I didn't want to spoil the fun of writing mine from scratch. So this is just a small, relatively simple component with solid core features that should perform reliably and efficiently.

I've been using it in my project for quite some time, and I'm a satisfied customer, so to speak, so I decided to share it.

Pro tip: It's totally not spaghetti code. ;) I tried to generally separate the responsibilities, but without creating a confusing amount of classes/files, so I pretty much nested everything into a single class. I think it's a relatively maintainable/extensible design, so you shouldn't have a very hard time adding new features if you wanted. (I also have some ideas for additional features, but those would require some more book-keeping, plus classes where nesting them is not really justifiable.)

Note that the comments in the code are a bit excessive if you're an experienced developer. I just tried to help others too to understand it better.

Update1: I added the capability of Transform tracking playback in the form of two new public methods. This means that the SoundManager can now be used for moving objects too. For this addition I refactored the class internally. Short testing shows this new feature to be working well, but please inform me of any bugs.

Update2: I encapsulated all debug log messages into a separate class, and added a logging setting to the Inspector. So you can turn off logging for deployed builds in a way that completely avoids string operations and allocations (since all debug messages are constructed inside this helper class). Available logging settings: None, LogOnlyInEditor and LogAlways.

Update3: I swear I'll stop adding these update sections here. :) Anyhow, I refactored the SoundManager class again. Plus I changed the public method signatures. The most visible change is that the methods now return the sound type in the callback, so you can route multiple playback finished notifications into a single method, and check there which one was finished. In terms of refactoring, internally the class changed a lot; basically I encapsulated all AudioSource handling responsibilities into a separate nested class, and cut out all code duplication in the method overloads.

Quick overview of Inspector pane:

SoundManager pane in Inspector

Rationale

Pretty much everybody uses some sort of audio or sound manager, from what I'm aware of. But if you're not sure what's the point:

Features

Usage examples

Just for illustrative purposes, because it's really obvious and straightforward to use.

(Note that the callback shown is obviously available as an optional parameter on all of the method overloads, not just on the longest. Also note that there is an overload for setting pitch and volume override for the simple PlaySound() method too.)

Setup

  1. Specify your sound types by editing the GameSound enum. This means that all the sounds you want to be able to play need to be named in this enum. This obviously has some drawbacks, for example you can't just nilly-willy delete values from the enum and shift the rest of the values, because Unity actually saves the enum values as an integer. But using the enums is very comfortable, so I personally like this approach. If you want, you can look into associating explicit integer values to your enum values, and then it's safer to modify it.

  2. Add the SoundManager script as a component to a GameObject. This hardly needs an explanation, if you have ever seen a computer before.

  3. Add entries to the SoundManager component's Sound List array in Inspector. Change the 'None' sound type to an actual sound type, select your AudioClip, and set your pitch and volume ranges. Note that - obviously - Unity stores everything you add here with the given instance of the component, so you'd probably want to make a prefab from it, and use that in your scenes, or set it not to destroy on load.

    (I have a ScriptableObject-based architecture that decouples configuration data from components, and possibly I'll convert my SoundManager to use that, but I felt it would complicate matters too much if I included it here. I intended to share this just as a simple but powerful component.)

  4. You're ready to call SoundManager's PlaySound() and PlaySoundPositioned() methods.

    (Note that SoundManager, as it is provided here, uses a very simple singleton implementation that exposes a static instance of itself, called Instance. This instance is created when the class is first instantiated, and any further instantiation (which shouldn't happen to begin with) will destroy itself. You can just change this to however you prefer to access your service components. For example you can just inject the SoundManager as a dependency into your classes through their constructor. Just kidding, since you can't use constructors at all in your Unity MonoBehaviour classes. ;P )

What this component doesn't have

Notes

Let me know if you happen to find any bugs, or spot any sort of weirdness with the code. I'm coming from normal .Net development, so I can't rule out the possibility that I'm unaware of some weirdness in how Unity handles lifecycle of objects, coroutines, or who knows what.

Licence

Since it seems some people are using this, and actually someone asked me earlier about the licence... I added a permissive MIT licence for your peace of mind.