Animation
SharpProspero.Animation moves a number from one value to another over a set time along an easing
curve, so a panel slides in, a bar fills, or a colour fades without hand-written per-frame maths. It
also evaluates smooth 2D paths for motion a straight A-to-B move cannot express.
Tween a value over time
A Tween moves a float from a start to an end over a duration, shaped by a curve. It holds no
reference to what it drives, so one tween can move a position, an alpha, or a colour channel. Create
it once, then advance it each frame with the time since the last and read the result:
using SharpProspero.Animation;
var slideIn = new Tween(from: -200, to: 0, durationSeconds: 0.3f, Ease.OutCubic);
// each frame, in OnFrame:
int x = (int)slideIn.Update((float)frame.DeltaSeconds);
// draw the panel at x this frame
if (slideIn.IsComplete) { /* settled */ }
Update(deltaSeconds) advances the tween and returns the new Value; a zero or negative delta leaves
it where it is. The frame delta comes from FrameContext.DeltaSeconds (see Application),
which is a double, so cast it to float on the way in.
durationSeconds must be positive; zero or a negative value throws ArgumentOutOfRangeException from
the constructor, not on the first update.
Read the running state through three properties:
| Member | Meaning |
|---|---|
Value |
The current value, shaped by the easing curve, between From and To. |
Progress |
How far through the current run, 0 to 1, before the curve is applied. |
IsComplete |
True once a Once tween has reached the end; a looping tween never completes. |
From, To, Ease and Mode are readable too, and return what the constructor was given.
Restart() moves the tween back to its start so it runs again from the beginning.
End behaviour with TweenMode
TweenMode, passed to the constructor, decides what happens when a run reaches the end:
| Mode | Behaviour |
|---|---|
Once |
Settles on the end value and reports IsComplete. The default. |
Loop |
Jumps back to the start and runs again, without end. |
PingPong |
Runs to the end, back to the start, then forward again, without end. |
var pulse = new Tween(from: 0.4f, to: 1f, durationSeconds: 0.8f, Ease.InOutSine, TweenMode.PingPong);
// each frame:
float alpha = pulse.Update((float)frame.DeltaSeconds);
A
LooporPingPongtween folds its elapsed time back into one period each update, so it stays precise even when left running for a long time.
Easing curves
Ease picks the shape of the motion. Easing.Apply(ease, t) maps a progress value t (clamped to
0..1) through the chosen curve, where 0 is the start and 1 is the end.
| Curve | Shape |
|---|---|
Linear |
A straight line: constant speed. |
InQuad / OutQuad / InOutQuad |
Squared ease in, out, or both. |
InCubic / OutCubic / InOutCubic |
Cubed ease — stronger than the squared form. |
InSine / OutSine / InOutSine |
Gentle sine ease in, out, or both. |
OutBack |
Overshoots past the end and settles back, for a springy finish. |
OutBounce |
Lands and bounces a few times before settling, like a dropped ball. |
For a one-off value without a tween, Easing.Interpolate gives the eased position from one value to
another at a fraction t:
float alpha = Easing.Interpolate(from: 0f, to: 1f, t: 0.5f, Ease.InOutSine);
This is the same maths a Tween runs internally, so use it when you already track your own progress
and only need the eased reading.
Splines for curved paths
Spline (in SharpProspero.Animation) evaluates smooth 2D paths: a camera or enemy that follows a
curve, a pan across a photo, a projectile arc. It works in Vector2 from
SharpProspero.Numerics.
Quadratic and cubic Bezier curves run from control points. The quadratic form takes a start, one control point, and an end; the cubic form takes two control points:
using SharpProspero.Animation;
using SharpProspero.Numerics;
Vector2 quad = Spline.Bezier(start, control, end, t);
Vector2 cubic = Spline.Bezier(start, controlA, controlB, end, t);
A Catmull-Rom spline passes through a list of waypoints. Give it the points and a t from 0 (the
first point) to 1 (the last); the ends are clamped so the curve does not overshoot past the first and
last point. An empty list throws ArgumentException; a list of one returns that point:
var waypoints = new[]
{
new Vector2(0, 0),
new Vector2(120, -40),
new Vector2(260, 30),
new Vector2(400, 0),
};
Vector2 pos = Spline.CatmullRom(waypoints, t);
CatmullRomSegment(p0, p1, p2, p3, t) evaluates a single segment from p1 to p2, with p0 and
p3 shaping the tangents at each end. Use it when you drive one span at a time rather than a whole
path.
Drive t with a Tween to move along a curve over time, combining the two ideas — an eased tween on
t gives a path that both bends in space and eases in speed.