26

Okay, this all takes place in a nice and simple 2D world... :)

Suppose I have a static object A at position Apos, and a linearly moving object B at Bpos with bVelocity, and an ammo round with velocity Avelocity...

How would I find out the angle that A has to shoot, to hit B, taking into account B's linear velocity and the speed of A's ammo ?

Right now the aim's at the current position of the object, which means that by the time my projectile gets there the unit has moved on to safer positions :)

tshepang
  • 12,111
  • 21
  • 91
  • 136
Led
  • 2,002
  • 4
  • 23
  • 31

11 Answers11

52

I wrote an aiming subroutine for xtank a while back. I'll try to lay out how I did it.

Disclaimer: I may have made one or more silly mistakes anywhere in here; I'm just trying to reconstruct the reasoning with my rusty math skills. However, I'll cut to the chase first, since this is a programming Q&A instead of a math class :-)

How to do it

It boils down to solving a quadratic equation of the form:

a * sqr(x) + b * x + c == 0

Note that by sqr I mean square, as opposed to square root. Use the following values:

a := sqr(target.velocityX) + sqr(target.velocityY) - sqr(projectile_speed)
b := 2 * (target.velocityX * (target.startX - cannon.X)
          + target.velocityY * (target.startY - cannon.Y))
c := sqr(target.startX - cannon.X) + sqr(target.startY - cannon.Y)

Now we can look at the discriminant to determine if we have a possible solution.

disc := sqr(b) - 4 * a * c

If the discriminant is less than 0, forget about hitting your target -- your projectile can never get there in time. Otherwise, look at two candidate solutions:

t1 := (-b + sqrt(disc)) / (2 * a)
t2 := (-b - sqrt(disc)) / (2 * a)

Note that if disc == 0 then t1 and t2 are equal.

If there are no other considerations such as intervening obstacles, simply choose the smaller positive value. (Negative t values would require firing backward in time to use!)

Substitute the chosen t value back into the target's position equations to get the coordinates of the leading point you should be aiming at:

aim.X := t * target.velocityX + target.startX
aim.Y := t * target.velocityY + target.startY

Derivation

At time T, the projectile must be a (Euclidean) distance from the cannon equal to the elapsed time multiplied by the projectile speed. This gives an equation for a circle, parametric in elapsed time.

sqr(projectile.X - cannon.X) + sqr(projectile.Y - cannon.Y)
  == sqr(t * projectile_speed)

Similarly, at time T, the target has moved along its vector by time multiplied by its velocity:

target.X == t * target.velocityX + target.startX
target.Y == t * target.velocityY + target.startY

The projectile can hit the target when its distance from the cannon matches the projectile's distance.

sqr(projectile.X - cannon.X) + sqr(projectile.Y - cannon.Y)
  == sqr(target.X - cannon.X) + sqr(target.Y - cannon.Y)

Wonderful! Substituting the expressions for target.X and target.Y gives

sqr(projectile.X - cannon.X) + sqr(projectile.Y - cannon.Y)
  == sqr((t * target.velocityX + target.startX) - cannon.X)
   + sqr((t * target.velocityY + target.startY) - cannon.Y)

Substituting the other side of the equation gives this:

sqr(t * projectile_speed)
  == sqr((t * target.velocityX + target.startX) - cannon.X)
   + sqr((t * target.velocityY + target.startY) - cannon.Y)

... subtracting sqr(t * projectile_speed) from both sides and flipping it around:

sqr((t * target.velocityX) + (target.startX - cannon.X))
  + sqr((t * target.velocityY) + (target.startY - cannon.Y))
  - sqr(t * projectile_speed)
  == 0

... now resolve the results of squaring the subexpressions ...

sqr(target.velocityX) * sqr(t)
    + 2 * t * target.velocityX * (target.startX - cannon.X)
    + sqr(target.startX - cannon.X)
