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

[vJASS] Jump

Level 13
Joined
Nov 22, 2006
Messages
1,260
Jump v2.0

By: Silvenon


Credits to:
  • Shadow1500 - JumpParabola function
  • PitzerMike - TreeFilter function (not the original function name, though)
  • PurplePoot - improvement suggestions
  • PipeDream, Vexorian and the rest listed in the credits there - Jass NewGen Pack
  • Vexorian - caster (Caster System) unit
  • Yixx - helped me with a bit with efficiency and testing


v.0.1
  • first release
v.0.2
  • removed the Jump wrapper function
  • minor performance improvements
  • polished the function a bit
  • remove an accidentally commented piece of line
  • removed the Data returnage
v.0.3
  • replaced the TreeFilter function, thanks to Av3n
  • removed the CSSafety requirement since only one timer is used, thanks to PurplePoot (I was obviously too stupid to figure that out myself)
  • fixed a syntax error (again, thanks to PurplePoot)
v.1.0
  • added a new parameter: animation
  • made the jumping unit stop any order
  • fixed a bug with jumping on terrains that are higher or lower than 0
  • the jumping unit cannot jump over map boundaries anymore
v.2.0
  • fixed the code completely
  • code actually works properly now
  • maybe bezier later
  • an efficiency fix, thanks to Yixx
  • edited so it now uses the caster unit from Vexorian's CasterSystem

JASS:
library Jump initializer Init

// ****************************************************************************
// **                                                                        **
// ** Jump v.20                                                              **
// ** ——————————                                                             **
// **                                                                        **
// ** Just a function I made for efficient jumping                           **
// **                                                                        **
// ****************************************************************************

//=======//
//Globals//
//=======//

globals
    private integer DUMMY_ID = 'e000'
    private integer array Ar
    
    private constant real Interval = 0.035
    private boolexpr Bool
    private location Loc1 = Location(0, 0)
    private location Loc2 = Location(0, 0)
    
    private unit Dummy
    private timer Tim = CreateTimer()
    private integer Total = 0
    
    private real MAX_X
    private real MAX_Y
    private real MIN_X
    private real MIN_Y
endglobals

//===========================================================================

//========================================//
//Credits to Shadow1500 for this function!//
//========================================//

private function JumpParabola takes real dist, real maxdist, real curve returns real
    local real t = (dist * 2) / maxdist - 1
    return (- t * t + 1) * (maxdist / curve)
endfunction

//=======================================//
//Credits to PitzerMike for this function//
//=======================================//

private function TreeFilter takes nothing returns boolean
    local destructable d = GetFilterDestructable()
    local boolean i = IsDestructableInvulnerable(d)
    local boolean result = false
    call SetUnitPosition(Dummy, GetWidgetX(d), GetWidgetY(d))
    if i then
        call SetDestructableInvulnerable(d, false)
    endif
    set result = IssueTargetOrder(Dummy, "harvest", d)
    if i then
      call SetDestructableInvulnerable(d, true)
    endif
    call IssueImmediateOrder(Dummy, "stop")
    set d = null
    return result
endfunction

//===========================================================================

private function TreeKill takes nothing returns nothing
    call KillDestructable(GetEnumDestructable())
endfunction

