2
\$\begingroup\$

I am working on a tower defense game in Flash. Right now most towers find the the nearest enemy in range (enemies are in an array), get the enemies coordinates, and fire a bullet. When it hits the coordinates [bullet.hitTestPoint(x, y)] it damages the enemy.

I want to design a tower that will shoot a bullet at the first enemy just like above, however, the bullet needs to go its max range and damage all enemies it hits along the way. I am having some trouble determining what enemies it is hitting.

The best way I have come up with so far is when the bullet reaches its max range, I draw a line from that point back to my tower. Then I loop through the enemy array and use [enemies[i].hitTestObject(bulletLine)]. If that returns true, it damages that enemy.

This seems to work okay, but I would like something more realtime and sometimes it seems like this is hitting enemies it shouldn't hit.

\$\endgroup\$

3 Answers 3

3
\$\begingroup\$

Simple:

Why not simply use your line idea, but instead of making a line for the whole path, make a line from the bullet's last position?

how:

Make the bullet an object, and give it a velocity and a direction (see vector), and then make a line from it's position in the last frame (make a variable to keep track of the previous position) and check against that!

This way you won't collide with any objects you shouldn't, and you can expand the game to something more complicated easily!

\$\endgroup\$
1
  • \$\begingroup\$ I wouldn't need to draw the line if I am checking for a hit every frame. I could just check if the bullet hit a target with the hitTestObject method. My main problem was that the bullet would hit the enemy each frame until it moved all the way passed. I just need a good way to store whether the enemies are hit. I am going to try and use an array to store hit enemies or look up more information about dictionaries. \$\endgroup\$
    – Sean
    Apr 25, 2011 at 12:20
2
\$\begingroup\$

My first suggestion is to just not remove the bullet when it hits something and keep using hitTestObject like you do with other objects, but I'm wondering if there is a reason that approach wouldn't work.

For example, how fast is this bullet moving? Is it firing out to the max range instantaneously?

\$\endgroup\$
4
  • \$\begingroup\$ My problem with this was that the bullet would keep hitting the same object because it would take a bit to pass through it. The hit test function is in my game loop. Each frame, I would have to loop through the array of enemies and see if it hits, but somehow have it so it's not hitting the same enemy multiple times. \$\endgroup\$
    – Sean
    Apr 22, 2011 at 16:59
  • \$\begingroup\$ I haven't worked much with flash, but couldn't you store some kind of "hit cooldown" on the enemy? Then it won't matter that the bullet hit more than once because only the first counts. If you could somehow store a reference to what you hit instead all the better, as then being hit by one source wouldn't prevent being hit by another at the exact same time. \$\endgroup\$
    – Lunin
    Apr 22, 2011 at 17:26
  • \$\begingroup\$ Just create a Dictionary to store whether an enemy has already been hit by that bullet. When looping through all the enemies first check if they are in the dictionary before doing the hitTest. If you've never used Dictionaries before, they are awesome: help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/… \$\endgroup\$
    – jhocking
    Apr 22, 2011 at 17:26
  • \$\begingroup\$ This might be a feature instead of a bug -- hits each monster more than once. If not, why not just track which monsters it hit and make sure that doesn't repeat? \$\endgroup\$
    – ashes999
    Oct 17, 2011 at 1:11
1
\$\begingroup\$

Hello you should consider using the dot product to compute the angle between two vectors.

Considering:

  • A is the vector from the tower to the max distance point aligned with the first enemy.
  • B is the vector from the tower to the enemy to test (one of the enemies list).

θ = acos( (A . B) / (|A| |B|) )

  • |A| is the vector magnitude of A.
  • |B| is the vector magnitude of B.

    |V| = square-root( V . V ) = square-root( Vx² + Vy² + ... )

Thus if θ is equal or close to 0° then they are parallels and in the same direction.


You could also consider using the cross product, but it's fit better for 3D. One of the use of the cross product is to determine if two vectors are parallels by checking whether the resulting vector is close to the zero vector, you can determine which enemies in your enemies list are aligned on the same vector as your first targeted enemy. It normally does apply to 3D vectors only, but as far as I remember you can use it with 2D vectors using a 0 value as Z value. (Take care they can be parallels and in opposite direction, ie: in the opposite side of the tower direction. You can use crossproduct to determine if they are the same direction)

Still considering the same A and B as in the dot product part:

A x B = [Ax, Ay, Az] x [Bx, By, Bz]

A x B = [Ay*Bz - Az*By , Az*Bx - Ax*Bz , Ax*By - Ay*Bx ]

If this result vector is equal to (or "close to", depending of you needs) [0,0,0] then they should be parallels. then compute the dot product to verify if they are the same direction.


Finally, could also consider computing the distance between the segment (from tower position to the max radius using the first enemy direction) and the point (your current enemies list) : http://paulbourke.net/geometry/pointline/, or the distance from a point to a plane if you use 3D and flying enemies on top of grounded ones.

Using the above techniques (distance from a point to a plan/segment), you should also consider previously reducing the number of enemies in your current enemies table using a simple vector dot product (the vector from the tower to the max distance in the first enemy direction, dot-product the vector from the tower to the enemy to test). If your dot product is greater than 0 they point to the "same direction", if it is equal to 0 the vectors are perpendiculars and if the dot product is lower than 0, the vectors are in "opposite" directions. This way you can reduce the number of enemies to consider by keeping only those in the front direction... I beg this is useful only with a huge number of enemies, so it's up to you to decide if it worth it or not.


Edited: to reorganize the ideas...

I beg your pardon if this is not clear enough, as I'm not really fluent at English, it could be unclear... so if I'm not I will try to reformulate.

\$\endgroup\$

You must log in to answer this question.

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