Search code examples
c#unity-game-engineaudio-source

How to change DontDestroyOnLoad'ed AudioSource's AudioClip on a new scene?


I have couple of different scenes and I would like to play different tunes in specific scenes. I created a game object and attached an audio clip and a script. The script basically keeps Unity away from destroying. So it can play on different scenes.

using UnityEngine;

public class OSTPlayer : MonoBehaviour
{
    private static OSTPlayer instance = null;

    private static OSTPlayer Instance
    {
        get { return instance; }
    }

    private void Awake()
    {
        if (instance != null && instance != this)
        {
            Destroy(this.gameObject);
            return;
        }
        else
        {   instance = this;   }
        DontDestroyOnLoad(this.gameObject);
    }
}

On a specific scene, I would like to change the audio clip, so I can play a different sound file. I wrote a code below (attached to a empty game object) and it looks it changes the audio clip. But there is no sound coming, like stop playing.

using UnityEngine;
using UnityEngine.SceneManagement;

public class StreetNavigate : MonoBehaviour
{
    public AudioClip clip1;//I am dragging n dropping from the editor

    private AudioSource BGMaudioSource;

    private void Start()
    {
        BGMaudioSource = GameObject.FindGameObjectWithTag("OST1").GetComponent<AudioSource>();
        BGMaudioSource.clip = clip1;
    }
}

Am I doing mistakes or what is the problem?


Solution

  • Note that only changing the clip will have no effect.

    Assigning clip with a new audio clip does not instantly change the clip that is being played.

    You also have to (re)start playing it via Play!


    To make things a bit easier:

    You already have a singleton pattern so you could simply make it public and do

    public class OSTPlayer : MonoBehaviour
    {
        // If possible already reference this via the Inspector
        [SerializeField] private AudioSource _audioSource;
    
        public AudioSource AudioSource => _audioSource;
    
        // Others can only read
        // Only this class can set the value
        public static OSTPlayer Instance {get; private set;}
    
        private void Awake()
        {
            if (instance != null && instance != this)
            {
                Destroy(this.gameObject);
                return;
            }
             
            instance = this;
            DontDestroyOnLoad(this.gameObject);
    
            // As fallback get it on runtime ONCE
            if(!_audioSource) _audioSource = GetComponent<AudioSource>();
        }
    
        public void PlayClip(AudioClip clip)
        {
            _audioSource.clip = clip;
            _audioSource.Play();
        }
    }
    

    and then in any script you can simply access it via

    OSTPlayer.Instance.AudioSource.clip = clip;   
    OSTPlayer.Instance.AudioSource.Play();
    

    Or remove the public access to the source and use the method I already added

    OSTPlayer.Instance.PlayClip(clip);