Sound in Unity. Background music.

Tulenber 3 July, 2020 ⸱ Intermediate ⸱ 4 min ⸱ 2019.4.1f1 ⸱

At some point, every game developer thinks, why is it so quiet?

If your game not built around sounds, such as Osu!, Guitar Hero, or Hotline Miami, you may find yourself in a situation when the game is almost ready, and then you understand: “Something is wrong.” After a couple of minutes of thinking, it turns out that there is no sound in it =) Many people rarely think about such an essential part of the game, and it is not surprising that they can recall it at the very last moment. So let’s talk a little bit about sound.

Sound in Unity

Unity’s audio assets are called AudioClip, and their playback revolves around the two components AudioListener and AudioSource. AudioListener is a component that behaves like a microphone; it picks up all the sounds on the scene and plays them through the speaker. AudioSource - responsible for playing sound on the scene.

Accordingly, for the game to have sound, you need to add the AudioListener component to some object on the scene, and usually, the camera becomes such an object. It should be noted that you can not add more than one listener. Also, you need to add AudioSource components for all sound-reproducing objects.

You can divide the work with sound into three groups:

  • Background music - we’ll cover it in this article
  • UI sounds - an acceptable approach would be to add AudioSource components to the necessary UI elements and bind sound playback to their UI events
  • Sounds in the scene - this group is more complicated than the UI elements because it requires additional mechanisms for adding sounds to dynamic objects. The entire range of possible sounds can be quite large, and listing them in advance is quite problematic. Work with this group requires a separate mechanism and a separate article =)

Goal

Add a mechanism for playing background music. Several tracks should be played one after another, with the possible addition of a delay between them. Provide the possibility of silencing sound (for example, to play ads).

Implementation

We will use singleton as a basis for our music handler. You can read more about singletons in our previous article.

To mute the sound, we use a variable that will track the count of events for muting and returning sounds.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class KhtMusicManager : KhtSingleton<KhtMusicManager>
{
    // Delay between tracks
    public int newTrackDelay = 0;
    // List of tracks
    public List<AudioClip> musicAudioClips = new List<AudioClip>();

    // Source for playing music
    private AudioSource _musicAudioSource = null;

    // Used to mute music
    private int _muted = 0;

    protected override void Awake()
    {
        // Set up singleton
        base.Awake();
        DontDestroyOnLoad(gameObject);

        // Add component to play music
        _musicAudioSource = gameObject.AddComponent<AudioSource>();
    }
    
    // Start is called before the first frame update
    void Start()
    {
        // Start playing music
        StartCoroutine(PlayBackgroudMusic());
    }

    // Mute the music
    public static void Mute()
    {
        // Checks for singleton
        if (ReferenceEquals(Instance, null))
        {
            return;
        }

        // If the sound is not muted
        if (Instance._muted == 0)
        {
            Instance._musicAudioSource.mute = true;
        }
        Instance._muted++;
    }

    // Turn on sound
    public static void TurnOn()
    {
        // Check for singleton and skip negative counter
        if (ReferenceEquals(Instance, null) || Instance._muted == 0)
        {
            return;
        }

        // Turn on the sound
        Instance._muted--;
        if (Instance._muted == 0)
        {
            Instance._musicAudioSource.mute = false;
        }
        
    }

    // Start the next track
    IEnumerator PlayBackgroudMusic()
    {
        // Current track index
        int musicIndex = 0;
        // Play music, if it exists
        while (musicAudioClips.Count > 0)
        {
            // Time to start the next track + delay
            float waitTime = musicAudioClips[musicIndex].length + newTrackDelay;
            // Play the melody once
            _musicAudioSource.PlayOneShot(musicAudioClips[musicIndex]);

            // Work with the current track index
            musicIndex++;
            if (musicIndex >= musicAudioClips.Count)
            {
                musicIndex = 0;
            }

            // Delay to enable the next track
            yield return new WaitForSeconds(waitTime);
        }
    }
}

Conclusion

The given implementation demonstrates a low entry-level for implementation sound in Unity. The system is quite simple at a basic level; however, if necessary, you can use more advanced components for mixing sounds and applying effects (for example, changing the car engine sound on entering a tunnel). The use of third-party libraries is also a frequent solution. Returning to our implementation, we can highlight the functionality that we would like to add: the ability to start the track by id, stop and restart, randomization. Although each such request is not something complicated, this is beyond the scope of the article, so let’s leave it for the future. See you next time! =)



Privacy policyCookie policyTerms of service
Tulenber 2020