Component that plays a looping background music track for the game, respects a music volume setting and speaker mute by stopping playback, and handles fade-in and restart when the loop ends.
namespace DesertPump;
/// <summary>
/// Keeps the background track playing on a loop, and takes the speaker button seriously -
/// muting stops the music rather than just silencing the effects.
/// </summary>
[Title( "Desert Pump Music" )]
[Category( "Desert Pump" )]
[Icon( "music_note" )]
public sealed class PumpMusic : Component
{
[Property]
public SoundEvent Track { get; set; }
/// <summary>
/// Ceiling for the track. The player's music slider scales this, so it stays
/// background even at full volume.
/// </summary>
[Property, Range( 0f, 1f )]
public float Volume { get; set; } = 0.6f;
/// <summary>What the track should actually play at, once settings are applied.</summary>
public float TargetVolume => Volume * PumpSettings.Current.EffectiveMusic;
/// <summary>Seconds to ease in, so it doesn't slam in at full level on load.</summary>
[Property, Range( 0f, 8f )]
public float FadeIn { get; set; } = 2.5f;
SoundHandle handle;
/// <summary>Whether the track is actually rolling right now.</summary>
public bool IsPlaying => handle.IsValid() && handle.IsPlaying;
protected override void OnEnabled()
{
Start();
}
protected override void OnDisabled()
{
Stop();
}
protected override void OnUpdate()
{
// Muting, or dragging the music slider to zero, stops the track rather than
// leaving it running silently.
if ( TargetVolume <= 0f )
{
Stop();
return;
}
// The track is a fixed-length loop, so restart it as soon as it runs out.
if ( !handle.IsValid() || !handle.IsPlaying )
{
Start();
return;
}
handle.Volume = TargetVolume;
}
void Start()
{
if ( Track is null || TargetVolume <= 0f )
return;
if ( handle.IsValid() && handle.IsPlaying )
return;
handle = Sound.Play( Track, (Sandbox.Audio.Mixer)null );
if ( !handle.IsValid() )
return;
handle.Volume = TargetVolume;
handle.Fadein = FadeIn;
}
void Stop()
{
if ( handle.IsValid() )
{
handle.Stop( 0.4f );
}
handle = null;
}
}