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
}