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!
This system accelerates units based on terrain height, and drags units down if they are going down terrain such as a mountain (in the map), basically any higher terrain that has a relatively fair amount of difference in Z which makes the unit become dragged by gravity.
I used to increase or decrease acceleration, but it seems there was a bug in that because when a unit accelerates down a mountain, it will be able to pass over a part of the mountain that it shouldnt be able to pass because of how steep the location is; which the unit would have not been able to pass before deaccelerating down the mountain. Of course this bug happens only if you move down a mountain and then up the mountain really fast.
Anyways, thats why i included the drag aspect of the acceleration, and the higher the movespeed is, the faster the drag will be, cus im basing the acceleration on the same concept of V = Vo + at.
Hope you enjoy the system, its MUI, Lagless and is GUI-Friendly. made many directions, most for GUI users since the system is vJASS.
please give credits if you use it in your map
also guys, you may need to remove acceleration at times like for example, a unit jumps, and when he finishes jumping, add his acceleration back again; instructions are in the trigger section in the map.
BTW ANY OF U GUYS CAN EDIT THIS SYSTEM AS LONG AS YOU GIVE CREDITS TO ME AS THE ORIGINAL CREATOR, il fix any bugs and add extra functions if wanted, but probably not adding much extra features; unless if there is a special request to do so.
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 = 10. //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.30 // timer periodic iteration
private constant real gravity = -9.81 // 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
------------------------------------------------
- may add a function to access drag acceleration
ChangeLog:
Version 1
EDIT: Remembered to flush the child hashtable of dragged units.
EDIT2: Mesed up in a JASS line for adding acceleration to all units in map
EDIT3: Made units being dragged get stopped by units in their way, and be able to continue their drag only after their path is safe. Only problem here is that warcraft uses 2d distance for unit collision, so it may look wierd in REALLY RARE situations.
EDIT4 (IMPORTANT): Added destructable collision while on drag.
EDIT5: made coding slightly more efficient by using a hardcoded radius for finding nearby units and destructables.
EDIT6: made it so ranged units can stil attack while being dragged down.
EDIT7: Fixed Boolexpr Leak since i used null in destructable check
Version 0.12
EDIT8: added an initial velocity for drag as it should be done
Version 0.13
timer iteration changed to 0.30 from 0.15
Version 0.14
Slightly improved coding efficiency.
Version 0.15
private group dragGroup is now constant
Version 0.16
the rect r is now a global variable
made a constant DEGTORAD variable instead of the bj_DEGTORAD
17:37, 28th Oct 2009
The_Reborn_Devil:
Seems like a quite simple yet useful system. The coding looks good although for better efficiency please inline some of the functions.
I couldn't find any leaks or bugs, but it would be better if you added...
Make another trigger for the Unit Enters Playable Map Area and then copy paste this
JASS:
call AddUnitAcceleration(GetTriggerUnit())
As for the on init trigger just create a unit group variable which has all the units the playable map area and then pick every unit in the group, then paste this
JASS:
call AddUnitAcceleration(GetEnumUnit())
Make a trigger for a unit that leaves playable map area and paste this
JASS:
call RemoveUnitAcceleration(GetTriggerUnit())
Now make a trigger in which if a unit dies, you will remove its corpse after 2.5 (or any higher number, max would probably be 5) seconds (so they can play their death animation). Now create a new unit group variable and make sure all the heroes or even units that you want to still have acceleration after they die will be in that group (because maybe you want to revive the hero or do something wierd with the unit). Now just do the check if the dying unit is in that group or not, if not then proceed to removing the unit out of the game.
This part might seem confusing so here is the trigger:
Removing unit corpse
Events
Unit - A unit Dies
Conditions
((Triggering unit) is in UnitsWithAcceleration) Equal to False
Actions
Wait 2.50 seconds
Unit - Remove (Triggering unit) from the game
*Copy paste the line codes in seperate custom script actions.
This is so cool, but this wont work for a herodefense map with a lot of units right? I need to add units already in the game and it will only work for that unit(?)
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.