• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Beware with cone spells!

Status
Not open for further replies.
Level 12
Joined
Jan 2, 2016
Messages
973
Few months ago, when I was still new to the editor - I tried to make a cone spell, and I noticed that when I aim it towards 180 deg (west) - it hits only half of the enemies it should.
I didn't know why it's doing that until few days ago. Now that I know, I decided to share the reason with you, so players can avoid creating not fully functional cone spells.
So, world editor's "GetAngleBetweenPoints" (which GUI uses) gets angles between -180 and 180 degreese. In cone spells the simplest way to define a cone is "Angle between( Position of Picked Unit - Target point of ability being cast) +/- 45 deg".
So if you cast the spell at 179 deg, and picked unit is at 181 deg - the game will evaluate the unit's angle as -179, so 179 - 45 = 134 deg, and the condition "-179 > 134" will not be met, so the unit will not get damaged.

I'm not sure what angles would I get if I used "arctan((y2-y1)/|x2-x1|)" (would it be defined from 0 to 360 or again from -180 to 180 again, or even from -90 to 90). The best way to avoid this would be to:
set a real variable to the angle between the castin unit and the target point of ability being cast
set a real vatiable to the angle between the casting unit and the picked unit
set the 2-nd angle to 'the 2-nd - the 1-st'
if the new angle's abs value is greater than 180 - set it to RSignBJ(-the angle)*(360 -|the angle|),
And after that - set the condition "if the angle is between -xx and xx then do actions"...

This way the example I gave earlier will turn out like this:
1-st angle = 179
2-nd angle = -179
set 2-nd angle to -179 - 179 = -358
|-358| is greater than 180, so set it to (1)*|(360-358)| = 2
Then the condition would be " if '2' is between -45 and 45 then do actions" and it will run.

Let's see if any other angles wouldn't give problems:
1-st angle = 120
2-nd angle = 100
set 2-nd angle to 100-120 = -20
|-20| is less than 180, so it will remain -20
it is between -45 and 45, so the trigger will run

1-st angle = 145
2-nd angle = -145
set 2-nd angle to -145 - 145 = -290
set 2-nd angle to (1)*(360 - 290) = 70
it's less than -45, so the trigger wouldn't run.

1-st angle = 80
2-nd angle = 90
set 2-nd angle to 90-80 = 10
10 is less than 180, so keep it 10
10 is between -45 and 45, so the trigger will run.

1-st angle = -100
2-nd angle = -10
set 2-nd angle to -10+100 = 90
90 is less than 180, so it remains 90
90 is greater than 45, so the trigger doesn't run.

1-st angle = -170
2-nd angle = 170
set 2-nd angle to 170+170 = 340
340 is greater than 180, so set it to (-1)*(360-340)= -20
-20 is between -45 and 45, so the trigger will run.
 
Last edited:
Level 12
Joined
Jan 2, 2016
Messages
973
I am defining the angle from -180 to 180 too, but I put the '0' towards the targeted point, instead of 'east'. ~kind a~
1-st I get the difference between the angles, by substraction.
But since this way can get me angles from -360 to 360 (angles 179 and -179 get -358, and with -179 to 179 is 358), I check if the abs value of the angle is greater than 180 deg - I set its value to its relative angle (from -180 to 180).
This way your cone spells will work properly :p

EDIT: I kind a fixed some things in the initial post, so it'd be more accurate :p
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
JASS:
    function NormalizeAngleRad takes real angle returns real
        local real modulus = angle - I2R(R2I(angle / TAU)) * TAU
        if modulus < 0 then
            set modulus = modulus + TAU
        endif
        return modulus
    endfunction
    
    function DenormalizeAngleRad takes real angle returns real
        return NormalizeAngleRad(angle) - PI
    endfunction
    
    function GroupAddUnitsInConeRad takes group whichGroup, real x, real y, real radius, real direction, real size returns group
        local unit FoG
        local group g = CreateGroup()
        local real x2
        local real y2
        local real difference
        
        call GroupEnumUnitsInRange(g, x, y, radius, null)
        loop
            set FoG = FirstOfGroup(g)
            exitwhen FoG == null
            call GroupRemoveUnit(g,FoG)
            
            set difference = DenormalizeAngleRad(AngleBetweenCoordinatesRad(x, y, GetUnitX(FoG), GetUnitY(FoG)) - direction)
            if difference > -size and difference < size then
                call GroupAddUnit(whichGroup, FoG)
            endif
        endloop
        
        call DestroyGroup(g)
        set g = null
        return whichGroup
    endfunction
 
Status
Not open for further replies.
Top