bonus-coding-a-random-audio-player

Bonus: Coding a random audio player

Repetitive sounds are very noticeable to humans. In games, we’re always trying to vary effects, so they don’t sound too similar.

We have two tools for that:

  1. Vary a little bit of the sound’s pitch. Not too much, or else the sound distorts. Vary it just enough to add some variety.
  2. Play a random sound from a list of similar sounds.

This is such a common pattern in almost every game that we decided to make it into a custom node.

Additionally, this allows us to demonstrate how easy it is to build your own nodes with custom functionality.

In the props/ directory, create a new script. Call it RandomAudioPlayer2D.

At the top, write:

class_name RandomAudioPlayer2D
extends AudioStreamPlayer2D

We’re going to export two variables.

The first, sounds, will be an array of audio files. We will pick a random file from it.

Not every RandomAudioPlayer2D needs to have a list of sounds. Sometimes, one sound is enough, and we just change the pitch.

So if no sounds are provided in the sounds array, we want the player to behave normally.

export(Array, AudioStream) var sounds = []

The second variable, randomize_pitch, will be a boolean. If it is True, we will shift the pitch randomly before playing.

export var randomize_pitch := true

We only have one function to write. We want to override the default play() function of the AudioStreamPlayer2D.

If we look up the definition of this function in the documentation, we get:

We need to implement the exact same function signature. A function signature is the summary of the inputs it takes and what it returns.

In this instance, play() receives a float, and returns void. We need to write it exactly like that so we can override it. Otherwise, we will get an error.

func play(from_position = 0.0) -> void:
    pass

The function we need to write needs to do the following:

Try to write it! If you’re stuck, the solution is below:

func play(from_position = 0.0) -> void:
    if sounds:
        stream = sounds[randi() % sounds.size()]
    if randomize_pitch:
        pitch_scale = rand_range(0.9, 1.6)
    .play(from_position)

Once this class is created, we can use it anywhere we would use an AudioStreamPlayer2D.

For example, we will find it in the Create New Node dialog.

We can now add this node to the Robot, the mob, and use it there.

Using the RandomAudioPlayer2D

Open the robot scene. There are two AudioStreamPlayer2D nodes there.

Locate the script you just wrote, and drag it over the first, then the second node

You’ll notice the script gets attached.

You’ll also find the script referenced in the Inspector at the very bottom:

More importantly, the sounds and randomize_pitch variables will show up in the Inspector.

Press the first pain_01.wav file once. Then press Shift, and press the last pain_05.wav.

drag the files over the sounds array of the DamageAudio node:

That’s how you use this node!

Do the same with the DeathAudio node and the death_xx.wav files.

While mobs, bullets, spells, and pickups don’t have alternate audio files, they can still profit from the randomize_pitch functionality, so make sure to add the script to all the AudioStreamPlayer2D nodes you encounter.

Note: For inherited scenes like Mob.tscn, Spell.tscn, and so on, you only need to attach the script in the base scene. All inherited scenes will be able to use it too.