intercepting objects in 3D space

I am fully aware that this is quite a common question. I have a player space ship and I want to calculate a position so that an enemy ship can shoot at me when I am moving and have a marker on the screen to help the player shoot at the enemy when it is moving.
I have found lots of threads asking this question all with very different answers and maths, some of these seem to be badly explained and/or wrong. Could someone show me the maths to do this or a link to a thread with an answer that you know is correct. Any help will be much appreciated.

You take the speed of your projectile, calculate how long it will travel to the target (distance), then you calculate the position the target will have in that time. This is the point you want to shoot at. Usually this is done iterative until the positions don’t differ much between 2 iterations. Note that any change of speed and/or rotation of the target will make your calculated point less optimal. But I have not seen a solution which also incoporates that. And there should be a “chance” to miss for the player anyway. I would be more interested to know why with all those fancy future tech weapons have still to be aimed manually ;).

While this does work, it’s not a great approach. Depending on the speed ratio between the projectile and the target it can get really off. It also highly depends on the angle.

A long time ago I made a WebPlayer example for this answer over here. I just created a WebGL build and updated my answer.

I’ll copy my method over here, just in case the links don’t work in the future:

public static Vector3 CalculateInterceptCourse(Vector3 aTargetPos, Vector3 aTargetSpeed, Vector3 aInterceptorPos, float aInterceptorSpeed)
{
     Vector3 targetDir = aTargetPos - aInterceptorPos;
     float iSpeed2 = aInterceptorSpeed * aInterceptorSpeed;
     float tSpeed2 = aTargetSpeed.sqrMagnitude;
     float fDot1 = Vector3.Dot(targetDir, aTargetSpeed);
     float targetDist2 = targetDir.sqrMagnitude;
     float d = (fDot1 * fDot1) - targetDist2 * (tSpeed2 - iSpeed2);
     if (d < 0.1f)  // negative == no possible course because the interceptor isn't fast enough
         return Vector3.zero;
     float sqrt = Mathf.Sqrt(d);
     float S1 = (-fDot1 - sqrt) / targetDist2;
     float S2 = (-fDot1 + sqrt) / targetDist2;
     if (S1 < 0.0001f)
     {
         if (S2 < 0.0001f)
             return Vector3.zero;
         else
             return (S2) * targetDir + aTargetSpeed;
     }
     else if (S2 < 0.0001f)
         return (S1) * targetDir + aTargetSpeed;
     else if (S1 < S2)
         return (S2) * targetDir + aTargetSpeed;
     else
         return (S1) * targetDir + aTargetSpeed;
}

This does even work when the projectile is slower than the enemy, given there’s enough room / time. Of course it’s still just a prediction based on the current velocity. So any future direction or velocity changes of course can not be considered.

1 Like

This answer on SE explains it pretty well and can be easily modified for 3D space: