• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[Solved] Facing Angles of Units

Status
Not open for further replies.
Level 13
Joined
Mar 24, 2013
Messages
1,105
I'm trying to craft a trigger that causes a unit to deal additional damage when it's target is facing it directly (By directly, I mean if a unit is the origin of a some circle with respect to the direction in which it is facing I want that semi circle to proc the additional damage. (Added a picture to further clarify) (Red is where the bottom footman would deal additional damage, Blue is where no bonus damage would be had)
attachment.php


This is what I've come up with so far, but it does not work...really at all...lol so any help would be very much appreciated!

Thanks!

  • Attempt
    • Events
      • Unit - A unit Is attacked
    • Conditions
    • Actions
      • Set TempReal = someValue
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Facing of (Attacking unit)) Greater than or equal to ((Facing of (Attacked unit)) + 90.00)
          • (Facing of (Attacking unit)) Less than or equal to ((Facing of (Attacked unit)) - 90.00)
        • Then - Actions
          • Unit - Cause (Attacking unit) to damage (Attacked unit), dealing TempReal damage of attack type Normal and damage type Normal
          • Special Effect - Create a special effect attached to the chest of (Attacked unit) using Objects\Spawnmodels\Other\BeastmasterBlood\BeastmasterBlood.mdl
          • Special Effect - Destroy (Last created special effect)
          • Game - Display to (All players) the text: Right Direction
        • Else - Actions
          • Game - Display to (All players) the text: Wrong Direction
 

Attachments

  • pic.png
    pic.png
    1.3 MB · Views: 456
I made a script for this. Here is the link:
http://wc3jass.com/5193/unitorientation/msg39877/topicseen/#new

It requires Jass NewGen Pack. If you don't want it to require Jass NewGen Pack, then you can just put this in your map header (open trigger editor, click on the map's name in the trigger list, paste the code there):
JASS:
    function IsUnitBehindUnit takes unit behind, unit inFront, real angleMargin returns boolean
        local real angle = ModuloReal(Atan2(GetUnitY(behind) - GetUnitY(inFront), GetUnitX(behind) - GetUnitX(inFront)) * bj_RADTODEG, 360)
        local real difference = GetUnitFacing(inFront) - angle
        if difference < 0 then
            set difference = -difference
        endif
        return difference > (180 - angleMargin) and difference < (180 + angleMargin)
    endfunction
    
    function IsUnitFacingUnitBehind takes unit behind, unit inFront, real angleMargin returns boolean
        local real difference = GetUnitFacing(inFront) - GetUnitFacing(behind)
        if difference < 0 then
            set difference = -difference
        endif
        return difference < angleMargin and IsUnitBehindUnit(inFront, behind, angleMargin)
    endfunction
    
    function IsUnitFacingUnit takes unit theFacer, unit toFace, real angleMargin returns boolean
        local real angle = ModuloReal(Atan2(GetUnitY(theFacer) - GetUnitY(toFace), GetUnitX(theFacer) - GetUnitX(toFace)) * bj_RADTODEG, 360)
        local real difference = GetUnitFacing(theFacer) - angle
        if difference < 0 then
            set difference = -difference
        endif
        return difference > (180 - angleMargin) and difference < (180 + angleMargin)
    endfunction

You would check:
  • Custom script: if IsUnitFacingUnit(GetAttacker(), GetTriggerUnit(), 90.00) then
  • ---- Add your actions that increase damage ----
  • ---- This will pass when the attacking unit is facing the attacked unit with a 90 degree margin ----
  • Custom script: endif
Hopefully it should work. :)

If you want to know how it works, then click the link above. It should have an image that explains some things. The angle margin is the angle left of the unit and right of the unit. There are 3 functions: to check if a unit is facing a unit, check if a unit is facing another unit's butt, and check if the unit is behind a unit.
 
ModuloReal is one of the good BJ's. I use it to convert the angle to an angle between 0 and 360.
JASS:
function ConvertAngle takes real angle returns real
    return ModuloReal(angle, 360)
endfunction

I don't inline it because it means I would have to assign the value of:
Atan2(GetUnitY(theFacer) - GetUnitY(toFace), GetUnitX(theFacer) - GetUnitX(toFace)) * bj_RADTODEG
to a local real variable. It is a very marginal speed difference (a matter of nanoseconds) and obfuscates the code. :) It could possibly be slower to inline it, but it depends on the speed of allocating a local variable (which is very fast). I just prefer it to be neater. :D
 
Level 37
Joined
Mar 6, 2006
Messages
9,243
Here's another method to pick units in a circle and detect if they are facing some unit:
  • Attack GUI
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • -------- -------------------------------------------------- --------
      • -------- Set unit variables --------
      • -------- -------------------------------------------------- --------
      • Set u1 = Paladin 0003 <gen>
      • Set plr = (Owner of u1)
      • -------- -------------------------------------------------- --------
      • -------- Set location variables --------
      • -------- -------------------------------------------------- --------
      • Set p1 = (Position of u1)
      • Set p2 = (p1 offset by 500.00 towards (Facing of u1) degrees)
      • -------- -------------------------------------------------- --------
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units within 500.00 of p2) and do (Actions)
        • Loop - Actions
          • Set u2 = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (u2 is alive) Equal to True
              • (Owner of u2) Equal to Player 2 (Blue) // Edit these conditions
            • Then - Actions
              • Custom script: set udg_b1 = InCone_isInCone(udg_u2, udg_u1, 90)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • b1 Equal to True
                • Then - Actions
                  • Special Effect - Create a special effect at (Position of u2) using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
                  • Special Effect - Destroy (Last created special effect)
                • Else - Actions
            • Else - Actions
      • -------- -------------------------------------------------- --------
      • -------- Clear leaks --------
      • -------- -------------------------------------------------- --------
      • Custom script: call RemoveLocation(udg_p1)
      • Custom script: call RemoveLocation(udg_p2)
