Author Topic: Function Request  (Read 587 times)

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Function Request
« on: February 09, 2011, 04:39:25 am »


               Just wondering if anyone has created a function to see if an object is facing a particular object or creature. I suck at math and cant quite get my head around a way to do it. I was thinking of using the vectors of the two objects in conjuction with the GetFacing function. You get the vector of the caller and then the vector of the object to check, figure out the +,- of the x and y and then check the get facing of the caller...something. I don't know.

Any help appreciated. Thank you in advance.
               
               

               


                     Modifié par GhostOfGod, 09 février 2011 - 04:49 .
                     
                  


            

Legacy_CalSailX

  • Jr. Member
  • **
  • Posts: 93
  • Karma: +0/-0
Function Request
« Reply #1 on: February 09, 2011, 05:17:29 am »


               There is a GetIsBehindBackstabTarget function on the vault that should be a good starting point for a function such as you want, at the very least you'll see a bit of code that can be modified to get what I think your looking for.
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Function Request
« Reply #2 on: February 09, 2011, 05:21:00 am »


               Thanks Cal. Looks like that might work.
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Function Request
« Reply #3 on: February 09, 2011, 05:21:00 am »


               Thanks Cal. Looks like that might work.

EDIT: Ugh..trig/geomentry. I might as well be reading a script in chinese. Don't suppose anyone would be willing to alter something like what Cal suggested to work a bit differently?


This is the script:

/*
fDeviation is the deviation from the facing angle which is permissable
fDistance is the distance between the source and the target which is permissable
*/
int GetIsBehindBackstabTarget( object oSource, object oTarget, float fDeviation, float fDistance ) {

    if(!GetIsObjectValid(oSource))
        return FALSE;

    if(!GetIsObjectValid(oTarget))
        return FALSE;

    float fFacingTarget=GetFacing(oTarget);

    float fFacingTargetX=cos(fFacingTarget);
    float fFacingTargetY=sin(fFacingTarget);



    float fFacingSource=GetFacing(oSource);

    float fFacingSourceX=cos(fFacingSource);
    float fFacingSourceY=sin(fFacingSource);



    location lTargetLocation=GetLocation(oTarget);
    vector vTargetLocation=GetPositionFromLocation(lTargetLocation);

    location lSourceLocation=GetLocation(oSource);
    vector vSourceLocation=GetPositionFromLocation(lSourceLocation);



    float fDirectionHorizontalBetween=vSourceLocation.x-vTargetLocation.x;
    float fDirectionVerticalBetween=vSourceLocation.y-vTargetLocation.y;



    float fDot=fFacingTargetX*fDirectionHorizontalBetween+fFacingTargetY*fDirectionVertica
lBetween;
    float fProductMags=sqrt(pow(fFacingTargetX, 2.0f)+pow(fFacingTargetY, 2.0f))*sqrt(pow(fDirectionHorizontalBetween, 2.0f)+pow(fDirectionVerticalBetween, 2.0f));

//Returns an angle from 0 to 180, the angle between the target's facing angle vector and the vector pointing from target to source
    float angleBetween=acos(fDot/fProductMags);

    if(angleBetween<(180.0f-fDeviation)) {
//Not valid angle, the source isn't standing within the correct wedge behind the target
        return FALSE;
    }


//Create a wedge of validity with fDeviation degrees deviation from the source's facing angle
    float fFacingSourcePlus=fFacingSource+fDeviation;
    float fFacingSourceMinus=fFacingSource-fDeviation;

//Obtain the actual facing angle between source and target
    float fFacingSourceToTarget=VectorToAngle(vTargetLocation-vSourceLocation);

/*
The following conditions check to determine if the source to target actual angle is within the permited deviation.
Note that an angle which is greater than 180 deviation from the facing could produce unpredictable results.
*/
    if(fFacingSourcePlus>360.0f) {
//Because the addition deviation is greater than 360 it will be necessary to perform two checks

        int isValid=FALSE;

        if(fFacingSourceToTarget>=fFacingSourceMinus && fFacingSourceToTarget<=360.0f) {
            isValid=TRUE;
        }

        if(!isValid) {
            float fFacingSourcePlus2=fFacingSourcePlus-360.0f;

            if(fFacingSourceToTarget>=0.0f && fFacingSourceToTarget<=fFacingSourcePlus2) {
                isValid=TRUE;
            }
        }


        if(!isValid) {
//Not valid angle, the source isn't properly facing the target

            return FALSE;
        }
    }
    else if(fFacingSourceMinus<0.0f) {
//Because the subtraction deviation is less than 0 it will be necessary to perform two checks

        int isValid=FALSE;

        if(fFacingSourceToTarget>=0.0f && fFacingSourceToTarget<=fFacingSourcePlus) {
            isValid=TRUE;
        }

        if(!isValid) {
            float fFacingSourceMinus2=fFacingSourceMinus+360.0f;

            if(fFacingSourceToTarget>=fFacingSourceMinus2 && fFacingSourceToTarget<=360.0f) {
                isValid=TRUE;
            }
        }


        if(!isValid) {
//Not valid angle, the source isn't properly facing the target

            return FALSE;
        }
    }
    else {
//Only one check necessary

        if(!(fFacingSourceToTarget>=fFacingSourceMinus && fFacingSourceToTarget<=fFacingSourcePlus)) {
//Not valid angle, the source isn't properly facing the target

            return FALSE;
        }
    }


    float fDistanceActual=GetDistanceBetweenLocations(lTargetLocation, lSourceLocation);

    if(fDistanceActual>fDistance) {
//Not valid distance between, greater than 2 meters away

        return FALSE;
    }

    return TRUE;
}
               
               

               


                     Modifié par GhostOfGod, 09 février 2011 - 05:45 .
                     
                  


            

