I designed and prototyped the missile attack! The math was clever and I want to show-off!
Let’s talk about cubic bezier curves, perlin noise, and rotation minimizing frames.
Doing Ichirō Itano proud.
I’ll keep this article a little lighter on code. I really want to focus instead of the geometry. Many people are intimidated by math, but keep in mind that you don’t need to understand everything to use it.
Even if this is retreading topics you’ve already mastered, hopefully my own solution shows you some new ways you can combine these techniques creatively.
Broadly speaking, there’s two flavors of movement code. Iterative Code updates an object position incrementally one frame at a time, in a process college-professors call integration. A common example of this Euler’s Method where we compute the velocity of the object and then nudge the position in that direction over a timestep:
void Update( float DeltaTime ) {
Vector3 Velocity = CalculateVelocity();
Vector3 Position = GetPosition();
SetPosition( Position + DeltaTime * Velocity );
}
Delta is just ‘math speak’ for “change in” as in “the change in time this Update()”.
This is the natural way to write character control, in which the player input varies every frame, or complex physics simulations where there is no known realtime analytical solution.
Alternatively, if you know the whole motion ahead of time, you can use Closed-Form Code where you plot the whole path from intial conditions (math heads call it a parametric curve), and sample the current time. A good example of this is the well-known Cubic Bezier Curve:
Vector3 CalcBezierPos( Vector3 P0, Vector3 P1, Vector3 P2, Vector3 P3, float t ) {
float t_ = 1 - t;
return
(t_ * t_ * t_) * P1 +
(3 * t_ * t_ * t) * P2 +
(3 * t_ * t * t) * P3 +
(t * t * t) * P4 ;
}
If you’ve every used any vector graphics tool you probably recognize this. Beziers are cubic polynomials which is a fancy way of saying the simplest path with four degrees of freedom: the endpoints P0 and P3 and the “control points” P1 and P2 which affect the orientation and curvature.
The input t is called the input parameter and is a ratio on the range 0-1. So e.g. t=0.333 is about a third of the way through. To move a point, we simply take the elapsed time since the start of the motion, divided by the duration.
float StartTime;
float Duration;
void Update() {
float CurrentTime = Time.time;
float Elapsed = CurrentTime - StartTime;
if( Elapsed >= Duration )
SetPosition( P3 ); // we're at the end
else
SetPosition( CalcBezierPos( P0, P1, P2, P3, Elapsed / Duration ) );
}
In addition to the position, we can also use the bezier parameters to calculate the derivative at t, which is the rate of change. This vector is useful because we says it’s tangent to the curve, i.e. it points in the direction of the motion. To convert this to speed, divide by the duration.
Vector3 CalcBezierDeriv( Vector3 P0, Vector3 P1, Vector3 P2, Vector3 P3, float t ) {
float t_ = 1 - t;
return (
( 3 * t_ * t_ ) * ( P1 - P0 ) +
( 6 * t_ * t ) * (