• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[vJASS] Projectile System with gravity and friction

Status
Not open for further replies.
Level 21
Joined
Mar 27, 2012
Messages
3,232
So far I've created pretty much everything I need for the system to work.
Now I'm working on the API, to make it easier to actually use it.
That's where I've come across a problem.
I don't know how to derive horisontal and vertical speed when I have source location, target location, projectile speed.
JASS:
globals
    //Constants
    real ConstantGravity = 1
    real ConstantFriction = 1
    real ConstantFrictionFactor = 0.95
    real LoopPeriod = 0.03
    
    /*
        ANYTHING below this point is not meant to be customized/changed
    */
    
    //Derivatives
    real PeriodFriction = ConstantFriction * LoopPeriod
    real PeriodFrictionFactor = ConstantFrictionFactor * LoopPeriod
    real PeriodGravity = ConstantGravity * LoopPeriod
    
    //Unit Data
    real array HorisontalAngle
    real array HorisontalVelocity
    real array VerticalVelocity
    
    //System Data
    integer UnitsLooped
    group HorisontalVelocityGroup = CreateGroup()
    group VerticalVelocityGroup = CreateGroup()
    trigger GravityLoopTrig
endglobals

library GravityProjectile //requires optional ExtraFunctions
        //Loop functions
        function LoopVertical takes nothing returns nothing
            local unit u = GetEnumUnit()
            local integer Data = GetUnitUserData(u) //Get the data of the unit or we won't know anything
            local real VerticalSpeed = VerticalVelocity[Data] //Clearly based on unit data
            call SetUnitFlyHeight(u,GetUnitFlyHeight(u)-VerticalSpeed,LoopPeriod)
            set VerticalSpeed = VerticalSpeed + PeriodGravity //Gravity
            if GetUnitFlyHeight(u) <= 0 then //To not fall through the ground
                set VerticalVelocity[Data] = 0
                call GroupRemoveUnit(VerticalVelocityGroup,u)
                call SetUnitFlyHeight(u,0,LoopPeriod)
            endif
            set UnitsLooped = UnitsLooped + 1
        endfunction

        function LoopHorisontal takes nothing returns nothing
            local unit u = GetEnumUnit()
            local integer Data = GetUnitUserData(u)
            local real HorisontalSpeed = HorisontalVelocity[Data]
            local real Angle = HorisontalAngle[Data]//Horisontal, as seen
            local real x = GetUnitX(u)
            local real y = GetUnitY(u)
            set x = x + HorisontalSpeed * Cos(Angle * bj_DEGTORAD)
            set y = y + HorisontalSpeed * Cos(Angle * bj_DEGTORAD)
            call SetUnitX(u,x)
            call SetUnitY(u,y)
            if GetUnitFlyHeight(u) <= 0 then //If the unit is on ground, then it is affected by friction
                set HorisontalVelocity[Data] = HorisontalVelocity[Data] * ConstantFrictionFactor - ConstantFriction
            endif
            if HorisontalVelocity[Data] <= 0 then //Without this units will start moving back after stopping
                call GroupRemoveUnit(HorisontalVelocityGroup,u)
            endif
            set UnitsLooped = UnitsLooped + 1
        endfunction

        //Loops
        function GravityLoop takes nothing returns boolean
            call ForGroup(VerticalVelocityGroup,function LoopVertical)
            call ForGroup(HorisontalVelocityGroup,function LoopHorisontal)
            if UnitsLooped == 0 then
                call DisableTrigger(GravityLoopTrig)
            endif
            return false
        endfunction

        //API functions
        function ProjectileLaunch takes unit u,real Direction,real HorisontalSpeed,real VerticalSpeed returns nothing
            local integer Data = GetUnitUserData(u)
            if HorisontalSpeed > 0 then
                set HorisontalAngle[Data] = Direction
                set HorisontalVelocity[Data] = HorisontalSpeed
                call GroupAddUnit(HorisontalVelocityGroup,u)
            endif
            if VerticalSpeed > 0 then
                set VerticalVelocity[Data] = VerticalSpeed
            endif
        endfunction
        
        function ProjectileLaunchToAngle takes unit u,real Direction,real Angle,real Speed returns nothing
        endfunction
        
        function ProjectileLaunchToPoint takes unit u, real x2, real y2, real Speed,boolean High returns nothing
            local real x1 = GetUnitX(u)
            local real y1 = GetUnitY(u)
            local real Direction = bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
            if High then //Whether to use the higher or lower angle(since all targets can be reached with both in the same time)
            else
            endif
            //bj_RADTODEG * Atan2(GetLocationY(locB) - GetLocationY(locA), GetLocationX(locB) - GetLocationX(locA))
            //call ProjectileLaunch(u,Direction,HorisontalSpeed,VerticalSpeed)
        endfunction

    //++Setting up the system(name unchanged so I won't have to call it myself)
    function InitTrig_GravityProjectile takes nothing returns nothing
        call TriggerAddCondition(GravityLoopTrig,function GravityLoop)
        call TriggerRegisterTimerEvent(GravityLoopTrig,LoopPeriod,true)
    endfunction
