using System.Linq; using UnityEngine; public class FirstPersonAudio : MonoBehaviour { public FirstPersonMovement character; public GroundCheck groundCheck; [Header("Step")] public AudioSource stepAudio; public AudioSource runningAudio; [Tooltip("Minimum velocity for moving audio to play")] /// "Minimum velocity for moving audio to play" public float velocityThreshold = .01f; Vector2 lastCharacterPosition; Vector2 CurrentCharacterPosition => new Vector2(character.transform.position.x, character.transform.position.z); [Header("Landing")] public AudioSource landingAudio; public AudioClip[] landingSFX; [Header("Jump")] public Jump jump; public AudioSource jumpAudio; public AudioClip[] jumpSFX; [Header("Crouch")] public Crouch crouch; public AudioSource crouchStartAudio, crouchedAudio, crouchEndAudio; public AudioClip[] crouchStartSFX, crouchEndSFX; AudioSource[] MovingAudios => new AudioSource[] { stepAudio, runningAudio, crouchedAudio }; void Reset() { // Setup stuff. character = GetComponentInParent(); groundCheck = (transform.parent ?? transform).GetComponentInChildren(); stepAudio = GetOrCreateAudioSource("Step Audio"); runningAudio = GetOrCreateAudioSource("Running Audio"); landingAudio = GetOrCreateAudioSource("Landing Audio"); // Setup jump audio. jump = GetComponentInParent(); if (jump) { jumpAudio = GetOrCreateAudioSource("Jump audio"); } // Setup crouch audio. crouch = GetComponentInParent(); if (crouch) { crouchStartAudio = GetOrCreateAudioSource("Crouch Start Audio"); crouchStartAudio = GetOrCreateAudioSource("Crouched Audio"); crouchStartAudio = GetOrCreateAudioSource("Crouch End Audio"); } } void OnEnable() => SubscribeToEvents(); void OnDisable() => UnsubscribeToEvents(); void FixedUpdate() { // Play moving audio if the character is moving and on the ground. float velocity = Vector3.Distance(CurrentCharacterPosition, lastCharacterPosition); if (velocity >= velocityThreshold && groundCheck && groundCheck.isGrounded) { if (crouch && crouch.IsCrouched) { SetPlayingMovingAudio(crouchedAudio); } else if (character.IsRunning) { SetPlayingMovingAudio(runningAudio); } else { SetPlayingMovingAudio(stepAudio); } } else { SetPlayingMovingAudio(null); } // Remember lastCharacterPosition. lastCharacterPosition = CurrentCharacterPosition; } /// /// Pause all MovingAudios and enforce play on audioToPlay. /// /// Audio that should be playing. void SetPlayingMovingAudio(AudioSource audioToPlay) { // Pause all MovingAudios. foreach (var audio in MovingAudios.Where(audio => audio != audioToPlay && audio != null)) { audio.Pause(); } // Play audioToPlay if it was not playing. if (audioToPlay && !audioToPlay.isPlaying) { audioToPlay.Play(); } } #region Play instant-related audios. void PlayLandingAudio() => PlayRandomClip(landingAudio, landingSFX); void PlayJumpAudio() => PlayRandomClip(jumpAudio, jumpSFX); void PlayCrouchStartAudio() => PlayRandomClip(crouchStartAudio, crouchStartSFX); void PlayCrouchEndAudio() => PlayRandomClip(crouchEndAudio, crouchEndSFX); #endregion #region Subscribe/unsubscribe to events. void SubscribeToEvents() { // PlayLandingAudio when Grounded. groundCheck.Grounded += PlayLandingAudio; // PlayJumpAudio when Jumped. if (jump) { jump.Jumped += PlayJumpAudio; } // Play crouch audio on crouch start/end. if (crouch) { crouch.CrouchStart += PlayCrouchStartAudio; crouch.CrouchEnd += PlayCrouchEndAudio; } } void UnsubscribeToEvents() { // Undo PlayLandingAudio when Grounded. groundCheck.Grounded -= PlayLandingAudio; // Undo PlayJumpAudio when Jumped. if (jump) { jump.Jumped -= PlayJumpAudio; } // Undo play crouch audio on crouch start/end. if (crouch) { crouch.CrouchStart -= PlayCrouchStartAudio; crouch.CrouchEnd -= PlayCrouchEndAudio; } } #endregion #region Utility. /// /// Get an existing AudioSource from a name or create one if it was not found. /// /// Name of the AudioSource to search for. /// The created AudioSource. AudioSource GetOrCreateAudioSource(string name) { // Try to get the audiosource. AudioSource result = System.Array.Find(GetComponentsInChildren(), a => a.name == name); if (result) return result; // Audiosource does not exist, create it. result = new GameObject(name).AddComponent(); result.spatialBlend = 1; result.playOnAwake = false; result.transform.SetParent(transform, false); return result; } static void PlayRandomClip(AudioSource audio, AudioClip[] clips) { if (!audio || clips.Length <= 0) return; // Get a random clip. If possible, make sure that it's not the same as the clip that is already on the audiosource. AudioClip clip = clips[Random.Range(0, clips.Length)]; if (clips.Length > 1) while (clip == audio.clip) clip = clips[Random.Range(0, clips.Length)]; // Play the clip. audio.clip = clip; audio.Play(); } #endregion }