Sounds playback¶
The game has a system made to play short SFX using a pooled set of AudioSources with configurable pich and volume with the optional ability to loop.
These are internally refered to as sounds. A sound unlike a music is made to be played using an AudioSource from the sounds
array. There are 15 of them available on boot and any playback will by default pick the first one that is free. These AudioClip are meant to be played in short burst as needed while a music is meant to play on music[0]
only and for a longer period. Check the music playback documentation for how music works.
Sounds shouldn't be confused with bleeps which have their own dedicated AudioSource called bleep
. Check the bleep documentation to learn more.
All sounds AudioClip are located in the Resources/audio/sounds
asset directory and they can be identified by their filename.
As for what consititute a free and a reserved sounds
AudioSource, the method GetFreeSound is what determines this:
private static int GetFreeSound()
It returns the first sounds
index (between 0 and 14) whose AudioSource's isPlaying
is false. If every sounds
elements are playing something, the last sounds
element is returned even if it is playing an AudioClip.
While it is possible to specify a particular sounds
index for the playback, specifying one is optional. By default, one will be provided using the return value of GetFreeSound.
Playing sounds¶
Every single sound playback is played through a method with a wide variety of overloads available: PlaySound.
public static AudioSource PlaySound(string soundclip)
public static AudioSource PlaySound(string soundclip, int id)
public static AudioSource PlaySound(string soundclip, int id, float pitch, float volume)
public static AudioSource PlaySound(string soundclip, int id, float pitch, float volume, bool loop)
public static AudioSource PlaySound(string clip, float volume)
public static AudioSource PlaySound(string clip, float pitch, float volume)
public static AudioSource PlaySound(AudioClip soundclip)
public static AudioSource PlaySound(AudioClip soundclip, int id)
public static AudioSource PlaySound(AudioClip soundclip, int id, float pitch)
public static AudioSource PlaySound(AudioClip soundclip, int id, float pitch, float volume)
public static AudioSource PlaySound(AudioClip soundclip, int id, float pitch, float volume, bool loop)
It will plays the soundclip
AudioClip using the sounds[id]
AudioSource with a pitch of pitch
, volume of soundvolume
* volume
and a loop property of loop
then returns the AudioSource where the AudioClip started playing as well as setting lastsoundid
to id
. In practice, id
can only be from 0 to 14 as sounds
has a fixed size of 15 enforced by LoadEssentials.
If SoundVolume returns false (meaning sounds are muted), the method returns null instead. NOTE: It does NOT return an empty AudioSource, this means the return value needs to be null checked to avoid an exception being thrown.
If id
is -1, the value to use as the id is determined automatically using the GetFreeSound method.
For the overloads taking a string instead of an AudioClip, soundclip
becomes the result of loading the AudioClip at Audio/Sounds/X
where X
is the string provided.
For overloads not taking every parameters, here are their default values:
id
: -1pitch
: 1.0 (normal)volume
: 1.0 (normal)loop
: false
There is also a method that allows to call PlaySound after a delay: LateSound.
public static IEnumerator LateSound(string sound, float delay)
It will yields for delay
amount of seconds before calling PlaySound(sound
) which plays the sound whose AudioClip is named sound
.
Additionally, there's also a managed way to call PlaySound using a sound that is bound to a specific animid called their move sound:
public static void PlayMoveSound(EntityControl entity)
public static void PlayMoveSound(int animid, int soundid, bool fly)
It either calls PlaySound using id
as the id with loop or does nothing depending on the animid
/ entity.originalid
and the value of fly
. If PlaySound is called, the soundclip, pitch and volume are determined depending on the animid
/ entity.originalid
where the sound represents the appropriate movement sound to play whenever any entity whose animid is animid
moves.
The overload with just an entity
parameter has the soundid
value default to 9 and fly
value default to whether or not entity
.height
is higher than 0.1 (meaning they have a visual offset in y).
Here are the specific properties for each supported value of animid
(if the value isn't in this list, PlaySound is not called and the method does nothing):
Scorpion
:Step
with 1.0 pitch and volumeDivingSpider
:WetStep
with 1.0 pitch and volumeFlyTrap
andKrawler
:Scuttle3
with 1.0 pitch and volumeArmorpillar
:FunnyStep
with 0.9 pitch and 0.3 volumeMushroom
: Iffly
is true,Fly
with 0.5 pitch and 1.0 volume, no PlaySound call otherwiseSeedling
andFlowering
: Iffly
is true,Toss2
with 1.1 pitch and 0.5 volume, no PlaySound call otherwiseThief
,Midge
andMantidfly
: Iffly
is true,BugWing
with 1.0 pitch and volume, no PlaySound call otherwiseSpuder
:Scuttle2
with 0.9 pitch and 0.8 volumeMimicSpider
:Scuttle2
with 1.1 pitch and 0.8 volumePlumpling
:ThumpSoft
with 0.65 pitch and 0.65 volumeCordycepsAnt
:Scuttle
with 0.5 pitch and 0.8 volumeAbomihoney
:PuddleMove
with 1.15 pitch and 1.0 volume
Finally, here are other helper methods that also calls PlaySound.
public static void PlayBuzzer()
Calls PlaySound(Buzzer
, 10).
public static void PlayScrollSound()
If sounds[10]
isn't playing anything, PlaySound is called to play the Audio/Sounds/Scroll
AudioClip on sounds[10]
with a pitch of 1.0 and a volume of 0.65. If this is called while in the pausemenu
with a windowid
of 4 or higher TODO: why "or higher" ??? , sounds[10]
volume gets set to svolume
so it follows the working value in the settings.
If sounds[10]
was playing something when this is called, this method does nothing.
public static void PlaySoundAt(string sound, float volume, Vector3 position)
Calls AudioSource.PlayClipAtPoint with the following parameters:
- clip: obtained by loading the
Audio/Sounds/X
AudioClip whereX
issound
- position:
position
- volume: GetSoundDistance(
position
) *volume
*soundvolume
Stopping sounds¶
It's possible to stop a sound after it was played if it's still playing. This is mainly useful to stop SFX that were played on loop. It involves a method called StopSound and there's 2 style of it: one that stops all sounds
playing something and one that stops a specific sounds
element.
public static void StopSound(AudioClip clip)
public static void StopSound(AudioClip clip, float delay)
public static void StopSound(string clipname)
public static void StopSound(string clipname, float delay)
This calls Stop on every sounds
whose clip is clip
to stop playing the AudioClip on any of these AudioSource. If delay
is above 0.0, a FadeSound coroutine is started instead with the matching sounds
element and the delay
value to smoothly fade the clip.
If SoundVolume returns false (meaning sounds are muted), this method does nothing.
On overload that takes a string instead of an AudioClip, the AudioClip is obtained by loading the asset at Audio/Sounds/X
where X
is the string provided.
On overloads without a delay
parameter, the default value is 0.0.
public static void StopSound(int clip)
public static void StopSound(int clip, float delay)
This calls Stop sounds[clip]
to stop playing the AudioClip on the AudioSource. If delay
is above 0.0, a FadeSound coroutine is started instead with sounds[clip]
and the delay
value to smoothly fade the clip.
If SoundVolume returns false (meaning sounds are muted), this method does nothing.
On the overload without a delay
parameter, the default value is 0.1.
There's also a way to stop a sound with fading using FadeSound:
public static IEnumerator FadeSound(AudioSource sound, float speed)
Decreases the volume of sound
by TieFramerate(speed
) every frame until it reaches 0.0 or sound
doesn't play anymore. Stop is called on sound
once this is over.
Sound distance¶
Sounds also have a concept of distance where closer sounds could sound louder than sounds playing further away. This is a concept present in EntityControl's sound
AudioSource.
The volume scaling is done through a method called GetSoundDistance. There's 2 style: either using a position to determine the volume or the distance as a float.
public static float GetSoundDistance(Vector3 position)
public static float GetSoundDistance(Vector3 position, float maxdistance)
Returns a number between 0.0 and 1.0 where 0.0 means position
is maxdistance
or more units away from MainCamera
position and 1.0 means position
is the same as MainCamera
position. It's a method that's meant to be used to compute the volume a sound should have relative to the MainCamera
so closer sounds louder than sounds located further away.
The overload without a maxdistance
parameter has its value default to 25.0.
public static float GetSoundDistance(float distance)
public static float GetSoundDistance(float distance, float maxdistance)
Returns a number between 0.0 and 1.0 where 0.0 means distance
is maxdistance
or more and 1.0 means distance
is 0.0 or lower. It's a method that's meant to be used to compute the volume an entity should have when comparing its camdistance
to sounddistance
so entities located closer sounds louder than entities located further away.
The overload without a maxdistance
parameter is UNUSED, but rmains functional and it has maxdistance
default to 25.0.
Other utilities methods¶
Here are other potentially useful methods to work with sounds
.
public static int SoundIsPlaying(string name)
Returns the index of the first sounds
that isPlaying
and whose clip.name is name
. If no sounds
is found with these conditions, -1 is returned.
public static bool SoundVolume()
Returns true if sounds aren't muted, false otherwise. More precisely, the method returns true if any of the following conditions is true:
soundvolume
is above 0.0 and there's nopausemenu
displayedsoundvolume
is above 0.0 and there is apausemenu
displayed, but itswindowid
isn't 4 (not on the settings window)- There is a
pausemenu
displayed with awindowid
is 4 (settings window) andpausemenu
.svolume
is above 0.0. This essentially means that if the game is on the PauseMenu's settings window, the working value of the sound volume setting must not be muted and it takes precedence oversoundvolume
in these conditions