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

Facing angle with KB3D (More of a math question, really)

Level 4
Joined
Apr 3, 2012
Messages
31
So I'm using KB3D to create a projectile spell, largely based on some of the examples in the test map. However, it seems there's an issue in the code, where the facing angle is incorrectly calculated - as a result, the projectile dummy unit spawns facing the correct direction, but always faces towards 0 degrees after half a second or so while travelling. This isn't noticeable in the test map, because the spells all use effects like fireballs or boulders where the facing angle doesn't matter, but if you replace one of the dummy units with e.g. an arrow, you can clearly see the issue.

Here's the part of the code that I believe is relevant:

JASS:
//Calculate the Angle
    if ( Target == null ) then
        set Angle = LoadReal(udg_KB3D_HA, 5, Loop) + LoadReal(udg_KB3D_HA, 30, Loop)//if there is no unit target
    else
        set Angle = Atan2(GetUnitY(Target) - Y, GetUnitX(Target) - X)//if there is a unit target
    endif
    //
    if LoadBoolean(udg_KB3D_HA, 16, Loop) then
        set Angle = GetUnitFacing(U)*0.0174533
        if LoadBoolean(udg_KB3D_HA, 44, Loop) then
            if GetUnitCurrentOrder(U) != 851986 and GetUnitCurrentOrder(U) != 851971 then
                set b = false
            endif
        else
            set b = false
        endif
    endif
  
    //Make Unit Face Angle
    if LoadBoolean(udg_KB3D_HA, 31, Loop) then
        call SetUnitFacing(U, Angle * 3.141592)
    endif

Removing the last part (Make Unit Face Angle) makes the unit always face the angle that it spawned, which could work if you have a fast projectile with low range, as you wouldn't notice the angle change. It's not a "true fix" however.

With some rudimentary testing, I found that decreasing the SetUnitFacing (through division) does nothing, while increasing it (through multiplication) would cause the projectile to actually change facing angle while midair - just, you know, I'm not great at math, so I don't know what the correct formula is, to make the projectile face the right way, instead of spinning to wherever.

Any help would be appreciated. :)
 
Level 12
Joined
Jan 10, 2023
Messages
191
I wish I had an easy answer for you, but I'm still skimming the code. It might be helpful to share an example of your projectile.

I am wondering after skimming KB3D if you use this function:
JASS:
function KB3D_PointBounce takes real BAngle, real x, real y returns real
    local real BAngle1
    local real BAngle2
    local real q //quadrant
    set BAngle = BAngle*0.01745329251994329576923690768489 // <--- this is a conversion from degrees to radians.
    // BAngle is now radians if it was degrees.  Unfortunately, the remainder of this function operates in degrees as we can all see.
    // We know this is the conversion because "Pi / 180 = thatNumber"  If it was already radians, it is now garbage.
 
    if 0<BAngle and BAngle<90 then // <--- this is a check of BAngle in degrees, but BAngle is radians or is garbage.
        set q = 1 // <--- garbage number, based on garbage
    elseif 90<BAngle and BAngle<180 then // <--- this is a check of BAngle in degrees, but BAngle is radians or is garbage.
        set q = 2 // <--- garbage number, based on garbage
    elseif 180<BAngle and BAngle<270 then // <--- this is a check of BAngle in degrees, but BAngle is radians or is garbage.
        set q = 3 //<---  garbage number, based on garbage
    elseif 270<BAngle and BAngle<360 then // <--- this is a check of BAngle in degrees, but BAngle is radians or is garbage.
        set q = 4 // <--- garbage number, based on garbage
    else
        set q = BAngle/90 + 2 // <--- radians divided by 90 are going to be between 0.0222 and Zero.
    endif                              //         Adding 2 would then make it somewhere between 2.0222 and 2.
 
    set BAngle1 = q*90 - BAngle // <--- q*90 will become a number of degrees, but Bangle is in radians or trash and q is trash
    set BAngle2 = - q*90 + BAngle + 90 // <--- will become a number of degrees, but Bangle is in radians or trash and q is trash
 
// The rest would be fine if the above wasn't fubar

    if KB3D_isPossiblePathability(x, y, (BAngle - 2*BAngle2), 40) then
        set BAngle = BAngle - 2*BAngle2
    elseif KB3D_isPossiblePathability(x, y, (BAngle + 2*BAngle1), 40) then
        set BAngle = BAngle + 2*BAngle1
    endif
 
    return BAngle
endfunction

Most of my point is in the comments, but can someone else verify that function is screwed up by the angles? If so, it may be a similar mistake elsewhere in the code even if you don't use this function.
Blizzard was very thoughtful and decided that we should get/set unit angles in degrees, but we should do our trigonometry using radians, because that's going to help no one, introduce confusion, and lose accuracy whenever we convert between the two...

