Linking up sfx to game objects

Hi everyone,
I am not able to link the sound effects to the game objects or scripts I need them to be.
What I’ve done so far is:
setting up a slider for sfx (working properly)
setting up a player for sfx (working as well) - I probably could have used only one player for music and sfx, but wasn’t too sure

SFX Slider and player are linked to the playerprefscontroller and optioncontroller.

Now, I should link the sfx in the scripts where I need them to be. I’ve tried every way I could think of and rewatched all the lessons regarding sound/music.

In the health script below, the lines commented out were the last way I’ve tried and how I could test that my slider works, but I get the (red) message that my deathSound is not assigned.

Health Script:

public class Health : MonoBehaviour
{
    [SerializeField] float health = 100f;
    [SerializeField] GameObject deathVFX = default;
    //[SerializeField] AudioSource deathSound; - this should be an array which didn't work either
    
    public void DealDamage(float damage)
    {
        health -= damage;
        if (health <= 0)
        {
            TriggerDeathVFX();
            //PlayDeathSound();
            Destroy(gameObject);
        }
    }

    private void TriggerDeathVFX()
    {
        if(!deathVFX)
        {
            return;
        }
        GameObject deathVFXObject = Instantiate(deathVFX, transform.position, transform.rotation);
        
        Destroy(deathVFXObject, 1f);
    }

   /* private void PlayDeathSound()
    {
        deathSound.volume = PlayerPrefsController.GetSFXVolume();

    }*/
    
}

PlayerPrefs:

public class PlayerPrefsController : MonoBehaviour
{
    const string MUSIC_VOLUME_KEY = "music volume";//from master to music volume
    const string SFX_VOLUME_KEY = "sfx volume";// from master sfx to sfx volume
    const string DIFFICULTY_KEY = "difficulty";
    const float MIN_VOLUME = 0f;
    const float MAX_VOLUME = 1f;

    const float MIN_DIFFICULTY = 0f;
    const float MAX_DIFFICULTY = 2f;

    public static void SetMusicVolume(float volume)
    {
        if (volume >= MIN_VOLUME && volume <= MAX_VOLUME)
        {
            Debug.Log("music volume");
            PlayerPrefs.SetFloat(MUSIC_VOLUME_KEY, volume);
        }
        else
        {
            Debug.LogError("Music volume is out of range");
        }
    }

    public static float GetMusicVolume()
    {
        return PlayerPrefs.GetFloat(MUSIC_VOLUME_KEY);
    }

    public static void SetSFXVolume(float volume)
    {
        if (volume >= MIN_VOLUME && volume <= MAX_VOLUME)
        {
            Debug.Log("sfx volume");
            PlayerPrefs.SetFloat(SFX_VOLUME_KEY, volume);
        }
        else
        {
            Debug.LogError("SFX volume is out of range");
        }
    }

    public static float GetSFXVolume()
    {
        return PlayerPrefs.GetFloat(SFX_VOLUME_KEY);
    }

    public static void SetDifficulty(float difficulty)
    {
        if (difficulty >= MIN_DIFFICULTY && difficulty <= MAX_DIFFICULTY)
        {
            PlayerPrefs.SetFloat (DIFFICULTY_KEY, difficulty);
        }
        else
        {
            Debug.LogError("Difficulty setting is not in range");
        }
    }

    public static float GetDifficulty()
    {
        return PlayerPrefs.GetFloat(DIFFICULTY_KEY);
    }
}

OptionController:

public class OptionController : MonoBehaviour
{
    [SerializeField] Slider musicSlider = default;
    [SerializeField] float defaultVolume = 0.8f;

    [SerializeField] Slider sFXSlider = default;
    [SerializeField] float defaultSFXVolume = 0.5f;

    [SerializeField] Slider difficultySlider = default;
    [SerializeField] float defaultDifficulty = 0f;


    // Start is called before the first frame update
    void Start()
    {
        musicSlider.value = PlayerPrefsController.GetMusicVolume();
        sFXSlider.value = PlayerPrefsController.GetSFXVolume();
        difficultySlider.value = PlayerPrefsController.GetDifficulty();
    }

