Every year I have to work and work to convince my students to add SFX them to their games. They resist and see it as a waste of time. They value graphics over audio. But when they finally add the SFX - it's magic! The "plunk" of an object being placed or the "click" of a button adds so much to the game!
Implementing SFX can be a messy process. I'm pretty confident that I DO NOT have the best solution, but it's a better solution that I had a few years ago. So I thought I'd toss out some info out to the winds of the interwebs on my approach to adding SFX within Unity.
I'm not procedurally generating sounds or anything half that interesting. I'm just playing clips but doing so with some variation in the clip, volume, and pitch. I do this with a custom class (not a monobehavior) that allows easy and quick adjustments in the Unity inspector.
The image of the inspector is from my current project and uses Odin Inspector - which is why the list looks different.
The code for the clip options is pretty sort and sweet. I've added two functions to clean up the implementation for when a clip needs to be played.
The "PlaySFX" function has two parameters, the first is the AudioSource of where the clip will be played and the second is a boolean that prevents or allows the current clip (if any) to end and the new clip to be played. UI sounds interrupting other UI sounds is generally okay but sounds such as explosions getting clipped by another explosion tends to breaks player immersion.
In some cases, I have created or cloned AudioSources to allow as many concurrent SFX as needed - but that's a whole other post. It's actually not too hard either.
Within the function the volume and pitch are both varied randomly. So no two button clicks (or other SFX) are identical, but if the variation is kept small they also sound similar avoiding possible confusion by the user that a new event has occurred.
New instances of the SFX can then be created for different actions. I keep mine private and call them via event, but allowing them to be public could work as well.
Next, I create a private function for each type of action. This private function will get called by an event.
Each of these functions can then subscribe to events that are called on other objects.
While this does require a bit more coding, it makes for a very clean and non-spaghetti like code base.
You can check out my full script on PasteBin.