public struct Data
    unit u
    integer q
    real md
    real d
    real c
    
    real sin
    real cos
    integer i = 1
    
    real p
    real r
    string s
    
    static method create takes unit u, integer q, real x2, real y2, real c, real r, string s1, string s2, string anim returns Data
        local Data dat = Data.allocate()
        
        local real x1 = GetUnitX(u)
        local real y1 = GetUnitY(u)
        local real dx = x1 - x2
        local real dy = y1 - y2
        local real a = Atan2(y2 - y1, x2 - x1)
        local location l1 = Location(x1, y1)
        local location l2 = Location(x2, y2)
        
        call MoveLocation(Loc1, x1, y1)
        
        set dat.u = u
        set dat.q = q
        set dat.md = SquareRoot(dx * dx + dy * dy)
        set dat.d = dat.md / q
        set dat.c = c
        set dat.sin = Sin(a)
        set dat.cos = Cos(a)
        set dat.p = (GetLocationZ(l2) - GetLocationZ(l1)) / q
        set dat.r = r
        set dat.s = s2
        
        if s1 != "" and s1 != null then
            call DestroyEffect(AddSpecialEffect(s1, x1, y1))
        endif
        
        call UnitAddAbility(u, 'Amrf')
        call UnitRemoveAbility(u, 'Amrf')
        call PauseUnit(u, true)
        call SetUnitAnimation(u, anim)
        
        call RemoveLocation(l1)
        call RemoveLocation(l2)
        
        set l1 = null
        set l2 = null
        
        return dat
    endmethod

    method onDestroy takes nothing returns nothing
        local real x = GetUnitX(.u)
        local real y = GetUnitY(.u)
        local rect r
        
        if .r != 0 then
            set r = Rect(x - .r, y - .r, x + .r, y + .r)
            call EnumDestructablesInRect(r, Bool, function TreeKill)
            call RemoveRect(r)

            set r = null
        endif
        
        if .s != "" and .s != null then
            call DestroyEffect(AddSpecialEffect(.s, x, y))
        endif
        
        call PauseUnit(.u, false)
        call IssueImmediateOrder(.u, "stop")
        call SetUnitAnimation(.u, "stand")
        call SetUnitFlyHeight(.u, 0, 0)
    endmethod
endstruct

private function Execute takes nothing returns nothing
    local Data dat
    local integer i = 0
    local real x
    local real y
    local location l
    local real h
    local rect r
    
    loop
        exitwhen i >= Total
        set dat = Ar[i]
        set x = GetUnitX(dat.u) + (dat.d) * dat.cos
        set y = GetUnitY(dat.u) + (dat.d) * dat.sin
        
        call MoveLocation(Loc2, x, y)
        
        set h = JumpParabola(dat.d * dat.i, dat.md, dat.c) - (GetLocationZ(Loc2) - GetLocationZ(Loc1)) + dat.p * dat.i
        
        if x < MAX_X and y < MAX_Y and x > MIN_X and y > MIN_Y then
            call SetUnitX(dat.u, x)
            call SetUnitY(dat.u, y)
        endif
        
        call SetUnitFlyHeight(dat.u, h, 0)
        
        if dat.i >= dat.q then
            call dat.destroy()
            set Total = Total - 1
            set Ar[i] = Ar[Total]
        else
            set dat.i = dat.i + 1
        endif
        
        set i = i + 1
    endloop
    
    if Total == 0 then
        call PauseTimer(Tim)
    endif
    
    set l = null
endfunction

function Jump takes unit whichUnit, real dur, real destX, real destY, real curve, real radius, string sfx1, string sfx2, string anim returns nothing
local Data dat = Data.create(whichUnit, R2I(dur / Interval), destX, destY, curve, radius, sfx1, sfx2, anim)
    
    if Total == 0 then
        call TimerStart(Tim, Interval, true, function Execute)
    endif
    
    set Ar[Total] = dat
    set Total = Total + 1
endfunction

//==================================================================================

private function Init takes nothing returns nothing
    set Bool = Filter(function TreeFilter)
    
    set Dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY_ID, 0, 0, 0)
    
    call UnitAddAbility(Dummy, 'Amrf')
    call UnitRemoveAbility(Dummy, 'Amrf')
    call UnitAddAbility(Dummy, 'Aloc')
    call SetUnitAnimationByIndex(Dummy, 90)
    
    call UnitAddAbility(Dummy, 'Ahrl')
    
    set MAX_X = GetRectMaxX(bj_mapInitialPlayableArea) - 64
    set MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea) - 64
    set MIN_X = GetRectMinX(bj_mapInitialPlayableArea) + 64
    set MIN_Y = GetRectMinY(bj_mapInitialPlayableArea) + 64
endfunction

endlibrary


