Figured out some things about Audioclips

EDIT: see comment below for explanation

I’ve figured out that PlayOneShot doesn’t work for collision sounds via OnCollisionEnter function if you have OTHER audioclips going through Update in a separate Audio function activated by user input via if statements. In this scenario, only input sounds will play.

Instead if I move the call to the Audio function away from update and into the input functions (which refer to Update anyway) it works… WHYYYY???

that makes no sense to me o_O

using UnityEngine;
using UnityEngine.SceneManagement;

public class Rocket : MonoBehaviour
{

    //Member variables
    Rigidbody rigidBody;

    [SerializeField] AudioClip Engine;
    [SerializeField] AudioClip Rotate;
    [SerializeField] AudioClip Die;
    [SerializeField] AudioClip winLevel;
    AudioSource audioSource;
    
    
    [SerializeField] float rcsThrust = 220f;
    [SerializeField] float mainThrust = 50f;
    [SerializeField] float upThrust = 50f;

    bool wonLevel = false;
    bool died = false;


    enum State {alive, dying, transcending};
    State state = State.alive;

    //[SerializeField] float rotateForce = 20f;

    // Start is called before the first frame update
    void Start()
    {
        rigidBody = GetComponent<Rigidbody>();
        audioSource = GetComponent<AudioSource>();
                
    }

    // Update is called once per frame
    void Update()
    { if (state == State.alive)
        {
            ThrustShip();
            RotateShip();
            
        }

        //Audio();    //IF I CALL AUDIO FUNCTION FROM HERE, 
                          //THE "DIE" AND "WINLEVEL" SOUNDS WON'T PLAY

    }

    private void ThrustShip()
    {
        if (Input.GetKey(KeyCode.Space) )
        {
            rigidBody.AddRelativeForce(Vector3.up * mainThrust);
            rigidBody.AddForce(Vector3.up * upThrust);
            Audio();   //INSTEAD IF I CALL AUDIO FROM HERE EVERYTHING WORKS
        }
                
    }
    private void RotateShip()
    {
        rigidBody.freezeRotation = true;


        float rotationThisFrame = rcsThrust * Time.deltaTime;

        if (Input.GetKey(KeyCode.A))
        {

            transform.Rotate(Vector3.forward * rotationThisFrame);

        }
        else if (Input.GetKey(KeyCode.D))
        {
            transform.Rotate(-Vector3.forward * rotationThisFrame);

        }

        rigidBody.freezeRotation = false;
        Audio();  //FROM HERE WORKS TOO 
    }


    void OnCollisionEnter(Collision collision)
    {

        if (state != State.alive)

        {
            return;
        }


        switch (collision.gameObject.tag) 
        {
            case "Friendly":
                //do nothing
                break;

            case "Finish":
                state = State.transcending;
                              
                audioSource.Stop();
                audioSource.PlayOneShot(winLevel);
                Invoke("LoadNextScene", 5f);
                break;

            case "Untagged":
                state = State.dying;
                                
                print("playaudio");
                audioSource.Stop();
                audioSource.PlayOneShot(Die);    
                Invoke("LoadStartScene", 5f);
                break;


        }
    }

    private void LoadStartScene()
    {
        SceneManager.LoadScene(0);
    }

    private void LoadNextScene()
    {
        SceneManager.LoadScene(1);
    }



    
    
    
    
    
    
    
    void Audio()
    {
        if (Input.GetKey(KeyCode.Space) && state == State.alive && !audioSource.isPlaying)
        {
            
            audioSource.PlayOneShot(Engine);
        }

         if (Input.GetKeyUp(KeyCode.Space) ||  state == State.dying || state == State.transcending)
        {
            audioSource.Stop();
        }





       /* if (died == true && !audioSource.isPlaying )
        {

            print("dead");
            audioSource.Stop();
            audioSource.PlayOneShot(Die);           
            died = false;
            
        }*/

        if (Input.GetKeyDown(KeyCode.A) && state == State.alive)
        {
            audioSource.PlayOneShot(Rotate);
        }

        if (Input.GetKeyDown(KeyCode.D) && state == State.alive)
        {
            audioSource.PlayOneShot(Rotate);
        }


       /* if (wonLevel == true && !audioSource.isPlaying)

        {
            audioSource.PlayOneShot(winLevel);
            wonLevel = false; 
                       
        }*/



    }

}

Ok, so I learnt a hell of a lot about how audioclips work just by trying to go against Ben’s code because I wanted all my audio in one function. This is a final working version of my code, but careful: if you had a second “long” sound like the thrust, we may have problems.

