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

Pitch, Yaw, and Roll calculation for a falling object

So, I have a spell idea based on this video:

In short, the spell is that a tower-like object (I used the guard tower for this) falls on the target enemy (or point in my case). I want the tower positioned slightly off the target point (around 100-200 unit) based on the caster current facing and then fall to the target point, dealing damage between those points.

The main issue I have is the 'fall' sequence. I figured the existence of the yaw, pitch, and roll will be critical for this particular need, but I have a hard time to figure out the calculation to drop the tower, especially if the angle is not horizontal nor vertical, but in-between both axes. I can work the damaging aspect and other calculations needed, but this one is quite a stump for me.

Say I cast it like this:
[1]
T O -
- ^ -

[2]
- -
O <
T -

T = Tower
^/< = Facing of Caster
O = Target Point

In short, the tower will be slightly off to the left of the caster, and then dropped to the target point, dealing damage to all units between both points on impact.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,543
Here's an example I threw together, by no means perfect but I think I got the math correct.
  • Tower Fall Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Tower Fall
    • Actions
      • Set VariableSet TF_Index = (TF_Index + 1)
      • Set VariableSet TF__Caster[TF_Index] = (Triggering unit)
      • -------- --------
      • -------- Define height, damage, and duration (this is not perfect - will need to adjust Loop trigger if you tweak timings): --------
      • Set VariableSet TF__Damage[TF_Index] = (200.00 x (Real((Level of (Ability being cast) for TF__Caster[TF_Index]))))
      • Set VariableSet TF__Duration[TF_Index] = 1.80
      • Set VariableSet TF__Height[TF_Index] = 2000.00
      • -------- --------
      • Set VariableSet TF_Caster_Point = (Position of TF__Caster[TF_Index])
      • Set VariableSet TF__End_Point[TF_Index] = (Target point of ability being cast)
      • -------- --------
      • Set VariableSet TF_Angle_Temp[0] = (Angle from TF_Caster_Point to TF__End_Point[TF_Index])
      • Set VariableSet TF_Angle_Temp[1] = (TF_Angle_Temp[0] - 30.00)
      • -------- --------
      • Set VariableSet TF__Start_Point[TF_Index] = (TF__End_Point[TF_Index] offset by -200.00 towards TF_Angle_Temp[1] degrees.)
      • -------- --------
      • Set VariableSet TF__Angle[TF_Index] = (Angle from TF__Start_Point[TF_Index] to TF__End_Point[TF_Index])
      • -------- --------
      • Special Effect - Create a special effect at TF__Start_Point[TF_Index] using buildings\human\HumanTower\HumanTower
      • Set VariableSet TF__Sfx[TF_Index] = (Last created special effect)
      • -------- --------
      • -------- These animations make the Scout Tower appear as a standard Guard Tower: --------
      • Special Effect - For Special Effect: TF__Sfx[TF_Index], Add Sub-Animation: First
      • Special Effect - Play Special Effect: TF__Sfx[TF_Index], Animation: Stand
      • Special Effect - Set Color of TF__Sfx[TF_Index] to color of Neutral Passive
      • -------- --------
      • Special Effect - Set Height of TF__Sfx[TF_Index] to: TF__Height[TF_Index]
      • Special Effect - Set Yaw of TF__Sfx[TF_Index] to: (Radians(TF__Angle[TF_Index]))
      • -------- --------
      • Custom script: call RemoveLocation( udg_TF_Caster_Point )
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • TF_Index Equal to 1
        • Then - Actions
          • Countdown Timer - Start TF_Timer as a Repeating timer that will expire in 0.02 seconds
        • Else - Actions
  • Tower Fall Loop
    • Events
      • Time - TF_Timer expires
    • Conditions
    • Actions
      • For each (Integer TF_Loop) from 1 to TF_Index, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • TF__Height[TF_Loop] Greater than 0.01
            • Then - Actions
              • -------- HANDLE HEIGHT (FALLING FROM SKY) --------
              • Set VariableSet TF__Height[TF_Loop] = (TF__Height[TF_Loop] - 20.00)
              • Special Effect - Set Height of TF__Sfx[TF_Loop] to: TF__Height[TF_Loop]
            • Else - Actions
              • Set VariableSet TF__Duration[TF_Loop] = (TF__Duration[TF_Loop] - 0.02)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • TF__Duration[TF_Loop] Greater than or equal to 1.77
                • Then - Actions
                  • -------- HANDLE LANDING ANIMATION (FROM SKY) --------
                  • Special Effect - Create a special effect at TF__Start_Point[TF_Loop] using Abilities\Spells\Orc\WarStomp\WarStompCaster.mdl
                  • Special Effect - Destroy (Last created special effect)
                  • Set VariableSet TF__Angle[TF_Loop] = 0.00
                • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • TF__Duration[TF_Loop] Greater than 0.00
                • Then - Actions
                  • -------- HANDLE PITCH (TIPPING OVER ANIMATION) --------
                  • Set VariableSet TF__Duration[TF_Loop] = (TF__Duration[TF_Loop] - 0.02)
                  • Set VariableSet TF__Angle[TF_Loop] = (TF__Angle[TF_Loop] + 2.00)
                  • Special Effect - Set Pitch of TF__Sfx[TF_Loop] to: (Radians(TF__Angle[TF_Loop]))
                • Else - Actions
                  • -------- END --------
                  • -------- --------
                  • -------- Deal damage: --------
                  • Unit Group - Pick every unit in (Units within 256.00 of TF__End_Point[TF_Loop].) and do (Actions)
                    • Loop - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ((Picked unit) belongs to an enemy of (Owner of TF__Caster[TF_Loop]).) Equal to True
                        • Then - Actions
                          • Unit - Cause TF__Caster[TF_Loop] to damage (Picked unit), dealing TF__Damage[TF_Loop] damage of attack type Spells and damage type Normal
                        • Else - Actions
                  • -------- --------
                  • -------- Handle art: --------
                  • Special Effect - Create a special effect at TF__End_Point[TF_Loop] using Objects\Spawnmodels\Other\NeutralBuildingExplosion\NeutralBuildingExplosion.mdl
                  • Special Effect - Destroy (Last created special effect)
                  • Special Effect - Set Height of TF__Sfx[TF_Loop] to: 5000.00
                  • Special Effect - Set Pitch of TF__Sfx[TF_Loop] to: 0.00
                  • Special Effect - Destroy TF__Sfx[TF_Loop]
                  • -------- --------
                  • -------- Dynamic indexing stuff: --------
                  • Set VariableSet TF__Start_Point[0] = TF__Start_Point[TF_Loop]
                  • Set VariableSet TF__End_Point[0] = TF__End_Point[TF_Loop]
                  • -------- --------
                  • Set VariableSet TF__Caster[TF_Loop] = TF__Caster[TF_Index]
                  • Set VariableSet TF__Start_Point[TF_Loop] = TF__Start_Point[TF_Index]
                  • Set VariableSet TF__End_Point[TF_Loop] = TF__End_Point[TF_Index]
                  • Set VariableSet TF__Angle[TF_Loop] = TF__Angle[TF_Index]
                  • Set VariableSet TF__Damage[TF_Loop] = TF__Damage[TF_Index]
                  • Set VariableSet TF__Duration[TF_Loop] = TF__Duration[TF_Index]
                  • Set VariableSet TF__Height[TF_Loop] = TF__Height[TF_Index]
                  • Set VariableSet TF__Sfx[TF_Loop] = TF__Sfx[TF_Index]
                  • -------- --------
                  • Custom script: call RemoveLocation( udg_TF__Start_Point[0] )
                  • Custom script: call RemoveLocation( udg_TF__End_Point[0] )
                  • -------- --------
                  • Set VariableSet TF_Loop = (TF_Loop - 1)
                  • Set VariableSet TF_Index = (TF_Index - 1)
                  • -------- --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • TF_Index Equal to 0
                    • Then - Actions
                      • Countdown Timer - Pause TF_Timer
                    • Else - Actions
