3
\$\begingroup\$

I have a gun which fires a projectile that has to hit an enemy. The problem is that the gun has to be automatic, i.e. - choose the angle in which it has to shoot, so that the projectile hits the enemy dead in the center.

It's been a looooong time since school, and my physics skills are a bit rusty, but they're there. I've been thinking to somehow apply the v = d/t formula to find the time needed for the projectile or enemy to reach a certain point. But the problem is that I can't find a common point for both the projectile and enemy trajectories. Yes, I can find a certain point for the projectile, and another for the enemy, but I would need lots of tries to find one where the two points coincide, which is stupid. There has to be a way to link them together but I can't figure it out.

I prepared some drawings and samples:

A simple version of my Flash game, dumbed down to the basics, just some shapes:

http://axonnsd.org/W/P001/MathSandBox.swf - click the mouse anywhere to fire a projectile.

Or, here is an image which describes my problem:

An image which describes my problem

So... who has any ideas about how to find x3/y3, thus leading me to find the angle in which the weapon has to tilt in order to fire a projectile to meet the enemy?

EDIT

I think it would be clearer if I also mention that I know: the speed of both Enemy and Projectile and the Enemy travels on a straight vertical line.

\$\endgroup\$
8

2 Answers 2

1
\$\begingroup\$

Searching for "aim at moving target":
Aiming and hitting a moving target

/**
* Shoot at a target
* 
* @param    t   The target to be shot
* @return       The bullet to be fired (or null if cannot hit)
*/
public function shoot(targ:Target, bulletSpeed:Number = BULLET_SPEED):Bullet
{
    var dx:Number = targ.x - this.x;
    var dy:Number = targ.y - this.y;
    var a:Number = targ.vx * targ.vx + targ.vy * targ.vy - bulletSpeed * bulletSpeed;
    var b:Number = 2 * (targ.vx * dx + targ.vy * dy);
    var c:Number = dx * dx + dy * dy;

    // Check we're not breaking into complex numbers
    var q:Number = b * b - 4 * a * c;
    if (q < 0) return null;

    // The time that we will hit the target
    var t:Number = ((a < 0 ? -1 : 1)*Math.sqrt(q) - b) / (2 * a);

    // Aim for where the target will be after time t
    dx += t * targ.vx;
    dy += t * targ.vy;
    var theta:Number = Math.atan2(dy, dx);

    // Fire the bullet
    var bullet:Bullet = new Bullet();
    bullet.target = targ;
    bullet.hitPoint = new Point(targ.x + targ.vx * t, targ.y + targ.vy * t);

    bullet.x = this.x;
    bullet.y = this.y;
    bullet.vx = bulletSpeed * Math.cos(theta);
    bullet.vy = bulletSpeed * Math.sin(theta);

    return bullet;
}
\$\endgroup\$
3
  • \$\begingroup\$ Hi and thanks for answering ::- D. What I always fail to understand is how to calculate targ.vx and targ.vy. I Think I should split the velocity vector on 2 axis but I am unsure how to do that... \$\endgroup\$
    – Axonn
    Commented Mar 8, 2011 at 1:59
  • \$\begingroup\$ in your case there is no vy, just a vx (you mentioned that the enemy motion was parallel to the ground) \$\endgroup\$ Commented Mar 8, 2011 at 10:10
  • \$\begingroup\$ What if it isn't? ::- D. Maybe in the future I will change this.... Anyway: I found how he calculated them: target.vx = Target.SPEED * Math.cos(theta); where theta is the angle of the target (I think). \$\endgroup\$
    – Axonn
    Commented Mar 8, 2011 at 11:13
2
\$\begingroup\$

I don't know about Flash technology, nor how the game is updated. Presuming that there can be an Update() method like the one encountered in XNA that is called from within the game loop, would it not be possible to simply calculate:

  1. the coordinates of your enemy's center, that is, (x2, y2) based on its current location;
  2. than the coordinates of the projectile's center (if needed) or only its boundaries;
  3. see if these both coordinates meet sometime, and if they do, this means your enemy's dead?

Once again, I do not pretend that this is doable in Flash, I only try to help the best I can with what I know. As far as I know, Flash has a behind script capability. Now, to make sure a method would be called X times per second might be another story in Flash, I unfortunately can't say.

EDIT #1

[...] the question is how to shoot so that the weapon hits it.

Here's my guess:

Let's take some arbitrary coordinates:

(X1, Y1) = (800, 600)
(X2, Y2) = (1000, 50)
(X3, Y3) = (X3, Y3) // Means these are to be determined.

Since this was not mentioned, I extrapolated a constant speed for both the enemy and the projectile.