This is because we include (as in Ben’s code) the condition “!audiosource.isplaying” to avoid layering, however this actually means that we only play the sound IF we are pessing the button AND IF there is no sound from ANY of the audio clips playing (they are held in the same audiosource). If there is sound the clip will not play.
As the thrust is a long drone sound, once it has started playing, it doesn’t really matter if we have a moment of silence (!audioSource.isPlaying) because our clip will still be playing for its minute-long duration, however if we had a secondary drone in the background from the same audiosource, the engine clip would not start because the “!isPlaying” condition would not be met.

Another interesting matter is trying to get the explosion to sound without cutting out. If we put state == State.dying as a condition, our file may sound more than once, so what I did was create a “bool Died” set to true when we collide with objects. Then we immediately set it to false after telling the audio to playback. Problem is, then the explosion audio clip (which is quite long) sometimes gets cut off too soon (bool Died is set too soon not giving audio clip time to play). Solution: if (audioSource.isplaying) {died == true}, then immediately after we set it to false.

using UnityEngine;
using UnityEngine.SceneManagement;

public class Rocket : MonoBehaviour
{

    //Member variables
    Rigidbody rigidBody;

    [SerializeField] AudioClip Engine;
    [SerializeField] AudioClip Rotate;
    [SerializeField] AudioClip Die;
    [SerializeField] AudioClip winLevel;
    AudioSource audioSource;
    
    
    [SerializeField] float rcsThrust = 220f;
    [SerializeField] float mainThrust = 50f;
    [SerializeField] float upThrust = 50f;

    bool wonLevel = false;
    bool died = false;
    
    enum State {alive, dying, transcending};
    State state = State.alive;

    

    void Start()
    {
        rigidBody = GetComponent<Rigidbody>();
        audioSource = GetComponent<AudioSource>();
                
    }

    
    void Update()
    {
        
        if (state == State.alive)
        {
            ThrustShip();
            RotateShip();
                             
        }
        Audio();
        

    }

    private void ThrustShip()
    {
        if (Input.GetKey(KeyCode.Space) )
        {
            rigidBody.AddRelativeForce(Vector3.up * mainThrust);
            rigidBody.AddForce(Vector3.up * upThrust);
            
        }
                
    }
    private void RotateShip()
    {
        rigidBody.freezeRotation = true;


        float rotationThisFrame = rcsThrust * Time.deltaTime;

        if (Input.GetKey(KeyCode.A))
        {

            transform.Rotate(Vector3.forward * rotationThisFrame);

        }
        else if (Input.GetKey(KeyCode.D))
        {
            transform.Rotate(-Vector3.forward * rotationThisFrame);

        }

        rigidBody.freezeRotation = false;
        
    }


    void OnCollisionEnter(Collision collision)
    {

        if (state != State.alive)

        {
            return;
        }


        switch (collision.gameObject.tag) 
        {
            case "Friendly":
                //do nothing
                break;

            case "Finish":
                state = State.transcending;
                wonLevel = true;
                //audioSource.Stop();
                //audioSource.PlayOneShot(winLevel);
                Invoke("LoadNextScene", 5f);
                break;

            case "Untagged":
                state = State.dying;
                died = true;
                
                //audioSource.Stop();
                //audioSource.PlayOneShot(Die);    
                Invoke("LoadStartScene", 5f);
                break;


        }
    }

    private void LoadStartScene()
    {
        SceneManager.LoadScene(0);
        died = false;
    }

    private void LoadNextScene()
    {
        SceneManager.LoadScene(1);
    }
            
            
    
    void Audio()
    {
        if (Input.GetKey(KeyCode.Space) && !audioSource.isPlaying && state == State.alive)
        {
            audioSource.PlayOneShot(Engine);
        }           
        
        
        if (died == true) 
        {            
            audioSource.Stop();
            audioSource.PlayOneShot(Die);
            if (audioSource.isPlaying) { died = true; }
            died = false;          
        }


        if (Input.GetKeyDown(KeyCode.A) && state == State.alive)
        {
            audioSource.PlayOneShot(Rotate);
        }

        if (Input.GetKeyDown(KeyCode.D) && state == State.alive)
        {
            audioSource.PlayOneShot(Rotate);
        }


        if (wonLevel == true) 

        {
            audioSource.Stop();
            audioSource.PlayOneShot(winLevel);
            if (audioSource.isPlaying) { wonLevel = true; }
            wonLevel = false;                        
        }



    }

}

Hi Oliver,

Good job, and thanks a lot for sharing your explanation. :slight_smile:

1 Like

Privacy & Terms