DiamondDebris.Shatter.cs
using System;
using System.Collections.Generic;
using Sandbox;
using static Diamonds.DiamondBoard;
namespace Diamonds;
public sealed partial class DiamondDebris
{
public sealed class ShatterSunburst
{
public Vector2 Position { get; internal set; }
public float Age { get; internal set; }
public float Lifetime { get; internal set; }
public float Scale { get; internal set; }
public float Rotation { get; internal set; }
public float Brightness { get; internal set; }
public int ColorIndex { get; internal set; }
internal Vector2 Velocity;
}
readonly List<ShatterSunburst> shatterSunbursts = new();
public IReadOnlyList<ShatterSunburst> ShatterSunbursts => shatterSunbursts;
readonly List<ShatterSunburst> crushSunbursts = new();
public IReadOnlyList<ShatterSunburst> CrushSunbursts => crushSunbursts;
public const float CrushBurstDuration = 0.25f;
public const float CrushBurstScale = 0.6f;
void EmitCrushSunburst( Particle shard )
{
if ( crushSunbursts.Count >= MaxShards ) crushSunbursts.RemoveAt( 0 );
crushSunbursts.Add( new ShatterSunburst
{
Position = shard.Position, ColorIndex = shard.ColorIndex,
Lifetime = CrushBurstDuration, Scale = CrushBurstScale,
Rotation = Range( -MathF.PI, MathF.PI ), Brightness = 0.4f
} );
}
void UpdateShatterSunbursts( float delta )
{
UpdateSunbursts( shatterSunbursts, delta );
UpdateSunbursts( crushSunbursts, delta );
}
static void UpdateSunbursts( List<ShatterSunburst> bursts, float delta )
{
for ( int i = bursts.Count - 1; i >= 0; i-- )
{
var burst = bursts[i];
burst.Age += delta;
if ( burst.Age >= burst.Lifetime ) { bursts.RemoveAt( i ); continue; }
burst.Position += burst.Velocity * delta;
}
}
void EmitShatterEffects( Diamond cell, bool gameOver )
{
var center = new Vector2( LaneX( cell.Lane ), cell.Y );
for ( int i = 0; i < 3; i++ )
{
if ( shatterSunbursts.Count >= 192 ) shatterSunbursts.RemoveAt( 0 );
float angle = Range( -MathF.PI, MathF.PI );
var outward = new Vector2( MathF.Cos( angle ), MathF.Sin( angle ) );
shatterSunbursts.Add( new ShatterSunburst
{
Position = center + outward * (i == 0 ? 0 : Range( 8, 18 )),
Velocity = outward * (i == 0 ? 0 : Range( 35, 75 )),
Lifetime = Range( 0.35f, 0.5f ), Scale = i == 0 ? 1.3f : Range( 0.5f, 0.8f ),
Rotation = Range( -MathF.PI, MathF.PI ), Brightness = Range( 0.4f, 0.6f ), ColorIndex = cell.ColorIndex
} );
}
int count = gameOver ? random.Next( 9, 15 ) : random.Next( 28, 43 );
for ( int i = 0; i < count; i++ )
{
float angle = Range( -MathF.PI, MathF.PI );
var outward = new Vector2( MathF.Cos( angle ), MathF.Sin( angle ) );
float radius = Range( 0.8f, 1.9f );
var position = center + outward * Range( 2, 18 );
if ( !HasRoom( position, radius + 0.5f ) ) continue;
// The vanished gem leaves an open pocket. Launch from inside it so
// nearby surviving gems naturally block and deflect the explosion.
AddSpark( position, outward * Range( 450, 950 ), radius, cell.ColorIndex );
}
}
}