Legacy_CalSailX

  • Jr. Member
  • **
  • Posts: 93
  • Karma: +0/-0
Function Request
« Reply #4 on: February 09, 2011, 06:12:56 am »


               

Anyone writing might need to know a bit more info...



Such as,

(1) Does the facing of the Target matter.... do they have to be facing us also?

(2) Do we just need to just see the Target or is distance a factor?

(3) How wide in degrees is the cone we use for "facing the target" do we want it to change depending on distance to target?

(4) Anything I forgot to ask that the script needs to check for.


               
               

               


                     Modifié par CalSailX, 09 février 2011 - 06:16 .
                     
                  


            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Function Request
« Reply #5 on: February 09, 2011, 06:39:51 am »


               Ah good point Cal. It'd probably only need parameters for the source, target and angle. Something like "int GetIsFacingObjectWithinAngle(oSource, oTarget, fAngle)".

I guess average peripheral vision is something like 120 to 140 degrees so having it adjustable would be nice.

Distance isn't necessary. Could always do a separate check for distance between objects or what not. And no the facing of the target doesn't matter. Line of sight also doesn't matter. I can do that with the line of sight function.
               
               

               


                     Modifié par GhostOfGod, 09 février 2011 - 06:59 .
                     
                  


            

Legacy_Melkior_King

  • Full Member
  • ***
  • Posts: 234
  • Karma: +0/-0
