Author Topic: Determing in a player inside a specific part of a circle.  (Read 2783 times)

I'm trying to detect things in front of a "cone" of the blockhead.
I'm completely ignoring the Z axis because i don't need it in this situation.

Basically, I want to see if the blue dot is there, and if i turned 90 degress to the Left, see if the yellow dot is there. Yes, I have the direction red is facing. Yes, I have everyone's position. Yes I know the radius of the circle. How would I go about doing this?

The default Blockland Field of View is 90 degrees, or 0.5 Radians. Using mAtan you can get the angle between two objects, and check if that's within a 0.25 Radian tolerance in either direction from the player's angle vector.

Code: [Select]
function isInFoV(%player, %object)
{
    %pPos = %player.getEyePoint();
    %oPos = %object.getPosition();

    %rise = getWord(%pPos, 1) - getWord(%oPos, 1);
    %run = getWord(%pPos, 0) - getWord(%oPos, 0);

    %angle = mAtan(%rise, %run);

    %viewVector = %player.getEyeVector();
    %angleOfView = mAtan(getWord(%viewVector, 1), getWord(%viewVector, 0));

    %distanceRadius = 50;

    if(mAbs(%angle - %angleOfView) < 0.251) && vectorDist(%pPos, %oPos) < %distanceRadius)
        return true;
    return false;
}
« Last Edit: October 06, 2013, 01:46:02 PM by $trinick »

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).
Code: [Select]
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.
Code: [Select]
%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
Code: [Select]
%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...
Code: [Select]
%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

Code: [Select]
%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.
Code: [Select]
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
Code: [Select]
|| VectorDist(%playerPos,%objPos) >%testDistance
Which becomes
Code: [Select]
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)
Code: [Select]
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;
}
« Last Edit: November 11, 2013, 01:24:37 AM by DYLANzzz »

The default Blockland Field of View is 90 degrees, or 0.5 Radians. Using mAtan you can get the angle between two objects, and check if that's within a 0.25 Radian tolerance in either direction from the player's angle vector.

Is there anything in particular that makes this superior to finding the dot product of the eye vector and the normalized position difference, and then doing checks on that (e.g. >= 0 for FOV 90)?

Is there anything in particular that makes this superior to finding the dot product of the eye vector and the normalized position difference, and then doing checks on that (e.g. >= 0 for FOV 90)?
Depends on how many calculation calls are required for both, my guess is that it really doesn't matter. You could also use the law of cosines, but that's effectively the same thing as doing the dot product anyway

Is there anything in particular that makes this superior to finding the dot product of the eye vector and the normalized position difference, and then doing checks on that (e.g. >= 0 for FOV 90)?
Pretty sure that they'd do exactly the same thing, but I'm not sure which is computationally faster.

Kudos to Dylan for making that entire post for OP.

Is there anything in particular that makes this superior to finding the dot product of the eye vector and the normalized position difference, and then doing checks on that (e.g. >= 0 for FOV 90)?
The difference in computational speed should be negligible.