    // Update is called once per frame
    void Update()
    {
        var musicPlayer = FindObjectOfType<MusicPlayer>();
        if (musicPlayer)
        {
            musicPlayer.SetVolume(musicSlider.value);
        }
        else 
        {
            Debug.LogWarning("No music player found....did you start from splash screen?");
        }

        var loadSound = FindObjectOfType<SFXPlayer>();
        if (loadSound)
        {
            loadSound.SetVolume(sFXSlider.value);
        }
        else
        {
            Debug.LogWarning("No sfx found....did you start from splash screen?");
        }
    }
    public void SaveAndExit()
    {
        PlayerPrefsController.SetMusicVolume(musicSlider.value);
        PlayerPrefsController.SetSFXVolume(sFXSlider.value);
        PlayerPrefsController.SetDifficulty(difficultySlider.value);
        FindObjectOfType<LevelLoader>().LoadMainMenu();
       
    }

    public void SaveandReturn()// for implementing maybe a jump back to the exact same spot during the game and save the playerprefs
    {
        PlayerPrefsController.SetMusicVolume(musicSlider.value);
        PlayerPrefsController.SetSFXVolume(sFXSlider.value);
        PlayerPrefsController.SetDifficulty(difficultySlider.value);
        //FindObjectOfType<LevelLoader>().LoadPreviousScene();// this needs to be fixed, problem being too many jumps...maybe
    }


    public void SetDefaults()
    {
        musicSlider.value = defaultVolume;
        sFXSlider.value = defaultSFXVolume;
        difficultySlider.value = defaultDifficulty;
    }
}

SFXPlayer:

public class SFXPlayer : MonoBehaviour
{
   
    AudioSource audioSource;
   
    // Start is called before the first frame update
    void Start()
    {
        DontDestroyOnLoad(this);
       
        audioSource = GetComponent<AudioSource>();
        audioSource.volume = PlayerPrefsController.GetSFXVolume();
    }

    public void SetVolume(float volume)
    {
        audioSource.volume = volume;
    }
}

