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