/**
* Simple Angular Jump System - by Robbepop
*
* Uses the following libraries:
* - Unit Indexer : http://www.hiveworkshop.com/forums/jass-resources-412/system-unit-indexer-172090/
* - Timer Utils : http://www.wc3c.net/showthread.php?t=101322
*
* This system can be used to let units jump to a certain point with variable speed and a starting angle.
* The speed is adjusted to the wc3-Engine and so values of 1 to 2000 are normal.
* The system is similar to a throwing system so only angles within the bounds of [0, 90) are valid.
* You should use the API function "UnitJumpToPoint()" to use this system.
*
* Special thanks goes to peq who analysed the system and gave me tips on how to improve the parabel function.
*
* I hope I documented the system well enough to give a slight understanding of how it works
* it should be even usable by GUI users because it has got only one API function which should be okay.
*
* If there are any questions about it please leave me a comment in hiveworkshop.com, [email protected] or at goh-rpg.de.to.
* And please give me credits if you use this simple jump system in your map.
*
* API:
* function UnitJumpToPosition takes unit u, real a, real s, real x, real y returns nothing
* function UnitJumpToPositionLoc takes unit u, real a, real s, location l returns nothing
*
* Takes the unit 'u' to jump with a starting angle of 'a' and a speed of 's' to the coordinates of ('x'/'y').
* A possbile usage example would be the following:
* call UnitJumpToPoint(udg_myUnit, 45, 600, 0, 0)
* Which would make the unit udg_myUnit jump to point (0,0) with 600 speed at a starting angle of 45°.
*
* function IsUnitJumping takes unit u returns boolean
*
* Can determine if a unit is currently jumping.
* A possible usage example would be the following:
* if IsUnitJumping(udg_myUnit) then
* call DoNothing()
* endif
*
* The system does not check for pathability so you should do this by yourself if you need it in some cases!
*
* The functions AngleBetweenCoords and DistanceBetweenCoords are helper functions.
* You may use them in your map's header (or utils) file if you want to but note that you then have to remove them from this script.
*/
library SimpleAngularJump requires TimerUtils, UnitIndexer
private function AngleBetweenCoords takes real ax, real ay, real bx, real by returns real
return Atan2(by - ay, bx - ax)
endfunction
private function DistanceBetweenCoords takes real ax, real ay, real bx, real by returns real
local real dx = bx - ax
local real dy = by - ay
return SquareRoot(dx * dx + dy * dy)
endfunction
struct SimpleAngularJump extends array
// The interval of the periodic timer.
private static constant real INTERVAL = 0.03125
// Can be adjusted to set the global expansion of height.
private static constant real HEIGHT_EXPANSION = 90.
private unit jumper
private real startAngle
private real destAngle
private real speed
private real curDist
private real maxDist
private real moveX
private real moveY
private real endX
private real endY
private real oldFlyHeight
private boolean active
public method isJumping takes nothing returns boolean
return .active
endmethod
private method destroy takes nothing returns nothing
call SetUnitFlyHeight(.jumper, .oldFlyHeight, 0.) // just for debug purpose to make the unit land properly always
call SetUnitX(.jumper, .endX)
call SetUnitY(.jumper, .endY)
set .active = false
set .jumper = null
endmethod
private static method periodic takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local real percentageDist
local real curAngle
set .curDist = .curDist + RAbsBJ(.speed)
set percentageDist = .curDist / .maxDist
set curAngle = .startAngle + percentageDist * .destAngle * 2.
call SetUnitX(.jumper, GetUnitX(.jumper) + .moveX)
call SetUnitY(.jumper, GetUnitY(.jumper) + .moveY)
call SetUnitFlyHeight(.jumper, GetUnitFlyHeight(.jumper) + thistype.HEIGHT_EXPANSION * curAngle / 60., 0.)
if .curDist >= .maxDist then
call ReleaseTimer(t)
call .destroy()
endif
set t = null
endmethod
public static method create takes unit u, real a, real s, real x, real y returns thistype
local timer t
local thistype this = GetUnitUserData(u)
local real angle
local real posX
local real posY
// Case: Unit was not already jumping.
if not .active then
set .jumper = u
set .startAngle = a
set .destAngle = - .startAngle
set .oldFlyHeight = GetUnitFlyHeight(u)
set t = NewTimer()
call SetTimerData(t, this)
call TimerStart(t, thistype.INTERVAL, true, function thistype.periodic)
endif
set .speed = s * thistype.INTERVAL
set posX = GetUnitX(u)
set posY = GetUnitY(u)
set angle = AngleBetweenCoords(posX, posY, x, y)
set .moveX = .speed * Cos(angle)
set .moveY = .speed * Sin(angle)
set .curDist = 0.
set .maxDist = DistanceBetweenCoords(posX, posY, x, y)
if .speed > 0 then
set .endX = GetUnitX(u) + .maxDist * Cos(angle)
set .endY = GetUnitY(u) + .maxDist * Sin(angle)
else
set .endX = GetUnitX(u) - .maxDist * Cos(angle)
set .endY = GetUnitY(u) - .maxDist * Sin(angle)
endif
set .active = true
return this
endmethod
endstruct
function IsUnitJumping takes unit u returns boolean
local SimpleAngularJump data = GetUnitUserData(u)
return data.isJumping()
endfunction
function UnitJumpToPosition takes unit u, real a, real s, real x, real y returns nothing
if a < 0 or a >= 90 then
debug call BJDebugMsg("ERROR: Angle (a) parameter is not within the bounds of [0, 90)")
return
elseif s == 0 then
debug call BJDebugMsg("ERROR: Speed (s) parameter is 0!")
return
elseif u == null then
debug call BJDebugMsg("ERROR: Unit (u) must be a unit!")
return
elseif IsUnitJumping(u) then
debug call BJDebugMsg("ERROR: Unit (u) can not jump while jumping!")
return
endif
if UnitAddAbility(u, 'Arav') then
call UnitRemoveAbility(u, 'Arav')
endif
call SimpleAngularJump.create(u, a, s, x, y)
endfunction
function UnitJumpToPositionLoc takes unit u, real a, real s, location l returns nothing
call UnitJumpToPosition(u, a, s, GetLocationX(l), GetLocationY(l))
endfunction
endlibrary