Aim projectile to intercept moving target from a moving ship

So I have created spaceship shooter game where ships have turrets on them . Now I want those turrets to shoot a moving target meaning I want the projectile to intercept and hit the target that is headed in some direction. Every projectile has its own speed which is constant. Also the ship which has the turret is also moving at a constant speed.

So far I have made this:

Vector2 toTarget = targetShip.GlobalPosition - Player.currentShip.GlobalPosition;
Vector2 targetVel = (targetShip.dir.Normalized() * targetShip.speed * delta) - (Player.currentShip.dir.Normalized() * Player.currentShip.speed * delta);
float distance = toTarget.Length();

float a = targetVel.Dot(targetVel) - (projectile.speed * projectile.speed);
float b = 2 * targetVel.Dot(toTarget);
float c = -distance * distance; //toTarget.Dot(toTarget);

float p = -b / (2 * a);
float q = Mathf.Sqrt((b * b) - 4 * a * c) / (2 * a);

float t1 = p - q;
float t2 = p + q;

if (t1 < 0 && t2 < 0)
{
return;
}

float timeToInterception = 1;
if (t1 > 0 && t2 > 0)
timeToInterception = Mathf.Min(t1, t2);
//else
//timeToInterception = Mathf.Max(t1, t2);

Vector2 aimSpot = targetShip.GlobalPosition + targetVel * timeToInterception;
dir = aimSpot - GlobalPosition;
GlobalRotation = Mathf.LerpAngle(GlobalRotation, dir.Angle(), turnRate * delta);


The Global Rotation is where the turret will look at and it shoots from its barrel. The method kinda works and sometimes does not work(the projectiles shoot behind the moving target). Vector2 targetVel = ( targetShip.dir.Normalized() * targetShip.speed * delta) - (Player.currentShip.dir.Normalized() * Player.currentShip.speed * delta); that part is me calculating velocities I am not sure if its correct...

I commented out the else part because the turrets just disappear from my ship if I let that be there and I am also uneducated why.

I've read THIS answer from this forum but I don't understand it especially his edit part. In his edit part I don't understand where to plug that projectile velocity. Also why is my turret disappearing when I uncomment else in my code?

If someone can give me some explanation I would be very thankful!

• Can you clarify what it is about the linked answer you don't understand? It seems to just be describing a standard relative velocity calculation (subtract the velocity of the frame of reference from the velocity of each entity to get their velocities relative to that frame of reference). Where do you run into trouble applying that, or other past Q&A about calculating intercept velocities/target leading? Nov 27, 2022 at 23:51
• Hey yea just did it in an edit. Nov 27, 2022 at 23:53
• The answer does not talk about that. It's just talking about how to take the "moving shooter" out of the equation, so you can use existing answers about aiming at a moving target from a stationary shooting point. You can consult past Q&A like 1, 2, 3, 4, and more (those were just the first few results I found searching for "target leading" and "intercept moving"). Nov 28, 2022 at 0:09
• Thank you I will look into it. Nov 28, 2022 at 0:11
• Seems duplicate of stackoverflow.com/questions/2248876/… which has many good answers Feb 8, 2023 at 18:06

Vector3 projectileDirection = aimPoint - (ownerShip.GlobalPosition + gunVelocity * t);


to account for the ship's own speed and direction, so we subtract that speed from the final projectile direction to actually hit the target correctly.

Leading a Target from Howling Moon Software

This tutorial helped me and it works great now! Thanks @DMGregory for the link!

This is how my code looks now:

Vector2 toTarget = (targetShip.GlobalPosition) - GlobalPosition;
Vector2 targetVel = (targetShip.dir.Normalized() * targetShip.speed);
Vector2 gunVelocity = (ownerShip.dir.Normalized() * ownerShip.speed);
Vector2 vr = targetVel - gunVelocity;

if (t > 0f)
{
Vector2 aimPoint = targetShip.GlobalPosition + targetVel * t;
dir = aimPoint - GlobalPosition;
GlobalRotation = Mathf.LerpAngle(GlobalRotation, dir.Angle(), turnRate * delta);
}


The function AimAhead is the one that calculates everything:

float a = vr.Dot(vr) - (projectile.speed * projectile.speed);
float b = 2 * vr.Dot(toTarget);
float c = toTarget.Dot(toTarget);

float det = b * b - 4 * a * c;

if (det > 0f)
{
return 2 * c / (Mathf.Sqrt(det) - b);
}
else
{
return -1f;
}

• This solution is obviously wrong since if targetVel is 0 then you're doing nothing to compensate for the gunVelocity Jun 10, 2023 at 21:36
• @shoosh Do you know the correct solution? I am having exactly this problem. Oct 29, 2023 at 20:50