14
\$\begingroup\$

I'm trying to find a good solution for a bullet to hit the enemy. The game is 2D tower defense, the tower is supposed to shoot a bullet and hit the enemy guaranteed.

I tried this solution - http://blog.wolfire.com/2009/07/linear-algebra-for-game-developers-part-1/

The link mentioned to subtract the bullet's origin and the enemy as well (vector subtraction). I tried that but a bullet just follows around the enemy.

float diffX = enemy.position.x - position.x;
float diffY = enemy.position.y - position.y;

velocity.x = diffX;
velocity.y = diffY;

position.add(velocity.x * deltaTime, velocity.y * deltaTime);

I'm familiar with vectors but not sure what steps (vector math operations) to be done to get this solution working.

\$\endgroup\$
1

4 Answers 4

11
\$\begingroup\$

Your reasoning was perfect: use a vector to move from my position to my target. This is the purpose of a vector; you simply forgot the speed!

Velocity is a vector: a speed and a direction. However, if you forget to normalize the difference vector and multiply it the bullet speed (a scalar), you are basically saying that if you are close to the target (the difference vector is small) the bullet slows down; while if you are far away the bullet speed is larger.

This is the underlying problem: you need to calculate both the direction and the magnitude of the vector.

\$\endgroup\$
4
  • \$\begingroup\$ Thanks for helping. I tried to use scalar after I calculate the difference vector, it looks it worked but looks not good. I tried to see if I calculate difference vector, normalize, then scalar the velocity. It looks better right now. Yes, I think I need the homing missiles in this game sometime later. Thanks again. \$\endgroup\$
    – Tashu
    Commented Jul 4, 2011 at 17:35
  • 1
    \$\begingroup\$ Does this answer make no sense to anyone else? \$\endgroup\$ Commented Jul 5, 2011 at 6:06
  • \$\begingroup\$ @Fxlll: Ok, I think I see what you are trying to say. There's a lot of fluff unrelated to the answer at the start/end, and I was also confused by your English (which I realize is probably not your fault). I've submitted an edit-suggestion to clean up this answer. \$\endgroup\$ Commented Jul 5, 2011 at 11:17
  • \$\begingroup\$ @BlueRaja - Danny Pflughoeft thanks for your effort! \$\endgroup\$
    – FxIII
    Commented Jul 5, 2011 at 12:46
8
\$\begingroup\$

If the target is moving in a steady direction at a steady pace, and your bullet path is in a straight line at a steady pace, you can use a quadratic equation to predict the exact spot they will intersect and aim your tower's gun at that spot.

Since it is a certainty that the bullet will hit it's mark, and you can calculate the exact time it will take from firing to impact, no collision detection would be required, simply fire the gun, wait the calculated time span, register a hit.

Here is pseudo code for the quadratic equation:

Vector totarget =  target.position - tower.position;

float a = Vector.Dot(target.velocity, target.velocity) - (bullet.velocity * bullet.velocity);
float b = 2 * Vector.Dot(target.velocity, totarget);
float c = Vector.Dot(totarget, totarget);

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

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

if (t1 > t2 && t2 > 0)
{
    t = t2;
}
else
{
    t = t1;
}

Vector aimSpot = target.position + target.velocity * t;
Vector bulletPath = aimSpot - tower.position;
float timeToImpact = bulletPath.Length() / bullet.speed;//speed must be in units per second
\$\endgroup\$
3
  • \$\begingroup\$ Thanks for the pseudo code, I will check on it to see how the quadratic equation works with this situation. Thanks again. \$\endgroup\$
    – Tashu
    Commented Jul 4, 2011 at 17:36
  • \$\begingroup\$ Problem is that user can be moving towards the bullet and right before hit, he can get away from the bullet's trace. In this case, would this solution be good enough ? \$\endgroup\$
    – Martin.
    Commented Jan 23, 2012 at 5:48
  • \$\begingroup\$ No, as qualified in the first sentence. This is not for all games but for a game where targets move at a constant velocity only. Constant velocity means both direction and speed. For instance, Defense Grid style game game can use this approach. \$\endgroup\$
    – Steve H
    Commented Jan 23, 2012 at 12:09
3
\$\begingroup\$

You need to 'predict' the objects position by the time the bullet will reach it. You can do this using the objects speed/velocity (hopefully that is constant ;)) and it's directional vector.

I'm not sure what the exact formula is off the top of my head but I think it's something like this:

NewPosition = OldPosition + (Speed * DirectionVector);

If you have a set path you will need to recalculate when the object changes direction. Use this NewPosition as your enemy.position vector and the bullet should hit the object without the 'homing effect'. Homing occurs due to the fact the enemy object has moved since the original vector was calculated, it can only ever catch up when an object is travelling in one direction long enough.

Hope this helps :)

\$\endgroup\$
1
  • 3
    \$\begingroup\$ Or you can cheat and automatically hit, then use the moving sprite as visual feedback. Or just fire your bullets at 50000²mph. \$\endgroup\$ Commented Jul 4, 2011 at 13:04
1
\$\begingroup\$

You can avoid using square root & power of 2.

var distX:Float = target.x - x;
var distY:Float = target.y - y;
_velX = distX / timeTravel;
_velY = distY / timeTravel;

// Take out if you want a nice slow down as approaches effect.  
timeTravel -= 1.0; // make sure u have a positive timeTravel.
x += _velX;
y += _velY;

if (distX < 0)
    distX = -distX;

if (distY < 0)
    distY = -distY;

if (_velX < 0)
    _velX = -_velX;

if (_velY < 0)
    _velY = -_velY;

// Should both snap @ the same time.
if (distX < _velX)
x = target.x; // snap & see what happens.

if (distY < _velY)
y = target.y; // snap & see what happens.

// TODO: call your onHitTarget here ...
// Hopefully this shall provide 10x the performance 
// of using Math.sqrt and all the extra multiplications.

It's all written from memory. By the way, use the elements that work - test it line by line if you're new at this. Float is Number in AS3.

\$\endgroup\$

You must log in to answer this question.

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