Home > OS >  2D: Moving Turret's Projectile Intercept moving target
2D: Moving Turret's Projectile Intercept moving target

Time:12-10

So I am in middle of making space game where spaceships have turrets on them.

Those turrets need to shoot at the moving target with a projectile of constant speed. AkA it needs to intercept and hit the target.

It works perfectly when my ship and npc ship are not moving at the same direction or almost the same direction. When they move at the same direction the turret is firing projectiles slightly behind the npc ship. But as soon as I make turn it hits npc ships consistently.

Also when I stand still npc ship is firing slightly in front of me but my ship is hitting npc ship all the time when I am standing still.

Here is my code:

Vector2 toTarget = (targetShip.GlobalPosition) - GlobalPosition;
            Vector2 targetVel = (targetShip.dir * targetShip.speed);
            Vector2 gunVelocity = (Player.currentShip.dir * Player.currentShip.playerSpeed);
            Vector2 vr = targetVel - gunVelocity;

            float t = AimAhead(toTarget, vr);

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

The aim ahead function:

 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;
        }

CodePudding user response:

Ah a funny mistake...

Vector2 aimPoint = targetShip.GlobalPosition   vr * t;

SHOULD BE:

Vector2 aimPoint = targetShip.GlobalPosition   targetVel * t;

Everything works perfect now.

CodePudding user response:

This looks correct for simple linear motion:

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

From there I would do this:

var bb = b * b;
var a2 = 2 * a;
var ac4 = 4 * a * c;

And use this check:

if (bb >= ac4 && a2 != 0.0)

Evidently bb >= ac4 is equivalent to the check you are using.

So why a2 != 0.0? Well, if you got the three first lines right, I suppose you are aware that we are using the solution to a quadratic equation. A quadratic has two solutions, which are (-b sqrt(bb - ac4))/a2 And (-b - sqrt(bb - ac4))/a2 That is the ± of the quadratic formula:

Quadratic formula

And I don't want a division by zero.

Ok, so we have two possible solutions. This is how I proceed:

var r = Mathf.Sqrt(bb - ac4);
var times = new float[]{(-b   r)/a2, (-b - r)/a2};
var time = float.PositiveInfinity;
foreach (var candidate_time in times)
{
    if (candidate_time < 0.0)
    {
        continue;
    }

    if (candidate_time < time)
    {
        time = candidate_time;
    }
}

if (float.IsInfinity(time))
{
    return -1f;
}

return time;

This is based on an implementation to hit a moving target that is following a path defined by line segments which you can find elsewhere. I could be doing more than necessary for this simple case.

  • Related