@Nikeyeia can you confirm whether or not you are using this function? if so, try just removing the fourth line
JASS:
set BAngle = BAngle*0.01745329251994329576923690768489
This would cause the number to remain in degrees, so it will function and if that doesn't work try doing that again, but instead try removing it from the fourth line and to the bottom, in the return like this:
JASS:
return BAngle*0.01745329251994329576923690768489 // but maybe remove like 500 decimals. or don't but this looks silly as hell.
The idea for putting it in the return is if it is expecting a return in radians, but the function clearly requires degrees.



EDIT:
After looking into it some more, I can say that the above function would be run if you have you are using the BounceOnUnit function, and that function runs under a few conditions so it could be a likely suspect.

There's also this, from everything I've seen other than the radians-degrees conversion error in the comment above, at all point when the angle is applied to a unit, the conversion is done properly, except where I pointed it out and once in the segment you shared:
JASS:
//Calculate the Angle
    if ( Target == null ) then
        // When Angle is set here, the real stored in udg_KB3D_HA, 5 was stored in radian units, so Angle is in radians.
        // udg_KB3D_HA, 30 is the arc, it would appear that this arc is to be input in degrees, but the system converts it properly to radians
        // I don't see much in the script as far as where to set the arc, only that it doesn't work with homing, and still I don't see it
        // ever being manipulated by any other function, but I may have just missed it... but then again I did use CTRL+F...
        set Angle = LoadReal(udg_KB3D_HA, 5, Loop) + LoadReal(udg_KB3D_HA, 30, Loop)//if there is no unit target
    else
        // This sets Angle to an angle in radians because Atan2 works that way
        set Angle = Atan2(GetUnitY(Target) - Y, GetUnitX(Target) - X)//if there is a unit target
    endif
    //
    if LoadBoolean(udg_KB3D_HA, 16, Loop) then
        // This sets Angle to an angle in radians because GetUnitFacing() returns an angle in degrees
        // and 0.0174533 converts that angle from degrees to radians.
        // 0.01745329251994329576923690768489 would have been more accurate :P
        // I would recommend leaving the operation as 3.14159/180.0 and 180.0/3.14159
        // If you are going back and forth between two units and they cannot rationalize with one another
        // as in if one is PI and the other is rational, then you should either fix a rational value for PI
        // such as 3.14159 and don't use its inverse, you will lose accuracy, but invert the ratio
        // (do 180.0/PI to get RADTODEG, and PI/180.0 for DEGTORAD)
        set Angle = GetUnitFacing(U)*0.0174533
        if LoadBoolean(udg_KB3D_HA, 44, Loop) then
            if GetUnitCurrentOrder(U) != 851986 and GetUnitCurrentOrder(U) != 851971 then
                set b = false
            endif
        else
            set b = false
        endif
    endif

// The error now is when the unit's angle is set, described in the comment below.
 
    //Make Unit Face Angle
    if LoadBoolean(udg_KB3D_HA, 31, Loop) then
        // Angle is in radians, meaning if it was facing 180 degrees, we are now calling that ~3.14159 (PI) radians
        // If that unit is supposed to be set to face 180 degrees, now that's 180 * PI degrees, or PI * PI radians
        // So if the unit should face 180 degrees, it instead faces ~565.48668 degrees, or ~205.48668 after we take out the extra spins.
        // We don't need or want to multiply by PI here.  just call SetUnitFacing( U, Angle ).
        call SetUnitFacing(U, Angle * 3.141592)
    endif
I'm guessing that decreasing it causes nothing because the value is being destroyed elsewhere and increasing it causes a spin because it is being continually miss-converted at times resulting in an eventual convergence to zero, when you increase this value, it no longer converges to zero and being to converge to some other value, maybe infinity or some high number resulting in a spin as that number does laps over 2PI / 360 degree increments.
 
