0
\$\begingroup\$

So I used this tutorial: https://www.youtube.com/watch?v=tLyj02T51Oc, to create an AudioManager that can be easily called from other scripts, and can fade sound effects. One thing I do not know how to do is how to play a sound when let's say the player is running. I only have a function that plays an sfx, but all the SFX have looped equal to false, and I know that a running noise will need the SFX to loop. How can I add a function to this script so that running noises can be correctly implemented? The script:

using System.Collections.Generic;
using UnityEngine;

public class AudioManager : MonoBehaviour
{
    #region Instances
    private static AudioManager _instance = null;
    public static AudioManager Instance
    {
        get
        {
            if (_instance == null) //if instance doesn't exist, find an AudioManager
            {
                _instance = new AudioManager();
            }
            return _instance;
        }
        private set
        {
            _instance = value;
        }
    }
    #endregion

    #region Fields
    //the audio source can only play one looping sound at a time
    private AudioSource musicSource; 
    private AudioSource musicSource2; //purpose of having 2 musicSources is that we can use them to achieve effects like CrossFade
    private AudioSource sfxSource;

    private bool firstMusicSourceIsPlaying;
    #endregion

    private void Awake()
    {
        if(_instance == null)
        {
            //Set this instance as the instance reference
            _instance = this;
        }
        else if(_instance != this)
        {
            //If the instance reference has already been set, and this is not the instance reference, destroy the game object
            Destroy(gameObject);
        }

        //Make sure we don't destroy this instance
        DontDestroyOnLoad(_instance); 

        //Create audio sources, and make them as references
        musicSource = this.gameObject.AddComponent<AudioSource>();
        musicSource2 = this.gameObject.AddComponent<AudioSource>();
        sfxSource = this.gameObject.AddComponent<AudioSource>();

        //loop musicSource
        musicSource.loop = true;
        musicSource2.loop = true;
    }

    //plays the music
    public void PlayMusic(AudioClip musicClip)
    {
        //Determine which source is active (if the boolean is true, play musicSource, else play musicSource2)
        AudioSource activeSource = (firstMusicSourceIsPlaying) ? musicSource : musicSource2;

        activeSource.clip = musicClip;
        activeSource.volume = 1; //volume is between 0 and 1
        activeSource.Play();
    }

    //fade out the first music, fade in the second (new) music
    public void PlayMusicWithFade(AudioClip newClip, float musicVolume, float transitionTime = 1.0f)
    {
        //Determine which source is active (if the boolean is true, play musicSource, else play musicSource2)
        AudioSource activeSource = (firstMusicSourceIsPlaying) ? musicSource : musicSource2;

        StartCoroutine(UpdateMusicWithFade(activeSource, newClip, transitionTime, musicVolume));
    }

    public void StopMusicWithFade(float musicVolume, float transitionTime = 1.0f)
    {
        //Determine which source is active (if the boolean is true, play musicSource, else play musicSource2)
        AudioSource activeSource = (firstMusicSourceIsPlaying) ? musicSource : musicSource2;

        StartCoroutine(UpdateStopMusicWithFade(activeSource, transitionTime, musicVolume));
    }

    public void PlayMusicWithCrossFade(AudioClip musicClip, float musicVolume, float transitionTime = 1.0f)
    {
        //Determine which source is active
        AudioSource activeSource = (firstMusicSourceIsPlaying) ? musicSource : musicSource2;
        AudioSource newSource = (firstMusicSourceIsPlaying) ? musicSource2 : musicSource;

        //Swap the source
        firstMusicSourceIsPlaying = !firstMusicSourceIsPlaying;

        //Set the fields of the audio source, then start the coroutine top crossfade
        newSource.clip = musicClip;
        newSource.Play();
        StartCoroutine(UpdateMusicWithCrossFade(activeSource, newSource, transitionTime, musicVolume));
    }

