• 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.
  • Create a faction for Warcraft 3 and enter Hive's 19th Techtree Contest: Co-Op Commanders! Click here to enter!
  • Create a void inspired texture for Warcraft 3 and enter Hive's 34th Texturing Contest: Void! Click here to enter!
  • The Hive's 21st Texturing Contest: Upgrade is now concluded, time to vote for your favourite set of icons! Click here to vote!

Unit acceleration in warcraft?

Status
Not open for further replies.
I'm trying to make a system to have units accelerate towards their maximum speed once they have been ordered to move. The max acceleration and acceleration rate will be stored in a struct variable.

My problem is that i'm having a hard time figuring out how to integrate it with an existing system already in the map, the Unit Acceleration System by Diehard@Azeroth:

JASS:
library Acceleration initializer Init
    
    globals
        private timer t = CreateTimer()
        private group accelUnits = CreateGroup()
        private location Zloc = Location(0.,0.)
        private integer maxAccel = 0
        private constant real checkDist = 10. 
        private timer d = CreateTimer()
        private constant group dragGroup = CreateGroup()
        private integer maxDrag = 0
        private hashtable ht = InitHashtable()
        private boolexpr kbBoolexpr
        private unit draggedUnit = null
        private unit tempFilter = null
        private boolexpr True
        private rect r = null
        private constant real DEGTORAD = 3.14159/180
        
        // CONFIGURABLES
        
        private constant real NoDrag = 5. //maximum difference in Z that cannot cause any drag, basically, the higher this value is, the lower
        // a terrain infront of the unit will be needed to drag the unit down, and vice versa. Values less than 0 wont work.
        
        private constant real dragIteration = 0.03 // drag timer periodic iteration
        private constant real tIteration = 0.45 // timer periodic iteration
        
        private constant real gravity = -12.21 // gravity's real value, make it lower to lower the acceleration/deacceleration change
        // END CONFIGURABLES
        
        private constant real dragGravity = gravity*dragIteration*-1
        private DN dat
    endglobals
    
    
    private function GetLocZ takes real x, real y returns real
        call MoveLocation(Zloc, x, y)
        return GetLocationZ(Zloc)
    endfunction
    
    private function returnTrue takes nothing returns boolean
        return true
    endfunction
    
    private function returnBoolean takes nothing returns boolean
        set tempFilter = GetFilterUnit()
        return GetUnitFlyHeight(tempFilter) <= 25 and IsUnit(tempFilter, draggedUnit) == false
    endfunction
    
    struct DN // Destructable detection
    integer dN = 0

        private static method returnValue takes nothing returns nothing
            set dat.dN = dat.dN + 1
        endmethod
    
        static method DestructablesNearby takes real x, real y returns boolean
            set dat = DN.allocate()
            set r = Rect(x-100, y-100, x+100, y+100)
            call EnumDestructablesInRect(r, True, function DN.returnValue)
            call RemoveRect(r)
            if dat.dN > 0 then
                return true
            else
                return false
            endif
        endmethod
    
    endstruct
    
    private function UnitsNearby takes real x, real y, unit dragged returns boolean
        local group nGroup = CreateGroup()
        local unit n
        set draggedUnit = dragged
        call GroupEnumUnitsInRange(nGroup, x, y, 60, kbBoolexpr)
        set n = FirstOfGroup(nGroup)
        call DestroyGroup(nGroup)
        set nGroup = null
        set draggedUnit = null
        if n == null then
            return false
        else
            set n = null
            return true
        endif
    endfunction
    
    private function coreDrag takes nothing returns nothing
        local unit e = GetEnumUnit()
        local integer i = GetHandleId(e)
        local real a = LoadReal(ht, i, 2)
        local real x = GetUnitX(e)
        local real y = GetUnitY(e)
        local real x2 = x+checkDist*Cos(a)
        local real y2 = y+checkDist*Sin(a)
        local real diffZ = GetLocZ(x2,y2)-GetLocZ(x,y)
        local real drag = LoadReal(ht, i, 1)
        local real x3 = x+drag*Cos(a)
        local real y3 = y+drag*Sin(a)
        if diffZ < -NoDrag and UnitsNearby(x2, y2, e) == false and DN.DestructablesNearby(x2, y2) == false and IsTerrainPathable(x3,y3, PATHING_TYPE_WALKABILITY) == false then
            set drag = drag + dragGravity
            call SaveReal(ht, i, 1, drag)
            call SetUnitX(e, x3)
            call SetUnitY(e, y3)
        else
            call GroupRemoveUnit(dragGroup, e)
            call SaveBoolean(ht, i, 0, false)
            set maxDrag = maxDrag - 1
            if maxDrag == 0 then
                call PauseTimer(d)
            endif
        endif
        set e = null
    endfunction
    
    private function DragUnits takes nothing returns nothing
        call ForGroup(dragGroup, function coreDrag)
    endfunction
    
    private function coreAccel takes nothing returns nothing
        local unit e = GetEnumUnit()
        local integer i = GetHandleId(e)
        local real f = GetUnitFacing(e)*DEGTORAD
        local real x = GetUnitX(e)
        local real y = GetUnitY(e)
        local real x2 = x+checkDist*Cos(f)
        local real y2 = y+checkDist*Sin(f)
        local real defaultSpeed = GetUnitDefaultMoveSpeed(e)
        local real diffZ = GetLocZ(x2,y2)-GetLocZ(x,y)
        local real newSpeed = defaultSpeed+(gravity*diffZ)
        if diffZ < -NoDrag and IsTerrainPathable(x2,y2, PATHING_TYPE_WALKABILITY) == false then
            if LoadBoolean(ht, i, 0) == false then
                call SaveBoolean( ht, i, 0, true )
                call SaveReal( ht, i, 1, dragGravity )
                call SaveReal( ht, i, 2, f )
                set maxDrag = maxDrag + 1
                call GroupAddUnit(dragGroup, e)
                call TimerStart(d, dragIteration, true, function DragUnits)
            endif
        else
            if LoadBoolean( ht, i, 0 ) == false then
                call SetUnitMoveSpeed(e, newSpeed)
            else
                call SetUnitMoveSpeed(e, defaultSpeed)
            endif
        endif
        set e = null
    endfunction
    
    private function AccelerateUnits takes nothing returns nothing
        call ForGroup(accelUnits, function coreAccel)
    endfunction
    
    function AddUnitAcceleration takes unit u returns nothing
        if u == null then
            return
        endif
        call GroupAddUnit(accelUnits, u)
        set maxAccel = maxAccel + 1
        call TimerStart(t, tIteration, true, function AccelerateUnits)
    endfunction

    function RemoveUnitAcceleration takes unit u returns nothing
        if u == null then
            return
        endif
        call GroupRemoveUnit(accelUnits, u)
        call SetUnitMoveSpeed( u, GetUnitDefaultMoveSpeed(u) )
        set maxAccel = maxAccel - 1
        if maxAccel == 0 then
            call PauseTimer(t)
        endif
    endfunction
    
    //-----------------------------------------------------------------
    private function Init takes nothing returns nothing
        set kbBoolexpr = Condition(function returnBoolean)
        set True = Condition(function returnTrue)
    endfunction
    
