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

[JASS] A formula for the Z axle?

Status
Not open for further replies.
Level 6
Joined
Jul 25, 2005
Messages
221
We all know the formula for moving a unit around in a circle on the X&Y plane:

X + dist * cos(angle+movementspeed * pi/180)*
Y + dist * sin(angle+movementspeed * pi/180)*

* also, reset when the angle hits 359 so you keep it in the same angle all teh time

now... the Z plane, a unit's flying height that is, should have a similar formula shouldn't it? I mean, the first formula can be used in some sort of spherical example I guess, can anyone give me a precise... accurate... splendid... awesomeness formula for moving a unit in the Z plane like a circle.

(Mind you, the easy part is to make the unit go back and forth in the Y plane, I've already done it, I can also make a square-ish form using distance, movement speed etc, all from the great book o' physics)

Me likey maths, teach me :cute:
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
There is a formula for this.
Search for it(jump parabola/jump spell/jump formula).
 
Level 6
Joined
Jul 25, 2005
Messages
221
The only one I found was in vJass, and I don't know that much vJass, would you mind searching and linking/copy+paste it for me and I will spam +rep for you :cute:
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
[jass=Create a sphere of units centred around 0,0,700, with an interval of pi/16, and the sphere having 500 radius, and discounting terrain height]local real r = 500
local real t
local real p = 0
loop
exitwhen p >= 2*bj_PI
set t = 0
loop
exitwhen t >= 2*bj_PI
call SetUnitFlyHeight(CreateUnit(Player(0),'h000',r*Cos(t)*Sin(p),r*Sin(t)*Sin(p),0),700+r*Cos(p),0)
set t = t + bj_PI/16
endloop
set p = p + bj_PI/16
endloop[/code]

Basically, as you said with Polar coordinates, you have:

newX = oldX + radius*Cos(theta)
newY = oldY + radius*Cos(theta)

Where radius is the circle's radius (distance), and theta is the angle.

With Spherical Coordinates, you have:

newX = oldX + radius*Cos(theta)*Sin(phi)
newY = oldY + radius*Sin(theta)*Sin(phi)
newZ = oldZ + radius*Cos(phi)

Where radius and theta are the same as before, and phi is your second angle.
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
Hm
I think that formula is incorrect.
newX = oldX + radius*Cos(theta)*Sin(phi)
newY = oldY + radius*Sin(theta)*Sin(phi)
newZ = oldZ + radius*Cos(phi)
Should be:
newX = oldX + radius*Cos(theta)*Cos(phi)
newY = oldY + radius*Sin(theta)*Cos(phi)
newZ = oldZ + radius*Sin(phi)
Heck, I am not 100% sure(again it's late ) ;)
 
Last edited:
Level 12
Joined
Apr 27, 2008
Messages
1,228
Oh, bugger.
Yeah phi is not fixed. I got confused with another thing where you would have a tilted parabola - I thought phi was the angle of the tilt.
So you agree with my suggestion about sin/cos? :p
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
:D
First thought: wtf.
A period of thinking.
Urika :p
Both ways are absolutely correct.
But it is the order at which you are going to place the the objects.
If phi starts from 0:
Your's/wiki's way will start at the top and will go down drawing a circle. My will start at the middle and go up, drawing a circle.
With the first way phi would indicate the angle with the vertical plane. With my way - the angle with the horizontal plane.
It is a matter of personal appeal as setting phi to the right value in one of the methods would make both ways the same.
To me it is more natural that the height should be sin*radius.
Here is the simple test:

JASS:
local real r = 600
local real t = bj_PI/64
local real p = 0
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, 3000.00, 0 )
loop
    exitwhen p >= 2*bj_PI
        call AddLightningEx("CLPB",true,r*Cos(p),-200,700+r*Sin(p),r*Cos(t),-200,700+r*Sin(t))
        call AddLightningEx("CLPB",true,r*Sin(p),200,700+r*Cos(p),r*Sin(t),200,700+r*Cos(t))
        call PolledWait(0.2)
    set p = p + bj_PI/32//to miss one branch
    set t = t + bj_PI/32//to miss one branch
endloop
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
No i am not :)
And also note that "exitwhen p >= 2*bj_PI" is wrong.
Should be exitwhen p >= bj_PI.
Here are the two tests for spheres
JASS:
local real r = 600
//local real t = (-1*bj_PI/2) + bj_PI/64
//local real p = -1*bj_PI/2
//local real end = bj_PI/2
local real t = bj_PI/64
local real p = 0
local real end = bj_PI
local real g
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, 3000.00, 0 )
loop
    exitwhen p >= end
        set g=0
        loop
            exitwhen g>=2*bj_PI
            //call AddLightningEx("CLPB",true,r*Cos(g)*Cos(p),-700+r*Sin(g)*Cos(p),700+r*Sin(p),r*Cos(g)*Cos(t),-700+r*Sin(g)*Cos(t),700+r*Sin(t))
            call AddLightningEx("CLPB",true,r*Cos(g)*Sin(p),700+r*Sin(g)*Sin(p),700+r*Cos(p),r*Cos(g)*Sin(t),700+r*Sin(g)*Sin(t),700+r*Cos(t))
            set g=g+bj_PI/32
        endloop
    call TriggerSleepAction(-1)
    set p = p + bj_PI/32
    set t = t + bj_PI/32