JASS:
library InCone
    public function isInCone takes unit source, unit target, real margin returns boolean
        return Cos(GetUnitFacing(source)*bj_DEGTORAD-Atan2(GetUnitY(target)-GetUnitY(source), GetUnitX(target)-GetUnitX(source))) > Cos(margin*bj_DEGTORAD)
    endfunction
endlibrary


My isInCone could be slighly slower than Purge's since it has Cos x2, but I like it since it is only one line and there won't be any noticeable difference. The latter Cos could be calculated before calling isInCone.
 

Attachments

  • Angle_Difference.w3x
    23.2 KB · Views: 77
Level 30
Joined
Nov 29, 2012
Messages
6,637
Here's another method to pick units in a circle and detect if they are facing some unit:
Attack GUI
Events
Player - Player 1 (Red) skips a cinematic sequence
Conditions
Actions
-------- -------------------------------------------------- --------
-------- Set unit variables --------
-------- -------------------------------------------------- --------
Set u1 = Paladin 0003 <gen>
Set plr = (Owner of u1)
-------- -------------------------------------------------- --------
-------- Set location variables --------
-------- -------------------------------------------------- --------
Set p1 = (Position of u1)
Set p2 = (p1 offset by 500.00 towards (Facing of u1) degrees)
-------- -------------------------------------------------- --------
Custom script: set bj_wantDestroyGroup = true
Unit Group - Pick every unit in (Units within 500.00 of p2) and do (Actions)
Loop - Actions
Set u2 = (Picked unit)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(u2 is alive) Equal to True
(Owner of u2) Equal to Player 2 (Blue)
Then - Actions
Custom script: set udg_b1 = InCone_isInCone(udg_u2, udg_u1, 90)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
b1 Equal to True
Then - Actions
Special Effect - Create a special effect at (Position of u2) using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
Special Effect - Destroy (Last created special effect)
Else - Actions
Else - Actions
-------- -------------------------------------------------- --------
-------- Clear leaks --------
-------- -------------------------------------------------- --------
Custom script: call RemoveLocation(udg_p1)
Custom script: call RemoveLocation(udg_p2)


JASS:
library InCone
    public function isInCone takes unit source, unit target, real margin returns boolean
        return Cos(GetUnitFacing(source)*bj_DEGTORAD-Atan2(GetUnitY(target)-GetUnitY(source), GetUnitX(target)-GetUnitX(source))) > Cos(margin*bj_DEGTORAD)
    endfunction
endlibrary
My isInCone could be slighly slower than Purge's since it has Cos x2, but I like it since it is only one line and there won't be any noticeable difference.

Put it in trigger tags, the GUI one. =)

EDIT: Oh nevermind, its fixed now.
 
Level 13
Joined
Mar 24, 2013
Messages
1,105
Hmm.. I feel like I must have implemented improperly or something.. because it seems to cause the extra damage from every angle...And I don't know why...I put a debug message just to confirm exactly which angles were firing it, and I couldn't get it to not give me my message-----
This lead me to shrink the 90 to 10 degrees to test.. where I guess it worked in a sense, it seemed that the first attack registered properly, but after that it just applied the extra damage on every attack+debugmsg after (This is without the unit moving, the unit just continuing to autoattack caused this)

EDIT: I'll look at Maker's tmw!
 
Level 13
Joined
Mar 24, 2013
Messages
1,105
So when I tried to use the test map by Maker I got numerous complier errors which lead it to disable the trigger, and I hadn't even touched them so maybe there's an error somewhere..?

@Purge
I did as you instructed, I pasted the IsUnitFacingUnit function in the Trigger editor -> map name and then used this trig to check. It works...in that if I attack while facing the unit it procs, and when I attack from behind it doesn't proc...the 1st time, anytime after that it procs (Even without moving)

  • UnitFacingUnit
    • Events
      • Unit - A unit Is attacked
    • Conditions
    • Actions
      • Custom script: if IsUnitFacingUnit(GetAttacker(), GetTriggerUnit(), 10.00) then
      • Unit - Cause (Attacking unit) to damage (Attacked unit), dealing 10.00 damage of attack type Normal and damage type Normal
      • Special Effect - Create a special effect attached to the chest of (Attacked unit) using Objects\Spawnmodels\Other\BeastmasterBlood\BeastmasterBlood.mdl
      • Special Effect - Destroy (Last created special effect)
      • Game - Display to (All players) the text: Proper Direction
      • Custom script: endif
 
My mistake, I used the wrong function. Brain fart. :p

It was always passing as true because the unit who is attacking is always facing the attacked unit. Hehe. You wanted to check if the unit is in front of the unit. Therefore, change it to this:
  • Custom script: if not IsUnitBehindUnit(GetAttacker(), GetTriggerUnit(), 90.00) then
  • // actions for extra damage
  • Custom script: endif
Basically, if the unit is not behind the unit with a 90 degree margin (therefore, in front of the unit with a 90 degree margin), then it will deal extra damage. Since this is kind of doing it backwards, you would increase the value of 90 in the function if you want the margin for being considered "in front" of the unit to be lower. So if you want the margin for being considered in front of the unit to be 60 degrees, the degrees you would input in the function above would be 180-60 = 120.
 
Status
Not open for further replies.
Top