- Home /
Almost any object can play a sound. They all need an Audio Source?
So, simple set up:
My game has 100 objects spawned.
These objects have a chance to play an ambient sound from an array of audio clips.
Do all 100 objects need an Audio Source? I mean, for a start, having a big speaker icon over every object in the game is really ugly in terms of the interface. But it also seems a bit inefficient.
Is there not a sort of global Audio Source for when you just want to play a sound? These are 2D sounds, they don't need any spatial calculations.
What do most people do for this? Create a global "Sound Manager" object and grab it in a script as a sole audio source? What is my best option?
Also, bonus question: Many of my objects come from prefabs. The prefab has a public array that defines the sound clips. If I spawn 50 of these prefabs with 10 items in the array, is that creating 500 sound clip objects or does it use the prefab for reference while the array is unaltered (i.e. just 10 sound clips)? Again, just thinking efficiency.
Answer by CanisLupus · Jan 03, 2015 at 12:31 PM
They don't all need an AudioSource. :)
1. You could call AudioSource.PlayClipAtPoint(audioClip, position, volume), which is a static method that temporarily creates an object for the sound at a certain position (and then deletes it when the sound completes). This way you don't need any AudioSource at all, and you can still play more than one sound at a time (I don't know if that is important for you). If your sounds play very frequently you might want to avoid creating lots of objects, though, but depending on the performance required it might not make a difference. Also, a small disadvantage: you can't get a reference to the dynamically created sound, so there's no pausing or stopping the sound.
2. You could also create a single object in the scene that contains the sound references (the array of AudioClips) and is called by the objects when they need to play a sound. It's a kind of "sound manager", like you mentioned, but for this purpose only. This avoids wasting memory with arrays of sound references in each object (see "bonus answer" below). You can still use AudioSource.PlayOneShot in the manager if you require many sounds at once (same disadvantages as above), or add an AudioSource component to the manager.
As to how you'll get the reference to this manager from each object (seeing as they are prefabs that get instantiated), you have many ways. The script that creates your objects from the prefab might store in them (actually, in a script they have) the reference to the manager. One of the best ways I know is to use events and a global events class (see this example), and each object throws an event when it wants to play a sound, which the manager acts on. This doesn't even require a reference to the manager. I'm avoiding "Find" solutions on purpose, as they are error-prone and rather slow.
3. Yet another way is to store your sounds in the Resources folder and then call Resources.Load("relative path to audio clip inside Resources") when a sound is needed. This would require no references to sounds, but would require usable names for them. This way, you could keep your objects (with no arrays), and then load the sound and use PlayOneShot (no manager is needed). It also only loads sound files as needed. The overhead of calling Resources.Load
to load a sound always seemed negligible in my use cases, but that depends on the scenario, of course.
All of these solutions sound reasonable to me. :) I have no strict preference, as it depends on the exact situation. Bottom line is: you should avoid having an array of references in every object if they are all the "same". Also avoid an AudioSource per object if many are created (I think 50 already qualifies :)).
Bonus answer: the audio clips themselves (audio waves) are referenced from your project, so you'll only have 10 sounds wasting memory, even if you have 50 objects. However, each of your instantiated objects will contain an array of 10 references, so that totals 500 references and, in that case, you might want a better solution. :)
(This doesn't exactly answer your bonus question, though. I wish I could tell you if the AudioClips in the arrays are simple references to the sound files in the project or are some kind of wrapper that occupies further memory. In the first case, all your objects will have an array of references, and that's it. 500 references and 10 sounds. In the second case, an object of type AudioClip has to be created for each sound reference, so 500 sound references, 500 AudioClips and 10 sounds. I'm not sure which one it is.)
Wow, a lot more detailed than I was hoping for. Thank you very much! I did end up creating a "Sound $$anonymous$$anager" last night, but I may give the event method a go ins$$anonymous$$d. AudioSource is also very handy to know about ^^ Aside from that I hadn't even considered that a single Audio Source would not be able to play multiple sounds at once. Seems really obvious now though.
You're welcome! :) If you want control over the sounds (Pause, Stop, etc), an object can also have multiple AudioSource components, each with a different clip. You can call GetComponents< AudioSource >()
to get every one in a GameObject (or add them dynamically with AddComponent< AudioSource >()
and store the returned AudioSources in a List, for example). There are many ways to handle this problem, which is both good and bad for you. ;) Good luck!
Indeed, lol.
I was wondering, in terms of loading a sound resource when playing the sound, would that mean Unity would play the sound in the AudioSource and then unload the sound from memory when it's done? (assu$$anonymous$$g no other reference is present) I realise this is more about Unity's garbage collection rather than sounds :P
I also assume you can't load a sound more than once into memory? $$anonymous$$y hope is a second load call would just reference the existing memory location rather than allocating more memory. (edit: From what I am reading it looks like they'd all reference the same memory ^^)
@Fikule If you set an AudioClip that was loaded with Resources.Load in an AudioSource, Unity will never unload the sound, as a reference to it still exists. Same thing if you store it in a variable. If you load and then play it with PlayOneShot... well, I'll be honest with you: I don't know. :) I believe Unity unloads unused assets loaded from Resources when the scene changes (they are "unused" if they don't persist to the next scene), but I'm not sure of its behavior otherwise, or how the garbage collector would act. You can call Resources.UnloadAsset over some loaded object if you want to force the unload yourself.
Your research seems correct. :) A call to load the same clip would not duplicate the memory occupied; only a reference would be created. Sounds and textures (for example) co$$anonymous$$g from your project only exist once in memory (if at all loaded). You can, however, have multiple materials that reference the same texture, the same way that multiple AudioSources can reference the same sound.
Is this still a thing? $$anonymous$$y version of UnityEngine (v5.something) seems to not have this as a static function!
I would imagine that you might be able to write an extension method to perform the same task, but then you'd need some sort of static coroutine to go with it for deleting the temp object after the sound plays, etc., etc., messy nonsense program$$anonymous$$g
You are right! I realize now that I meant to say AudioSource.PlayClipAtPoint(clip, position, volume=1f)
. That is the correct static method, though it requires a position for the sound (that is expected due to possible positional effects). PlayOneShot, on the other hand, does require an existing source, and will play the sound at its location. I'm sorry for the confusion! I'll update the answer now.
Your answer
Follow this Question
Related Questions
Play AudioSource Backwards 2 Answers
Play sound at scene change time 1 Answer
Is there a way to create a random Audiosource loop? 2 Answers
Question about audio (AudioSource). My ingame sound doesn't sound like the original audio file? 3 Answers
Only able to play a single sound through AudioSource. 1 Answer