# 2D Topdown Shooter - Line of sight based purely on angle and rotation

In a game I'm working on, enemies constantly rotate around as they move around the map. I want them to only shoot the player if they're within a field of view.

bool inLineOfSight(float playerX, float playerY, float enemyX, float enemyY, float enemyRotation);


Enemy rotation is in degrees not radians. Picture kind of shows what I'm looking for. An enemy should not be able to see the player unless they're within field of view. Should mention that raycasting isn't necessary as I've already sorted that out.

How would I make sure that the player is within an enemies field of view based on angle and position only?

• You're missing the sight radius. Commented Dec 17, 2019 at 1:25
• Sight radius is going to be a constant that I don't know yet since I haven't tried it. I think 45 would work somewhat Commented Dec 17, 2019 at 1:29

Any form of visibility checking is based on angles:

Take the direction an enemy is looking at. Let's call this unit vector "D".

vec2 D;
D.x = cos(enemyRotation);
D.y = sin(enemyRotation);


Now let's take draw a line between the enemy and the player. Let's call this "P"

vec2 P = player.position - enemy.position;


So, in order to discern, naively, whether the player is within the "cone" of vision for an enemy, we need to do two mathematical checks:

Angle check. Store the length of P, then normalize it so it is unit length (length = 1) get the dot product of D and P, and compare it to the cone angle. If this value is greater than the cosine of the cone angle, then the player is outwith an "infinite" cone of vision. Otherwise, the enemy can potentially see the player.

float l = sqrtf(dot(P,P));
vec2 p = P/l;
if ( dot(p,D) > cos(EnemyConeAngle))
return false;


The enemy cone angle is the angle between the look ahead direction, and the edge of the cone. It's max value should be less than 90 degrees.

Second, range check. We need to make the cone finite. This is easily done, by comparing the maximum visual range of the enemy to the length if P.

if (l <= enemyRange)
{
return true;
}


This, however, does not take into account if there is an obstruction in the way.

Crudely, you can take P as a ray, and see if any scenery is hit by it before it reaches the player. Google "ray vs bounding box" for more info on this.

I would also recommend you learn to use radians, if you haven't already. Most maths libraries prefer to use radians in their internal calculations, and honestly, it doesn't make a huge difference to your code to support it.

• After these two checks you can simply raycast ("shoot a n imaginary bullet at them"), because this should occur rare enough to be viable performance-wise Commented Jan 16, 2020 at 12:48