// This code is part of the Fungus library (https://github.com/snozbot/fungus) // It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) using UnityEngine; using System.Collections.Generic; namespace Fungus { /// /// Type of audio effect to play. /// public enum AudioMode { /// Use short beep sound effects. Beeps, /// Use long looping sound effect. SoundEffect, } /// /// Manages audio effects for Dialogs. /// public class WriterAudio : MonoBehaviour, IWriterListener { [Tooltip("Volume level of writing sound effects")] [Range(0,1)] [SerializeField] protected float volume = 1f; [Tooltip("Loop the audio when in Sound Effect mode. Has no effect in Beeps mode.")] [SerializeField] protected bool loop = true; // If none is specifed then we use any AudioSource on the gameobject, and if that doesn't exist we create one. [Tooltip("AudioSource to use for playing sound effects. If none is selected then one will be created.")] [SerializeField] protected AudioSource targetAudioSource; [Tooltip("Type of sound effect to play when writing text")] [SerializeField] protected AudioMode audioMode = AudioMode.Beeps; [Tooltip("List of beeps to randomly select when playing beep sound effects. Will play maximum of one beep per character, with only one beep playing at a time.")] [SerializeField] protected List beepSounds = new List(); [Tooltip("Long playing sound effect to play when writing text")] [SerializeField] protected AudioClip soundEffect; [Tooltip("Sound effect to play on user input (e.g. a click)")] [SerializeField] protected AudioClip inputSound; protected float targetVolume = 0f; // When true, a beep will be played on every written character glyph protected bool playBeeps; // True when a voiceover clip is playing protected bool playingVoiceover = false; public bool IsPlayingVoiceOver { get { return playingVoiceover; } } // Time when current beep will have finished playing protected float nextBeepTime; public float GetSecondsRemaining() { if (IsPlayingVoiceOver) { return targetAudioSource.clip.length - targetAudioSource.time; } else { return 0F; } } protected virtual void SetAudioMode(AudioMode mode) { audioMode = mode; } protected virtual void Awake() { // Need to do this in Awake rather than Start due to init order issues if (targetAudioSource == null) { targetAudioSource = GetComponent(); if (targetAudioSource == null) { targetAudioSource = gameObject.AddComponent(); } } targetAudioSource.volume = 0f; } protected virtual void Play(AudioClip audioClip) { if (targetAudioSource == null || (audioMode == AudioMode.SoundEffect && soundEffect == null && audioClip == null) || (audioMode == AudioMode.Beeps && beepSounds.Count == 0)) { return; } playingVoiceover = false; targetAudioSource.volume = 0f; targetVolume = volume; if (audioClip != null) { // Voice over clip provided targetAudioSource.clip = audioClip; targetAudioSource.loop = loop; targetAudioSource.Play(); } else if (audioMode == AudioMode.SoundEffect && soundEffect != null) { // Use sound effects defined in WriterAudio targetAudioSource.clip = soundEffect; targetAudioSource.loop = loop; targetAudioSource.Play(); } else if (audioMode == AudioMode.Beeps) { // Use beeps defined in WriterAudio targetAudioSource.clip = null; targetAudioSource.loop = false; playBeeps = true; } } protected virtual void Pause() { if (targetAudioSource == null) { return; } // There's an audible click if you call audioSource.Pause() so instead just drop the volume to 0. targetVolume = 0f; } protected virtual void Stop() { if (targetAudioSource == null) { return; } // There's an audible click if you call audioSource.Stop() so instead we just switch off // looping and let the audio stop automatically at the end of the clip targetVolume = 0f; targetAudioSource.loop = false; playBeeps = false; playingVoiceover = false; } protected virtual void Resume() { if (targetAudioSource == null) { return; } targetVolume = volume; } protected virtual void Update() { targetAudioSource.volume = Mathf.MoveTowards(targetAudioSource.volume, targetVolume, Time.deltaTime * 5f); } #region IWriterListener implementation public virtual void OnInput() { if (inputSound != null) { // Assumes we're playing a 2D sound AudioSource.PlayClipAtPoint(inputSound, Vector3.zero); } } public virtual void OnStart(AudioClip audioClip) { if (playingVoiceover) { return; } Play(audioClip); } public virtual void OnPause() { if (playingVoiceover) { return; } Pause(); } public virtual void OnResume() { if (playingVoiceover) { return; } Resume(); } public virtual void OnEnd(bool stopAudio) { if (stopAudio) { Stop(); } } public virtual void OnGlyph() { if (playingVoiceover) { return; } if (playBeeps && beepSounds.Count > 0) { if (!targetAudioSource.isPlaying) { if (nextBeepTime < Time.realtimeSinceStartup) { targetAudioSource.clip = beepSounds[Random.Range(0, beepSounds.Count)]; if (targetAudioSource.clip != null) { targetAudioSource.loop = false; targetVolume = volume; targetAudioSource.Play(); float extend = targetAudioSource.clip.length; nextBeepTime = Time.realtimeSinceStartup + extend; } } } } } public virtual void OnVoiceover(AudioClip voiceOverClip) { if (targetAudioSource == null) { return; } playingVoiceover = true; targetAudioSource.volume = volume; targetVolume = volume; targetAudioSource.loop = false; targetAudioSource.clip = voiceOverClip; targetAudioSource.Play(); } #endregion } }