    //Update the volume overtime to achieve a fade effect
    private IEnumerator UpdateMusicWithFade(AudioSource activeSource, AudioClip newClip, float transitionTime, float musicVolume)
    {
        //Make sure that the source is active and playing
        if (!activeSource.isPlaying)
        {
            activeSource.Play();
        }

        //transition float
        float t = 0.0f;

        //fade out
        for (t = 0; t < transitionTime; t += Time.deltaTime)
        {
            //Music clip's volume is going to be reduced a bit every second
            activeSource.volume = (musicVolume - ((t / transitionTime) * musicVolume));

            //Makes sure this is updated over multiple frames
            yield return null;
        }

        //transition to new clip
        activeSource.Stop();
        activeSource.clip = newClip;
        activeSource.Play();

        //fade in
        for (t = 0; t < transitionTime; t += Time.deltaTime)
        {
            //Music clip's volume starts at 1, and for every second it is going to be reduced a bit
            activeSource.volume = (t / transitionTime) * musicVolume;

            //Makes sure this is updated over multiple frames
            yield return null;
        }
    }

    private IEnumerator UpdateStopMusicWithFade(AudioSource activeSource, float transitionTime, float musicVolume)
    {
        //transition float
        float t = 0.0f;

        //fade out
        for (t = 0; t < transitionTime; t += Time.deltaTime)
        {
            //Music clip's volume is going to be reduced a bit every second
            activeSource.volume = (musicVolume - ((t / transitionTime) * musicVolume));

            //Makes sure this is updated over multiple frames
            yield return null;
        }

        //stops music
        activeSource.Stop();
    }

    private IEnumerator UpdateMusicWithCrossFade(AudioSource original, AudioSource newSource, float transitionTime, float musicVolume)
    {
        float t = 0.0f;

        for (t = 0.0f; t <= transitionTime; t += Time.deltaTime)
        {
            original.volume = (musicVolume - ((t / transitionTime) * musicVolume));
            newSource.volume = (t / transitionTime) * musicVolume;
            yield return null;
        }

        original.Stop();
    }

    //plays the SFX
    public void PlaySFX(AudioClip clip)
    {
        //if we just use Play, let's say we have two SFX overlapping, Play will just mute the previous audio clip
        sfxSource.PlayOneShot(clip); 
    }

    //plays the SFX, but allows to change the volume
    public void PlaySFX(AudioClip clip, float volume)
    {
        sfxSource.PlayOneShot(clip, volume);
    }

    //good for options menu
    public void SetMusicVolume(float volume)
    {
        musicSource.volume = volume;
        musicSource2.volume = volume;
    }

    public void SetSFXVolume(float volume)
    {
        sfxSource.volume = volume;
    }
}
```
\$\endgroup\$
  • \$\begingroup\$ Often a running sound would be played through an audio source on the character, not through a manager, so that you get correct spatialization of the sound depending on where the character is relative to the camera (left-right panning, distance attenuation, doppler shift, and HRTF effects if you're using them). Also, running sounds often don't loop per se, but rather re-triger periodically, jumping around a collection of variant sounds pseudo-randomly so the character doesn't sound too robotic and repetitive. \$\endgroup\$ – DMGregory Apr 28 at 13:05
  • \$\begingroup\$ @DMGregory Does Unity have anything comparable to Unreal's AnimNotify system? \$\endgroup\$ – Natalo77 Apr 28 at 13:06
  • \$\begingroup\$ Yes. Usually this is done through Animation Events to synchronize things like footfall foley to the moment the feet touch down in the animation. \$\endgroup\$ – DMGregory Apr 28 at 13:12
0
\$\begingroup\$

Probably the easiest and best way to go is with animation events. There is actualy a video tutorial covering that. I recommend you watch this and follow along.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ This answer would be even better if it included at least a quick summary of the main points of the video. This also helps readers evaluate the quality of the answer without clicking in to watch the whole video, which will tend to earn you more upvotes. ;) \$\endgroup\$ – DMGregory May 28 at 16:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.