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