Sorry for the huge amount of code:(
Any help is appreciated
cheers

Hi Patricia,

Are there any error messages in your console? Have you already tried to add Debug.Logs to your code to see what is going on during runtime?

NullReferenceException means that a reference (“link”) to an instance is missing. Double click on the error message to see to which line in your code it is referring. If you exposed a field in the Inspector, make sure that it’s not empty.

Hi NIna,
thank you for coming back to me.

I uncommented the code in my health script and the message is this:

UnassignedReferenceException: The variable deathSound of Health has not been assigned.
You probably need to assign the deathSound variable of the Health script in the inspector.
Health.PlayDeathSound () (at Assets/Scripts/Health.cs:35)
Health.DealDamage (System.Single damage) (at Assets/Scripts/Health.cs:17)
Projectile.OnTriggerEnter2D (UnityEngine.Collider2D otherCollider) (at Assets/Scripts/Projectile.cs:23)

plus, as I just noticed, it interferes with the value of my projectiles.

Here how I have set up one of my attackers

Where is the referenced AudioSource? In your Hierarchy? Does that component or its game object get destroyed at some point, for example, because the cat game object gets destroyed or because a new scene gets loaded?

That would explain the error message because your last screenshot shows that the references are there, so I’m pretty sure that the referenced object gets destroyed during runtime. The question is: When and where? Once you figured that out, the rest of the problem should be easy to fix.

Thank you again for your reply. The referenced Audio Source is in the SFXPlayer.
I need to go through the “destroying” part and probably where I link it to again.
Thank you for your help!

If you cannot figure the issue out, add the OnDestroy method to your SFXPlayer class with a Debug.Log in its code block. OnDestroy is a Unity method.

And a Debug.Log to the method which gets called via the Health component. If the Health component calls the Play method of the SFXPlayer AudioSource component, make it call a method in the SFXPlayer component and have the SFXPlayer component access the AudioSource object. This way, you will probably be able to get a bit more interpretable feedback by Unity.

ok, so far I managed to get rid of the errors, I did not get the sound to play when I want it to.
If I leave the tick on “play on awake” it plays when the enemy is spawned, if I untick, it doesn’t play at all. My health script with changes:

public class Health : MonoBehaviour
{
    [SerializeField] float health = 100f;
    [SerializeField] GameObject deathVFX = default;
    [SerializeField] AudioSource deathSound = default;
    //AudioSource deathSound; //- this should be an array which didn't work either
    
    public void DealDamage(float damage)
    {
        health -= damage;
        if (health <= 0)
        {
            TriggerDeathVFX();
            PlayDeathSound();
            Destroy(gameObject);
        }
    }

    private void TriggerDeathVFX()
    {
        if(!deathVFX)
        {
            return;
        }
        GameObject deathVFXObject = Instantiate(deathVFX, transform.position, transform.rotation);
        Destroy(deathVFXObject, 1f);
    }

   private void PlayDeathSound()
    {
        Debug.Log("Am I being called1?");
        if (!deathSound)
        {
            return;
        }
        deathSound.volume = PlayerPrefsController.GetSFXVolume();
        deathSound.Play();
        Debug.Log("Am I being called2?");

    }
    
}

my two debug.log’s are being called.

Somehow, I cannot shake off the feeling that I am approaching this the wrong way…anyways, I will continue this tomorrow…

Could it be that the AudioSource is attached to the enemy?

If the AudioSource is attached to the enemy, and the enemy game object gets destroyed, the AudioSource gets destroyed along with it, and the sound cannot be played.

Probably, I believe I need to set it up on my sfxplayer and then “just” make a reference to it in the health script to playoneshot when the enemy dies.
I will try to do this in the next couple of days and let you know if I managed to do so.
Thank you so much for your help and support again

I think I solved the problem with ClipAtPoint, not sure though if I did the right thing.
The volume is controlled by my sfx manager.
I appreciate if you, Tina, or anybody else knowing what the are doing could quickly check. Thank you in advanced, here the code:
Health Script:

public class Health : MonoBehaviour
{
    [SerializeField] float health = 100f;
    [SerializeField] GameObject deathVFX = default;
    [SerializeField] AudioClip deathSound = default;
    private float deathSoundVolume = 0f;

    public void Start()
    {
        deathSoundVolume = PlayerPrefsController.GetSFXVolume();
    }
     
    public void DealDamage(float damage)
    {
        health -= damage;
        if (health <= 0)
        {
            Die();
        }
    }

     private void Die()
    {
        TriggerDeathVFX();
        Destroy(gameObject);
    }

    private void TriggerDeathVFX()
    {
        if(!deathVFX)
        {
            return;
        }
        GameObject deathVFXObject = Instantiate(deathVFX, transform.position, transform.rotation);
        Destroy(deathVFXObject, 1f);
        AudioSource.PlayClipAtPoint(deathSound, Camera.main.transform.position, deathSoundVolume);
    }
}

SFXPlayer:

public class SFXPlayer : MonoBehaviour
{
    AudioSource audioSource;
    AudioSource deathSound = default;
   

    // Start is called before the first frame update
    void Start()
    {
        DontDestroyOnLoad(this);
        audioSource = GetComponent<AudioSource>();
        audioSource.volume = PlayerPrefsController.GetSFXVolume();
    }

    public void AudioClip()
    {
        deathSound.volume = audioSource.volume;
    }
 
    public void SetVolume(float volume)
    {
        audioSource.volume = volume;
    }
}

If it works, you did the right thing. :wink:

I briefly skimmed your code, and I did not spot any issue. For this reason, I would suggest to consider the problem solved unless you see a problem with your solution.


See also:

well, if you didn’t see anything wrong with my code, then it is solved . Thank you so much for your support :slight_smile:

You’re welcome. Have a nice weekend. :slight_smile:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms