Playing Audio Clip Once

I’m working on a game that will play a sound when the player collects a crystal. I’ve tried using the PlayOneShot line to make it play only once but that doesn’t seem to work. The only time I get a sound is when it is in the update function, but that just keeps looping it. I’ve attached the code to this post for your convenience. Thanks in advance!

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

public class GameManager : MonoBehaviour
{
  
    public GameObject player;
    public GameObject gameOverMenu;
    public GameObject levelCompleteMenu;
    public GameObject crystal;
  
    //The following three objects are for the sound I want to play
    public GameObject collectable;
    public AudioClip coinCollect;
    public AudioSource collectableSound;
  
    // Start is called before the first frame update
    void Start()
    {
      
    }

    // Update is called once per frame
    void Update()
    {
        if(player == null)
        {
            //Restart();
            gameOverMenu.SetActive(true);
        }

        if(crystal == null)
        {
            levelCompleteMenu.SetActive(true);
        }
    }

    void Restart()
    {
        SceneManager.LoadScene("LevelOne");
    }

    //This function is for the sound that I am trying to play
    void Collectable()
    {
        if(collectable == null)
        {
        collectableSound.PlayOneShot(coinCollect);
        }
    }
}

Well, your Collectable() method isn’t being called by anything in the code you gave, so that’s why it won’t trigger the sound. As you found out already, putting it in Update() will work, but after the collectable is picked up it will always be null which means the sound gets played each frame. I can suggest a couple of options -

For the way you have it set up, the fix would be to add a bool levelComplete; flag to your class variables, then adjust your Collectable() method like so:

    //This function is for the sound that I am trying to play
    void Collectable()
    {
        if(collectable == null && levelComplete == false)
        {
            collectableSound.PlayOneShot(coinCollect);
            levelComplete = true;
        }
    }

Then if you call Collectable() inside Update(), you should have the sound play only once immediately as the crystal is picked up. You just need to reset levelComplete back to false when you move to a new level.

Possibly a more efficient way of doing it is to play the sound effect at the same point you handle the collision that collects and destroys the crystal object. Assuming you have a script on your player object that is handling the collision checks against the collectable, you can move the AudioClip and AudioSource in there and play it inside OnTriggerEnter() or OnCollisionEnter() method - whichever you’re using.

Hope this helps!

Thanks Telkir for the instructions! It worked like a charm.