Question regarding audio

Is it possible to continue playing audio even after the source object is destroyed? If so, how can that be done?
I have a projectile that gets destroyed when it collides with any solid. When it gets destroyed, the sound cuts off.

Hi @DordusRising Its probably a much better idea to use an audio source that isn’t on the object being destroyed. There’s no sense in instantiating an AudioSource component every time the object is instantiated. Rather, create a globally available audio source. This way, you can tell the spawned projectile to use that audio source instead, and you won’t have any cutoff issues like you’re describing.

The best practice for accomplishing this relies on what’s called a singleton game manager, which contains a reference to either an audio manager (more complex but overall a better solution) or an audio source (simpler to set up but limiting in scope). The game manager’s instance is then used directly by the script which needs to play audio.

If this sounds confusing or like a lot, no worries I’ll step you through it.

First, what is a singleton? A singleton is a single instance of a game object/component that makes sure its the only one of its kind. It also will persist between scene changes. Here’s a more complete description of a singleton.

A game manager singleton is a single instance of a script/component that handles a lot of the overall chores required for your game. Typical things in a game manager are: other managers (like an audio manager), current play state (paused, in menu, in play, etc), links to settings scriptable objects, and more. The nice thing about using a game manager singleton is that it can be accessed and referenced from any other script during app execution.

How to create a singleton? First, you’ll need some code which handles the creation of the singleton instance

`


using UnityEngine;

namespace SingletonLibrary
{
public class Singleton : MonoBehaviour where T : MonoBehaviour
{
private static bool _Shutdown = false;
private static object _Lock = new object();
private static T _Instance;

    public static T Instance {
        get {
            if(Singleton<T>._Shutdown) {
                Debug.LogWarning("Singleton<" + typeof(T) + ">: Instance: Shutdown enabled. Returning null.");
                return null;
            }

            lock(Singleton<T>._Lock) {
                if(Singleton<T>._Instance == null) {
                    Singleton<T>._Instance = (T)FindObjectOfType(typeof(T));

                    if(Singleton<T>._Instance == null) {
                        GameObject tempSingleton = new GameObject();
                        Singleton<T>._Instance = tempSingleton.AddComponent<T>();
                        tempSingleton.name = typeof(T).ToString() + " (Singleton)";
                        GameObject.DontDestroyOnLoad(tempSingleton);
                    }
                }
                return Singleton<T>._Instance;
            }
        }
    }

    private void OnApplicationQuit()
    {
        Singleton<T>._Shutdown = true;
    }

    private void OnDestroy()
    {
        Singleton<T>._Shutdown = true;
    }
}

}

`

Next, you’ll need to create the game manager script, whose class derives from the singleton. Here’s how to do that:

`

using UnityEngine;
using SingletonLibrary;

namespace Libraries.Managers
{
public class GameManager : Singleton
{

}

}

`

Once you’ve saved this, go back into the unity editor, create a new empty game object called GameManager. Then, assign the GameManager script to it.

You now have a game manager singleton! Its not ready for the audio playback, but we’re really close now :slight_smile:

I’m going to show you setting up the audio source here for simplicities sake. Now, inside the game manager class block, add a public audio source, like:

`


using UnityEngine;
using SingletonLibrary;

namespace Libraries.Managers
{
public class GameManager : Singleton
{
public AudioSource audioSource = null;
}
}

`

Once saved, go back into the unity editor. Now, create a child object of the game manager object. Add an audio source to this object. Then, assign that audio source to the game manager audio source parameter. Once set, you’ll now be able to play one shot audio clips from anywhere else in your code.

How to do that? Let’s assume your projectile class contains the audio clip parameter, which it will play. And we’ll assume that the parameter is called ‘projectileClip’. To play ‘projectileClip’ from the projectile script, simply call PlayOneShot on the audio source from the game manager instance using the clip, as:

GameManager.Instance.audioSource.PlayOneShot(this.projectileClip);

And that’s it.