So we start of with this scene.
The black dot is the player, the red dot is the target.
You're looking to see if an object is within the green dotted lines which has an angle of FoVAngle or TestAngle (whatever you prefer to call it)
So because of these, we have three things being accepted into our function. The player object, the target object, and the angle we're testing for (and the distance we're checking for).
function isInsideTestAngle(%player, %object, %testAngle, %testDistance)
{
%playerPos = getWords(%player.getEyePoint(),0,1) SPC "0";
%objPos = getWords(%object.getPosition(),0,1) SPC "0";
Here we have two vectors. There's the player view, and the object displacement vector
To get these we have the bit of code below. Notice how we're getting rid of the z component of the vector for simplicity and because we dont need it.
%playerView = getWords(%player.getEyeVector(),0,1) SPC "0";
%objectDisplacement = VectorSub(%objPos,%playerPos);
Now we can take these vectors and find their angle.
First we're going to break them down into their component form...
The code for this would look something like what follows but we'll end up doing this all in one line of code just because that's how I wrote it
%playerViewX = getWord(%playerView,0);
%playerViewY = getWord(%playerView,1);
%objectDisplacementX = getWord(%objectDisplacement,0);
%objectDisplacementY = getWord(%objectDisplacement,1);
Now we take those components and find the angle. Remember from trigonometry, geometry, whichever class you had sin cos and tan (or if you haven't just listen in) that the tangent of an angle gives the ratio between the opposite side over the adjacent side. Since we have the opposite and the adjacent side and not the angle, we'll be using the arc tangent (mATan(%side1, %side2)). We don't actually need to make the ratio as torque just accepts both side lengths.
So the angles...
Would be calculated as follows...
%playerViewAngle = mATan(getWord(%playerView,1),getWord(%playerView,0));
%objectDisplacementAngle = mATan(getWord(%objectDisplacement,1), getWord(%objectDisplacement,0));
Now we can find the AngleDelta (the angle between the two). Here, we will subtract the two angles and take the absolute value. Notice how the angle will be the same no matter what order we subtract in considering we will be taking the absolute value in the end
%deltaAngle = mAbs(%playerViewAngle - %objectDisplacementAngle);
Since this gave use the angle between the view of the player and object displacement, we can check to see whether it's inside our test angle.
The function takes a test angle that's the angle of the FoV (or whatever you'd like to call it). Because it's the entire FoV and the vector for the player view cuts it right down the middle, we'll be checking to see if our delta angle is between 0 radians and TestAngle/2 radians different.
if(%deltaAngle > %testAngle/2)
return false;
The second part is to test whether it's in the circle, which is just a simple distance test
|| VectorDist(%playerPos,%objPos) >%testDistance
Which becomes
if(%deltaAngle > %testAngle/2 || VectorDist(%playerPos,%objPos) > %testDistance)
return false;
return true;
So we have the full code (couldn't think of a better name for the function)
Note that testAngle should be in radians (convert degress to radians with some online tool or just multiply your degree value by (pi/180)
function isInsideTestAngle(%player, %object, %testAngle, %testDistance)
{
%playerPos = getWords(%player.getEyePoint(),0,1) SPC "0";
%objPos = getWords(%object.getPosition(),0,1) SPC "0";
%playerView = getWords(%player.getEyeVector(),0,1) SPC "0";
%objectDisplacement = VectorSub(%objPos,%playerPos);
%playerViewAngle = mATan(getWord(%playerView,1),getWord(%playerView,0));
%objectDisplacementAngle = mATan(getWord(%objectDisplacement,1), getWord(%objectDisplacement,0));
%deltaAngle = mAbs(%playerViewAngle - %objectDisplacementAngle);
//This was added at a later date into this explanation
//The reason this is here is because when you get the relative angle, it should never be over $pi. If it is, we have the wrong angle. To get the right one
//we have to subtract the angle from 2*$pi.
if(%deltaAngle > $pi)
%deltaAngle = (2*$pi) - %deltaAngle;
if(%deltaAngle > %testAngle/2 || VectorDist(%playerPos,%objPos) > %testDistance)
return false;
return true;
}