Keith Power
Keith Power

Reputation: 14151

Unity playing AudioClip Null Reference

I have an AudioManager.cs script which I use the Singleton pattern with. From my SplashController.cs script I an trying to play an audio clip AudioManager.Instance.PlayMusic(intro); but I get an error with this line NullReferenceException: Object reference not set to an instance of an object The audio files does exist because I do a Debug.Log(introClip);

I have checked while the game is running and the musicSource = gameObject.AddComponent<AudioSource>() as AudioSource; is created by the AudioManager

Could it be a timing issue where the AudioSource; is created after the audio clip is being played. I have run similar code before and I have not run onto this issue.

AudioManager.cs

using UnityEngine;
using System.Collections;
using UnityEngine.Audio;

public class AudioManager : Singleton<AudioManager>
{

    [Header("Mixer Groups")]
    public AudioMixer masterMixer;
    public AudioMixerGroup masterGroup;//The master mixer group
    public AudioMixerGroup musicGroup;//The music mixer group
    public AudioMixerGroup sfxGroup;  //The sfx mixer group

    public int lowestDeciblesBeforeMute = -20;

    AudioSource musicSource;          //Reference to the generated music Audio Source
    AudioSource musicSource2;         //Reference to the generated music Audio Source
    AudioSource sfxSource;            //Reference to the generated sfx Audio Source

    private float musicVolume = 1;
    // Multiple musics
    private bool firstMusicSourceIsActive;

    #region Public Enums

    public enum AudioChannel { Master, Music, Sfx }

    #endregion Public Enums

    void Awake()
    {

        //Generate the Audio Source "channels" for our game's audio
        musicSource = gameObject.AddComponent<AudioSource>() as AudioSource;
        musicSource2 = gameObject.AddComponent<AudioSource>() as AudioSource;
        sfxSource = gameObject.AddComponent<AudioSource>() as AudioSource;

        //Assign each audio source to its respective mixer group so that it is
        //routed and controlled by the audio mixer
        musicSource.outputAudioMixerGroup = musicGroup;
        musicSource2.outputAudioMixerGroup = musicGroup;
        sfxSource.outputAudioMixerGroup = sfxGroup;

        // Make sure to enable loop on music sources
        musicSource.loop = true;
        musicSource2.loop = true;

    }


    // Play a single clip through the sound effects source.
    public void PlaySfx(AudioClip clip)
    {
        sfxSource.PlayOneShot(clip);
    }

    // Play a single clip through the music source.
    public void PlayMusic(AudioClip clip)
    {
        musicSource.clip = clip;
        musicSource.Play();
    }
}

SplashController.cs

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class SplashController : MonoBehaviour {
    public float waitTime = 5;
    public AudioClip introClip;

    // Use this for initialization
    void Start () {
        Debug.Log(introClip);
        AudioManager.Instance.PlayMusic(introClip);
        StartCoroutine(LoadMenu());
    }

    private IEnumerator LoadMenu()
    {
        yield return new WaitForSeconds(waitTime);
        SceneManager.LoadScene(1);
    }
}

Singleton.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    public static T Instance { get; private set; }

    protected void Awake()
    {
        if (Instance == null)
        {
            Instance = this as T;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

Upvotes: 0

Views: 2318

Answers (2)

Aaron Franke
Aaron Franke

Reputation: 4092

The problem with your approach is that the void Awake method in the derived class is overriding the protected void Awake in the base Singleton<> class.

To make your approach work, you need to call the base method from the new one:

void Awake()
{
    base.Awake();
    // The rest of AudioManager.Awake() here.
}

Upvotes: 0

Iggy
Iggy

Reputation: 4888

You could try using a lazy singleton:

using UnityEngine;

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    protected static T instance;

    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                instance = (T)FindObjectOfType(typeof(T));

                if (instance == null)
                {
                    Log.Error("An instance of " + typeof(T) + " is needed in the scene, but there is none.");
                }
            }

            return instance;
        }
    }
}

Upvotes: 1

Related Questions