• 🏆 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!

[Trigger] How to select units within a cone ?

Status
Not open for further replies.
Level 6
Joined
Jan 4, 2014
Messages
227
[Solved] How to select units within a cone ?

Good day, i want to select units in a cone shape in front of my hero using angels ( i used breath of frost buffs to select units but it does not feet my needs )
GUI pleas :D Thanks :)
 
Last edited:
Level 25
Joined
Sep 26, 2009
Messages
2,378
You cannot select units in cone shape, however you can select all nearby units and check their position towards the caster. If the angle between caster and unit in unit group is within certain radius, that unit should be in the in what would be the cone shape.

Another problem that raises here is that the GUI action for finding out angle between points doesn't get from 0° to 360°, but from 180° to -180°.

For most efficient way via gui, you will need a few variables and custom scripts (these are needed to prevent memory leaks and all you have to do with them is you basically copy what I write)
Variables:
unit1, unit2 = unit variables
loc1, loc2 = point variables
angle = real variable

The trigger is in the hidden tabs.
  • Actions
    • -------- --------------------------------- --------
    • -------- -- Set variables -- --------
    • -------- --------------------------------- --------
    • Set unit1 = (Triggering unit)
    • Set loc1 = (Position of unit1)
    • Set angle = (Facing of unit1)
    • -------- --------------------------------- --------
    • -------- - Check nearby units - --------
    • -------- --------------------------------- --------
    • Custom script: set bj_wantDestroyGroup = true
    • Unit Group - Pick every unit in (Units within 900.00 of loc1) and do (Actions)
      • Loop - Actions
        • Set unit2 = (Picked unit)
        • Set loc2 = (Position of unit2)
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • (unit2 is alive) Equal to True
            • (unit2 belongs to an enemy of (Owner of unit1)) Equal to True
            • (Acos((Cos((angle - (Angle from loc1 to loc2)))))) Less than or equal to 45.00
          • Then - Actions
            • -------- IN --------
          • Else - Actions
            • -------- OUT --------
        • Custom script: call RemoveLocation(udg_loc2)
    • -------- --------------------------------- --------
    • -------- ------ Clear Leaks ------ --------
    • -------- --------------------------------- --------
    • Custom script: call RemoveLocation(udg_loc1)
    • Custom script: set udg_loc1 = null
    • Custom script: set udg_loc2 = null
The trigger in hidden tabs finds every unit which is alive, is enemy to the caster and is in 90° cone in front of caster (90° = 45° to left and 45° to right from where the caster is looking).

You may want to get the angle of caster differently, depending on how your spell behaves.

a) If your spell targets enemy unit, and you want to damage everyone in cone, but from the angle "from caster to targeted unit", then you will need to do this:
  • Actions
    • Set unit1 = (Triggering unit)
    • Set loc1 = (Position of unit1)
    • Set loc2 = (Position of (Target unit of ability being cast))
    • Set angle = (Angle from loc1 to loc2)
    • Custom script: call RemoveLocation(udg_loc2)
    • Custom script: set udg_loc2 = null
I got the angle between caster and target by getting position of those units and saving the angle into variable. Then I remove only the second location - loc2, because I will still need loc1 when I pick all nearby units into unit group, just like in previous trigger.


b) If you don't target a unit, but you target point, then the approach will be very similar:
  • Actions
    • Set unit1 = (Triggering unit)
    • Set loc1 = (Position of unit1)
    • Set loc2 = (Target point of ability being cast)
    • Set angle = (Angle from loc1 to loc2)
    • Custom script: call RemoveLocation(udg_loc2)
    • Custom script: set udg_loc2 = null
Instead of getting position of the target, I immediately got the target point of ability being cast and saved it into loc2.
 
If it's too complicated with cos you also simple could do:
  • Actions
    • Set facing = (Facing of Unit)
    • Set pt1 = (Position of Unit)
    • Unit Group - Pick every unit in (Units within 512.00 of (pt1) and do (Actions)
      • Schleifen - Aktionen
        • Set pt2 = (Position of (Picked unit))
        • Set angle = (Angle from pt1 to pt2)
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • 'IF'-Bedingungen
            • angle < (facing + 45.00)
            • angle > (facing - 45.00)
          • Then - Actions
            • Game - Display to (All players) the text: in cone
          • Else - Actions
            • Game - Display to (All players) the text: not in cone
      • ... remove leaks
Edit:

oops, saw you second post too late... so you got it?

And "in" means unit is in cone, so do what ever you want to do. (to your question @nichilus)
 
Level 6
Joined
Jan 4, 2014
Messages
227
(Acos((Cos((angle - (Angle from loc1 to loc2)))))) Less than or equal to 45.00 Thats what i seeked for 6 hours !!
Fus Ro Dah !!! Thanks man it works perfectly :)

