Game/2D/GridRenderer.cs

Component attached to a GameObject that hooks into a BombHandSystem to play fuse and explosion sounds during a detonation chain and to manage temporary fuse-line GameObjects. Visual fuse lines are not implemented here. It subscribes to Hand events, plays FuseSound at a cell world position, and destroys any created fuse-line GameObjects on clear.

NetworkingFile Access
using Sandbox;

/// <summary>
/// GridRenderer is now just a stub that handles the fuse-line
/// world-space animation between bombs during detonation.
/// All grid display is handled by GridPanel.razor (ScreenPanel UI).
///
/// Attach to any GameObject in the scene. Wire up Hand in inspector.
/// Can be left empty for now — fuse lines are a Day 2 polish task.
/// </summary>
public sealed class GridRenderer : Component
{
	[Property] public BombHandSystem Hand { get; set; }
	[Property] public GridManager Grid { get; set; }

	[Property] public SoundEvent ExplosionSound { get; set; }
	[Property] public SoundEvent ChestOpenSound { get; set; }
	[Property] public SoundEvent FuseSound { get; set; }

	protected override void OnStart()
	{
		if ( Hand is null ) return;
		Hand.OnChainStep += HandleChainStep;
		Hand.OnDetonationFinished += ( _, _ ) => ClearFuseLines();
	}

	readonly System.Collections.Generic.List<GameObject> _fuseLines = new();

	void HandleChainStep( int stepIdx, int totalSteps, int chestsSoFar, int projectedCleared, float mult )
	{
		var sim = Hand?.PreviewChain();
		if ( sim == null || stepIdx >= sim.Sequence.Count ) return;
		var node = sim.Sequence[stepIdx];

		if ( FuseSound is not null )
			Sound.Play( FuseSound, Grid?.CellWorldPos( node.R, node.C ) ?? Vector3.Zero );

		// Fuse line visual — Day 2 task, skip for now
	}

	void ClearFuseLines()
	{
		foreach ( var go in _fuseLines )
			if ( go.IsValid() ) go.Destroy();
		_fuseLines.Clear();
	}
}