Last edited:
Level 4
Joined
Apr 3, 2012
Messages
31
Heya, thanks for responding.
(Prefacing by reminding that I'm not great at math nor JASS)

I'm pretty sure I don't use the first function; as I don't make use of bouncing in general. I did try both the suggestions you wrote, and neither fixed the issue. Here's the projectile spell I'm trying to make work:

  • Events
    • Unit - A unit Starts the effect of an ability
  • Conditions
    • (Ability being cast) Equal to Powershot
  • Actions
    • Set VariableSet TempUnit = (Casting unit)
    • Set VariableSet TempUnit2 = (Target unit of ability being cast)
    • Set VariableSet Loc = (Position of TempUnit)
    • Set VariableSet Loc2 = (Position of TempUnit2)
    • Unit - Create 1 Dummy (Powershot) for (Owner of TempUnit) at (Loc offset by 50.00 towards (Angle from Loc to Loc2) degrees.) facing (Angle from Loc to Loc2) degrees
    • Set VariableSet KB3D_Unit = (Last created unit)
    • Set VariableSet KB3D_Speed = 500.00
    • Set VariableSet KB3D_EndFx = Abilities\Spells\Human\Thunderclap\ThunderClapCaster.mdl
    • Set VariableSet KB3D_AoEEndDamage = 100.00
    • Set VariableSet KB3D_AoE = 250.00
    • Set VariableSet KB3D_AllowOutSiding = True
    • Set VariableSet KB3D_DisableUnit = True
    • Set VariableSet KB3D_AttackType = Spells
    • Set VariableSet KB3D_DamageType = Magic
    • Set VariableSet KB3D_TrailFx = Abilities\Weapons\Arrow\ArrowMissile.mdl
    • Set VariableSet KB3D_iKB = False
    • Set VariableSet KB3D_Damager = TempUnit
    • Set VariableSet KB3D_Targeted_Unit = TempUnit2
    • Set VariableSet KB3D_HomingMissile = True
    • Set VariableSet KB3D_LineDamage = 50
    • Set VariableSet KB3D_Zoffset = (Current flying height of TempUnit2)
    • Custom script: call ExecuteFunc( "KB3D_Registration" )
As for your edit, your comments make sense to me. That said, as far as I can gather, your suggestions for what might fix the issue is to change "0.0174533" to "3.14159/180.0", and change "call SetUnitFacing(U, Angle * 3.141592)" to "call SetUnitFacing(U, Angle)". This doesn't seem to fix the issue however; so please let me know if something went over my head, or if you have other suggestions as to what could cause the problem.
 
Level 12
Joined
Jan 10, 2023
Messages
191
The idea behind changing 0.0174533 to 3.14159/180.0 is to use the true ratio, not a decimal, in other words:
(3.14159/180.0)(180.0/3.14159) = 1 but 0.0174533(180.0/3.14159) = ~1

You could just the same use radians/0.0174533=degrees and
degrees*0.0174533=radians
The point is just that the conversion factor is exact.

Honestly it's not a major thing and probably won't amount to anything at all, especially if there is little bouncing/change in angle over the course of the motion.
I just had trouble finding issues other than nit-picky math ones and the big one about using radians in degree-seeking functions that turned out not to be relevant to this problem.

I'll take a look at your trigger in comparison to the example trigger soon, might be a few days, memorial day/ work = no WE :/
 
Level 4
Joined
Apr 3, 2012
Messages
31
Thanks, I appreciate it :)

I figured the degrees/radians conversion was mostly nitpicking yeah, but I suppose it's a good habit to do conversion correctly.

Also, don't feel rushed; I'm not necessarily in a hurry to get this particular spell to work - technically, I could just get rid of the angle update altogether, as the missile spell is a lot faster (500 speed is for testing purposes), and it's almost unnoticeable on fast projectiles with low range. I would like to use the system further down the line as well though, and it would be nice to have the flexibility of using angled projectiles.

Alternatively, if there is a similar system which is as simple to use for projectile spells that doesn't have this problem, I suppose I could switch to that, though I haven't found one that is quite as flexible myself.
 
Level 4
Joined
Apr 3, 2012
Messages
31
It's a long shot, but figured I'd try bumping this thread up, in a final attempt to see if anyone has a solution.

Alternatively, if someone can point me to a different projectile system, which can be used for mostly simple spells, LMK.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,509
This "face immediately" function exists now, which didn't exist at the time of KB3D's creation:
  • Unit - Make (Triggering unit) face 0.00
vJASS:
call BlzSetUnitFacingEx( GetTriggerUnit(), 0.00 )
Maybe that will help?

For Missile systems, this does everything and is very easy to use:
 
Level 4
Joined
Apr 3, 2012
Messages
31
Heya, thanks for responding.

After checking the system you linked, I think I'll take a shot at using that instead. My needs are not large so it feels a bit overkill, but I might find other uses for it down the line.

The reason I've never seen it is because it doesn't show up in the spell resource page when searching for "missile" or "projectile". "missiles" does it though. Thanks for pointing me to it.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,509
I rely on google for most if not all of my Hive searches (sorry Hive), it seems to work a lot better. Search "Hiveworkshop Uncle + Topic" and you'll probably find some good/recent info since I've been pretty active these last 3 years.

This thread contains a demo map (Battleship Missile System 1) I made which showcases using the missile system in GUI:

I believe I removed most if not all of the optional stuff that came with the missile system. You may want to copy the system from my map if you're like me and don't want too much bloat (those are good systems though, if you plan on using them).
 
Last edited:
Top