Author Topic: Get*ObjectInShape - Half-Circles  (Read 486 times)

Legacy_Vermain

  • Newbie
  • *
  • Posts: 12
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« on: September 12, 2013, 11:32:46 pm »


               I've got a reaaaallly weird question: Is there any way to do some kind of half-circle shape for the Get*ObjectInShape functions, or do something approximate to that? To explain: I'm trying to make an ability that takes flanking into account, so that if an ally and I are on opposite sides of an opponent, the ability does something in addition to what it does normally. I'm sure there's a mathematical solution, but I'm frankly an idiot when it comes to trigonometry!
               
               

               


                     Modifié par Vermain, 12 septembre 2013 - 10:32 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #1 on: September 13, 2013, 12:02:11 am »


               Two potential answers, depending on how much you care about the precise shape.

Easy way:

// Get the first object in nShape
// - nShape: SHAPE_*
// - fSize:
//   -> If nShape == SHAPE_SPHERE, this is the radius of the sphere
//   -> If nShape == SHAPE_SPELLCYLINDER, this is the length of the cylinder
//      Spell Cylinder's always have a radius of 1.5m.
//   -> If nShape == SHAPE_CONE, this is the widest radius of the cone
//   -> If nShape == SHAPE_SPELLCONE, this is the length of the cone in the
//      direction of lTarget. Spell cones are always 60 degrees with the origin
//      at OBJECT_SELF.
//   -> If nShape == SHAPE_CUBE, this is half the length of one of the sides of
//      the cube
// - lTarget: This is the centre of the effect, usually GetSpellTargetLocation(),
//   or the end of a cylinder or cone.
// - bLineOfSight: This controls whether to do a line-of-sight check on the
//   object returned. Line of sight check is done from origin to target object
//   at a height 1m above the ground
//   (This can be used to ensure that spell effects do not go through walls.)
// - nObjectFilter: This allows you to filter out undesired object types, using
//   bitwise "or".
//   For example, to return only creatures and doors, the value for this
//   parameter would be OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR
// - vOrigin: This is only used for cylinders and cones, and specifies the
//   origin of the effect(normally the spell-caster's position).
// Return value on error: OBJECT_INVALID
object GetFirstObjectInShape(int nShape, float fSize, location lTarget, int bLineOfSight=FALSE, int nObjectFilter=OBJECT_TYPE_CREATURE, vector vOrigin=[0.0,0.0,0.0])


Use a SHAPE_CONE or SHAPE_SPELLCONE.

More complex answer:
Look at goaneng's Pentagrams and Summoning Circles. He has a hemisphere, which you can rotate in any direction on any axis (x, y, or z). While that code is only for vfx, the inc_draw include has all the vector math already done for you, and very elegantly. You should be able to adapt it pretty easily. As an added plus, he includes a demo module. When I was coding special effects for some of HG's portals, I simply added certain areas from HG to the demo mod and tinkered with the effects until I got exactly what I wanted. In any event, the testing room he provides should help you figure out rotation etc.

[Edit] Doh, just read the latter half of your post, where you do what I usually ask people to do: say what they're going to use it for. This recent thread was extremely helpful when it came to vector math, and had a very similar problem, though he wanted a deflection area in FRONT of the target in that case.

Funky
               
               

               


                     Modifié par FunkySwerve, 12 septembre 2013 - 11:04 .
                     
                  


            

Legacy_Vermain

  • Newbie
  • *
  • Posts: 12
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #2 on: September 13, 2013, 01:20:28 am »


               Thanks for your assistance!! I was thinking about just using SHAPE_CONE, although I wasn't sure what I'd need to plug in to ensure it was a full half-circle. Is lSize used to establish the arc between the two radii? (God, I hope I'm using the right terminology. ._.)
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #3 on: September 13, 2013, 02:16:29 am »


               Tell you what, I'll make both our lives simpler. Here's a minorly-tweaked function originally by Axe Murderer:


// Returns TRUE if object oBehind is located behind object oInFront as
// determined by the direction oInFront is facing.
int GetIsLocatedBehind( object oInFront, object oBehind){

    if( !GetIsObjectValid(oInFront) || !GetIsObjectValid( oBehind))
        return FALSE;

    int nFrontType = GetObjectType(oInFront), nRearType = GetObjectType(oBehind));

    if ((nFrontType != OBJECT_TYPE_PLACEABLE    &&
        nFrontType != OBJECT_TYPE_CREATURE)     ||
        (nRearType != OBJECT_TYPE_PLACEABLE     &&
        nRearType != OBJECT_TYPE_CREATURE)
        return FALSE;

    float fFacing = GetFacing(oInFront);
    float fBehind = VectorToAngle(GetPositionFromLocation(GetLocation(oBehind)) -GetPositionFromLocation(GetLocation( oInFront)));
    while(fFacing > 360.0)
        fFacing -= 360.0;
    while(fFacing <= 0.0)
        fFacing += 360.0;
    while(fBehind > 360.0)
        fBehind -= 360.0;
    while(fBehind <= 0.0)
        fBehind += 360.0;
    // "Behind" here is defined as 45 degrees left or right of directly 180
    // degrees from oInFront's facing direction. To narrow the "cone", change
    // the 45.0 to something smaller. Make it larger to widen it. It should
    // not be more than 90.0 or else your getting in front of the guy. 90.0
    // is directly off his left or right shoulder, 0.0 is directly behind him.
    return (fabs( fBehind -fFacing) >= (180.0 -45.0));
}

Funky
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #4 on: September 13, 2013, 02:25:39 am »


               Found that using the Omnibus, by the way, so props to OldTimeRadio as well. The Krit offers another function in that thread, as well, which is titled 'Finding out if PC stands behind an NPC' - I just didn't feel like re-lineating and re-indenting a second function when that one appears to do exactly what you want.

Funky
               
               

               
            

Legacy_Vermain

  • Newbie
  • *
  • Posts: 12
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #5 on: September 13, 2013, 02:28:05 am »


               Thank you a ton for your effort! I'll get a-working with this stuff right away.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #6 on: September 13, 2013, 04:01:04 am »


               Why not just get the angle between your  (attacker and  target) and compare it to the angle between your (attacker and ally)  if  your ally is farther away then your target.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #7 on: September 13, 2013, 04:14:20 am »


               Two reasons: 1) I'm lazy 2) I wanted a generalizable solution. I rather like axe's solution, though you're right, it's not custom-tailored to OP's original question.

Also I think Axe's has some unnecessary checks, as GetFacing only returns between 0 and 360, according to the Lexicon, but hey. '<img'> If you want to post the simplest vector math solution, I'd love to see it, as I'm still quite weak in that department.

Funky
               
               

               
            

Legacy_Vermain

  • Newbie
  • *
  • Posts: 12
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #8 on: September 13, 2013, 04:29:42 am »


               

Lightfoot8 wrote...

Why not just get the angle between your  (attacker and  target) and compare it to the angle between your (attacker and ally)  if  your ally is farther away then your target.


I think I might do something like this, yeah. Is it basically just:

-Get angles for myself/ally in comparison to target.
-Add 180 to ally's result.
-Subtract/add 45 degrees (or however large/small I want the flanking area to be) and see if I'm outside of that arc. (As well as making sure to apply sanity checks so I'm not at 480 degrees or something weird!)
-If so, and in range (distance check), I must be flanking.

Along those lines, anyways? I'm still working on streamlining my code, but I think I have the basic jist of it.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #9 on: September 14, 2013, 03:40:21 pm »


               int GetisFlanked( object oAttaker, object oTarget, object oAlly)
{
   vector posAttaker = GetPosition(oAttaker);
   vector posTarget = GetPosition(oTarget);
   vector posAlly = GetPosition(oAlly);

   vector VectorToTargetFromAttacker = posTarget- posAttaker ;
   float AngleToTargetFromAttacker   = VectorToAngle( VectorToTargetFromAttacker);

   vector VectorToAllyFromTarget =   posAlly - posTarget;
   float  AngleToAllyFromTarget  =  VectorToAngle( VectorToAllyFromTarget);

   float DifferanceBetweenAngles =  AngleToTargetFromAttacker - AngleToAllyFromTarget;

   //Adjust the angle so our results to compair will always be positive by adding
   //Half the the test range.  This just allows us to be able to do a single
   //compairsion check instead of two.
   //EDIT: I Need AdjustedAngle to be an int so I can do my sanity check the way
   //I like to.
   int AdjustedAngle = FloatToInt(DifferanceBetweenAngles) + 45;

   // Sainty check. make sure the angle is in the 0 - 360 range.
   AdjustedAngle %= 360;
   if  (AdjustedAngle < 0) AdjustedAngle += 360;

   // Check and return if the n adjusted Angle is +/- 45 deg
   // since we have already added 45 degrees we only need to check if it is less
   // then 90
   return AdjustedAngle <= 90;

}

Will hopefully be able to post more information reguarding the code later tonight.

EDIT: Pasting with Chrome is a pain.  
               
               

               


                     Modifié par Lightfoot8, 14 septembre 2013 - 02:43 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #10 on: September 14, 2013, 07:37:15 pm »


               

Lightfoot8 wrote...

Will hopefully be able to post more information reguarding the code later tonight.

I'd appreciate it, but thanks for posting what you did. '<img'>

Funky
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #11 on: September 15, 2013, 10:59:07 pm »


                 In Vermain's  question we have three points that we need to work with to figure out if two of them are flanking a target.   I will throw three points( A, B and C)  out and try to explain how to compare the relationships between them.  

'Posted

  In NWN if point A, B and C where the locations of objects, we could get the position of that object by using the GetPosition function.    GetPosition returns it's data in the vector data type.   Now  many would say that is position is not a vector it is just a single point, since it is not defined in the traditional way, that being a direction and a magnitude.  Or lets just say a distance in a direction, the magnitude being the distance. 

  For that matter, the NWN data type for the vector, does not even store it in the traditional way. Instead of storing them in a structure that contains a distance and a direction element. they are stored in a structure that contains the Change in the x direction and change in the y direction. It is basically the same thing just stored in a different format.  Given a direction and distance the change in x and y can be calculated and vice  versa.  

  Stored in this format our position can be considered as a vector from the position (0,0).  drawing the vectors for my positions would look like this.  
'Posted  

so our positions are fundamentally vectors from the (0,0) position.  It is important to note that vectors in themselves do not have a fixed starting location. they only represent a distance and direction that one thing is from another.    

To find a vector between two points, subtract the position of your source point from the position of your destination point.
'Posted

as shown above,  the order of the subtraction does not effect the magnitude of the vector.  both A-B and B-A have the same magnitude,   the only difference in the vectors is that they go in oppsit directions.    

For Vermain's problem, if we consider point A to the the position of the attacker and Point B to be the position of the target  it is easy to see that angle of vector B-A  will give us an angle that we can compare against.  

'Posted

All we need to do for Vermin's problem is compare the differance between the angles for the B-A vector and the angle of the C-B vector.   

pA = GetPosition(A) 
pB = GetPosition('B)' 
pC = GetPosition© 
fAngle= VectorToAngle(pB-pA)- VectortoAngle ( pC-pB)
               
               

               


                     Modifié par Lightfoot8, 22 septembre 2013 - 04:08 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #12 on: September 16, 2013, 12:00:04 am »


               

  vector VectorToTargetFromAttacker = posTarget- posAttaker ;
  float AngleToTargetFromAttacker = VectorToAngle( VectorToTargetFromAttacker);

  vector VectorToAllyFromTarget = posAlly - posTarget;
  float AngleToAllyFromTarget = VectorToAngle( VectorToAllyFromTarget);

  float DifferanceBetweenAngles = AngleToTargetFromAttacker - AngleToAllyFromTarget;


Something doesn't look right about this.  The AngleToTargetFromAttacker is supplementary to the AngleToAttackerFromTarget (new term).  Thus the DifferenceBetweenAngles  is supplementary to (AngleToAttackerFromTarget + AngleToAllyFromTarget) which can vary based on orientation (e.g. If both the attacker and ally are due east of the target the difference calculated would be 180.  If both the attacker and ally are due north of the target the difference calculated would be 0).

Also fabs (float absolute value) can be used without having to impose a sanity check (or go through the steps of adding half the total angle).
               
               

               


                     Modifié par WhiZard, 15 septembre 2013 - 11:11 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #13 on: September 16, 2013, 12:52:12 am »


               

WhiZard wrote...

  vector VectorToTargetFromAttacker = posTarget- posAttaker ;
  float AngleToTargetFromAttacker = VectorToAngle( VectorToTargetFromAttacker);

  vector VectorToAllyFromTarget = posAlly - posTarget;
  float AngleToAllyFromTarget = VectorToAngle( VectorToAllyFromTarget);

  float DifferanceBetweenAngles = AngleToTargetFromAttacker - AngleToAllyFromTarget;


 Thus the DifferenceBetweenAngles  is supplementary


 No the angles should not be supplementary  They would be if I used VectorToAttackerfrom target.   but I did not It is the vector to the target from the attacker.  Hmm,  perhaps I am missing what you are saying.   Yes is both are the same direction from the target the difference in the angles will be 180  that is by design, since we want the difference to be 0 when they are directly opposing.    
   

Also fabs (float absolute value) can be used without having to impose a sanity check (or go through the steps of adding half the total angle).


I have gotten burned to many times going that rout.   the sanity checks are more for keeping the angles in the 360 range.    Even the last script I posted for Shadow was flawed at certain angles due to omitting the sanity checks. As for the + 45, that is just the way I like to do it.
 
Edit:  
'Posted


The code is using the B-A vector not the A-B vector. 

e.g. If both the attacker and ally are due east of the target the difference calculated would be 180.  If both the attacker and ally are due north of the target the difference calculated would be 0).


No the difference would still be 180 in both cases,  Or should be,  I will double check my code later.  Given I have not tested it at all.
               
               

               


                     Modifié par Lightfoot8, 16 septembre 2013 - 04:38 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Get*ObjectInShape - Half-Circles
« Reply #14 on: September 16, 2013, 04:39:53 am »


               Rechecked and you are right.  I used the term supplementary (180 - x) when I should have done opposite (180 + x).  From that you get that your difference is the opposite (180 + x) of the angle formed from ally to target (vertex) to attacker which you are then limiting to the 90 degree back arc from the attacker to target by your inequality.

In this case fabs would work as there is no possibility of exceeding 360, but I understand your general dislike of it.