Check if target is within attacking angle

Started by
13 comments, last by alvaro 13 years, 9 months ago
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.
Advertisement
You can use the dot product of the two position vectors to find the angle between them.
It's not a bug... it's a feature!
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?
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.
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;
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-codevector3 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.
Yes, sorry about that. That is what I was thinking in my head but I clearly did not communicate that!
It's not a bug... it's a feature!
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
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.)
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.

This topic is closed to new replies.

Advertisement