Unity3D – CSharp Audio – Walking Footsteps

First you have to consider:

– if character is grounded
– different audio clips depending of movement direction
– random pitch (velocità di riproduzione)
– random audio clips
– trigger zones for different ground surfaces
– trigger zones for different environments

1. In my oipinion the best practice is using an AnimationEvents to synch the Animation and the SFX (http://docs.unity3d.com/Manual/animeditor-AnimationEvents.html)

AnimationEvents -> will calls -> FootstepSfxScript.cs

2. Script some conditions:


using UnityEngine; 
using System.Collections;

public class FootSteps : MonoBehaviour {

	public CharacterController controller; 
	public AudioClip[] concrete ; 
	public AudioClip[] wood ; 
	public AudioClip[] dirt ; 
	public AudioClip[] metal ; 
	public AudioClip[] glass ; 
	public AudioClip[] sand; 
	public AudioClip[] snow; 
	public AudioClip[] floor; 
	public AudioClip[] grass;
	
	private bool step = true; 
	float audioStepLengthWalk = 0.45f; 
	float audioStepLengthRun = 0.25f;
	
	void OnControllerColliderHit ( ControllerColliderHit hit) {
		
		if (controller.isGrounded && controller.velocity.magnitude < 7 && controller.velocity.magnitude > 5 && hit.gameObject.tag == "Untagged" && step == true ) {
			WalkOnConcrete();
		} else if (controller.isGrounded && controller.velocity.magnitude > 8 && hit.gameObject.tag == "Concrete" && step == true || controller.isGrounded && controller.velocity.magnitude > 8 && hit.gameObject.tag == "Untagged" && step == true) {
			RunOnConcrete();
		} else if (controller.isGrounded && controller.velocity.magnitude < 7 && controller.velocity.magnitude > 5 && hit.gameObject.tag == "Wood" && step == true) {
			WalkOnWood();
		} else if (controller.isGrounded && controller.velocity.magnitude > 8 && hit.gameObject.tag == "Wood" && step == true) {
			RunOnWood();
		} else if (controller.isGrounded && controller.velocity.magnitude < 7 && controller.velocity.magnitude > 5 && hit.gameObject.tag == "Dirt" && step == true) {
			WalkOnDirt();
		} else if (controller.isGrounded && controller.velocity.magnitude > 8 && hit.gameObject.tag == "Dirt" && step == true) {
			RunOnDirt();
		} else if (controller.isGrounded && controller.velocity.magnitude < 7 && controller.velocity.magnitude > 5 && hit.gameObject.tag == "Metal" && step == true) {
			WalkOnMetal();
		} else if (controller.isGrounded && controller.velocity.magnitude > 8 && hit.gameObject.tag == "Metal" && step == true) {
			RunOnMetal();       
		} else if (controller.isGrounded && controller.velocity.magnitude < 7 && controller.velocity.magnitude > 5 && hit.gameObject.tag == "Glass" && step == true) {
			WalkOnGlass();
		} else if (controller.isGrounded && controller.velocity.magnitude > 8 && hit.gameObject.tag == "Glass" && step == true) {
			RunOnGlass();
		} else if (controller.isGrounded && controller.velocity.magnitude < 7 && controller.velocity.magnitude > 5 && hit.gameObject.tag == "Sand" && step == true) {
			WalkOnSand();
		} else if (controller.isGrounded && controller.velocity.magnitude > 8 && hit.gameObject.tag == "Sand" && step == true) {
			RunOnSand();            
		} else if (controller.isGrounded && controller.velocity.magnitude < 7 && controller.velocity.magnitude > 5 && hit.gameObject.tag == "Snow" && step == true) {
			WalkOnSnow();
		} else if (controller.isGrounded && controller.velocity.magnitude > 8 && hit.gameObject.tag == "Snow" && step == true) {
			RunOnSnow();
		} else if (controller.isGrounded && controller.velocity.magnitude < 7 && controller.velocity.magnitude > 5 && hit.gameObject.tag == "Floor" && step == true) {
			WalkOnFloor();
		} else if (controller.isGrounded && controller.velocity.magnitude > 8 && hit.gameObject.tag == "Floor" && step == true) {
			RunOnFloor();   
		} else if (controller.isGrounded && controller.velocity.magnitude < 7 && controller.velocity.magnitude > 5 && hit.gameObject.tag == "Grass" && step == true) {
			WalkOnGrass();
		} else if (controller.isGrounded && controller.velocity.magnitude > 8 && hit.gameObject.tag == "Grass" && step == true) {
			RunOnGrass();                   
			
		}       
	}
	
	IEnumerator WaitForFootSteps(float stepsLength) { step = false; yield return new WaitForSeconds(stepsLength); step = true; } 

/////////////////////////////////// CONCRETE //////////////////////////////////////// 
	/// 
void WalkOnConcrete() {
	
	audio.clip = concrete[Random.Range(0, concrete.Length)];
	audio.volume = 0.1f;
	audio.Play();
	StartCoroutine(WaitForFootSteps(audioStepLengthWalk));
}

void RunOnConcrete() {
	
	audio.clip = concrete[Random.Range(0, concrete.Length)];
	audio.volume = 0.3f;
	audio.Play();
	StartCoroutine(WaitForFootSteps(audioStepLengthWalk));
}

////////////////////////////////// WOOD ///////////////////////////////////////////// 

void WalkOnWood() {

audio.clip = wood[Random.Range(0, wood.Length)];
audio.volume = 0.1f;
audio.Play();
StartCoroutine(WaitForFootSteps(audioStepLengthWalk));
}

void RunOnWood() {
	
	audio.clip = wood[Random.Range(0, wood.Length)];
	audio.volume = 0.3f;
	audio.Play();
	StartCoroutine(WaitForFootSteps(audioStepLengthRun));
}

/////////////////////////////////// DIRT ////////////////////////////////////////////// 

void WalkOnDirt() {

audio.clip = dirt[Random.Range(0, dirt.Length)];
audio.volume = 0.1f;
audio.Play();
StartCoroutine(WaitForFootSteps(audioStepLengthWalk));
}

void RunOnDirt() {
	
	audio.clip = dirt[Random.Range(0, dirt.Length)];
	audio.volume = 0.3f;
	audio.Play();
	StartCoroutine(WaitForFootSteps(audioStepLengthRun));
}

////////////////////////////////// METAL /////////////////////////////////////////////// 

void WalkOnMetal() {

audio.clip = metal[Random.Range(0, metal.Length)];
audio.volume = 0.1f;
audio.Play();
StartCoroutine(WaitForFootSteps(audioStepLengthWalk));
}

void RunOnMetal() {
	
	audio.clip = metal[Random.Range(0, metal.Length)];
	audio.volume = 0.3f;
	audio.Play();
	StartCoroutine(WaitForFootSteps(audioStepLengthRun));
}

////////////////////////////////// GLASS /////////////////////////////////////////////// 

void WalkOnGlass() {

audio.clip = glass[Random.Range(0, glass.Length)];
audio.volume = 0.1f;
audio.Play();
StartCoroutine(WaitForFootSteps(audioStepLengthWalk));
}

void RunOnGlass() {
	
	audio.clip = glass[Random.Range(0, glass.Length)];
	audio.volume = 0.3f;
	audio.Play();
	StartCoroutine(WaitForFootSteps(audioStepLengthRun));
}

////////////////////////////////// SAND /////////////////////////////////////////////// 

void WalkOnSand() {

audio.clip = sand[Random.Range(0, sand.Length)];
audio.volume = 0.1f;
audio.Play();
StartCoroutine(WaitForFootSteps(audioStepLengthWalk));
}

void RunOnSand() {
	
	audio.clip = sand[Random.Range(0, sand.Length)];
	audio.volume = 0.3f;
	audio.Play();
	StartCoroutine(WaitForFootSteps(audioStepLengthRun));
}

////////////////////////////////// SNOW /////////////////////////////////////////////// 

void WalkOnSnow() {

audio.clip = snow[Random.Range(0, snow.Length)];
audio.volume = 0.1f;
audio.Play();
StartCoroutine(WaitForFootSteps(audioStepLengthWalk));
}

void RunOnSnow() {
	
	audio.clip = snow[Random.Range(0, snow.Length)];
	audio.volume = 0.3f;
	audio.Play();
	StartCoroutine(WaitForFootSteps(audioStepLengthRun));
}

////////////////////////////////// FLOOR /////////////////////////////////////////////// 

void WalkOnFloor() {

audio.clip = floor[Random.Range(0, floor.Length)];
audio.volume = 0.1f;
audio.Play();
StartCoroutine(WaitForFootSteps(audioStepLengthWalk));
}

void RunOnFloor() {
	
	audio.clip = floor[Random.Range(0, floor.Length)];
	audio.volume = 0.3f;
	audio.Play();
	StartCoroutine(WaitForFootSteps(audioStepLengthRun));
}

////////////////////////////////// GRASS /////////////////////////////////////////////// 

void WalkOnGrass() {

audio.clip = grass[Random.Range(0, grass.Length)];
audio.volume = 0.1f;
audio.Play();
StartCoroutine(WaitForFootSteps(audioStepLengthWalk));
}

void RunOnGrass() {
	
	audio.clip = grass[Random.Range(0, grass.Length)];
	audio.volume = 0.3f;
	audio.Play();
	StartCoroutine(WaitForFootSteps(audioStepLengthRun));
}

}// END class FootSteps

For italian people: come funziona?

1. Ottengo il Character Controller

public CharacterController controller; 

2. Inserisco in un array le clip sonore

public AudioClip[] wood ; 

3. Definisco la lunghezza delle clip

float audioStepLengthWalk = 0.45f; 
float audioStepLengthRun = 0.25f;

4. Verifico delle condizioni:

} else if (controller.isGrounded && controller.velocity.magnitude < 7 && controller.velocity.magnitude > 5 && hit.gameObject.tag == "Wood" && step == true) {
			WalkOnWood();
} else if (controller.isGrounded && controller.velocity.magnitude > 8 && hit.gameObject.tag == "Wood" && step == true) {			RunOnWood();

– controller.isGrounded -> controllo che il controller sia a terra
– controller.velocity.magnitude < 7 -> la velocità del controller sul piano xz, se bassa stà camminando, se più alta sta correndo
– hit.gameObject.tag == “Wood” -> il tipo di terreno che il controller sta toccando
– step == true -> la variabile step è vera

5. Richiama la funziona specifica

void WalkOnWood() {

audio.clip = wood[Random.Range(0, wood.Length)]; // seleziona casualmente l'audio prelevandolo dall'array
audio.volume = 0.1f; // da un volume, basso possibilmente
audio.Play(); // play l'audio
StartCoroutine(WaitForFootSteps(audioStepLengthWalk));// avvia Couroutine per evitare la riproduzione continua
}

6. La Coroutine per riprodurre il suono

IEnumerator WaitForFootSteps(float stepsLength) { step = false; yield return new WaitForSeconds(stepsLength); step = true; } 

– WaitForFootSteps(float stepsLength) -> riceve la lunghezza della clip
– step = false -> interrompe la condizione -> if (controller.isGrounded … && step == true)
– yield return new WaitForSeconds(stepsLength) -> attende fino alla fine della riproduzione del suono
– step = true; -> fa ripartire la condizione if