Wait for sound is played

Hi!

I was wondering how you could play a sound, but only after the first sound is already played. For example, when i press the key “1” a sound plays, then when I press key “2” a second sound needs to play, but only if the first one is done playing.

Does anyone know how to do that?

var sound1: AudioClip;
var sound2: AudioClip;
var sound3: AudioClip;
var sound4: AudioClip;
var sound5: AudioClip;

function Start () {

}


function Update () {

	if (Input.GetKeyDown ("1")&& !audio.isPlaying)
		{
			AudioSource.PlayClipAtPoint(sound1, transform.position);
	}
	
	if (Input.GetKeyDown ("2")&& !audio.isPlaying)
		{
			AudioSource.PlayClipAtPoint(sound2, transform.position);
	}
	
	if (Input.GetKeyDown ("3")&& !audio.isPlaying)
		{
			AudioSource.PlayClipAtPoint(sound3, transform.position);
	}
	
	if (Input.GetKeyDown ("4")&& !audio.isPlaying)
		{
			AudioSource.PlayClipAtPoint(sound4, transform.position);
	}
	
	if (Input.GetKeyDown ("5")&& !audio.isPlaying)
		{
			AudioSource.PlayClipAtPoint(sound5, transform.position);
	}
}

For that, don’t use AudioSource.PlayClipAtPoint as this will instantiate a new AudioSource at the position and clip you specify via its input arguments, and plays that clip at that position, when the clip is done playing the AudioSource that got instantiated will get destroyed.

So simply, attach an AudioSource to your gameObject, and play the clips normally with audio.Play.

Here’s what I just came up for you (tested), it’s a bit hacky, but really cool: The basic idea behind this script, is to use a list of audio clips, each time you press a number, like 1, 2, 3 etc the sound equivalent to that number will get added to the end of the list. Then, we simply play the first clip from the list (at index 0), we don’t do anything till we finish playing that clip, and when you do we remove it from our list. And since it was at index 0, the next clip after it will take its place, so we can still keep playing at the same index :slight_smile: - The variable hasJustStartedPlaying (just a boolean flag) is very important key for this hack to work properly. See the script to understand the logic.

import System.Collections.Generic;

private var clipsToPlay : List.<AudioClip> = new List.<AudioClip>();
private var hasJustStartedPlaying : boolean;

function Update()
{
     if (Input.GetKeyDown ("1")) {
        clipsToPlay.Add(sound1);
     }
     else if (Input.GetKeyDown ("2")) {
        clipsToPlay.Add(sound2);
     }
     else if ....

     PlayClips();
}

function PlayClips()
{
	// if there's no audio playing, and we haven't started playing yet
	if (!audio.isPlaying && !hasJustStartedPlaying) {
		if (clipsToPlay.Count > 0) {
			hasJustStartedPlaying = true;
			audio.clip = clipsToPlay[0]; // we'll always play the first clip, and when we're done with it, we'll nuke it
			audio.Play();
		}
	}

	// keep skipping frames while the clip is playing
	while (audio.isPlaying)
		yield;

	// when we reach this point, we're done playing the clip, so we'll nuke it from the list
	// why do we need to check for `hasJustStartedPlaying`? well, remove it and see what happens, and try to guess why it happened...
	if (clipsToPlay.Count > 0 && hasJustStartedPlaying)
	{
		clipsToPlay.RemoveAt(0);
		hasJustStartedPlaying = false;
	}
}

Btw using a Queue structure instead of a List in this situation is more suitable, but for simplicity’s sake, I used a list.

EDIT: After reading your comment

“I want it so when you press 1 a sound plays, then if you press 2, 3, 4 etc nothing happens. Not even after the first sound is done. I just want to be able to play a sound when there’s no other sound playing. So I don’t want the sounds to stack on each other.”

The solution becomes rather much simpler:

function Update()
{
   var clip2Play : AudioClip = null;
   if (Input.GetKeyDown("1") {
      clip2Play = sound1;
   }
   else if (Input.GetKeyDown("2") {
      clip2Play = sound2;
   }
   else if ...

   if (!audio.isPlaying && clip2Play != null) {
      audio.clip = clip2Play;
      audio.Play();
   }
}

In Unity 5 I’m using the PlayDelayed(float seconds) function together with isPlaying as follows:

	if (soundToWait.isPlaying) {
		nextSound.PlayDelayed (soundToWait.clip.length);
	} else {
		nextSound.Play();
	}

It is not perfect though. The ideal would be that instead using soundToWait.clip.length, we could do something like "soundToWait.timeLeftToFinishSound"… Maybe it is possible. I did not research it deeply!