+ sqr(target.velocityY) * sqr(t)
    + 2 * t * target.velocityY * (target.startY - cannon.Y)
    + sqr(target.startY - cannon.Y)
- sqr(projectile_speed) * sqr(t)
  == 0

... and group similar terms ...

sqr(target.velocityX) * sqr(t)
    + sqr(target.velocityY) * sqr(t)
    - sqr(projectile_speed) * sqr(t)
+ 2 * t * target.velocityX * (target.startX - cannon.X)
    + 2 * t * target.velocityY * (target.startY - cannon.Y)
+ sqr(target.startX - cannon.X)
    + sqr(target.startY - cannon.Y)
  == 0

... then combine them ...

(sqr(target.velocityX) + sqr(target.velocityY) - sqr(projectile_speed)) * sqr(t)
  + 2 * (target.velocityX * (target.startX - cannon.X)
       + target.velocityY * (target.startY - cannon.Y)) * t
  + sqr(target.startX - cannon.X) + sqr(target.startY - cannon.Y)
  == 0

... giving a standard quadratic equation in t. Finding the positive real zeros of this equation gives the (zero, one, or two) possible hit locations, which can be done with the quadratic formula:

a * sqr(x) + b * x + c == 0
x == (-b ± sqrt(sqr(b) - 4 * a * c)) / (2 * a)
Jeffrey Hantin
  • 35,734
  • 7
  • 75
  • 94
  • This is great stuff ::- D. Completely saved my sorry ass. – Axonn Mar 09 '11 at 10:20
  • Note that this approach will fail whenever target and projectile have the same speed, independent of direction, as a==0 and causes division by zero issues. See Broofa's answer which handles this and another potential problem case. – e100 Sep 28 '12 at 17:01
  • @e100 I did leave out some of the corner cases, such as dealing with zero coefficients; I may have to go back and add them sometime. – Jeffrey Hantin Sep 28 '12 at 21:53
  • how did you get a,b and c values Jeffery? – relaxxx Nov 30 '12 at 19:35
  • @relaxxx They're portions of the standard-form quadratic equation in the math block above. `x` is `t`, `a` is the chunk multiplied by `sqr(t)`, `b` is the chunk multiplied by `t`, and `c` is the chunk added in with no multiplication by `t`. – Jeffrey Hantin Dec 03 '12 at 23:31
  • thank you. I did see your note about sqr not being sqrt but when I came back later, I have of course forgotten it and mismatch sqr for sqrt... once again, thank you for your answer and comment – relaxxx Dec 04 '12 at 08:54
  • @JeffreyHantin Hi, I know this question is quite old but I wondered whether you could explain the two solutions of `t`. I can see how there would be one solution (two linear lines crossing) but what would the second be? – unknownSPY Jul 21 '15 at 13:21
  • @unknownSPY, assuming both solutions for `t` are positive and unobstructed, substituting them back would yield two different leading angles you could fire at that would both produce hits. This effect is most pronounced when the projectile is slower than the target: you could aim to hit the target directly as it approaches, or to put the projectile in the target's path as it departs. – Jeffrey Hantin Jul 21 '15 at 22:25
  • @JeffreyHantin Thanks for the reply, Can I assume then that if the projectile is travelling faster than the target, there will only be one solution? – unknownSPY Jul 22 '15 at 09:49
  • @unknownSPY, I believe in that case there will always be two solutions for `t`, one positive and one negative, but only the positive solution is useful. – Jeffrey Hantin Jul 23 '15 at 00:03
  • How to handle a target that has a radius? It's not just point? – kriper Oct 27 '21 at 07:20
  • 1
    @kriper Selecting an arbitrary point on the target will work, or I believe you can use `sqr(target_radius + t * projectile_speed)` in the circle equation and work out the implications from there. – Jeffrey Hantin Oct 28 '21 at 06:32
27

+1 on Jeffrey Hantin's excellent answer here. I googled around and found solutions that were either too complex or not specifically about the case I was interested in (simple constant velocity projectile in 2D space.) His was exactly what I needed to produce the self-contained JavaScript solution below.