endlibrary

This system already uses a periodic timer like the one i need, and it also modifies the units speed based on the height difference of the terrain infront of it. I'd like this to include increasing/resetting a units acceleration.

To detect when a unit has stopped, i'm using the ability "carrion swarm" which is automatically casted to the target order point when a unit is ordered to move.

To me this sounds pretty simple, but everyone i talk to about it claims that it is very complicated and that there are many things that could go wrong.
Could anyone explain to me what it is that i have to do, and what i should do to make it efficient?

Thanks.
 
Well, i understand how his system works and where i should implement things, but i want to know the basics on how to create a system for acceleration.

My idea on it is to simply have one constant for acceleration rate, a counter for each time the timer loops, and a variable for deafult speed +max speed (by own means of propelling). I would then take deafult speed + acceleration speed*counter (if acceleration speed*counter < MaxSpeed) and use that instead of deafult speed in the elevation based acceleration system (the one i posted). I just get that feeling of "is it really just that simple?" though, and want to ask on what i need to make a system like this, and maybe an example on how it is done in other games.
 
Level 11
Joined
May 31, 2008
Messages
698
just use v = v0 + a*t
v = velocity
v0 = initial velocity (which would probably just be zero for this)
a = acceleration
t = time
every time the loop runs, set t = t + whatever the time interval is on the loop
Just be sure to set t = 0 whenever the unit comes to a stop.
 
Status
Not open for further replies.
Top