|
|
|
|
using System.Collections;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
namespace Projectiles
|
|
|
|
|
{
|
|
|
|
|
[System.Serializable]
|
|
|
|
|
public class AudioSetup
|
|
|
|
|
{
|
|
|
|
|
public AudioClip[] Clips;
|
|
|
|
|
public float Volume = 1f;
|
|
|
|
|
public float Pitch = 1f;
|
|
|
|
|
public float MaxPitchChange;
|
|
|
|
|
public float Delay;
|
|
|
|
|
public bool Loop;
|
|
|
|
|
public float FadeIn;
|
|
|
|
|
public float FadeOut;
|
|
|
|
|
|
|
|
|
|
[Space]
|
|
|
|
|
public bool Repeat;
|
|
|
|
|
public int RepeatPlayCount;
|
|
|
|
|
public float RepeatDelay;
|
|
|
|
|
|
|
|
|
|
public void CopyFrom(AudioSetup other)
|
|
|
|
|
{
|
|
|
|
|
Clips = other.Clips;
|
|
|
|
|
Volume = other.Volume;
|
|
|
|
|
MaxPitchChange = other.MaxPitchChange;
|
|
|
|
|
Delay = other.Delay;
|
|
|
|
|
Loop = other.Loop;
|
|
|
|
|
FadeIn = other.FadeIn;
|
|
|
|
|
FadeOut = other.FadeOut;
|
|
|
|
|
|
|
|
|
|
Repeat = other.Repeat;
|
|
|
|
|
RepeatPlayCount = other.RepeatPlayCount;
|
|
|
|
|
RepeatDelay = other.RepeatDelay;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum EForceBehaviour
|
|
|
|
|
{
|
|
|
|
|
None,
|
|
|
|
|
ForceAny,
|
|
|
|
|
ForceDifferentSetup,
|
|
|
|
|
ForceSameSetup,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Utility that helps with playing gameplay sounds and effects.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[RequireComponent(typeof(AudioSource))]
|
|
|
|
|
public sealed class AudioEffect : MonoBehaviour
|
|
|
|
|
{
|
|
|
|
|
// PUBLIC MEMBERS
|
|
|
|
|
|
|
|
|
|
public AudioSetup DefaultSetup => _defaultSetup;
|
|
|
|
|
public AudioSetup CurrentSetup => _currentSetup;
|
|
|
|
|
public AudioSource AudioSource => _audioSource;
|
|
|
|
|
public bool IsPlaying => _audioSource.isPlaying == true || _delayedPlayRoutine != null;
|
|
|
|
|
|
|
|
|
|
public int LastPlayedClipIndex { get; set; }
|
|
|
|
|
|
|
|
|
|
// PRIVATE MEMBERS
|
|
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
private AudioSetup _defaultSetup;
|
|
|
|
|
|
|
|
|
|
private AudioSource _audioSource;
|
|
|
|
|
private bool _playOnAwake;
|
|
|
|
|
|
|
|
|
|
private int _playCount;
|
|
|
|
|
private Coroutine _delayedPlayRoutine;
|
|
|
|
|
|
|
|
|
|
private AudioSetup _currentSetup;
|
|
|
|
|
|
|
|
|
|
// PUBLIC METHODS
|
|
|
|
|
|
|
|
|
|
public void Play(EForceBehaviour force = EForceBehaviour.None)
|
|
|
|
|
{
|
|
|
|
|
Play(_defaultSetup, force);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Play(AudioSetup setup, EForceBehaviour force = EForceBehaviour.None)
|
|
|
|
|
{
|
|
|
|
|
if (IsPlaying == true)
|
|
|
|
|
{
|
|
|
|
|
if (force == EForceBehaviour.None)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (force == EForceBehaviour.ForceDifferentSetup && setup == _currentSetup)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (force == EForceBehaviour.ForceSameSetup && setup != _currentSetup)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (setup.Clips == null || setup.Clips.Length == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
StartPlay(setup);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Stop(bool forceImmediateStop = false)
|
|
|
|
|
{
|
|
|
|
|
StopDelayedPlay();
|
|
|
|
|
|
|
|
|
|
if (forceImmediateStop == false && _currentSetup != null && _currentSetup.FadeOut > 0f)
|
|
|
|
|
{
|
|
|
|
|
_audioSource.FadeOut(this, _currentSetup.FadeOut);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_audioSource.Stop();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MonoBehaviour INTERFACE
|
|
|
|
|
|
|
|
|
|
private void Awake()
|
|
|
|
|
{
|
|
|
|
|
_audioSource = GetComponent<AudioSource>();
|
|
|
|
|
|
|
|
|
|
_playOnAwake = _audioSource.playOnAwake;
|
|
|
|
|
_audioSource.playOnAwake = false;
|
|
|
|
|
_audioSource.Stop();
|
|
|
|
|
|
|
|
|
|
_defaultSetup.Loop |= _audioSource.loop;
|
|
|
|
|
|
|
|
|
|
if (_defaultSetup.Clips.Length == 0 && _audioSource.clip != null)
|
|
|
|
|
{
|
|
|
|
|
_defaultSetup.Clips = new AudioClip[] { _audioSource.clip };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnEnable()
|
|
|
|
|
{
|
|
|
|
|
_audioSource.enabled = true;
|
|
|
|
|
|
|
|
|
|
if (_playOnAwake == true)
|
|
|
|
|
{
|
|
|
|
|
Play();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnDisable()
|
|
|
|
|
{
|
|
|
|
|
StopDelayedPlay();
|
|
|
|
|
_audioSource.enabled = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PRIVATE METHODS
|
|
|
|
|
|
|
|
|
|
private void StartPlay(AudioSetup setup)
|
|
|
|
|
{
|
|
|
|
|
AudioSetup previousSetup = _currentSetup;
|
|
|
|
|
_currentSetup = setup;
|
|
|
|
|
|
|
|
|
|
LastPlayedClipIndex = NextClipIndex(setup);
|
|
|
|
|
|
|
|
|
|
if (LastPlayedClipIndex < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (_currentSetup.Clips[LastPlayedClipIndex] == null)
|
|
|
|
|
return; // Do not start playing if there will be nothing to play
|
|
|
|
|
|
|
|
|
|
StopDelayedPlay();
|
|
|
|
|
_playCount = 0;
|
|
|
|
|
|
|
|
|
|
bool waitForFadeOut = IsPlaying == true && previousSetup != null && previousSetup.FadeOut > 0.01f;
|
|
|
|
|
|
|
|
|
|
if (_currentSetup.Delay < 0.01f && waitForFadeOut == false)
|
|
|
|
|
{
|
|
|
|
|
PlayClip(LastPlayedClipIndex);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
float delay = _currentSetup.Delay;
|
|
|
|
|
|
|
|
|
|
if (waitForFadeOut == true)
|
|
|
|
|
{
|
|
|
|
|
delay += previousSetup.FadeOut;
|
|
|
|
|
_audioSource.FadeOut(this, previousSetup.FadeOut);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_delayedPlayRoutine = StartCoroutine(PlayDelayed_Coroutine(delay, LastPlayedClipIndex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void PlayClip(int clipIndex)
|
|
|
|
|
{
|
|
|
|
|
_audioSource.Stop();
|
|
|
|
|
StopAllCoroutines(); // Stop audiosource fadings
|
|
|
|
|
|
|
|
|
|
LastPlayedClipIndex = clipIndex;
|
|
|
|
|
|
|
|
|
|
_audioSource.clip = _currentSetup.Clips[clipIndex];
|
|
|
|
|
_audioSource.volume = _currentSetup.Volume;
|
|
|
|
|
_audioSource.loop = _currentSetup.Loop;
|
|
|
|
|
_audioSource.pitch = _currentSetup.Pitch + Random.Range(-_currentSetup.MaxPitchChange, _currentSetup.MaxPitchChange);
|
|
|
|
|
|
|
|
|
|
if (_currentSetup.FadeIn > 0f)
|
|
|
|
|
{
|
|
|
|
|
_audioSource.FadeIn(this, _currentSetup.FadeIn, volume: _currentSetup.Volume);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_audioSource.Play();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_playCount++;
|
|
|
|
|
|
|
|
|
|
if (_currentSetup.Repeat == true && _playCount < _currentSetup.RepeatPlayCount)
|
|
|
|
|
{
|
|
|
|
|
_delayedPlayRoutine = StartCoroutine(PlayDelayed_Coroutine(_audioSource.clip.length + _currentSetup.RepeatDelay, clipIndex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private IEnumerator PlayDelayed_Coroutine(float delay, int clipIndex)
|
|
|
|
|
{
|
|
|
|
|
if (delay > 0.01f)
|
|
|
|
|
{
|
|
|
|
|
yield return new WaitForSeconds(delay);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_delayedPlayRoutine = null;
|
|
|
|
|
|
|
|
|
|
PlayClip(clipIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void StopDelayedPlay()
|
|
|
|
|
{
|
|
|
|
|
if (_delayedPlayRoutine != null)
|
|
|
|
|
{
|
|
|
|
|
StopCoroutine(_delayedPlayRoutine);
|
|
|
|
|
_delayedPlayRoutine = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int NextClipIndex(AudioSetup setup)
|
|
|
|
|
{
|
|
|
|
|
if (setup.Clips.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarningFormat("Cannot play sound on {0} - missing audio clip", gameObject.name);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int clipIndex = Random.Range(0, setup.Clips.Length);
|
|
|
|
|
|
|
|
|
|
if (clipIndex == LastPlayedClipIndex)
|
|
|
|
|
{
|
|
|
|
|
clipIndex = (clipIndex + 1) % setup.Clips.Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return clipIndex;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|