• Advertisement
Sign in to follow this  

Check if target is within attacking angle

This topic is 2775 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello guys, Im making a small action rpg, building its base at the moment
I've got
* An attacking character
* A n/s/w/e orientation and a defined position within a matrix
* An attack range
* An angle of attack
* A target point

I want to find out if the target point is withing the attacking area, defined by a direction, opening angle and range.

Could any one give me any algorithm idea?

Sorry if this is in the wrong session.

Share this post


Link to post
Share on other sites
Advertisement
You can use the dot product of the two position vectors to find the angle between them.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dom_152
You can use the dot product of the two position vectors to find the angle between them.
The dot product of the two position vectors won't give you any useful information. Do you mean the dot product of the attacking character's forward vector and the (normalized) vector to the target?

Share this post


Link to post
Share on other sites
Quote:
Original post by jyk
Do you mean the dot product of the attacking character's forward vector and the (normalized) vector to the target?


What exactly do you mean? I can possibly find the angle between the two points and use that and the distance?

This is confusing me, I'm not really being able to understand properly how to do it.

Share this post


Link to post
Share on other sites
You can find the angle between two 2-d vectors as follows:
float signed_angle(vector2 v1, vector2 v2)
{
return atan2(perp_dot(v1, v2), dot(v1, v2));
}
The input vectors need not be unit length. (The only requirement is that neither of them has a magnitude that is zero or near zero.)

You can then determine whether the target is within the field of view as follows:
vector2 diff = target.position - character.position;
float angle = abs(signed_angle(character.forward, diff));
return angle <= field_of_view / 2;

Share this post


Link to post
Share on other sites
Quote:
Original post by jyk
Quote:
Original post by Dom_152
You can use the dot product of the two position vectors to find the angle between them.
The dot product of the two position vectors won't give you any useful information. Do you mean the dot product of the attacking character's forward vector and the (normalized) vector to the target?


Agreed. You'd need the forward vector of the attacker. And the thread asks for the angle. To get the angle you would need to use arc-cosine of the dot product.


// Pseudo-code
vector3 diff = attacker.pos - other.pos;
diff.normalize();
float dot = attackerFwd.Dot(diff);
float angle = acos(dot); // Note: make sure dot is between -1 or 1.

Share this post


Link to post
Share on other sites
Yes, sorry about that. That is what I was thinking in my head but I clearly did not communicate that!

Share this post


Link to post
Share on other sites
The easiest to solve is the question "is the target within range?" and that's found using the pythagorean theorem.

To keep this simple we'll define the vectors for the entities' position.

Player -> (p.x, p.y) = p
Enemy -> (e.x, e.y) = e

And the range is just a float
Range -> r

if ((e - p).LengthSquared() < r * r)
{
// Within range
}

If you want you can expand it out to:
if ((e.x - p.x) * (e.x - p.x) + (e.y - p.y) * (e.y - p.y) < r * r)
{
// Within range
}

Now we want to find if the enemy is within a given angle. The dot product can be used:
angleBetweenTwoVectors = acos((a.x * b.x + a.y * b.y) / (a.Length() * b.Length());

First we need to define N,S,W,E. Assuming x and y are positive right and down respectively then:
N -> (0, -1)
S -> (0, 1)
W -> (-1, 0)
E -> (1, 0)
We'll call this direction.

So we have one of the vectors given to us. The other one is created from (e - p). It can be thought of as the vector starting at p and going to e. Since the direction vector is already a unit vector (length of 1) then to find the angle plus or minus between them we can do:

angleBetweenDirectionAndPlayerToEnemy = acos((direction.x * (e.x - p.x) + direction.y * (e.y - p.y)) / sqrt((e.x - p.x) * (e.x - p.x) + (e.y - p.y) * (e.y - p.y)));

This is easier if you have a vector library:
angleBetweenDirectionAndPlayerToEnemy = Math.Acos(Vector2.Dot(direction, (e - p)) / (e - p).Length());

So yeah then you just do:

if (Math.Acos(Vector2.Dot(direction, (e - p)) / (e - p).Length()) < angleOfAttack)
{
// Within angle of attack
}

Put them together like:
if ((e - p).LengthSquared() < r * r && Math.Acos(Vector2.Dot(direction, (e - p)) / (e - p).Length()) < angleOfAttack)
{
// Player can attack the enemy
}

// edit hmm I must have had this open before replying. Anyway I had a cool example I used to give out when people asked this question:
Turret. Your problem seems more tile based though :P

Share this post


Link to post
Share on other sites
Quote:
Original post by lordikon
*** Source Snippet Removed ***
I'd actually recommend using atan2() rather than acos() (as shown above), as it does not require that the input vectors be unit length, and is a little more stable and robust. (In particular, it eliminates the need for clamping the dot product output to the range [-1, 1] to compensate for potential numerical error.)

Share this post


Link to post
Share on other sites
Quote:
Original post by Sirisian
Now we want to find if the enemy is within a given angle. The dot product can be used:
Similarly, I'd recommend using atan2() rather than acos().

Another option would be to pre-compute and cache the cosine of half the field of view, and then simply compare the dot product of the forward vector and the normalized vector to the target to this value.

Share this post


Link to post
Share on other sites
Thanks a lot, everyone.
I was really lacking the math and mind speed to reach that conclusion.

<still reading all replies>

But as far as I see, the question is already answered, thanks a lot.

Share this post


Link to post
Share on other sites
Quote:
Original post by jyk
Quote:
Original post by Sirisian
Now we want to find if the enemy is within a given angle. The dot product can be used:
Similarly, I'd recommend using atan2() rather than acos().
Good point. I'll have to start doing that. That would be an interesting bug in the future. :P

Share this post


Link to post
Share on other sites
Quote:
Original post by jyk
Quote:
Original post by lordikon
*** Source Snippet Removed ***
I'd actually recommend using atan2() rather than acos() (as shown above), as it does not require that the input vectors be unit length, and is a little more stable and robust. (In particular, it eliminates the need for clamping the dot product output to the range [-1, 1] to compensate for potential numerical error.)


I recommend not using either. In the acos solution, you will end up checking
acos(something) > angle


Instead, check
something > cos(angle)


So just use `cos(angle)' as the basic description of how wide your sector is, and you can remove all trigonometry from your code.

Share this post


Link to post
Share on other sites
Quote:
Original post by alvaro
I recommend not using either. In the acos solution, you will end up checking
acos(something) > angle


Instead, check
something > cos(angle)


So just use `cos(angle)' as the basic description of how wide your sector is, and you can remove all trigonometry from your code.
I said that right here:
Quote:
Original post by jyk
Another option would be to pre-compute and cache the cosine of half the field of view, and then simply compare the dot product of the forward vector and the normalized vector to the target to this value.

Share this post


Link to post
Share on other sites
Quote:
Original post by jyk
Quote:
Original post by alvaro
[...] So just use `cos(angle)' as the basic description of how wide your sector is, and you can remove all trigonometry from your code.
I said that right here:
Quote:
Original post by jyk
Another option would be to pre-compute and cache the cosine of half the field of view, and then simply compare the dot product of the forward vector and the normalized vector to the target to this value.


Ooops! Sorry I missed that.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement