Game/DemoCharge.cs
namespace Monolith;
/// <summary>
/// The visible marker for a planted demolition charge. Pulses so it reads as armed and is
/// findable again after you have flown away from it.
/// </summary>
public sealed class DemoCharge : Component
{
private PointLight light;
private ModelRenderer renderer;
private GameTimeSince timeSincePlaced;
public static DemoCharge Spawn( Scene scene, Vector3 position )
{
if ( scene == null ) return null;
var obj = new GameObject( true, "Demolition Charge" );
obj.NetworkMode = NetworkMode.Never;
obj.WorldPosition = position;
var charge = obj.AddComponent<DemoCharge>();
// A visible body, not just a light. The whole point of the slow flight is that you
// watch the charge travel and pick your moment, and a light alone shows nothing once
// it is inside the rock or crossing empty space.
var mr = obj.AddComponent<ModelRenderer>();
mr.Model = Projectile.SharedBoltModel;
mr.Tint = new Color( 1f, 0.30f, 0.12f );
obj.WorldScale = new Vector3( 26f, 11f, 11f );
charge.renderer = mr;
var pointLight = obj.AddComponent<PointLight>();
pointLight.LightColor = new Color( 1f, 0.25f, 0.15f ) * 8f;
pointLight.Radius = 260f;
pointLight.Shadows = false;
charge.light = pointLight;
return charge;
}
protected override void OnStart()
{
timeSincePlaced = 0;
}
protected override void OnUpdate()
{
// Frozen while a blocking screen or the pause menu is up. See GameTime.
if ( GameTime.Paused )
return;
if ( !light.IsValid() )
return;
// Roughly twice a second, so it is obviously ticking rather than merely lit.
float pulse = 0.55f + 0.45f * MathF.Sin( timeSincePlaced * 9f );
light.LightColor = new Color( 1f, 0.25f, 0.15f ) * (5f + 7f * pulse);
light.Radius = 220f + 80f * pulse;
if ( renderer.IsValid() )
renderer.Tint = new Color( 1f, 0.22f + 0.35f * pulse, 0.10f );
}
}