Let’s say your character has a position of (me.x, me.y), and is facing at at an angle of me.angle.
1) Figure out which direction is 0 degrees (or 0 radian, pay attention to how your angles are expressed.)
2) depending on the answer to 1), you can determine the direction (vector) me is facing, and construct its bearing vector in cartesian coordinates. It’s going to be either (Math.cos(me.angle), Math.sin(me.angle)) or some permutation of it, with possibly a negative sign or two thrown in for good measure. Anyway.
3) Let’s say the point you want to check for visibility is at (target.x, target.y). The vector that goes from me to target is (aim.x, aim.y) = (target.x – me.x, target.y – me.y), that shouldn’t be a problem, right? It’s norm is also, trivially: norm = Math.sqrt(aim.x^2 + aim.y^2)
4) This is the payload: turns out that aim . bearing = ||aim|| ||bearing|| cos(angle between aim and bearing)
Here bold denotes vectors and ||.|| signifies norm. The norm of bearing is 1 by construction and we’ve called ||aim|| norm above, therefore criterion = cos(interesting angle) = (aim.x * bearing.y + aim.y * bearing.x) / norm
5) Check criterion vs. a threshold which is cos(me.fieldOfView). if criterion > threshold then the object in in sight, if it’s below it’s not.
6) Wrap all this nicely in a function that belongs in whatever class me is, and takes the target coordinates as argument. It should return a Boolean. Something like:
public function canSee(targetx:Number, targety:Number):Boolean
// Other variable declarations left as an exercise to the reader.
// Computation of bearing for 0 angle pointing straight up. YMMV.
bearingx = -Math.sin(this.angle * Constants.DEGREETORADIAN); // Constant defined as Math.PI / 180
bearingy = Math.cos(this.angle * Constants.DEGREETORADIAN); // in the Constants module.
aimx = targetx - this.x;
aimy = targety - this.y;
norm = Math.sqrt(aimx * aimx + aimy * aimy);
criterion = (aimx * bearingy + aimy * bearingx) / norm;
return (criterion > this.fieldOfView);