Enemy's speed:
    Ve = d/t = 20 px/s

Projectile's speed:
    Vp = d/t = 10 px/s

Then, we have to determine when the projectile could reach the Y3 coordinate:

h = Y1 - Y3
h = 600 - 50
h = 550 px // This means that the projectile has to travel 550 px at 10 px/s to reach Y3

In how much time will the projectile reach Y3?

t = 10 px/s * 550 px
t = 550 px / 10 px
t = 55 s // Then, 55s is required for the projectile to reach Y3

Now, where will the enemy be in 55 seconds?

Ve = d/t = d/55s
20px/s = d/55s
d = 20px * 55s
d = 1100 px

Now, we can determine X3 with the following formula:

X3 = X2 - d
X3 = 1000 - 1100
X3 = -100 // Remember, these are arbitrary coordinates

X3 would then be outside the visible area in this example, which doesn't matter here since the Cartesian plan includes negative coordinates. What matters most is that from this (X3,Y3) coordinate, we'll be able to find the required angle.

We can now determine the size of a new right-triangle following these coordinates:

(X3, Y3) = (-100, 50)
(X1, Y1) = (800, 600)
(X3, Y1) = (-100, 600)

Which allows us to find out the distance on X that the projectile needs to travel:

d = X1 - X3
d = 800 - (-100)
d = 800 + 100
d = 900 px

And we already know the height that the projectile needs to travel on Y which is 550px. Then, we can calculate the hypotenuse according to pytaghorian theory.

sqr(a) + sqr(b) = sqr(c) // Where sqr(c) represents the sqr(hypotenuse)
sqr(c) = sqr(900) + sqr(550)
sqr(c) = 810,000 + 302,500
sqr(c) = 1,112,500
c = sqrt(1,112,500)
c = 1,054.75116 (rounded value)

Then, we can now find the cos(A), where A is the angle which we're looking for.

cos(A) = adjacent side / hypotenuse
cos(A) = 900 / 1,054.75116
cos(A) = 0.853282 (rounded value)

From cos(A) we can now determine angle A:

A = cos-1(cos(A))
A = cos-1(0.853282)
A = 31.42956561 (rounded value)

References

  1. Triangle (Wikipedia);
  2. Finding an Angle in a Right Angled Triangle;
  3. Trigonometry Calculator - Right Triangles.

I do hope this helped at least a little!

\$\endgroup\$
9
  • \$\begingroup\$ Hit testing is not a problem. My question wasn't about that. I want to anticipate the angle with which the weapon must shoot in order for the projectile to hit the enemy. So the fact that the enemy WILL be HIT is a GIVEN. It will be hit, the question is how to shoot so that the weapon hits it. \$\endgroup\$
    – Axonn
    Commented Mar 7, 2011 at 16:56
  • 1
    \$\begingroup\$ If we take it as the enemy only travels on the X axis, then we know Y3 for sure, as it should be the same as Y2, that is what allows us to say what Y3 is worth, since the enemy, in your sample, seems to only travel horizontally. From there, the solution I brought forward is correct. Besides, if you say that the enemy might travel in height too, that is, get closer to or further from the projectile, that is another story, and I would then agree with you that we don't know Y3. Otherwise, we do. =) \$\endgroup\$ Commented Mar 7, 2011 at 23:50
  • 1
    \$\begingroup\$ I get your idea, and the fact is the Y3 is the same wherever it is on X. Aside, you're right saying that the line length changes, since we finally get 1054.75116px hytpotenuse value. Hence a recalculation is required to measure in how much time the projectile will reach the target, which results to be about 105 seconds for this hypotenuse value. Then, we miss the enemy. I'll consider that in my next update. I'm going to think about it a little more. =) Thanks for informing me! =) \$\endgroup\$ Commented Mar 8, 2011 at 2:44
  • 1
    \$\begingroup\$ I thought there is a simpler solution to my problem and thank you for trying to find it. Your solution is definitely simpler (less calculations) than the other stuff I've seen, but, unfortunately not perfect. It may work in most cases, but it may fail in others. I now understand why the other solutions are a bit harder (involve a few more calculations), that's because the problem is tricky. The advantage with the other solutions (see bummzack's comments to my original post) is that the object may move on whatever axis as well! ::- D. \$\endgroup\$
    – Axonn
    Commented Mar 8, 2011 at 10:11
  • 1
    \$\begingroup\$ Thanks for pointing me out what works. This is a good start for improvement and new learnings as well, now that I may understand what works better in the other solution, I shall take an eye out to it. Thanks for your kind recognition of my efforts. At least, it helped a bit! =) \$\endgroup\$ Commented Mar 8, 2011 at 11:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .