Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

comparing facing and angle[math help]

Discussion in 'Triggers & Scripts' started by Diehard@Azeroth, Oct 5, 2009.

  1. Diehard@Azeroth

    Diehard@Azeroth

    Joined:
    Sep 21, 2007
    Messages:
    483
    Resources:
    1
    Spells:
    1
    Resources:
    1
    ok, im doing a game where, if shooting is initiated, the units face is close to the angle between the shooting units position and the being shooted's position. Here is what i did for the comparison:

    i had a variable as a "degree boundary",

    Code (vJASS):
    degBoundary = .65


    lets say (im doing this in radians, but can do it in degrees if you want me to)
    so i put the units facing in a variable and converted it to Radians,

    Code (vJASS):
    facing = Deg2Rad(GetUnitFacing(udg_PlayerHero[unitId]))


    and then got the angle in a variable and left it as is (since its already radians). Now here is the comparison part:

    Code (vJASS):
    if facing > angle+degBoundary or facing < angle-degBoundary then


    facing being the facing, angle being the angle between the units, from the shooting unit to the unit being shooted: i used

    Code (vJASS):
    Atan2(y2-y,x2-x)


    . Sorry had to use some JASS here just incase you didnt know, its fairly basic though and can be understood through logic.

    thanks for your time
     
  2. Saia_Djinn

    Saia_Djinn

    Joined:
    Feb 15, 2009
    Messages:
    458
    Resources:
    0
    Resources:
    0
    and what exactly was the trouble
     
  3. aznricepuff

    aznricepuff

    Joined:
    Feb 22, 2006
    Messages:
    749
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    Yea, you didn't exactly tell us what your problem is. But I'm guessing it has something to do with this:
    if facing > angle+degBoundary or facing < angle-degBoundary then
    If you're trying to see if the facing is outside some range, then this bugs because of how angles are represented. GetUnitFacing() returns something between 0 and 2pi. Atan2 returns something between -pi and pi. So if the unit is facing 270 degrees (south), i.e. 3pi/2 and the shooting angle is the SAME angle (270 degrees or 3pi/2), Atan2 will actually give you -pi/2, not 3pi/2. You do your check:

    if facing > angle+degBoundary or facing < angle-degBoundary then


    facing will be 3pi/2. angle will be -pi/2. Obviously 3pi/2 is way more than -pi/2 + 0.65, so your check thinks the unit isn't facing the right way even when it is.

    This angle thing is always annoying. There's multiple ways to solve it. One is to use some function to convert all angles to between some value (i.e. always between 0 and 2pi or always between -pi and pi) before working with them. Then all you need to worry about is the wraparound (2pi to 0 or -pi to pi). Alternatively (and this is the method i prefer), you can use vectors to compare angles. Remember that for any two vectors u and v:

    cos (theta) = (u dot v) / (|u||v|)

    where theta is the angle between the two vectors. This method never fails. The only caveat is that you have to take the absolute value of theta before doing checks:

    if (RAbsBJ(theta) < threshold) then


    or if you want to avoid the BJ call:

    if (theta < threshold and theta > -threshold) then


    You don't have to worry about anything else when using the vector method.
     
  4. Diehard@Azeroth

    Diehard@Azeroth

    Joined:
    Sep 21, 2007
    Messages:
    483
    Resources:
    1
    Spells:
    1
    Resources:
    1
    thanks man. il do it ^^ +rep ofc :p
    EDIT: i messed up, meh... sry not so good at math, can u tell me what i did wrong? thanks again
    Code (vJASS):
            local unit t = GetTriggerUnit()
            local integer unitId = GetPlayerId(GetTriggerPlayer())+1
            local real Cooldown = udg_PLAYERGUN_RELOADTIME[unitId]
            local real Delay = udg_PLAYERGUN_SHOOTDELAY[unitId]
            local real Dist
            local real facing = Cos( Deg2Rad(GetUnitFacing(udg_PlayerHero[unitId])) )
            local real threshold = Cos( Atan2(GetUnitY(t)-GetUnitY(udg_PlayerHero[unitId]),GetUnitX(t)-GetUnitX(udg_PlayerHero[unitId]))+degBoundary )
            call DisplayTimedTextToPlayer(GetTriggerPlayer(),0,0,.45, R2S(threshold))
            call DisplayTimedTextToPlayer(GetTriggerPlayer(),0,0,.45, R2S(facing))
            if (facing < threshold and facing > -threshold) then
                return
            endif
     
    Last edited: Oct 6, 2009
  5. YourNameHere

    YourNameHere

    Joined:
    Apr 29, 2007
    Messages:
    745
    Resources:
    4
    Maps:
    1
    Spells:
    2
    JASS:
    1
    Resources:
    4
    Actually GetUnitFacing() returns a angle in degrees, but I assume you mean that it's between 0 and 2pi when its converted into radians.
     
  6. aznricepuff

    aznricepuff

    Joined:
    Feb 22, 2006
    Messages:
    749
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    What exactly is your event? You're using GetTriggerUnit() and GetTriggerPlayer() in the same actions, and since I can't think of an event that has both a triggering unit and a triggering player, I'm thinking one of those won't work.
     
  7. Diehard@Azeroth

    Diehard@Azeroth

    Joined:
    Sep 21, 2007
    Messages:
    483
    Resources:
    1
    Spells:
    1
    Resources:
    1
    A unit is selected by player, unitId = player id of player + 1, and the units are already preset in the variables,. Thanks for responding pretty dam fast man :D
    btw im sure they both work accordingly, since i damge the triggered unit and do various things to the unit in the variable.
     
  8. aznricepuff

    aznricepuff

    Joined:
    Feb 22, 2006
    Messages:
    749
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    Ah, unit selection event...forgot about tht one cuz I've never used tht before...ever.

    Anyway, the way you get vectors is: for the vector between selected unit and the hero, just use the dx and dy of their locations, and for the vector representing the facing angle, just create a unit vector with direction of the facing, where dx = Cos(facing) and dy = Sin(facing). So:

    Code (vJASS):

        local unit u = GetTriggerUnit()
        local integer id = GetPlayerId(GetTriggerPlayer()) + 1
        local real facing = GetUnitFacing(udg_PlayerHero[i]) * bj_DEGTORAD
        local real dx = GetUnitX(u) - GetUnitX(udg_PlayerHero[id])
        local real dy = GetUnitY(u) - GetUnitY(udg_PlayerHero[id])
        local real angleBetween = Acos((dx * Cos(facing) + dy * Sin(facing)) / (dx * dx + dy * dy))
        // the line above computes dot product of the two vectors, divides it by the product of their magnitudes, and then takes the arccosine to get the angle between the two vectors

        if (angleBetween < threshold and angleBetween > -threshold) then
            // ...
     
     
  9. uberfoop

    uberfoop

    Joined:
    May 17, 2005
    Messages:
    85
    Resources:
    1
    Maps:
    1
    Resources:
    1
    That's...not how you use scalar product to find the angle difference. Particularily since, as you said, you're supposed to divide by the product of their magnitudes; right now you're just dividing by the square of the magnitude of A.

    Right now, you're doing:
    Code (Text):

    Acos((A dot B) / A^2)
     
    It should be:

    Code (Text):

    ACos((A dot B) / (lAl*lBl)
     
    So, in other words:

    Code (vJASS):

        local real facing = GetUnitFacing(u2) * bj_DEGTORAD    
        local real dx = GetUnitX(u1) - GetUnitX(u2)    
        local real dy = GetUnitY(u1) - GetUnitY(u2)
        local real bx = Cos(facing)
        local real by = Sin(facing)
        local real angleBetween = Acos((dx * bx + dy * by) / (SquareRoot(dx * dx + dy * dy) * SquareRoot(bx * bx + by * by)))
        if (angleBetween < threshold and angleBetween > -threshold) then
     
     
  10. aznricepuff

    aznricepuff

    Joined:
    Feb 22, 2006
    Messages:
    749
    Resources:
    4
    Maps:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    4
    O right. I forgot to square root the magnitude. But I left out the magnitude of the other vector for good reason. It's a unit vector, therefore magnitude = 1.
     
  11. Cokemonkey11

    Cokemonkey11

    Wurst Reviewer

    Joined:
    May 9, 2006
    Messages:
    3,271
    Resources:
    18
    Tools:
    1
    Maps:
    5
    Spells:
    3
    Tutorials:
    2
    JASS:
    7
    Resources:
    18
    btw, use *bj_DEGTORAD instead of Deg2Rad()
     
  12. Diehard@Azeroth

    Diehard@Azeroth

    Joined:
    Sep 21, 2007
    Messages:
    483
    Resources:
    1
    Spells:
    1
    Resources:
    1
    Thanks for all your resposnes guys!, il do the changes right away!
    EDIT~~~

    ok im sorry for not telling you my problem, so you prob assumed the wrong problem, basically a unit is going to shoot a unit, therefore, the units facing angle and angle between them should not differ much, thats why i compared with facing of unit > Angle+degBoundary or facing of unit < angle-degBoundary so that if his facing goes outside a range of the angle itself, then the shooting will not be correct. I think that what you guys gave me does the complete opposite tho,
    ...or did i do another sad mistake? :p
    here is code: I declared the global threshold
    Code (vJASS):
    private real threshold = .45 //in radians

    Here are the actions
    Code (vJASS):
           local unit t = GetTriggerUnit()
            local integer unitId = GetPlayerId(GetTriggerPlayer())+1
            local real Cooldown = udg_PLAYERGUN_RELOADTIME[unitId]
            local real Delay = udg_PLAYERGUN_SHOOTDELAY[unitId]
            local real Dist
            //
            local real facing = GetUnitFacing(udg_PlayerHero[unitId])*bj_DEGTORAD
            local real dx = GetUnitX(t)-GetUnitX(udg_PlayerHero[unitId])
            local real dy = GetUnitY(t)-GetUnitY(udg_PlayerHero[unitId])
            local real bx = Cos(facing)
            local real by = Sin(facing)
            local real angleBetween = Acos((dx * bx + dy * by) / (SquareRoot(dx * dx + dy * dy) * SquareRoot(bx * bx + by * by)))  
            //local real threshold = Atan2(dy,dx)
            //
            call DisplayTimedTextToPlayer(GetTriggerPlayer(),0,0,.45, R2S(angleBetween))
            if (angleBetween < threshold and angleBetween > -threshold) then
                return
            endif
     
    Last edited: Oct 7, 2009