Question: Preventing an AudioSource from overlapping multiple AudioClips

Hello. I think this may be my first time posting here so I apologize if I violate any forum conventions.

I am working on a simple game in which you feed a cat different food items which results in the AudioSource representing the cat playing 1 of 4 AudioClips.

The player needs to have the ability to feed the cat more than one food item within the length of one AudioClip. I would explain why but it’s not really relevant.

The problem is that this is resulting in the second AudioClip starting before the first AudioClip has finished. It comes out sounding like more than one AudioClip overlapping.

I would like the first AudioClip to finish playing before a second AudioClip can be activated, but I don’t want them to stack in a queue.

This is the script I have at the moment. It is attached to the food object that you click.

	// Update is called once per frame
	void Update () {

		//This is a timer before the food object starts moving across the screen
		if (timer > 0) {
			timer--;
		//once the timer is done, the food starts moving along the Y axis of the screen
		} else {
			nextPosition.Set(this.transform.position.x , this.transform.position.y + foodSpeed , this.transform.position.z);
			this.transform.SetPositionAndRotation (nextPosition, this.transform.rotation); 

			//if the food makes it to the end of the screen, it is moved back to its starting point
			if (this.transform.position.y > endLine.y) {
				this.transform.SetPositionAndRotation (startPoint, this.transform.rotation);
				timer = foodDelay;
			}
		}

		//if the screen is touched, use the eat food method <--This is where things start getting messy
		if ((Input.touchCount > 0) && (Input.GetTouch(0).phase == TouchPhase.Began)) {
			eatFood ();
		}
			
	}

//This method checks to see if you hit the food and then resets the foods position
	//and also runs the play sound method. <--Probably where the bigger problem is.
	void eatFood() {
		//checks to a tap. Did I mention that this is an Android game?
		Ray raycast = Camera.main.ScreenPointToRay (Input.GetTouch (0).position);
		RaycastHit raycastHit;
		//Ok I guess this is really where the checking happens
		if (Physics.Raycast (raycast, out raycastHit)) {
			//These two lines reset the food
			this.transform.SetPositionAndRotation (startPoint, this.transform.rotation);
			timer = foodDelay;
			//And here is the thing that is probably causing the problems
			playSound ();
		}
	}

//this plays a portion of an audio clip.
	void playSound () {

		//The sound is choosen at random. I only now realize how stupid it is to
		//convert the random value to an integer-ish value
		randomNumber = Random.value * 4;

		/*
		 * This line of code was my easy fix solution but even it wouldn't work.
		 * This idea was to stop the old AudioClip before starting a new one.
		 * Unfortunately Unity didn't like me calling audioSource.Stop from
		 * a method.
		audioSource.Stop;
		*/

		if (randomNumber < 1f) {
			audioSource.PlayOneShot (nomming1, 1f);
		} else if ((randomNumber > 1f) && (randomNumber < 2f)) {
			audioSource.PlayOneShot (nomming2, 1f);
		} else if ((randomNumber >= 2f) && (randomNumber < 3f)) {
			audioSource.PlayOneShot (nomming3, 1f);
		} else if (randomNumber >= 3f) {
			audioSource.PlayOneShot (nomming4, 1f);
		}
			Debug.Log ("Playing audio");
	}

This seems like a problem that a lot of people would probably come across but I haven’t found anything addressing it which makes me think that I may be missing something obvious. Can someone point me in the right direction?

-Thanks

I found a work around to this and I figured I should post it here in case anyone else is having the same problem I am.

What I ended up doing was moving all of my sound effect to one script attached to my AudioSource. In that script I made a variable called “playSignal” which can be changed by other scripts to tell the AudioSource which clip to load and play.

Here is the code:

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

public class SoundController : MonoBehaviour {

	//We make a public static variable that holds this instance of the class so
	//it can be accessed from outside.
	public static SoundController instance;
	//These are different sounds the cat can make
	public AudioClip nom1, nom2, nom3, nom4;
	//There is also a bird...
	public AudioClip chirp1;
	//different volumes for each
	public float nomVolume, chirpVolume;

	//this private variable can be changed using a method at the bottom
	private int playSignal;
	//obviously we need to access the AudioSource
	private AudioSource audioSource;

	// Use this for initialization
	void Start () {
		audioSource = this.GetComponent<AudioSource> ();
		instance = this;
	}
	
	// Update is called once per frame
	void Update () {

		//We check to make sure the audioSource is not playing anything before 
		//starting a new AudioClip
		if (!audioSource.isPlaying) {
			//Pick what to play based on the playSignal variable
			switch (playSignal) {
			//I'm only going to comment one of these cases
			case 1:
				//Load the AudioClip
				audioSource.clip = nom1;
				//Set the volume
				audioSource.volume = nomVolume;
				//use Play, not PlayOneShot, so audioSource.isPlaying works
				audioSource.Play ();	
				Debug.Log ("Playing 1");
				break;
			case 2:
				audioSource.clip = nom2;
				audioSource.volume = nomVolume;
				audioSource.Play ();
				Debug.Log ("Playing 2");
				break;
			case 3:
				audioSource.clip = nom3;
				audioSource.volume = nomVolume;
				audioSource.Play ();
				Debug.Log ("Playing 3");
				break;
			case 4:
				audioSource.clip = nom4;
				audioSource.volume = nomVolume;
				audioSource.Play ();
				Debug.Log ("Playing 4");
				break;
			case 5:
				audioSource.clip = chirp1;
				audioSource.volume = chirpVolume;
				audioSource.Play ();
				Debug.Log ("Playing 5");
				break;
			}
		} 
		//Must reset the playSignal to 0 so it wont loop
		playSignal = 0;
		Debug.Log ("Signal reset");
	}

	/*This method lets you set the playSignal from outside the class
	*I know this could be done by making playSignal public but my
	*CS teachers beat getters and setters into me.
	*/
	public void setPlaySignal (int signal) {
		Debug.Log ("Signal = " + signal);
		playSignal = signal;
	}
}

I hope someone out there finds this useful. If any moderators come across this and think it’s junk, I understand if you feel the need to delete this question now that it is resolved.