Burgershot
  • Home
  • Members
  • Team
  • Help
  • Search
  • Register
  • Login
  • Home
  • Members
  • Help
  • Search
Burgershot General Programming Math: vertical viewing angle

 
  • 0 Vote(s) - 0 Average
Math: vertical viewing angle
Freaksken
Offline

open.mp Developer

Posts: 80
Threads: 4
Joined: Feb 2019
Reputation: 6
Location: Belgium
#1
2019-07-15, 08:18 PM (This post was last modified: 2019-07-15, 09:00 PM by Freaksken.)
I have a system in which I've worked out the code for giving an NPC a horizontal viewing angle (left image). How would I achieve a similar result, but now for the vertical direction (right image)?
[Image: viewing_angle.png?raw=1]

Below is the code for the left image, for reference. This is a math question, thus the code isn't really necessary, but might help you understand the problem. Just ignore that the angles start from the NPC's center instead of his eyes, that's easy enough to fix. As you can see, the z-position is irrelevant for the horizontal viewing angle, but probably not for the vertical viewing angle (not sure).
PHP Code:
static bool:FAI_IsPlayerInAggroViewingAngle(playerid, npcid) {
    
// Get NPC position
    
new Float:xn, Float:yn, Float:zn;
    
FCNPC_GetPosition(npcid, xn, yn, zn);

    
// Get player position
    
new Float:xp, Float:yp, Float:zp;
    if(!
IsPlayerNPC(playerid)) {
        
GetPlayerPos(playerid, xp, yp, zp);
    } else {
        
FCNPC_GetPosition(playerid, xp, yp, zp);
    }

    
// Calculate the angle between these 2 points
    
new Float:angleBetweenPoints = atan2(xp - xn, yp - yn);

    
// Get the NPC facing angle adjusted for the weird GTA angle system
    
new Float:npcFacingAngle = 360.0 - FCNPC_GetAngle(npcid);

    
// Calculate the smallest difference between these 2 angles as a value between -180.0 and 180.0
    
new Float:angleDifference = angleBetweenPoints - npcFacingAngle;
    if(
angleDifference > 180.0) {
        
angleDifference -= 360.0;
    }
    if(
angleDifference < -180.0) {
        
angleDifference += 360.0;
    }

    
// Get the absolute value of this angle
    
angleDifference = floatabs(angleDifference);

    
// Check if the player is within the aggro viewing angle
    
if(angleDifference <= FAI_NPCs[npcid][FAI_NPC_AGGRO_VIEWING_ANGLE][playerid]/2) {
        return 
true;
    }
    return 
false;
} 

Here's another visualisation of what the result should look like:
[Image: viewing_angle2.png?raw=1]
Always keep in mind that a lot of people are active on this forum in their spare time.
They are sacrificing time they could easily spend on things they would rather do, to help you instead.
hiddos
Offline

open.mp Developer

Posts: 19
Threads: 0
Joined: Apr 2019
Reputation: 1
#2
2019-07-15, 09:27 PM (This post was last modified: 2019-07-16, 06:20 PM by hiddos.)
An alternative way of doing both of these together is through some vector calculations. You want to essentially do step 3 of the image below:


[Image: angle_vectors.png]

Some rough code (that I didn't test for accuracy) would look like:

PHP Code:
new Float:xn, Float:yn, Float:zn;
FCNPC_GetPosition(npcid, xn, yn, zn);

// Get player position
new Float:xp, Float:yp, Float:zp;
if(!
IsPlayerNPC(playerid)) {
   GetPlayerPos(playerid, xp, yp, zp);
}
 else {
    FCNPC_GetPosition(playerid, xp, yp, zp);
}

// First the vector from the NPC to the player
Float:vector_diff[3] = {xp-xn, yp-yn, zp-zn};


Float:facing_angle = FCNPC_GetAngle(npcid) + 90; // add 90 degrees to align with unit circle
// Then a unit vector for the angle the NPC is facing - nb. norm of this vector does not matter, but for unit vectors it's 1
Float:vector_facing[3] = {floatcos(facing_angle), floatsin(facing_angle), 0.0f};

// Calculate the dot product, to get the numerator: 
Float:dot_product = vector_diff[0] * vector_facing[0] + 
                    vector_diff[1] * vector_facing[1] + 
                    vector_diff[2] * vector_facing[2];

// Calculate the denominator
Float:normcalc = VectorSize(vector_diff[0], vector_diff[1], vector_diff[2]); // VectorSize(vector_facing) = 1, so multiplication is not needed in this special case

//Then this is the angle between the facing angle and the player
Float:angle = acos(dot_product/normcalc);

return 
angle <= max_viewing_angle; // Insert your own variable here 
Freaksken
Offline

open.mp Developer

Posts: 80
Threads: 4
Joined: Feb 2019
Reputation: 6
Location: Belgium
#3
2019-07-15, 10:07 PM (This post was last modified: 2019-07-15, 10:08 PM by Freaksken.)
An idea I had myself, was to (imagining) a rotation of the coordinate system around the y-axis, so that the same code I gave could work with now x = z and y = y. However, that doesn't seem to work when the NPC has any other rotation than 0.0 degrees.
Always keep in mind that a lot of people are active on this forum in their spare time.
They are sacrificing time they could easily spend on things they would rather do, to help you instead.
hiddos
Offline

open.mp Developer

Posts: 19
Threads: 0
Joined: Apr 2019
Reputation: 1
#4
2019-07-16, 06:20 PM
Something I overlooked in my answer: getting the absolute value of the angle is not necessary as the range out arccos is [0-180] (or [0-pi]). As such I've edited the post
Freaksken
Offline

open.mp Developer

Posts: 80
Threads: 4
Joined: Feb 2019
Reputation: 6
Location: Belgium
#5
2019-08-15, 08:26 PM
I brushed up on my maths knowledge and now understand your solution (and how simple it actually is). Thnx again!
Always keep in mind that a lot of people are active on this forum in their spare time.
They are sacrificing time they could easily spend on things they would rather do, to help you instead.
« Next Oldest | Next Newest »



  • View a Printable Version
  • Subscribe to this thread
Forum Jump:

© Burgershot - Powered by our Community and MyBB Original Theme by Emerald

Linear Mode
Threaded Mode