The Yaw is set using the Angle between the start point (where the tower spawns) and the end point (where you cast the spell). This makes the Special Effect face the target point. The angle needs to be converted from degrees to radians since yaw/pitch/roll use radians.

The Pitch handles the tipping over effect. I start it at 0 and increase it at a constant rate over time. A positive number here makes it tip towards the direction it's facing (it's yaw). If it increases too much it'll freak out and get all distorted. Again, convert to radians.

Roll is unnecessary.
 

Attachments

  • Tower Fall 1.w3m
    22.8 KB · Views: 3
Last edited:
Here's an example I threw together, by no means perfect but I think I got the math correct.
  • Tower Fall Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Tower Fall
    • Actions
      • Set VariableSet TF_Index = (TF_Index + 1)
      • Set VariableSet TF__Caster[TF_Index] = (Triggering unit)
      • -------- --------
      • -------- Define height, damage, and duration (this is not perfect - will need to adjust Loop trigger if you tweak timings): --------
      • Set VariableSet TF__Damage[TF_Index] = (200.00 x (Real((Level of (Ability being cast) for TF__Caster[TF_Index]))))
      • Set VariableSet TF__Duration[TF_Index] = 1.80
      • Set VariableSet TF__Height[TF_Index] = 2000.00
      • -------- --------
      • Set VariableSet TF_Caster_Point = (Position of TF__Caster[TF_Index])
      • Set VariableSet TF__End_Point[TF_Index] = (Target point of ability being cast)
      • -------- --------
      • Set VariableSet TF_Angle_Temp[0] = (Angle from TF_Caster_Point to TF__End_Point[TF_Index])
      • Set VariableSet TF_Angle_Temp[1] = (TF_Angle_Temp[0] - 30.00)
      • -------- --------
      • Set VariableSet TF__Start_Point[TF_Index] = (TF__End_Point[TF_Index] offset by -200.00 towards TF_Angle_Temp[1] degrees.)
      • -------- --------
      • Set VariableSet TF__Angle[TF_Index] = (Angle from TF__Start_Point[TF_Index] to TF__End_Point[TF_Index])
      • -------- --------
      • Special Effect - Create a special effect at TF__Start_Point[TF_Index] using buildings\human\HumanTower\HumanTower
      • Set VariableSet TF__Sfx[TF_Index] = (Last created special effect)
      • -------- --------
      • -------- These animations make the Scout Tower appear as a standard Guard Tower: --------
      • Special Effect - For Special Effect: TF__Sfx[TF_Index], Add Sub-Animation: First
      • Special Effect - Play Special Effect: TF__Sfx[TF_Index], Animation: Stand
      • Special Effect - Set Color of TF__Sfx[TF_Index] to color of Neutral Passive
      • -------- --------
      • Special Effect - Set Height of TF__Sfx[TF_Index] to: TF__Height[TF_Index]
      • Special Effect - Set Yaw of TF__Sfx[TF_Index] to: (Radians(TF__Angle[TF_Index]))
      • -------- --------
      • Custom script: call RemoveLocation( udg_TF_Caster_Point )
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • TF_Index Equal to 1
        • Then - Actions
          • Countdown Timer - Start TF_Timer as a Repeating timer that will expire in 0.02 seconds
        • Else - Actions
  • Tower Fall Loop
    • Events
      • Time - TF_Timer expires
    • Conditions
    • Actions
      • For each (Integer TF_Loop) from 1 to TF_Index, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • TF__Height[TF_Loop] Greater than 0.01
            • Then - Actions
              • -------- HANDLE HEIGHT (FALLING FROM SKY) --------
              • Set VariableSet TF__Height[TF_Loop] = (TF__Height[TF_Loop] - 20.00)
              • Special Effect - Set Height of TF__Sfx[TF_Loop] to: TF__Height[TF_Loop]
            • Else - Actions
              • Set VariableSet TF__Duration[TF_Loop] = (TF__Duration[TF_Loop] - 0.02)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • TF__Duration[TF_Loop] Greater than or equal to 1.77
                • Then - Actions
                  • -------- HANDLE LANDING ANIMATION (FROM SKY) --------
                  • Special Effect - Create a special effect at TF__Start_Point[TF_Loop] using Abilities\Spells\Orc\WarStomp\WarStompCaster.mdl
                  • Special Effect - Destroy (Last created special effect)
                  • Set VariableSet TF__Angle[TF_Loop] = 0.00
                • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • TF__Duration[TF_Loop] Greater than 0.00
                • Then - Actions
                  • -------- HANDLE PITCH (TIPPING OVER ANIMATION) --------
                  • Set VariableSet TF__Duration[TF_Loop] = (TF__Duration[TF_Loop] - 0.02)
                  • Set VariableSet TF__Angle[TF_Loop] = (TF__Angle[TF_Loop] + 2.00)
                  • Special Effect - Set Pitch of TF__Sfx[TF_Loop] to: (Radians(TF__Angle[TF_Loop]))
                • Else - Actions
                  • -------- END --------
                  • -------- --------
                  • -------- Deal damage: --------
                  • Unit Group - Pick every unit in (Units within 256.00 of TF__End_Point[TF_Loop].) and do (Actions)
                    • Loop - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ((Picked unit) belongs to an enemy of (Owner of TF__Caster[TF_Loop]).) Equal to True
                        • Then - Actions
                          • Unit - Cause TF__Caster[TF_Loop] to damage (Picked unit), dealing TF__Damage[TF_Loop] damage of attack type Spells and damage type Normal
                        • Else - Actions
                  • -------- --------
                  • -------- Handle art: --------
                  • Special Effect - Create a special effect at TF__End_Point[TF_Loop] using Objects\Spawnmodels\Other\NeutralBuildingExplosion\NeutralBuildingExplosion.mdl
                  • Special Effect - Destroy (Last created special effect)
                  • Special Effect - Set Height of TF__Sfx[TF_Loop] to: 5000.00
                  • Special Effect - Set Pitch of TF__Sfx[TF_Loop] to: 0.00
                  • Special Effect - Destroy TF__Sfx[TF_Loop]
                  • -------- --------
                  • -------- Dynamic indexing stuff: --------
                  • Set VariableSet TF__Start_Point[0] = TF__Start_Point[TF_Loop]
                  • Set VariableSet TF__End_Point[0] = TF__End_Point[TF_Loop]
                  • -------- --------
                  • Set VariableSet TF__Caster[TF_Loop] = TF__Caster[TF_Index]
                  • Set VariableSet TF__Start_Point[TF_Loop] = TF__Start_Point[TF_Index]
                  • Set VariableSet TF__End_Point[TF_Loop] = TF__End_Point[TF_Index]
                  • Set VariableSet TF__Angle[TF_Loop] = TF__Angle[TF_Index]
                  • Set VariableSet TF__Damage[TF_Loop] = TF__Damage[TF_Index]
                  • Set VariableSet TF__Duration[TF_Loop] = TF__Duration[TF_Index]
                  • Set VariableSet TF__Height[TF_Loop] = TF__Height[TF_Index]
                  • Set VariableSet TF__Sfx[TF_Loop] = TF__Sfx[TF_Index]
                  • -------- --------
                  • Custom script: call RemoveLocation( udg_TF__Start_Point[0] )
                  • Custom script: call RemoveLocation( udg_TF__End_Point[0] )
                  • -------- --------
                  • Set VariableSet TF_Loop = (TF_Loop - 1)
                  • Set VariableSet TF_Index = (TF_Index - 1)
                  • -------- --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • TF_Index Equal to 0
                    • Then - Actions
                      • Countdown Timer - Pause TF_Timer
                    • Else - Actions
The Yaw is set using the Angle between the start point (where the tower spawns) and the end point (where you cast the spell). This makes the Special Effect face the target point. The angle needs to be converted from degrees to radians since yaw/pitch/roll use radians.

The Pitch handles the tipping over effect. I start it at 0 and increase it at a constant rate over time. A positive number here makes it tip towards the direction it's facing (it's yaw). If it increases too much it'll freak out and get all distorted. Again, convert to radians.

Roll is unnecessary.

This fits perfectly with my needs! I changed the 30 degree to 90 degree to make it more align with the way I imagine it. Anyway, I am planning to re-create this in 1.31 for better accessibility and I recall two of the three axes are switched. Which ones are those?
 
Top