Change sound depending on material

Okay, I know this has been asked before, and I think I have gone through every thread I could find.

Is there a way to be able to play a loopable footstep sound that changes depending on which material the player is on?

I have tried some different solutions.

  1. A raycast that checks which material the players is on and change the sound depending on that. My problem when was that it started my sound over and over and over again, at the same time so it did not work. My workaround for this was to use a bool to see if footstep sound was playing or not, and if not play one. This worked, but then when I changed material it did not change from the last sound it played.

  2. Same thing but with a OnCollisionStay, then I had the same problem. It did not change the sound when switching material, or it started the sound over and over again.

So I have used this solution for now (see code below), but it far from perfect working. It has problem sometimes changing the sound, and sometimes starts the sound twice and so on.

So now my question is: Does anyone have a better solution for me with this? There must be a good way of doing this in Unity.

Thanks in advance.

    void OnCollisionEnter(Collision colPlayer)
    {
        bPlayingFootStepSound = false;
    }

    void OnCollisionExit(Collision colPlayer)
    {
        bPlayingFootStepSound = false;
    }

    /// <summary>
    /// Use player collision on ground to see which sounds to use on which material
    /// </summary>
    /// <param name="colPlayer"></param>
    void OnCollisionStay(Collision colPlayer)
    {
        if (bPlayingFootStepSound == false)
        {
            bPlayingFootStepSound = true;

            if (colPlayer.gameObject.tag == "Grass")
            {
                audio.clip = a_GrassFootsteps;
                audio.loop = true;
                audio.Play();
            }
            else if (colPlayer.gameObject.tag == "Dirt")
            {
                audio.clip = a_DirtFootsteps;
                audio.loop = true;
                audio.Play();
            }
            else if (colPlayer.gameObject.tag == "Leaf")
            {
                audio.clip = a_LeafFootsteps;
                audio.loop = true;
                audio.Play();
            }
            else if (colPlayer.gameObject.tag == "Gravel")
            {
                audio.clip = a_GravelFootsteps;
                audio.loop = true;
                audio.Play();
            }
            else if (colPlayer.gameObject.tag == "Concrete")
            {
                audio.clip = a_ConcreteFootsteps;
                audio.loop = true;
                audio.Play();
            }
        }

    }

    public void StopFootStep()
    {
        if (bPlayingFootStepSound == true)
        {
            bPlayingFootStepSound = false;
            audio.Stop();
        }

    }

I would disable the loop flag in the audioclip and move the if statements to OnCollisionEnter(), to play the sound just once when player hits ground. Also remove the OnCollisionStay and OnCollisionExit calls. That means your player should move up and down a bit when walking or running. Or you could actívate the sound with your speed if you are using a rigidbody.

Another solution is playing the sound based on the player movement. Based on bobStepCounter being multiple of a value, use PlayClipAtPoint.

  	// Calculate bob movement only if we are walking
	if ( isWalking )
	{
		// Only count steps if player is grounded
		if ( isGrounded )
		{
 				bobStepCounter += Vector3.Distance ( lastPlayerPosition, transform.position )  * bobWalkSpeed;
		}
	}