endloop
I doubt I need to say something about the "//"
About the angle, just run the two tests :)
 
Last edited:
Level 6
Joined
Jul 25, 2005
Messages
221
Wow, you've given lots of information, me likey spheres but I also want to know how and why they turn out the shapes they do. I'm not THAT good at math yet, explain in layman terms... :p this is my stupid code for the moment, trying to use your info to create it. As I mentioned earlier (I think) I'm trying to move a unit using the y and z plane only.

Here's my stupid code:

JASS:
function height takes nothing returns nothing
local gamecache gc = udg_AbilityCache
local string s = I2S(H2I(GetExpiredTimer()))
local real r = GetStoredReal(gc, s, "r")
local real x = GetStoredReal(gc, s, "x")
local real y = GetStoredReal(gc, s, "y")
local real h = GetStoredReal(gc, s, "h")
local real newh = h + 600*Cos(bj_PI/16)
    call SetUnitFlyHeight( gg_unit_hgry_0023, newh, 10000)
    call SetUnitX( gg_unit_hgry_0023, somex....)
    call StoreReal( gc,s, "h", newh)
endfunction
function Trig_lul_Actions takes nothing returns nothing
local gamecache gc = udg_AbilityCache
local timer t = CreateTimer()
local string s = I2S(H2I(t))
local real r = 0
local real x = GetUnitX(gg_unit_hgry_0023)
local real y = GetUnitY(gg_unit_hgry_0023)
local real h = GetUnitFlyHeight( gg_unit_hgry_0023 )
    call StoreReal(gc, s, "r", r)
    call StoreReal(gc, s, "x", x)
    call StoreReal(gc, s, "y", y)
    call StoreReal(gc, s, "h", h)
    call TimerStart( t, 0.5, true, function height) 
endfunction
 
//===========================================================================
function InitTrig_lul takes nothing returns nothing
    set gg_trg_lul = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_lul, Player(0), "go", true)
    call TriggerAddAction( gg_trg_lul, function Trig_lul_Actions )
endfunction

I have absolutely no clue of what to do...

EDIT: If you could create a map for me doing this and giving comments or, drawing some sort of picture on how these formulas work I'd be forever grateful :cute:
 
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
I posted this on the vJASS Jump Thread. It saves a lot of work, rather than using cosine and sine all the time. Btw use the function on In-line.

since you are mainly interested on the effect I'll explain how to use it.

We are going to have an start point, an end point and a heigth. For interpolating X&Y axis we use this function:

JASS:
function LinearInterp takes real a, real b, real t returns real
     return a + (b-a)*t
endfunction
//a = start point and b = endpoint

use it inline, it means that you are going to paste the function's return in your main function and replace the parameters.

You may be wondering what t does, imagine it like a frame step. the first point is made when t = 0, when t = 1, it returns the end point and when t = 0.5 it returns the mid point.

Use it for each axis individually.

Example:
JASS:
globals
    unit Ur
    real x
    real y
    real my
    real mx
    real t
    real steps
endglobals

function Move takes nothing returns nothing
    call SetUnitX(Ur, x + mx*t)
    call SetUnitY(Ur, y + my*t)
    if t >= 1.0 then
        call PauseTimer(GetExpiredTimer())
        call DestroyTimer(GetExpiredTimer())
    endif
    set t = t + steps
endfunction


function TestInterp takes unit u, real x1, real x2, real y1, real y2, real s, real time returns nothing
local timer R = CreateTimer()
set t = 0.0
set Ur = u
set x = x1
set y = y1
set mx = x2-x1
set my = y2-y1
set steps = 1.0/s
set time = time/s
call TimerStart(R,time,true,function Move)
endfunction

function Main takes nothing returns nothing
local unit u = CreateUnit(Player(0),'h000',0.0,0.0, 270.0)
call TestInterp(u,0.0,500.0,0.0,-200.0, 10.0, 1.0)
endfunction

Now lets modify it so, he jumps, using the parabolic function, for the z axis.

JASS:
globals
    unit Ur
    real x
    real y
    real z
    real my
    real mx
    real mz
    real t
    real steps
endglobals

function Move takes nothing returns nothing
    call SetUnitX(Ur, x + mx*t)
    call SetUnitY(Ur, y + my*t)
    call SetUnitFlyHeight( Ur, z + mz*(1.0-t)*t, 10000)
    if t >= 1.0 then
        call PauseTimer(GetExpiredTimer())
        call DestroyTimer(GetExpiredTimer())
    endif
    set t = t + steps
endfunction

function TestInterp takes unit u, real x1, real x2, real z1, real y1, real y2, real h, real s, real time returns nothing
local timer R = CreateTimer()
set t = 0.0
set Ur = u
set x = x1
set y = y1
set z = z1
set mx = x2-x1
set my = y2-y1
set mz = 2*(h-z1)
set steps = 1.0/s
set time = time/s
call TimerStart(R,time,true,function Move)
endfunction

function Main takes nothing returns nothing
local unit u = CreateUnit(Player(0),'h000',0.0,0.0, 270.0)
call TestInterp(u,0.0,500.0,0.0,0.0,-200.0, 500.0, 10.0, 1.0) //multiply the true heigths by 2
endfunction
 
Last edited:
Status
Not open for further replies.
Top