The one point I would add is that there are a couple special cases you have to watch for in addition to the discriminant being negative:

  • "a == 0": occurs if target and projectile are traveling the same speed. (solution is linear, not quadratic)
  • "a == 0 and b == 0": if both target and projectile are stationary. (no solution unless c == 0, i.e. src & dst are same point.)

Code:

/**
 * Return the firing solution for a projectile starting at 'src' with
 * velocity 'v', to hit a target, 'dst'.
 *
 * @param ({x, y}) src position of shooter
 * @param ({x, y, vx, vy}) dst position & velocity of target
 * @param (Number) v   speed of projectile
 *
 * @return ({x, y}) Coordinate at which to fire (and where intercept occurs). Or `null` if target cannot be hit.
 */
function intercept(src, dst, v) {
  const tx = dst.x - src.x;
  const ty = dst.y - src.y;
  const tvx = dst.vx;
  const tvy = dst.vy;

  // Get quadratic equation components
  const a = tvx * tvx + tvy * tvy - v * v;
  const b = 2 * (tvx * tx + tvy * ty);
  const c = tx * tx + ty * ty;

  // Solve quadratic
  const ts = quad(a, b, c); // See quad(), below

  // Find smallest positive solution
  let sol = null;
  if (ts) {
    const t0 = ts[0];
    const t1 = ts[1];
    let t = Math.min(t0, t1);
    if (t < 0) t = Math.max(t0, t1);
    if (t > 0) {
      sol = {
        x: dst.x + dst.vx * t,
        y: dst.y + dst.vy * t
      };
    }
  }

  return sol;
}

/**
 * Return solutions for quadratic
 */
function quad(a, b, c) {
  let sol = null;
  if (Math.abs(a) < 1e-6) {
    if (Math.abs(b) < 1e-6) {
      sol = Math.abs(c) < 1e-6 ? [0, 0] : null;
    } else {
      sol = [-c / b, -c / b];
    }
  } else {
    let disc = b * b - 4 * a * c;
    if (disc >= 0) {
      disc = Math.sqrt(disc);
      a = 2 * a;
      sol = [(-b - disc) / a, (-b + disc) / a];
    }
  }
  return sol;
}

// For example ...
const sol = intercept(
  {x:2, y:4},              // Starting coord
  {x:5, y:7, vx: 2, vy:1}, // Target coord and velocity
  5                        // Projectile velocity
)

