A component that animates a block popping in. It captures the block's intended LocalScale, sets it to a tiny start scale on enable, then over Duration (after an optional Delay) eases the scale up with an overshoot using an EaseOutBack curve and destroys itself when finished.
using Sandbox;
namespace Breakout;
/// <summary>
/// Plays the "pop in" animation when a brick appears: it starts tiny and scales up to full size
/// with a slight overshoot, then removes itself. Delay lets rows stagger their entrance so the
/// wall drops in from top to bottom.
/// </summary>
[Title( "Block Spawn In" ), Category( "Breakout" ), Icon( "animation" )]
public sealed class BlockSpawnIn : Component
{
[Property] public float Delay { get; set; }
[Property] public float Duration { get; set; } = 0.24f;
private const float StartScale = 0.02f;
private Vector3 targetScale;
private bool captured;
private TimeSince sinceEnabled;
protected override void OnEnabled()
{
if ( !captured )
{
targetScale = LocalScale;
captured = true;
}
LocalScale = targetScale * StartScale;
sinceEnabled = 0f;
}
protected override void OnUpdate()
{
if ( Duration <= 0f )
{
LocalScale = targetScale;
Destroy();
return;
}
float t = (sinceEnabled - Delay) / Duration;
if ( t < 0f )
{
LocalScale = targetScale * StartScale;
return;
}
if ( t >= 1f )
{
LocalScale = targetScale;
Destroy();
return;
}
LocalScale = targetScale * EaseOutBack( t );
}
// Easing curve that shoots a little past full size and settles back, giving each brick a
// springy pop as it appears.
private static float EaseOutBack( float t )
{
const float s = 1.70158f;
t -= 1f;
return 1f + t * t * ((s + 1f) * t + s);
}
}