Function Request
« Reply #6 on: February 09, 2011, 11:02:09 am »


               (deleted - didn't work)
               
               

               


                     Modifié par Melkior_King, 09 février 2011 - 11:35 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Function Request
« Reply #7 on: February 09, 2011, 05:35:28 pm »


               

GhostOfGod wrote...

Just wondering if anyone has created a function to see if an object is facing a particular object or creature. I suck at math and cant quite get my head around a way to do it. I was thinking of using the vectors of the two objects in conjuction with the GetFacing function. You get the vector of the caller and then the vector of the object to check, figure out the +,- of the x and y and then check the get facing of the caller...something. I don't know.

Any help appreciated. Thank you in advance.


This is not as hard as you are tring to make it.  \\\\\\\\\\\\\\\\

Im not at the toolset right now so will just give a brief outline. 

float  AngleOffset = GetFacing(oSelf)- GetAngleBetweenLocations (oSelf,Otarget);

That should give you the angle oSlef would have to turn his head to look at oTarget.  A Postive AngleOffset  would be looking to the left and a Negtive AngleOffset would be looking to the Right.    Then all you need is how much of an Angle in front you want to be able to preceive.  Lets say a full 180 degerees. 

Float  fViewArc = 180.0
If (abs(AngleOffset) < fViewArc/2)  Then I can see.

Hope that helps.
               
               

               


                     Modifié par Lightfoot8, 09 février 2011 - 05:38 .
                     
                  


            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Function Request
« Reply #8 on: February 09, 2011, 06:41:20 pm »


               Thanks for the replies guys. Well I gave it a shot with what you posted Lightfoot but with no luck. I haven't had a math class in 15 years and don't remember much. Also failed geometry. haha. But anyway this is what I came up with:


//npc heartbeat
#include "x0_i0_position"
int GetIsFacingTarget(object oSelf, object oTarget, float fViewArc);
int GetIsFacingTarget(object oSelf, object oTarget, float fViewArc)
{
location lSelf = GetLocation(oSelf);
location lTarget = GetLocation(oTarget);
float AngleOffset = GetFacing(oSelf) - GetAngleBetweenLocations(lSelf,lTarget);
//float  fViewArc = 180.0;
if (abs(FloatToInt(AngleOffset)) < (FloatToInt(fViewArc)/2))
return TRUE;
else return FALSE;
}

void main()
{
object oSelf = OBJECT_SELF;
object oTarget = GetNearestObjectByTag("");
if (GetIsFacingTarget(oSelf, oTarget, 120.0))
    {
    SendMessageToPC(oTarget, "I see you.");
    }
}

No matter where I'm at the npc can still see me. So I'm pretty sure I just have something wrong here since I don't know what I'm doing. ':lol:'
               
               

               
            

Legacy_Baragg

  • Sr. Member
  • ****
  • Posts: 496
  • Karma: +0/-0
Function Request
« Reply #9 on: February 09, 2011, 09:21:36 pm »


               K, if you want the PC to be facing can't you just use a moveto to do so? IE: AssignCommand(oPC, ActionMoveToObject(object, int, float))? That should move them to it facing it right?
               
               

               
            

Legacy__six

  • Hero Member
  • *****
  • Posts: 1436
  • Karma: +0/-0
Function Request
« Reply #10 on: February 09, 2011, 09:31:44 pm »


               Warning: the logic here is a bit strange, I'm not used to working with the way NWN handles rotation ingame (not to mention it uses a different zero direction in the toolset to ingame). I've tested it fairly extensively though.

// Determine if oSource is facing oTarget using tolerance of angle fRange
// * returns TRUE if facing, else FALSE
// _six
int GetIsFacingObject(object oSource, object oTarget, float fRange);
int GetIsFacingObject(object oSource, object oTarget, float fRange)
{
   // Create directional vector
   vector vDir = GetPosition(oTarget) - GetPosition(oSource);
   float fVLen = GetDistanceBetween(oTarget, oSource);
   vDir /= fVLen;

   // Calculate angle between two objects, and facing of source
   float angle = acos(vDir.y);
   float facing = GetFacing(oSource);

   // Make sure angle is signed equivalently to the dir vector
   if(vDir.x < 0.0f) angle = 0.0f - angle;

   // Deal with NWN's rotation offset - due north is actually 90 degrees
   if(angle > 90.0f) angle -= 360.0f;

   // If angle falls within range given, must be facing
   if(facing < 90.0f - angle + fRange/2.0f
   && facing > 90.0f - angle - fRange/2.0f)
   {   return TRUE;
   }

   // ...otherwise can't be, return FALSE
   return FALSE;
}
               
               

               


                     Modifié par _six, 09 février 2011 - 09:41 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Function Request
« Reply #11 on: February 09, 2011, 10:53:15 pm »


               Yea Six already has one for you.  Nice work there Six.

But I could not just leave it without finding the problem in the way I suggested.  I can to the conclusion that the Angle Between locations function is not worth a crud. 

Anyway here is another option for you.  Just fixed replaced the bad function in what you wrote. 


//npc heartbeat

int GetIsFacingTarget(object oSelf, object oTarget, int nViewArc);
int GetIsFacingTarget(object oSelf, object oTarget, int nViewArc)
{
location lSelf = GetLocation(oSelf);
location lTarget = GetLocation(oTarget);

float AngleOffset = VectorToAngle( GetPosition(oTarget) - GetPosition(oSelf)) - GetFacing(oSelf) ;

//float  fViewArc = 180.0;
return (abs(FloatToInt(AngleOffset)) <  nViewArc/2);
}
void main()
{
object oSelf = OBJECT_SELF;
object oTarget = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
if (GetIsFacingTarget(oSelf, oTarget, 120))
    {
    SendMessageToPC(oTarget, "I see you.");
    }
}


               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Function Request
« Reply #12 on: February 09, 2011, 11:23:40 pm »


               I almost forgot, 

Since abs(FloatToInt(AngleOffset)) Returns the angle that the PC is from driectly in front of the NPC.  You could use it for a percent chance that the NPC spots the PC. 

int nOffSet= abs(FloatToInt(AngleOffset));

int nChanceToSopt = 50;
if (nOffSet < 45 )  nChanceToSopt = 100;
if (if (nOffSet > 60 )  nChanceToSopt = 0;

Just a thought. 
 
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Function Request
« Reply #13 on: February 09, 2011, 11:43:48 pm »


               Thank you guys so much. As usual you are all amazing.

Both _six's and Lightfoot's methods are working perfectly. It's a toss up.

One of these days if I put as much effort into learning math as I do scripting, I could script as well. haha.

Anyway thank you again to all who replied.
               
               

               
            

Legacy_CalSailX

  • Jr. Member
  • **
  • Posts: 93
  • Karma: +0/-0
Function Request
« Reply #14 on: February 10, 2011, 01:34:43 am »


               Both _six and Lightfoot did better then what I'd come up with...  grin...  that guard wearing a helm is going to take a hit to his spotting something at the edges of visual cone if it's not moving.



Thanks for stepping up guys, and thanks GOG for asking for this function.