Entities/Blocks/BlockMagnet.cs

A BlockMagnet entity class that extends LaneBlock to implement a magnet block. It configures pull direction (opposite move), inward force, particle kind and travel, overlay color and applies magnet impulse to players.

Native Interop
namespace BlockParty;

/// <summary>
/// Magnet block — the pulling counterpart to <see cref="BlockWind"/>. While its eyes are open (phase 1+)
/// it exerts a block-width lane of attraction, dragging the player and projectiles (fireballs, teardrops)
/// TOWARD the block — but NOT blocks or lasers. Phase 1 pulls along a single lane on the OPPOSITE side to
/// <see cref="Block.MoveDirection"/> (so a block moving right reaches out to its left and drags things
/// right, toward itself); phase 2 pulls along four lanes in every cardinal direction at once.
///
/// All of the lane geometry, per-column blocking, force application, particle streaming and overlay
/// rendering live in <see cref="LaneBlock"/>; the magnet just flips the sign — the force pulls back
/// toward the face (<c>-D</c>) and particles stream inward and die when they reach the block — feeds the
/// player's magnet channel, uses darker purple dust, and a purple tint.
/// </summary>
public sealed class BlockMagnet : LaneBlock
{
	// Purple lane tint (RGB); alpha is applied per-tick from OVERLAY_ALPHA × strength.
	const float OVERLAY_R = 0.34f, OVERLAY_G = 0.12f, OVERLAY_B = 0.52f;
	const float OVERLAY_ALPHA = 0.7f; // alpha at full strength (eyes fully open)

	// Phase 1: pull along the lane OPPOSITE to the way we're moving.
	protected override Direction GetPhase1Direction() => Globals.GetOppositeDirection( MoveDirection );

	protected override Vector2 GetForceDirection( in Lane lane ) => -lane.D; // pull inward toward the block

	protected override void ApplyPlayerForce( Player player, Vector2 impulse ) => player.AddMagnetImpulse( impulse );

	protected override ParticleKind ParticleKind => ParticleKind.MagnetDust;

	// Magnet particles fly INWARD toward the face, so they travel their offset-from-the-face distance.
	protected override float GetParticleTravel( float reach, float along ) => along;

	protected override Color GetOverlayColor( float strength ) => new Color( OVERLAY_R, OVERLAY_G, OVERLAY_B, OVERLAY_ALPHA * strength );
}