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

Homing Missile with turn limit

Status
Not open for further replies.
Hello. I am about 2 days breaking my head trying to think how to calculate angles to make a GUI missile to turn in correct direction (left or right).

I cant freaking figure it out. Help please.
Here is some variables that missile have and some explaining how it works:
-Missile is NOT turning to unit with facing, but with ANGLE.
-Missile have detection range, so it fly at line unit detect an enemy.
-Missile have turn speed, so it cant turn too fast.

I tryed a lot of angle calculations, but it bugs a lot when rocket come from diferent sides and angles. The logic is kinda like this.
 

Attachments

  • Teh Problem.jpg
    Teh Problem.jpg
    56.3 KB · Views: 234
It turns wrong when target is closer to the right and angle of missile is ~ 180-0

  • HM Setings
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Huming Missile
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • HM_index[1] Equal to 0
        • Then - Actions
          • Trigger - Turn on HM Loop <gen>
        • Else - Actions
      • Set HM_index[1] = (HM_index[1] + 1)
      • Set HM_index[2] = (HM_index[2] + 1)
      • Set HM_On[HM_index[2]] = True
      • Set HM_Owner[HM_index[2]] = (Triggering unit)
      • Set HM_Level[HM_index[2]] = (Level of Huming Missile for (Triggering unit))
      • Set HM_LifeTime[HM_index[2]] = (1.00 + (0.50 x (Real(HM_Level[HM_index[2]]))))
      • Set HM_Speed[HM_index[2]] = (13.00 + (2.00 x (Real(HM_Level[HM_index[2]]))))
      • Set HM_Collision[HM_index[2]] = 50.00
      • Set HM_AoE[HM_index[2]] = 150.00
      • Set HM_Damage[HM_index[2]] = ((Random real number between 150.00 and 200.00) + (50.00 x (Real(HM_Level[HM_index[2]]))))
      • Set HM_DetectionDistance[HM_index[2]] = (300.00 + (100.00 x (Real(HM_Level[HM_index[2]]))))
      • Set HM_TurnSpeed[HM_index[2]] = (1.00 + (1.00 x (Real(HM_Level[HM_index[2]]))))
      • Set HM_Point[0] = (Position of (Triggering unit))
      • Set HM_Point[1] = (Target point of ability being cast)
      • Set HM_Angle[HM_index[2]] = (Angle from HM_Point[0] to HM_Point[1])
      • Unit - Create 1 Huming Missile for (Owner of (Triggering unit)) at HM_Point[0] facing (Angle from HM_Point[0] to HM_Point[1]) degrees
      • Set HM_Rocket[HM_index[2]] = (Last created unit)
      • Unit - Add Storm Crow Form to (Last created unit)
      • Unit - Remove Storm Crow Form from (Last created unit)
      • Animation - Change HM_Rocket[HM_index[2]] flying height to 60.00 at 0.00
      • Set HM_Target[HM_index[2]] = No unit
      • Custom script: call RemoveLocation(udg_HM_Point[0])
      • Custom script: call RemoveLocation(udg_HM_Point[1])
  • HM Loop
    • Events
      • Time - Every 0.02 seconds of game time
    • Conditions
    • Actions
      • For each (Integer HM_index[3]) from 1 to HM_index[2], do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • HM_On[HM_index[3]] Equal to True
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • HM_LifeTime[HM_index[3]] Less than or equal to 0.00
                • Then - Actions
                  • Set HM_Point[5] = (Position of HM_Rocket[HM_index[3]])
                  • Destructible - Pick every destructible within HM_AoE[HM_index[3]] of HM_Point[5] and do (Actions)
                    • Loop - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ((Picked destructible) is alive) Equal to True
                          • (Destructible-type of (Picked destructible)) Equal to Fall Tree Wall
                        • Then - Actions
                          • Destructible - Kill (Picked destructible)
                        • Else - Actions
                  • Set HM_Group = (Units within HM_AoE[HM_index[3]] of HM_Point[5] matching ((((Matching unit) is A ground unit) Equal to True) and (((Matching unit) is alive) Equal to True)))
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Number of units in HM_Group) Greater than 0
                    • Then - Actions
                      • Unit Group - Pick every unit in HM_Group and do (Actions)
                        • Loop - Actions
                          • Unit - Cause HM_Owner[HM_index[3]] to damage (Picked unit), dealing HM_Damage[HM_index[3]] damage of attack type Hero and damage type Normal
                    • Else - Actions
                  • Custom script: call RemoveLocation ( udg_HM_Point[5] )
                  • Custom script: call DestroyGroup ( udg_HM_Group )
                  • Unit - Kill HM_Rocket[HM_index[3]]
                  • Set HM_On[HM_index[3]] = False
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • HM_index[3] Less than HM_index[2]
                    • Then - Actions
                      • Set HM_Angle[HM_index[3]] = HM_Angle[HM_index[2]]
                      • Set HM_AoE[HM_index[3]] = HM_AoE[HM_index[2]]
                      • Set HM_Collision[HM_index[3]] = HM_Collision[HM_index[2]]
                      • Set HM_Damage[HM_index[3]] = HM_Damage[HM_index[2]]
                      • Set HM_DetectionDistance[HM_index[3]] = HM_DetectionDistance[HM_index[2]]
                      • Set HM_Level[HM_index[3]] = HM_Level[HM_index[2]]
                      • Set HM_LifeTime[HM_index[3]] = HM_LifeTime[HM_index[2]]
                      • Set HM_On[HM_index[3]] = HM_On[HM_index[2]]
                      • Set HM_Owner[HM_index[3]] = HM_Owner[HM_index[2]]
                      • Set HM_Rocket[HM_index[3]] = HM_Rocket[HM_index[2]]
                      • Set HM_Speed[HM_index[3]] = HM_Speed[HM_index[2]]
                      • Set HM_Target[HM_index[3]] = HM_Target[HM_index[2]]
                      • Set HM_TurnSpeed[HM_index[3]] = HM_TurnSpeed[HM_index[2]]
                    • Else - Actions
                  • Set HM_index[3] = (HM_index[3] - 1)
                  • Set HM_index[2] = (HM_index[2] - 1)
                  • Set HM_index[1] = (HM_index[1] - 1)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • HM_index[2] Equal to 0
                    • Then - Actions
                      • Trigger - Turn off (This trigger)
                    • Else - Actions
                • Else - Actions
                  • Set HM_LifeTime[HM_index[3]] = (HM_LifeTime[HM_index[3]] - 0.02)
                  • Set HM_Point[2] = (Position of HM_Rocket[HM_index[3]])
                  • Set HM_Group = (Units within HM_DetectionDistance[HM_index[3]] of HM_Point[2] matching ((((Matching unit) is alive) Equal to True) and ((((Matching unit) is A ground unit) Equal to True) and (((Matching unit) belongs to an enemy of (Owner of HM_Owner[HM_index[3]])) Equal to
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Number of units in HM_Group) Greater than 0
                    • Then - Actions
                      • Set CUD_Unit = No unit
                      • Unit Group - Pick every unit in HM_Group and do (Actions)
                        • Loop - Actions
                          • Set HM_Point[6] = (Position of (Picked unit))
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • (Distance between HM_Point[2] and HM_Point[6]) Less than CUD_Distance
                            • Then - Actions
                              • Set CUD_Distance = (Distance between HM_Point[2] and HM_Point[6])
                              • Set CUD_Unit = (Picked unit)
                            • Else - Actions
                          • Custom script: call RemoveLocation ( udg_HM_Point[6] )
                      • Set HM_Target[HM_index[3]] = CUD_Unit
                      • Set CUD_Distance = 10000000.00
                    • Else - Actions
                      • Set HM_Target[HM_index[3]] = No unit
                  • Custom script: call DestroyGroup ( udg_HM_Group )
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • Or - Any (Conditions) are true
                        • Conditions
                          • (HM_Target[HM_index[3]] is dead) Equal to True
                          • HM_Target[HM_index[3]] Equal to No unit
                    • Then - Actions
                    • Else - Actions
                      • Set HM_Point[4] = (Position of HM_Target[HM_index[3]])
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Angle from HM_Point[2] to HM_Point[4]) Less than or equal to (HM_Angle[HM_index[3]] + HM_TurnSpeed[HM_index[3]])
                          • (Angle from HM_Point[2] to HM_Point[4]) Greater than or equal to (HM_Angle[HM_index[3]] - HM_TurnSpeed[HM_index[3]])
                        • Then - Actions
                          • Set HM_Angle[HM_index[3]] = (Angle from HM_Point[2] to HM_Point[4])
                        • Else - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • ((Angle from HM_Point[2] to HM_Point[4]) - HM_Angle[HM_index[3]]) Less than or equal to 180.00
                              • ((Angle from HM_Point[2] to HM_Point[4]) - HM_Angle[HM_index[3]]) Greater than 0.00
                            • Then - Actions
                              • Set HM_Angle[HM_index[3]] = (HM_Angle[HM_index[3]] + HM_TurnSpeed[HM_index[3]])
                            • Else - Actions
                              • Set HM_Angle[HM_index[3]] = (HM_Angle[HM_index[3]] - HM_TurnSpeed[HM_index[3]])
                      • Custom script: call RemoveLocation ( udg_HM_Point[4] )
                  • Set HM_Point[3] = (HM_Point[2] offset by HM_Speed[HM_index[3]] towards HM_Angle[HM_index[3]] degrees)
                  • Unit - Move HM_Rocket[HM_index[3]] instantly to HM_Point[3], facing HM_Angle[HM_index[3]] degrees
                  • Destructible - Pick every destructible within HM_Collision[HM_index[3]] of HM_Point[3] and do (Actions)
                    • Loop - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ((Picked destructible) is alive) Equal to True
                          • (Destructible-type of (Picked destructible)) Equal to Fall Tree Wall
                        • Then - Actions
                          • Set HM_LifeTime[HM_index[3]] = 0.00
                        • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Terrain pathing at HM_Point[3] of type Walkability is off) Equal to True
                    • Then - Actions
                      • Set HM_LifeTime[HM_index[3]] = 0.00
                    • Else - Actions
                      • Set HM_Group = (Units within HM_Collision[HM_index[3]] of HM_Point[3] matching (((((Matching unit) is A ground unit) Equal to True) and (((Matching unit) is alive) Equal to True)) and ((Owner of (Matching unit)) Not equal to (Owner of HM_Rocket[HM_index[3]]))))
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Number of units in HM_Group) Greater than 0
                        • Then - Actions
                          • Set HM_LifeTime[HM_index[3]] = 0.00
                        • Else - Actions
                      • Custom script: call DestroyGroup ( udg_HM_Group )
                  • Custom script: call RemoveLocation ( udg_HM_Point[2] )
                  • Custom script: call RemoveLocation ( udg_HM_Point[3] )
            • Else - Actions
