I ended up during my research finding quite a number of different articles on this problem, however in the main they boiled down to basically the same maths with variations. I have to be honest quadratic equations are a little beyond me, and unsurprisingly I wasn’t able to find a decent explanation of the (mathematical) terms involved.
That said I’m not above using something that works, even if I can’t work out exactly how it was derived. In order to “road test” the algorithm I decided to make a simple test bed, naturally I reached for Raylib for this! I first created a target that followed a very simple rectangular path.
The test bed, will wait for a random period of time and then fire at the moving target. Obviously if the target changes velocity or direction the shot will miss, its a dumb projectile not a cruise missile!
It should be noted, that by coincidence a shot can sometimes hit the target even if the aim point ends up off the targets path.
You can grab the source code for the test bed here.
Here’s the meat of the maths….
// quadratic terms
float a = Vector2DotProduct(targVel, targVel) - (shotSpeed * shotSpeed);f
loat b = 2.0 * Vector2DotProduct(targVel, totarget);
float c = Vector2DotProduct(totarget, totarget);
// quadratic formular simplfied down to this...
float p = -b / (2.0 * a);
float q = (float)sqrt((b * b) - 4.0 * a * c) / (2.0 * a);
float t = p - q;
// target velocity * t + target pos = aim point (t = time or steps till hit)
targVel = Vector2Scale(targVel, t);
shotDest = Vector2Add(target, targVel);
// shot increment calculation
shotInc = Vector2Subtract(shotDest, shotPos);
shotInc = Vector2Normalize(shotInc);
shotInc = Vector2Scale(shotInc, shotSpeed);