Thanks Icemanbo, i tried it before i was able to get units from all angels except the ones from -45° to 45° due to the jump from 360 to 0, so i used cosinus but it gave me weired results.
 
Last edited by a moderator:
Level 25
Joined
Sep 26, 2009
Messages
2,378
If it's too complicated with cos you also simple could do:
I don't think that will work well.
I'm not sure atm how "facing of (unit)" is handled, but the function "angle from p1 to p2" returns angle ranging between -180 to +180, while I believe "facing of unit" returns angle ranging between 0 to 360.
If I am correct, you would get problems if you were to pick units in cone that faces the general direction of 180°, as the facing +-45° would still get incorrect values in some cases.

Code:
Angle between points:
135°     90°    45°
         |
180°  ---|---   0°
         |
[B][COLOR="Yellow"]-135°  -90°  -45°[/COLOR][/B]


------------

Facing of unit:
135°     90°    45°
         |
180°  ---|---   0°
         |
[B][COLOR="yellow"]225°    270°  315°[/COLOR][/B]
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
(Acos((Cos((angle - (Angle from loc1 to loc2)))))) Less than or equal to 45.00 Thats what i seeked for 6 hours !!
Inefficient and obsolete.

(Cos((angle - (Angle from loc1 to loc2))) Greater than or equal to (Cos(45.00))

Which optimizes to...
(Cos((angle - (Angle from loc1 to loc2))) Greater than or equal to 0.707

Saves on a function call. It works because of the symmetry of Cos around 0 degress. In fact you can use this approach to get deviation from 180 as well with less than or equals to a negative number. If you want deviation from a right angle (90/270) you need to use Sin.
 
Level 6
Joined
Jan 4, 2014
Messages
227
i tried all direction and it works fine :)

@Dr Super Good i tried cosinus before but it gave me weired results ^^
Thanks :)
 
Last edited by a moderator:
Level 6
Joined
Jan 4, 2014
Messages
227
first i used :
if UnitAngel is between (HeroAngel - 45) and (HeroAngel + 45 ) but it did work wrong because of units between 315° and 45° around the Hero so i used cosinus, if Cos[UnitAngel] is between Cos[(HeroAngel - 45)] and Cos[(HeroAngel + 45 )] but it started skipping units most of the times or at some angels selecting no unit.
and then i used Acos as nichilius told me and it did work perfect, so maybe comparing small reals in WC3 engine is not that precise ^^
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
if Cos[UnitAngel] is between Cos[(HeroAngel - 45)] and Cos[(HeroAngel + 45 )]
This makes no sense anyway and is not what I told you to do.

1. Get angle of picked unit with respects to origin of cone.
2. Subtract this angle by the angle of cone.
3. Get the Cos of this angle.
4. Compare if result is greater than the cos of half the cone angle).

Cos is a symmetric function so if the unit is 179 degrees away from the angle of the cone in either direction the cos on 179 or -179 is the same.

Cos runs from 1 at 0 degrees to -1 at 180 degrees. Combined with the symmetry above you can test if an angle range is met with respects from 0 or -180 by inverting the comparison. For angles with respect to 90 and 270 you need to use Sin as that is symmetric there.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
You have the angle of the unit with respects to the cone origin from 1.
You then have your angle of the cone (if the cone was directly in front of a unit this would be that unit's facing).
You then get the angle of the unit (step 1) and subtract it by the angle of the cone (whatever you define your cone to face).
The result is an angle that represents the difference between the cone facing and the unit. If this angle is too large the unit will be outside the cone.

The other steps are just analysing this angle to make sense of it. Step 3 converts it from an angle into the cosine of the angle which is easier to analyse due to the symmetry and finite range (unlike the angle which has multiple different values that are technically equivalent). Step 4 tests this result to get if the unit was inside the cone.
 
There's a lot simpler way you can do this, with some help from a damage detection system. Simply use a cone spell that applies a debuff, such as breath of fire, then catch the event by detecting when a unit takes damage, and checking if it has the debuff of the spell you used; if it does, then it has been hit by the cone spell, and you can apply further actions from that point. Much simpler, and doesn't involve complicated maths. Though, be sure to remove the debuff in your trigger.
 
Status
Not open for further replies.
Top