Game/BlastEffect.cs
namespace Monolith;
/// <summary>
/// A brief light flash where a blast landed. This fires up to twenty times a second per player
/// at high upgrade levels, so it is deliberately one GameObject with one light and no particles.
/// </summary>
public sealed class BlastEffect : Component
{
[Property] public float Lifetime { get; set; } = 0.18f;
[Property] public float StartRadius { get; set; } = 200f;
[Property] public float StartBrightness { get; set; } = 6f;
private PointLight light;
private Color baseColor = Color.White;
private GameTimeSince timeSinceSpawn;
/// <summary>Hard cap so a screen full of drones cannot flood the scene with lights.</summary>
private static int liveCount;
private const int MaxLive = 24;
public static void Spawn( Scene scene, Vector3 position, float worldRadius, bool isCharge )
{
if ( scene == null ) return;
if ( liveCount >= MaxLive ) return;
var obj = new GameObject( true, "Blast" );
obj.WorldPosition = position;
var effect = obj.AddComponent<BlastEffect>();
effect.StartRadius = MathF.Max( 120f, worldRadius * 3f );
effect.StartBrightness = isCharge ? 20f : 6f;
effect.Lifetime = isCharge ? 0.45f : 0.18f;
effect.baseColor = isCharge
? new Color( 1f, 0.65f, 0.25f )
: new Color( 0.75f, 0.88f, 1f );
var pointLight = obj.AddComponent<PointLight>();
pointLight.LightColor = effect.baseColor * effect.StartBrightness;
pointLight.Radius = effect.StartRadius;
pointLight.Shadows = false;
effect.light = pointLight;
liveCount++;
}
protected override void OnStart()
{
timeSinceSpawn = 0;
}
protected override void OnDestroy()
{
liveCount = Math.Max( 0, liveCount - 1 );
}
protected override void OnUpdate()
{
// Frozen while a blocking screen or the pause menu is up. See GameTime.
if ( GameTime.Paused )
return;
float t = timeSinceSpawn / Lifetime;
if ( t >= 1f )
{
GameObject.Destroy();
return;
}
if ( light.IsValid() )
{
// Expand and fade. Colour is scaled rather than alpha faded, because light
// intensity in s&box comes from the magnitude of LightColor.
float fade = (1f - t) * (1f - t);
light.Radius = StartRadius * (0.4f + t * 0.6f);
light.LightColor = baseColor * (StartBrightness * fade);
}
}
}