endlibrary
 
You can use Kinematic equations for that... normally, horizontal speed will be constant and vertical speed will be dependent on the height of the missile in relation to the starting height (since it's affected by gravitational acceleration)... Vertical speed of the initial velocity/speed can be obtained via Sine function of the angle at which a projectile is fired with respect to the horizontal axis. In warcraft terms, it will depend on the angular counterpart of the missile's arc... and the horizontal speed is obtained via Cosine of the same angle used to get the vertical speed.
 
y do u have all of this outside the library ?
JASS:
globals
    //Constants
    real ConstantGravity = 1
    real ConstantFriction = 1
    real ConstantFrictionFactor = 0.95
    real LoopPeriod = 0.03
    
    /*
        ANYTHING below this point is not meant to be customized/changed
    */
    
    //Derivatives
    real PeriodFriction = ConstantFriction * LoopPeriod
    real PeriodFrictionFactor = ConstantFrictionFactor * LoopPeriod
    real PeriodGravity = ConstantGravity * LoopPeriod
    
    //Unit Data
    real array HorisontalAngle
    real array HorisontalVelocity
    real array VerticalVelocity
    
    //System Data
    integer UnitsLooped
    group HorisontalVelocityGroup = CreateGroup()
    group VerticalVelocityGroup = CreateGroup()
    trigger GravityLoopTrig
endglobals
y not put it in the library and make everything private and make the constants actual constants ?
 
Level 21
Joined
Mar 27, 2012
Messages
3,232
y do u have all of this outside the library ?
JASS:
stuff
y not put it in the library and make everything private and make the constants actual constants ?

Why outside the library? Because I can. Globals blocks never get through to the actual code; afaik they're added into the variables list and the block itself deleted. So in this case I don't see any difference except semantics. So I just did it in the way that keeps things easier for myself to understand.

Afaik JASS doesn't have any actual constants, so vJASS can't make them into such either. In that sense I don't see a reason to use the keyword.

About privacy - Well, I could do that, but at this point it would only serve to make the system more confusing for myself(and variable names longer).

You can use Kinematic equations for that... normally, horizontal speed will be constant and vertical speed will be dependent on the height of the missile in relation to the starting height (since it's affected by gravitational acceleration)... Vertical speed of the initial velocity/speed can be obtained via Sine function of the angle at which a projectile is fired with respect to the horizontal axis. In warcraft terms, it will depend on the angular counterpart of the missile's arc... and the horizontal speed is obtained via Cosine of the same angle used to get the vertical speed.

Alright, I can make the constants into arrays instead(most of them). (Actually seems like a very good idea, since then I could make some time-related spells)

Anyways, I am not very strong in maths, so what is the exact formula for getting the velocities?
 
ik that jass doesnt have constants but ur using vJass lol. vJass does have constants as it doesnt compile code with constants that have set constant variable = value. so it wont allow someone to accidentally overwrite data.

also ur logic doesnt make sense since jass doesnt have libraries we shouldnt use libraries then according to ur logic.

also y do names need to get longer when u make variables private ?
unless u thought i meant make the functions private ?
i only make the functions private that i dont want anyone to touch the rest are just normal functions lol
 
Level 21
Joined
Mar 27, 2012
Messages
3,232
ik that jass doesnt have constants but ur using vJass lol. vJass does have constants as it doesnt compile code with constants that have set constant variable = value. so it wont allow someone to accidentally overwrite data.

also ur logic doesnt make sense since jass doesnt have libraries we shouldnt use libraries then according to ur logic.

also y do names need to get longer when u make variables private ?
unless u thought i meant make the functions private ?
i only make the functions private that i dont want anyone to touch the rest are just normal functions lol

What I mean is that if someone already has the power to overwrite something, then they probably will fuck something up anyway when trying to do so. Using a separate keyword to guarantee that they can't do that is just pointless imo.

I use things that have a point for me. I use libraries because then I can be sure that it works with any spells I create.

The names become longer because that's how private variables are handled in vJASS. It's not like they're truly private. They just get different names. (struct/libray name + underscore + variable name)

Making functions private can make sense though, in order to avoid conflicts with other systems. At the moment it's just extra text for me, as I have no such conflicts in any of my maps. Sure, if I'll make this system publicly available then I'll also do every thing possible to prevent people from doing dumb mistakes, but before that I don't need to. I just need the whole thing to work for my uses.

I bet I didn't teach you anything new about vJASS. Just explaining my reasoning.
 
Status
Not open for further replies.
Top