How do I add sounds on the key down?

Hello,
I am trying to add sound to a different states of the game and on key down. I have no issue with adding a background sound that plays during the game, but not of the sounds are playing when I change game state. If I remove state specific function that key down triggers, sound plays OK.

Here is the part of the code:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

[RequireComponent(typeof(AudioSource))]

public class TextController : MonoBehaviour
{

public Text text;
public Image image;
public Sprite[] sprites;
public AudioClip[]  sounds;

IEnumerator PlayAudioClip(AudioClip myClip) {

        gameObject.GetComponent<AudioSource>().clip = myClip;
        gameObject.GetComponent<AudioSource>().Play();

        yield return new WaitForSeconds(myClip.length);

    }

void Cell()
{

    text.text = cellStr;

    if (Input.GetKeyDown(KeyCode.S))                            { StartCoroutine(PlayAudioClip(sounds[0])); myState = States.sheet_0; }
    else if (Input.GetKeyDown(KeyCode.M))                       { myState = States.mirror; }
    else if (Input.GetKeyDown(KeyCode.L))                       { myState = States.lock_0; }

    image.sprite = sprites[0];

}

So, if I delete myState = States.sheet_0; and just leave StartCoroutine(PlayAudioClip(sounds[0]));}

I can hear sound on S key down .

What do I do wrong here?

Thanks in advance.

1 Like

Hello @KituTheGreat, how are you?

Hey, I honestly don’t see a reason why would you use an coroutine in this case and why changing states would change the behave of this method, would you mind pasting the code under the Update() method to help me understand how it works?

Coroutines delay the block of code After the yield return new WaitForSeconds();, anything written before this line will be called instantly,

Hi Joao,
Thanks a lot for a quick response.
I used coroutine, so it finish playing sound before it goes to the next code line. Here is the my Update() method:

void Update()
{

    print(myState);

    if      (myState == States.menu)                                { Menu(); image.enabled = false; }
    else if (myState == States.cell)                                {Cell(); }
    else if (myState == States.sheet_0)                             {Sheets_0(); }
    else if (myState == States.sheet_1)                             {Sheets_1(); }
    else if(myState == States.lock_0)                               {Lock_0(); }
    else if (myState == States.lock_1)                              {Lock_1(); }
    else if (myState == States.mirror)                              {Mirror(); }
    else if (myState == States.cell_mirror)                         {Cell_Mirror(); }
    else if (myState == States.corridor_0)                          {Corridor_0(); }
    else if (myState == States.stairs_0)                            {Stairs_0(); }
    else if (myState == States.floor)                               {Floor(); }
    else if (myState == States.closet_door)                         {Closet_Door(); }
    else if (myState == States.stairs_1)                            {Stairs_1(); }
    else if (myState == States.corridor_1)                          {Corridor_1(); }
    else if (myState == States.corridor_2)                          {Corridor_2(); }
    else if (myState == States.corridor_3)                          {Corridor_3(); }
    else if (myState == States.in_closet)                           {In_Closet(); }
    else if (myState == States.stairs_2)                            {Stairs_2(); }
    else if (myState == States.courtyard)                           {Courtyard(); }

    if (myState != States.menu)
    {
        image.enabled = true;
    }
}

Thanks again.

1 Like

No problem!

The coroutine only delays what is inside its own code block, you would have to put the myState = States.sheets_0 inside the coroutine and after the yield return. What is inside the. Sheets_0() method? Don’t seems that the problem is within the update method.

I am not sure how can I add myState = States.sheets_0 to the coroutine. Because depending on where this got called from, myState would be different.

Here is the Sheets_0() method:

void Sheets_0()
{
StartCoroutine(PlayAudioClip(sounds[0]));
text.text = sheet_0Str;

    if (Input.GetKeyDown(KeyCode.R))                            { myState = States.cell; }

    
    image.sprite = sprites[1];
}

I also tried to remove first line of the code in this method, but that didn’t make any difference.

1 Like

oh, that is why, since the delay happens after the sound is played, it will instantily execute both the coroutine inside the sheets and the one inside the Cell(), the one inside the sheets is overwriting the other one.

I don’t know, try using this, it might work but I haven’t tried it:

[code]IEnumerator PlayAudioClip(AudioClip myClip, States ThisState)
{

gameObject.GetComponent<AudioSource>().clip = myClip;
    gameObject.GetComponent<AudioSource>().Play();

    yield return new WaitForSeconds(myClip.length);
    MyState = ThisState;
}

[/code]
and call it by using:

StartCoroutine(PlayAudioClip(sounds[0]), States.sheet_0);

Let me know if it does work

I’ve just tested it, and it worked here, it changed the scene after the WaitForSeconds parameter using States ThisStates as identifier and calling it with StartCoroutine(PlayAudioClip(sounds[0]), States.sheet_0);.

Let me know if it solves this problem, if it doesn’t I will give it further testing

Hi Joao,
Sorry for the delay. I was able to test it today and it is working perfectly!!!
Thank you so much.

1 Like

Im glad for being able to help!

Is there a way to show sprite, then splay sound in the method?

void Sheets_0()
{

text.text = sheet_0Str;

if (Input.GetKeyDown(KeyCode.R))                            { myState = States.cell; }


image.sprite = sprites[1];

}

If I try to play sound by adding code after “image.sprite = sprites[1];” , it doesn’t do anything.

have you added the image reference to the “image” variable?

Yes. In the unity editor it is pointing to a UI image object.

Are you trying to play the sound on the button press?

Is there an error showing up on your console?

Are you using an audio source to play the sound? Is the clip attached to it?

Maybe try this :https://docs.unity3d.com/ScriptReference/AudioSource.PlayOneShot.html

Here is the link to the code:
http://pastebin.com/q86TmTuM

I was able to play sound on the button press.
Now want to add sound to play after image.sprite shows on the screen.

I tried like this:

void Sheets_0()
{

text.text = sheet_0Str;

if (Input.GetKeyDown(KeyCode.R)) { myState = States.cell; }

image.sprite = sprites[1];

    gameObject.GetComponent<AudioSource>().clip = sounds[3];
    gameObject.GetComponent<AudioSource>().Play();

}

But that didn’t work. No sound. I also don’t see any errors in the console.

Yes. Using AudioSource and clip is attached. I can play the same clip on key press.

I would try adding a global variable for Audio source and then grabbing the component in the START method, then use it from there to attach whatever audio you need and playing it. Instead of requesting it on every function call like you have it currently.

I didn’t get it. How would I make it global? It is just one code game. Could you show an example, please? Thx.

Void AudioSource aSource; //add this under your other variables

Void Start(){
aSource = gameObject.GetComponent();
}

Now you can use that variable anywhere and just attach the audio clip to it and then make it play.

aAource.clip = whatever clip
aSource.play()

This way you can add it to the bottom of your image and it should be fine. As long as the volume on the audio source is up of course

But the sound is playing, since there is only one instance of the main script and you actually never changed the actual scene, your sound source already is global…

Still thinking about what may be causing the image problem… Can you paste a screenshot of the inspector please?

I can see why you think the AudioSource is global, since its only on this game object, but in the code he is grabbing the Audio Source every single time he calls the play sound function and it is never assigned to a variable.
(This is taxing to the engine, and not a great habit. That’s just my opinion though, so take it like a grain of salt)

Also, there doesn’t seem to be an issue in the console based on what was mentioned. Maybe is not getting to that part of the code?

Try adding some

Debug.Log(“testing”);

before and after to see if it’s going through there.

1 Like

Oh…i know this as caching a reference, sorry for misunderstanding. It is indeed a good practice since getcomponent is an pretty heavy method!

1 Like