I am creating a map with tank deathmatch scenario. Speciality is that cannon rotate with arrow keys, so gameplay is very different and more fun (I belive so). big thx to ikillforyou for creating models for me :)
 

Attachments

  • Teh Bug.jpg
    Teh Bug.jpg
    270 KB · Views: 258
well i found one problem that i think relates to why your missile may be turning the wrong way

(i may be wrong, so if it doesnt work i'll look a little more(i havent touched warIII's editor in a while))
Error.jpg

that line will always validate as true, because degrees never turn negative,
they'll go to 359, then back to 0

359,360(0),1,2,3,4,5... etc.

i think.

so that else statement is never reached.
cause i think without the "and" condition (and all conditions are true), it, by default, uses an Or (so an "Or" condition is kind of useless to my thoughts.


it checks out because by the looks of your screenshots, your missile is only turning right, meaning you are only adding degrees, and have no way of subtracting

(+ = right, - = left)
 
Wrong. Check out value of HM_Angle[HM_index[3]]. It is 0-180, -180-0. I tryed to convert it to always positive value (if less than 0 than 360 + Angle) but it works still wrong.

Want me to take 8 screenshots from each side and angle I can shot? lame.
but I still can do that :p In wc3, object editor have 0-360 degress for facing. But in positions on surface count like 180-0-(-180).
This is pain in ass :/
The way to calculate must be easy but I am so confused about it.
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
This very easy to understand (no sin or cos functions used) example trigger determines whether a unit should turn to left or right if it wants to change it's facing towards an object as quickly as possible.

For example, your unit is facing at 90° and the object is at 120°. Then you should turn to left so you make 30° turn. If you turn to right, you have to make 330° turn.

  • Untitled Trigger 013
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • Set point1 = (Position of Mountain King 0011 <gen>)
      • Set point2 = (Position of Paladin 0005 <gen>)
      • Set real1 = (Facing of Mountain King 0011 <gen>)
      • Set real2 = (Distance between point1 and point2)
      • Set point3 = (point1 offset by real2 towards real1 degrees)
      • Set point4 = (point1 offset by real2 towards (real1 + 1.00) degrees)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Distance between point3 and point2) - (Distance between point4 and point2)) Greater than or equal to 0.00
        • Then - Actions
          • Game - Display to (All players) the text: Shorter by turning left.
        • Else - Actions
          • Game - Display to (All players) the text: Shorter by turning right.
      • Custom script: call RemoveLocation(udg_point1)
      • Custom script: call RemoveLocation(udg_point2)
      • Custom script: call RemoveLocation(udg_point3)
      • Custom script: call RemoveLocation(udg_point4)
With that +1 thing I simulate a left turn and then test whether the angle became bigger or smaller.

General note: You can use cos(facing) and cos(angle from a to b). That way they both return values from -1 to 1. Then work from there.
 
perhaps you can work with X-positions and Y-positions to find the angle between the two units

this sounds like a trigonometry problem.

a simple one if i remember..

find the values of X and Y relative to war3's XY axes for each unit
tangent of the absolute value of the quotient of the differences in Y values over the differences in X values, then convert it to Degrees

so.

tan(|(y2-y1)/(x2-x1)|)*(180/pi)


this will give you the angle in degrees relative to the line formed between the two units and the X-axis.
 
Status
Not open for further replies.
Top