The best way to randomize sounds in Unity 3D C#
By Victor Engström
The worst random
To make the most out of the sounds in a game you want to have the least repetition and most variation. The most basic way to do this is to have a random sound selection like this:
// The worst random audioSource.clip = audioClipArray[Random.Range(0, audioClipArray.Length)];
Why is this a problem?
The Random.Range is a problem because its true random and does not care if it plays sound number 1 five times in a row:
Possible outcome: 1, 1, 1, 1, 1
This can lead to where you get the same sound repeating after itself any number of times.
How to make a better random
One way to make the random better is to remember the last selected value and retry the random if gets that one next time. The problem with this is that you can get very repetitive variations anyway.
// The better but not best random while (audioSource.clip == lastAudioClip) { audioSource.clip = audioClipArray[Random.Range(0, audioClipArray.Length)]; } lastAudioClip = audioSource.clip;
The worst-case scenario here is that you’d get sound alternating between two variations even if you had more. Like the example below:
Possible outcome 1, 2, 1, 2, 1
The best way
The best way I’ve found is to remember half the length of the possible variations.
using UnityEngine;
[System.Serializable]
public class RandomAudioClip {
public AudioClip[] audioClipArray;
private int audioClipIndex;
private int[] previousArray;
private int previousArrayIndex;
// The best random method
public AudioClip GetRandomAudioClip() {
// Initialize
if (previousArray == null) {
// Sets the length to half of the number of AudioClips
// This will round downwards
// So it works with odd numbers like for example 3
previousArray = new int[audioClipArray.Length / 2];
}
if (previousArray.Length == 0) {
// If the the array length is 0 it returns null
return null;
} else {
// Psuedo random remembering previous clips to avoid repetition
do {
audioClipIndex = Random.Range(0, audioClipArray.Length);
} while (PreviousArrayContainsAudioClipIndex());
// Adds the selected array index to the array
previousArray[previousArrayIndex] = audioClipIndex;
// Wrap the index
previousArrayIndex++;
if (previousArrayIndex >= previousArray.Length) {
previousArrayIndex = 0;
}
}
// Returns the randomly selected clip
return audioClipArray[audioClipIndex];
}
// Returns if the randomIndex is in the array
private bool PreviousArrayContainsAudioClipIndex() {
for (int i = 0; i < previousArray.Length; i++) {
if (previousArray[i] == audioClipIndex) {
return true;
}
}
return false;
}
}
This way if the array is 4 AudioClips (remembering the last two) it could pick:
Possible outcome 1, 3, 2, 1, 4, 3
The problems with the worst-case scenarios of the other random ways are not present in this way of randomization.
Conclusion
Sure, it’s a bit of work to set up, but it sounds way better. Also, not even the big shots like Fmod uses this better random, they use the random where you remember the last played sound and not multiple which can yield bad sounding results.
Happy randomization!
Victor Engström
Simon
Hey!
Thanks for the tutorial! I just implemented this in one of my Unity projects, and it saved me quite some time not having to optimize randomization myself. Works pretty damn well so far!
One thing I noticed was when using an array with 3 clips, you might still end up with two clips alternating. I’m guessing this is due to the previousArray rounding down and ending up with only 1 remembered clip.
Still a really useful piece of code I’ll be using for my audio implementation!
Sonigon
Glad to help mate 🙂
Its is supposed to round down, but you probably easily could change it yourself to round up if you’d want! 🙂