Client-side music controller for the MansionGame. It chooses a music track for the current level, crossfades between tracks when the level changes, starts/stops playback, and applies a smooth volume lerp to a configured target volume.
using Sandbox;
namespace BrickJam;
public sealed partial class MansionGame
{
/// <summary>How fast the music fades in/out (per second). Legacy faded on the server tick.</summary>
public float MusicVolumeChangeRate => 0.5f;
/// <summary>Target music volume - background level, the tracks are mastered loud.</summary>
public float MusicVolume => 0.15f;
private SoundHandle musicHandle;
private LevelType musicLevel = LevelType.None;
private float musicVolume;
/// <summary>
/// Client-side music orchestration (every client, host included - music is local audio). Scene-System
/// port of the legacy host-side <c>ProcessMusic</c>: drive the track from the replicated
/// <see cref="CurrentLevelType"/> and crossfade when the level changes.
/// </summary>
protected override void OnUpdate()
{
var track = Level.GetMusic( CurrentLevelType );
if ( CurrentLevelType != musicLevel )
{
// Level changed: fade the old track out, then swap once it's silent.
musicVolume = musicVolume.LerpTo( 0f, MusicVolumeChangeRate * Time.Delta );
if ( musicVolume <= 0.01f )
{
musicHandle?.Stop();
musicHandle = null;
musicLevel = CurrentLevelType;
musicVolume = 0f;
}
ApplyMusicVolume();
return;
}
// Same level: keep the track playing (restart if the asset isn't looped) and fade toward target.
if ( !string.IsNullOrEmpty( track ) )
{
if ( musicHandle is null || musicHandle.IsStopped )
{
musicHandle = Sound.Play( track );
if ( musicHandle is not null )
musicHandle.Volume = musicVolume; // start at the current (faded) level, not full blast
}
musicVolume = musicVolume.LerpTo( MusicVolume, MusicVolumeChangeRate * Time.Delta );
}
else
{
musicVolume = musicVolume.LerpTo( 0f, MusicVolumeChangeRate * Time.Delta );
if ( musicVolume <= 0.01f && musicHandle is not null )
{
musicHandle.Stop();
musicHandle = null;
}
}
ApplyMusicVolume();
}
private void ApplyMusicVolume()
{
if ( musicHandle is not null && !musicHandle.IsStopped )
musicHandle.Volume = musicVolume;
}
}