Straight lines are rarely enough — paths, camera moves, and animation need smooth curves. Learn lerp and easing, Bézier curves for authored paths, and Catmull-Rom splines that pass through points.
Linear interpolation moves at constant speed, which often looks robotic. Easing functions reshape the interpolation factor t so motion accelerates and decelerates naturally — ease-in, ease-out, ease-in-out. Applying an easing curve to a lerp is the difference between a mechanical slide and a satisfying, polished animation, and it costs almost nothing.
def lerp(a, b, t): return a + (b - a) * t
def ease_in_out(t): # smoothstep — slow, fast, slow
return t * t * (3 - 2 * t)
def ease_out(t): # decelerate toward the end
return 1 - (1 - t) ** 2
# animate a value from 0 to 100 over t in [0, 1]:
for i in range(0, 11, 2):
t = i / 10
print(round(lerp(0, 100, ease_in_out(t)), 1))
# 0, 10.4, 35.2, 64.8, 89.6, 100 -> eases in and out, not linear.
# reshape t with an easing curve, then lerp -> instantly more polished motion.A Bézier curve is defined by control points: the curve starts at the first and ends at the last, with the middle points pulling its shape without being touched. Cubic Béziers (four points) are the standard for authored paths — a camera fly-through, a projectile arc, the timing curves in animation software. Evaluating one is repeated lerping (De Casteljau’s algorithm).
def lerp(a, b, t): return a + (b - a) * t
def bezier_cubic(p0, p1, p2, p3, t):
# De Casteljau: repeated lerps collapse 4 points to 1 point on the curve
a = lerp(p0, p1, t); b = lerp(p1, p2, t); c = lerp(p2, p3, t)
d = lerp(a, b, t); e = lerp(b, c, t)
return lerp(d, e, t)
# a 1D example (do it per-axis for a 2D/3D curve):
for i in range(5):
t = i / 4
print(round(bezier_cubic(0, 0, 10, 10, t), 2))
# starts at p0, ends at p3; p1/p2 bend the curve without being passed through.
# used for camera paths, motion arcs, and animation timing curves.A Bézier does not pass through its middle control points, which is awkward when you have waypoints the path must hit. A Catmull-Rom spline is built to pass smoothly through every point you give it, making it ideal for paths defined by waypoints — an enemy patrol route, a rollercoaster track, a camera rail. You supply the points; the spline draws a smooth curve through them.
def catmull_rom(p0, p1, p2, p3, t):
# smooth curve that PASSES THROUGH p1 and p2 (p0, p3 shape the ends)
t2, t3 = t*t, t*t*t
return 0.5 * ((2*p1) +
(-p0 + p2) * t +
(2*p0 - 5*p1 + 4*p2 - p3) * t2 +
(-p0 + 3*p1 - 3*p2 + p3) * t3)
# path through waypoints [10, 5, 8, 20] — interpolate the middle segment:
for i in range(5):
t = i / 4
print(round(catmull_rom(10, 5, 8, 20, t), 2)) # goes THROUGH 5 and 8
# use for patrol routes, camera rails, tracks — anything defined by waypoints.Match the tool to the need: lerp plus easing for simple A-to-B motion, Bézier when an artist authors a shape with handles, and Catmull-Rom when the path must pass through given waypoints. Curves are everywhere in game feel — movement, cameras, animation, and procedural generation — so knowing which to reach for keeps motion smooth and intentional.
Which curve?
lerp + easing simple A -> B motion with nice acceleration
(UI, camera follow, value tweens)
Bézier an ARTIST shapes the curve with control handles
(animation timing, authored paths, vector graphics)
Catmull-Rom the path must PASS THROUGH given waypoints
(patrol routes, camera rails, tracks)
All are built on lerp underneath. Curves are core to game FEEL — movement,
cameras, animation, procedural paths. Pick by whether you author handles or
supply waypoints.