console.log('Fire at', sol)
broofa
  • 37,461
  • 11
  • 73
  • 73
  • Why is `t` a global variable? – vpzomtrrfrt May 14 '15 at 13:17
  • Oops. Fixed. Thx @vpzomtrrfrt – broofa May 15 '15 at 16:01
  • Its been a long time, are you still in the loop broofa ? I have a question which i would ask you in that case in regards to this problem and your solution. – user431806 Mar 30 '17 at 21:14
  • @user431806 what's up? – broofa Apr 01 '17 at 00:45
  • Ok. The solution you offered works at intercepting a target with a fixed speed. I have a projectile that can travel only a certain distance and i want to know if it is able to intercept another projectile, that also travels fixed, not unlimited distance. Say both interceptor and intercepted projectile can only move 200 magnitude - how would i adjust your code to account for the fixed maximum distance ? example http://codepen.io/AncientSion/pen/wzWNAV as you can see, the intercepting trajectory is fine, however, it assume an unlimited continuation of the target movement. A simple idea ? – user431806 Apr 01 '17 at 19:49
  • 1
    @user431806 Sorry for the *VERY* late response (I don't SO much these days). The solution returned by this code is the X/Y coordinate at which target and projectile will intercept. You need only compute the distance to that point from your firing point and act accordingly. – broofa Jan 02 '19 at 22:29
11

First rotate the axes so that AB is vertical (by doing a rotation)

Now, split the velocity vector of B into the x and y components (say Bx and By). You can use this to calculate the x and y components of the vector you need to shoot at.

B --> Bx
|
|
V

By


Vy
^
|
|
A ---> Vx

You need Vx = Bx and Sqrt(Vx*Vx + Vy*Vy) = Velocity of Ammo.

This should give you the vector you need in the new system. Transform back to old system and you are done (by doing a rotation in the other direction).

Eric
  • 95,302
  • 53
  • 242
  • 374
  • 1
    For completeness, Vy = sqrt(aVelocity*aVelocity - Bx*Bx), and the angle is atan2(Vy, Vx) + angle used to rotate to that position. – FryGuy Feb 12 '10 at 01:05
  • 9
    I don't understand the answer *at all*. Is there another way of phrasing it or depicting it? – Clay Fowler May 08 '10 at 04:25
  • @Clay: Basic idea is to consider the velocities in terms of the velocity along the initial AB direction and the direction perpendicular to AB (the initial direction here too). In the answer AB is made to lie along y axis (by change of co-ordinates). THe x component of the velocities in the new system must be equal for them to collide. –  May 08 '10 at 06:45
  • 6
    While I appreciate that this is a different way of looking at (and solving) the problem than the quadratic approaches I've seen in most other places - I don't feel it's particularly well explained. Ways to improve: 1/ Better diagram (show actual vectors, not just x/y components), 2/ elaborate on how coordinate transform is (un)applied, 3/ elaborate on how to solve for Ax and Bx – broofa Aug 15 '10 at 14:41
  • @broofa: The split into x/y component is the essential part of the solution, so doing 1 will make the answer less valuable and confusing. About 2 and 3, these are common and well known operations when dealing with vectors (especially in game development). Rotation is multiplication by a matrix and getting Ax, is just getting the x component. –  Aug 16 '10 at 00:48
  • 1
    @moron: Your diagram shows that A and B are on the Y axis, but that's about it. It doesn't illustrate the most important part: that Bx and Vx are the same (in fact, you're Vx/Bx lines are different lengths.) I believe showing the vectors, with a vertical line extending through the end points to the x-axis, labeled "Bx/Vx" would better express this. Re: 2 and 3, sure, these are common and well known problems. But you don't carry them through to a solution - you leave it as an "exercise for the reader". Code, or at least formulas, that express each step of the solution would be useful. – broofa Sep 01 '10 at 02:45
  • @broofa: Sorry, if I have to explain every step in every answer, I will be spending most of my time on very few answers while I could be helping more people. This answer was well understood by the person who asked the question originally. Frankly, I am surprised that you expect to see details about stuff which is very well known and that you the crude figure is, well, crude. –  Sep 01 '10 at 22:18
  • FWIW, there's a good explanation over here: http://danikgames.com/blog/how-to-intersect-a-moving-target-in-2d/ – Mark E. Haase Dec 18 '16 at 03:32
8

Jeffrey Hantin has a nice solution for this problem, though his derivation is overly complicated. Here's a cleaner way of deriving it with some of the resultant code at the bottom.

I'll be using x.y to represent vector dot product, and if a vector quantity is squared, it means I am dotting it with itself.

origpos = initial position of shooter
origvel = initial velocity of shooter

targpos = initial position of target
targvel = initial velocity of target

projvel = velocity of the projectile relative to the origin (cause ur shooting from there)
speed   = the magnitude of projvel
t       = time

We know that the position of the projectile and target with respect to t time can be described with some equations.

curprojpos(t) = origpos + t*origvel + t*projvel
curtargpos(t) = targpos + t*targvel

We want these to be equal to each other at some point (the point of intersection), so let's set them equal to each other and solve for the free variable, projvel.

origpos + t*origvel + t*projvel = targpos + t*targvel
    turns into ->
projvel = (targpos - origpos)/t + targvel - origvel

Let's forget about the notion of origin and target position/velocity. Instead, let's work in relative terms since motion of one thing is relative to another. In this case, what we now have is relpos = targetpos - originpos and relvel = targetvel - originvel

projvel = relpos/t + relvel

We don't know what projvel is, but we do know that we want projvel.projvel to be equal to speed^2, so we'll square both sides and we get

projvel^2 = (relpos/t + relvel)^2
    expands into ->
speed^2 = relvel.relvel + 2*relpos.relvel/t + relpos.relpos/t^2

We can now see that the only free variable is time, t, and then we'll use t to solve for projvel. We'll solve for t with the quadratic formula. First separate it out into a, b and c, then solve for the roots.

Before solving, though, remember that we want the best solution where t is smallest, but we need to make sure that t is not negative (you can't hit something in the past)

a  = relvel.relvel - speed^2
b  = 2*relpos.relvel
c  = relpos.relpos

h  = -b/(2*a)
k2  = h*h - c/a

if k2 < 0, then there are no roots and there is no solution
if k2 = 0, then there is one root at h
    if 0 < h then t = h
    else, no solution
if k2 > 0, then there are two roots at h - k and h + k, we also know r0 is less than r1.
    k  = sqrt(k2)
    r0 = h - k
    r1 = h + k
    we have the roots, we must now solve for the smallest positive one
    if 0<r0 then t = r0
    elseif 0<r1 then t = r1
    else, no solution

Now, if we have a t value, we can plug t back into the original equation and solve for the projvel

 projvel = relpos/t + relvel

Now, to the shoot the projectile, the resultant global position and velocity for the projectile is

globalpos = origpos
globalvel = origvel + projvel

And you're done!

My implementation of my solution in Lua, where vec*vec represents vector dot product:

local function lineartrajectory(origpos,origvel,speed,targpos,targvel)
    local relpos=targpos-origpos
    local relvel=targvel-origvel
    local a=relvel*relvel-speed*speed
    local b=2*relpos*relvel
    local c=relpos*relpos
    if a*a<1e-32 then--code translation for a==0
        if b*b<1e-32 then
            return false,"no solution"
        else
            local h=-c/b
            if 0<h then
                return origpos,relpos/h+targvel,h
            else
                return false,"no solution"
            end
        end
    else
        local h=-b/(2*a)
        local k2=h*h-c/a
        if k2<-1e-16 then
            return false,"no solution"
        elseif k2<1e-16 then--code translation for k2==0
            if 0<h then
                return origpos,relpos/h+targvel,h
            else
                return false,"no solution"
            end
        else
            local k=k2^0.5
            if k<h then
                return origpos,relpos/(h-k)+targvel,h-k
            elseif -k<h then
                return origpos,relpos/(h+k)+targvel,h+k
            else
                return false,"no solution"
            end
        end
    end
end
Jim G.
  • 15,141
  • 22
  • 103
  • 166
Trey Reynolds
  • 693
  • 8
  • 11
2

Following is polar coordinate based aiming code in C++.

To use with rectangular coordinates you would need to first convert the targets relative coordinate to angle/distance, and the targets x/y velocity to angle/speed.

The "speed" input is the speed of the projectile. The units of the speed and targetSpeed are irrelevent, as only the ratio of the speeds are used in the calculation. The output is the angle the projectile should be fired at and the distance to the collision point.

The algorithm is from source code available at http://www.turtlewar.org/ .


// C++
static const double pi = 3.14159265358979323846;
inline double Sin(double a) { return sin(a*(pi/180)); }
inline double Asin(double y) { return asin(y)*(180/pi); }

bool/*ok*/ Rendezvous(double speed,double targetAngle,double targetRange,
   double targetDirection,double targetSpeed,double* courseAngle,
   double* courseRange)
{
   // Use trig to calculate coordinate of future collision with target.
   //             c
   //
   //       B        A
   //
   // a        C        b
   //
   // Known:
   //    C = distance to target
   //    b = direction of target travel, relative to it's coordinate
   //    A/B = ratio of speed and target speed
   //
   // Use rule of sines to find unknowns.
   //  sin(a)/A = sin(b)/B = sin(c)/C
   //
   //  a = asin((A/B)*sin(b))
   //  c = 180-a-b
   //  B = C*(sin(b)/sin(c))

   bool ok = 0;
   double b = 180-(targetDirection-targetAngle);
   double A_div_B = targetSpeed/speed;
   double C = targetRange;
   double sin_b = Sin(b);
   double sin_a = A_div_B*sin_b;
   // If sin of a is greater than one it means a triangle cannot be
   // constructed with the given angles that have sides with the given
   // ratio.
   if(fabs(sin_a) <= 1)
   {
      double a = Asin(sin_a);
      double c = 180-a-b;
      double sin_c = Sin(c);
      double B;
      if(fabs(sin_c) > .0001)
      {
         B = C*(sin_b/sin_c);
      }
      else
      {
         // Sin of small angles approach zero causing overflow in
         // calculation. For nearly flat triangles just treat as
         // flat.
         B = C/(A_div_B+1);
      }
      // double A = C*(sin_a/sin_c);
      ok = 1;
      *courseAngle = targetAngle+a;
      *courseRange = B;
   }
   return ok;
}

Joe
  • 881
  • 7
  • 7
  • Hey thanks for the answer I am looking to implement it right now, however it is not Clear to me what is targetDirection – Coldsteel48 Sep 21 '16 at 18:47
1

Here's an example where I devised and implemented a solution to the problem of predictive targeting using a recursive algorithm: http://www.newarteest.com/flash/targeting.html

I'll have to try out some of the other solutions presented because it seems more efficient to calculate it in one step, but the solution I came up with was to estimate the target position and feed that result back into the algorithm to make a new more accurate estimate, repeating several times.

For the first estimate I "fire" at the target's current position and then use trigonometry to determine where the target will be when the shot reaches the position fired at. Then in the next iteration I "fire" at that new position and determine where the target will be this time. After about 4 repeats I get within a pixel of accuracy.

jhocking
  • 5,527
  • 1
  • 24
  • 38
  • That's a very bad algorythm, sorry to say that. – AgentFire May 19 '14 at 15:35
  • What's wrong with it? just saying "bad" is pretty vague lol. Works well for my needs, plus I've had someone point out an advantage I didn't even realize: if there is no solution, the algorithm will still result in the shooter aiming in the general direction of the target. – jhocking May 19 '14 at 15:45
  • 1
    Suppose the situation when projectile's speed is less than target's. Also suppose the situation when projectile's speed is target's speed minus some epsilon. In the latter case the projectile **will** eventually reach the target, the first case might not even be solved. – AgentFire May 19 '14 at 17:28
  • re no solution possible: that's why you only recurse like 4 times, not until solution is found. – jhocking May 19 '14 at 20:46
  • 1
    First case scenario might not be solved even in 1 billion recurions (hi, stack overflow). Actually, it will "fail" in its calculations from the **second** pass. – AgentFire May 20 '14 at 03:05
1

I just hacked this version for aiming in 2d space, I didn't test it very thoroughly yet but it seems to work. The idea behind it is this:

Create a vector perpendicular to the vector pointing from the muzzle to the target. For a collision to occur, the velocities of the target and the projectile along this vector (axis) should be the same! Using fairly simple cosine stuff I arrived at this code:

private Vector3 CalculateProjectileDirection(Vector3 a_MuzzlePosition, float a_ProjectileSpeed, Vector3 a_TargetPosition, Vector3 a_TargetVelocity)
{
    // make sure it's all in the horizontal plane:
    a_TargetPosition.y = 0.0f;
    a_MuzzlePosition.y = 0.0f;
    a_TargetVelocity.y = 0.0f;

    // create a normalized vector that is perpendicular to the vector pointing from the muzzle to the target's current position (a localized x-axis):
    Vector3 perpendicularVector = Vector3.Cross(a_TargetPosition - a_MuzzlePosition, -Vector3.up).normalized;

    // project the target's velocity vector onto that localized x-axis:
    Vector3 projectedTargetVelocity = Vector3.Project(a_TargetVelocity, perpendicularVector);

    // calculate the angle that the projectile velocity should make with the localized x-axis using the consine:
    float angle = Mathf.Acos(projectedTargetVelocity.magnitude / a_ProjectileSpeed) / Mathf.PI * 180;

    if (Vector3.Angle(perpendicularVector, a_TargetVelocity) > 90.0f)
    {
        angle = 180.0f - angle;
    }

    // rotate the x-axis so that is points in the desired velocity direction of the projectile:
    Vector3 returnValue = Quaternion.AngleAxis(angle, -Vector3.up) * perpendicularVector;

    // give the projectile the correct speed:
    returnValue *= a_ProjectileSpeed;

    return returnValue;
}
Kentyman
  • 11
  • 1
1

I made a public domain Unity C# function here:
http://ringofblades.com/Blades/Code/PredictiveAim.cs

It is for 3D, but you can easily modify this for 2D by replacing the Vector3s with Vector2s and using your down axis of choice for gravity if there is gravity.

In case the theory interests you, I walk through the derivation of the math here:
http://www.gamasutra.com/blogs/KainShin/20090515/83954/Predictive_Aim_Mathematics_for_AI_Targeting.php

Kain Shin
  • 21
  • 3
0

I've seen many ways to solve this problem mathematically, but this was a component relevant to a project my class was required to do in high school, and not everyone in this programming class had a background with calculus, or even vectors for that matter, so I created a way to solve this problem with more of a programming approach. The point of intersection will be accurate, although it may hit 1 frame later than in the mathematical computations.

Consider:

S = shooterPos, E = enemyPos, T = targetPos, Sr = shooter range, D = enemyDir
V = distance from E to T, P = projectile speed, Es = enemy speed

In the standard implementation of this problem [S,E,P,Es,D] are all givens and you are solving either to find T or the angle at which to shoot so that you hit T at the proper timing.

The main aspect of this method of solving the problem is to consider the range of the shooter as a circle encompassing all possible points that can be shot at any given time. The radius of this circle is equal to:

Sr = P*time

Where time is calculated as an iteration of a loop.

Thus to find the distance an enemy travels given the time iteration we create the vector:

V = D*Es*time

Now, to actually solve the problem we want to find a point at which the distance from the target (T) to our shooter (S) is less than the range of our shooter (Sr). Here is somewhat of a pseudocode implementation of this equation.

iteration = 0;
while(TargetPoint.hasNotPassedShooter)
{
    TargetPoint = EnemyPos + (EnemyMovementVector)
    if(distanceFrom(TargetPoint,ShooterPos) < (ShooterRange))
        return TargetPoint;
    iteration++
}
SpiderShlong
  • 224
  • 1
  • 8
0

Basically , intersection concept is not really needed here, As far as you are using projectile motion, you just need to hit at a particular angle and instantiate at the time of shooting so that you get the exact distance of your target from the Source and then once you have the distance, you can calculate the appropriate velocity with which it should shot in order to hit the Target.

The following link makes teh concept clear and is considered helpful, might help: Projectile motion to always hit a moving target

systemdebt
  • 4,589
  • 10
  • 55
  • 116
0

I grabbed one of the solutions from here, but none of them take into account movement of the shooter. If your shooter is moving, you might want to take that into account (as the shooter's velocity should be added to your bullet's velocity when you fire). Really all you need to do is subtract your shooter's velocity from the target's velocity. So if you're using broofa's code above (which I would recommend), change the lines

  tvx = dst.vx;
  tvy = dst.vy;

to

  tvx = dst.vx - shooter.vx;
  tvy = dst.vy - shooter.vy;

and you should be all set.