This is just Shadow1500's JumpParabola function put in use. Jump function makes a unit jump according to the following parameters:
  • whichUnit = jumping unit
  • dur = duration of the jump
  • destX = x of the destination point
  • destY = y of the destination point
  • curve = well, uhmm, better look here for explanation
  • radius = when the unit lands, it will kill all trees in this radius (if you don't want any tree killing, just put 0)
  • sfx1 = jumping effect, if you don't want any, just put ""
  • sfx2 = landing effect, if you don't want any, just put ""
  • anim = animation played once during the jump (e. g. "attack"), you can put "", if you don't want any, just put ""

Copy the dummy unit called caster (Caster System) from Vexorian's CasterSystem map. The id of the copied unit in your map will most probably be 'e000', but if it's not, you MUST change the DUMMY_ID constant integer (in the code above) to that unit's id.

The reason why I used this specific version of a dummy unit is because I want to make you start using it (if you already haven't), because it's really great. You can have a single dummy unit for casting, effects etc. For effects you can just attach an effect to its origin, then you can modify the size, the vertex and whatever else with just applying the changes for the unit! Having that unit really simplifies everything and you don't have to create a dummy unit for each moving special effect.

All you need to do to be able to modify everything is do the following sequence:

JASS:
call UnitAddAbility(<caster>, 'Amrf')
call UnitRemoveAbility(<caster>, 'Amrf')
call UnitAddAbility(<caster>, 'Aloc')
call SetUnitAnimationByIndex(<caster>, 90)

You can change the Interval constant to modify the interval of the timer that's executing the jump, but it's really unnecessary.

Example of usage:

JASS:
function Test takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local real d = 500
    local real a = GetUnitFacing(u) * bj_DEGTORAD
    local real dur = 1
    local real x1 = GetUnitX(u)
    local real y1 = GetUnitY(u)
    local real x2 = x1 + d * Cos(a)
    local real y2 = y1 + d * Sin(a)
    local real c = 1.8
    local real r = 200
    local string sfx2 = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
    
    call Jump(u, dur, x2, y2, c, r, "", sfx2, "")
endfunction


Requires: Jass NewGen Pack





Report any bugz plz!!!!111oneone
 
Last edited:
Level 40
Joined
Dec 14, 2005
Messages
10,532
-Same critique of the tree filter function

JASS:
set Total = Total + 1
set Ar[Total-1] = dat
-Kinda picky here (t'would just save a few characters and an operation), but you should move the set Ar[...] above the other line, and thus not have to subtract 1.

-Why do you return dat? It seems like all that is going to accomplish is to allow users to screw up the spell.

-Is there a point in including a Jump wrapper function?

-It would be <slightly> faster to have the location be a global and use MoveLocation than to constantly create/destroy it.

-It's slightly faster <and shorter in code> to reference parameters directly than through the struct (in the create method), so (for example), replacing dat.q with q would be ideal. (Not a big deal, though)

-Possibly include a boolean option (parameter) for the z-support or remove it completely? Most people won't notice it sitting there commented out, especially the type of people who might be using this.

JASS:
set Ar[i] = Ar[Total-1]
set Total = Total - 1
-Like above, an unnecessary operation.

-Unless you're using CSData or something similar, it's CreateTimer(), not NewTimer() (And you don't seem to mention CSData or an equivalent)
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
-Same critique of the tree filter function

Yeah, yeah, fixing that......

-Why do you return dat? It seems like all that is going to accomplish is to allow users to screw up the spell.

I thought someone will find that useful, fixing.....

-Kinda picky here (t'would just save a few characters and an operation), but you should move the set Ar[...] above the other line, and thus not have to subtract 1.

I was wondering why Vex did that way also, I remember I tried your way, but something stopped me........fixing that also..... (you really are picky :p)

-Is there a point in including a Jump wrapper function?

Not really, I thought you would say same as for the Knockback function.

-It would be <slightly> faster to have the location be a global and use MoveLocation than to constantly create/destroy it.

Yeah, fixing that......

-It's slightly faster <and shorter in code> to reference parameters directly than through the struct (in the create method), so (for example), replacing dat.q with q would be ideal. (Not a big deal, though)

I thought the speed is the same since they are just global variables.......but ok, fixing......

-Possibly include a boolean option (parameter) for the z-support or remove it completely? Most people won't notice it sitting there commented out, especially the type of people who might be using this.

Whooops! Forgot to uncomment it :), fixing......

-Like above, an unnecessary operation.

Same as above :). Wow, I'm gonna save a loooot of space this way :p

-Unless you're using CSData or something similar, it's CreateTimer(), not NewTimer() (And you don't seem to mention CSData or an equivalent)

CSData is small side-system made by Vex that allows attaching integers to other handles, works like UnitUserData with units. The functions are SetCSData(<handle>, <integer>) and GetCSData(<handle>)

You probably meant CSSafety library which I've put as requirements, look closer :).
 
Last edited:
Level 9
Joined
Jul 18, 2005
Messages
319
The Tree filter is horrible.... try using this one instead:
JASS:
function IsDestructableTree takes destructable d returns boolean
  local boolean i = IsDestructableInvulnerable(d)
  local unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), <invisible caster>,GetWidgetX(d), GetWidgetY(d), 0)
  local boolean result = false
  call UnitAddAbility(u, 'Ahrl')
  if i then
    call SetDestructableInvulnerable(d, false)
  endif
  set result = IssueTargetOrder(u, "harvest", d)
  call RemoveUnit(u)
  if i then
    call SetDestructableInvulnerable(d, true)
  endif
  return result
endfunction

Use that... I got it from pitzermike's post at wc3c.

Its mroe effcient custom wise as well

-Av3n
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Ok, Pooty, I did everything you asked. Is there anything else? If there is, try to merge all your remaining suggestions in your next post so that I can fix it asap.

Tnx Av3n..........but then the code would require an invisible caster unit and that's really unnecessary. The efficiency difference is probably unnoticeable.

After all, that function is called just once and won't really be any efficient if I change it to your suggestion. If somebody complains about lags, I will modify it.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Tnx Av3n..........but then the code would require an invisible caster unit and that's really unnecessary. The efficiency difference is probably unnoticeable.

After all, that function is called just once and won't really be any efficient if I change it to your suggestion. If somebody complains about lags, I will modify it.
It's not because of efficiency. It's because if you make 10 custom trees, this way works fine with them.

I'll just have to stick this in a map and test it sometime, but it seems fine.
 
Level 4
Joined
Dec 30, 2006
Messages
72
nice, i used this in my map and tested it, but theres some part that makes the jump looks crappy

like when my hero jumps to that target, the first movement doesnt lift the hero up instead sliding first before jumping and also when it lands, it slides the hero for 1 movement before stopping

what i wanted is to remove the part where the unit slides, instead of jumping directly, or stopping directly
heres an illustration of the jump below
 

Attachments

  • Jump.JPG
    Jump.JPG
    26 KB · Views: 4,074
Level 13
Joined
Nov 22, 2006
Messages
1,260
Thanks for reporting this, but I really must say I have no idea how to fix this. I'll think about it.

I tried to do something which should get rid of the first slide, but then it will probably slide even more in the end.

I can't test this, I rely on you guys.
 
Level 4
Joined
Dec 30, 2006
Messages
72
i must have stated it wrong
heres a brief information about the bug

the unit jumps in a perfect arc, jumps directly, creates the lift-off effect, and lands on the target area perfectly, BUT, after landing at the destination, it slides along the way, like it reached for 500 - 600 range, and when it stopped sliding, then the landing effect spawns
 
Level 4
Joined
Dec 30, 2006
Messages
72
tried it

when jumping, it jumps half way across the target location, and then slide its way to the target location, meaning 50% jump, and 50% slide from the starting loc to the target loc, the jump still not fixed...

btw, how did u make this code without wc3? did u only used notepad in making it? if yes, then that means u created the code without any test?
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
tried it

when jumping, it jumps half way across the target location, and then slide its way to the target location, meaning 50% jump, and 50% slide from the starting loc to the target loc, the jump still not fixed...

Crap, I'm sorry, we'll just have to wait for PurplePoot (it seems like for some reason he's always the only one who can help).

btw, how did u make this code without wc3? did u only used notepad in making it? if yes, then that means u created the code without any test?

I made it with wc3, but it looked fine to me, I didn't see any sliding of the type you mentioned (I didn't look very carefully). And now my mom uninstalled my wc3 because I was "spending too much time on it and not enough time on the school".
 
Level 4
Joined
Dec 30, 2006
Messages
72
I made it with wc3, but it looked fine to me, I didn't see any sliding of the type you mentioned (I didn't look very carefully). And now my mom uninstalled my wc3 because I was "spending too much time on it and not enough time on the school".
wtf! thats the funniest reason ive ever heared...lol
 
Level 4
Joined
Dec 30, 2006
Messages
72
what do u mean by +es?
ill try it again someday, because im not working on my RotG Reborn map for now, because i created another map

BTW, i used spongebob as the model for the previous tests, does the model affect the jump?
and yeah also, i set the duration as 1 sec and the arc to 0.85 to make it higher
 
Bah nobody uses Bezier anymore, when they are a lot better than other formulas.

This can be simplified to a basic interpolation formula:

JASS:
function LinearInterp takes real a, real b, real t returns real
     return a + (b-a)*t
endfunction
function BezierInterp takes real a, real b, real c, real t returns real
     return a + 2*(b-a)*t + (c -2*b + a)*t*t
endfunction

In this 3 points bezier curve a, b, c represent points respectively and t represents the step, 0 >= t <= 1.

now lets say we are going to make a perfect parabol.
in a jump, we would try to make a perfect parabol without much problems. The first condition we set for the X & Y axis is that, a is the start point, b is the mid point between c and a; and c is the end point. Thus X & Y axis will be interpolated linearly, and we will eliminate b, since it's the midpoint.

for Z axi (heigth) we'll use the bezier interpolation, if we take into account that heigth is an absolute value, then a = c, no matter in which terrain type the unit starts and ends, in ground of heigth is 0.0. Thus:

JASS:
function ParabolicInterp takes real a, real b, real t returns real
     return a + 2*(b-a)*t + 2*(a-b)*t*t //we multiply last by -1 and we change inside symbols
endfunction
//thus it simplifies to
function ParabolicInterp takes real a, real b, real t returns real
     return a + 2*(b-a)*(1.0-t)*t
endfunction

but if we are interpolating over and over then 2*(b-a) would turn into a constant value so it ends up being.
JASS:
function ParabolicInterp takes real a, real m, real t returns real
     return a + m*(1.0-t)*t  //where m is 2*(b-a)
endfunction
 
Level 4
Joined
Dec 30, 2006
Messages
72
u need to go to "Custom Script" action and type
  • call Jump(udg_caster, 1, GetLocationX(udg_point), GetLocationY(udg_point), 1.8, 300, udg_sfx, udg_sfx2)
heres the function, use it for reference
JASS:
function Jump takes unit whichUnit, real dur, real destX, real destY, real curve, real radius, string sfx1, string sfx2 returns nothing
 
Level 5
Joined
Jan 15, 2007
Messages
199
Add support for running a specified function when jump is complete?

Ex: Tauren jump slam thingy
-Jumps the Tauren to a target area, smashing all the n00bs to make them fly backwards from him when he lands.

warcraft0675.gif


Its also nice to have a pause option and options for playing a units animation. Maybe JumpEx?

Ex: Priestess Tiger hop
-Makes the tiger jump 600 distance towards its angle (plays walk animation while jumping and short time)

warcraft0743.gif


You could make it run the function on land by adding a taken string to JumpEx, and then ExecuteFunc( takenstring )ing it when the person lands.

EDIT: After testing, I noticed that you forgot to IssueImmediateOrder( .u, "stop" ) after unpausing them in the ondestroy method
And there isn't random sliding at the end/start >.>
Also, make it so you cant jump 0 distance, to "Protect users from themselves" as Dusk would put it
 
Last edited:
Level 13
Joined
Nov 22, 2006
Messages
1,260
The jump has a bug : your unit can be removed from the game by jumping in the black zone, out of the map...

Really? I thought I fixed that.... too bad, gonna check it out later.

After testing, I noticed that you forgot to IssueImmediateOrder( .u, "stop" ) after unpausing them in the ondestroy method
Also, make it so you cant jump 0 distance, to "Protect users from themselves" as Dusk would put it

Sure, thanks for advice.
 
Level 1
Joined
Aug 5, 2008
Messages
2
Hey, Not sure if im the only one getting this problem. However after it does the jump sequence it just keeps sliding and never unpauses. Heres what I have for the code.

Nvm got it working. However I found a bug, if you jump into ground lower then you it has u floating higher.
 
Last edited:
Level 6
Joined
Jun 15, 2008
Messages
175
What's the variable settings? I'm not that good at jass, I've tried looking at it, and I cant seem to find a place, where you state, if I have to create something in my map, besides a Dummy unit.
What do I need to do to make this work in my map?
Also, I tried copy pasting, this into JC, and made a syntax check, got a whole bunch of errors. Can anyone explain?
 
Top