Transposer/Entities/PixelParticle.cs
namespace Sandbox.Transposer;

/// <summary>
/// Generic coloured particle with direction, speed, lifetime, and easing.
/// Bounces off screen edges and fades out. Used for the white explosion
/// effect when collecting a coin.
/// </summary>
public class PixelParticle : Entity
{
	private Color _color;
	private float _speedMax;
	private Vector2 _direction;
	private float _lifetimeMax;
	private float _lifetime;    // Counts DOWN — drives opacity (full → transparent).
	private float _elapsedTime; // Counts UP  — drives speed easing (fast → slow).

	public PixelParticle( Color color, float x, float y, TransposerScene scene,
		Vector2 direction, float speed, float lifetime )
	{
		_color = color;
		_scene = scene;
		_speedMax = speed;
		_direction = direction;
		_hitbox = new PixelRect( 0, 0, 1, 1 );
		_lifetimeMax = lifetime;
		_lifetime = lifetime;
		_collideable = true;
		ExactX = x;
		ExactY = y;
		_layer = Globals.DEPTH_PARTICLE;
	}

	public override void UpdateEntity( float deltaTime )
	{
		base.UpdateEntity( deltaTime );

		_elapsedTime += deltaTime;

		// Speed eases from full to 20% over the particle's lifetime — fast burst, slow drift.
		float speed = PixelUtils.Map( _elapsedTime, 0f, _lifetimeMax, _speedMax, _speedMax * 0.2f, EaseType.SineOut );
		Vector2 newPos = ExactPos + _direction * speed * deltaTime;
		int newX = (int)MathF.Round( newPos.x );
		int newY = (int)MathF.Round( newPos.y );

		if ( newX < 3 || newX > Screen.PixelWidth - 4 )
			_direction = new Vector2( -_direction.x, _direction.y );
		else if ( newY < 3 || newY > Screen.PixelHeight - 4 )
			_direction = new Vector2( _direction.x, -_direction.y );
		else
			ExactPos = newPos;

		_lifetime -= deltaTime;
		if ( _lifetime <= 0f )
			_scene.RemoveEntity( this );
	}

	public override void Draw()
	{
		float opacity = PixelUtils.Map( _lifetime, _lifetimeMax, 0f, 1f, 0f, EaseType.SineOut );
		Screen.AddPixel( PixelX, PixelY, new Color32( (byte)(_color.r * 255), (byte)(_color.g * 255), (byte)(_color.b * 255), (byte)(opacity * 255f) ) );
	}
}