- Joined
- Jan 11, 2009
- Messages
- 3,414
Hi!
I have this cannonball struct i made for my map that moves the balls using vectors and corrects their height by saving the last terrain height and comparing it to the current height every cycle (and then substracting or adding the difference to the current height).
My problem is that the ball doesn't appear corrected at all, infact, it bounces up and down adn tend to go up and then crash dive when moving up steep slopes.
Please let me know if this is just a fault in the SetunitFlyHeight native or if it just me who fail at coding!
Here is the script:
Also, The_Reborn_Devil was so nice as to help me with the formula for calculating required launch angle for the ball to reach target x/y, but sadly, it does not compensate for target height (that is why i added the "-(Asin(z_diff/dist)*bj_RADTODEG)" ).
If someone can come up with ideas for making a viable formula for this, please tell me! It would be great to have some nice accurate cannonballs going!
I have this cannonball struct i made for my map that moves the balls using vectors and corrects their height by saving the last terrain height and comparing it to the current height every cycle (and then substracting or adding the difference to the current height).
My problem is that the ball doesn't appear corrected at all, infact, it bounces up and down adn tend to go up and then crash dive when moving up steep slopes.
Please let me know if this is just a fault in the SetunitFlyHeight native or if it just me who fail at coding!
Here is the script:
JASS:
library Cannonball requires ListModule, GroupUtils
globals
private location LOC
private constant real INTERVAL = 0.038 //loop interval
private constant real VEL = 2200*INTERVAL //bullet velocity
private constant real G = 9.81*INTERVAL //the constant of gravity
endglobals
private function BallDoDamage takes nothing returns boolean
local Knockback K
local ball B = bj_forLoopAIndex //i needed a global variable to pass over the ball struct, so i borrowed this one!
if (IsUnitType(GetFilterUnit(), UNIT_TYPE_GIANT) == false ) then
if (IsUnitType(GetFilterUnit(), UNIT_TYPE_ANCIENT) == false ) then
if (GetUnitFlyHeight(B.u) < 200) then
if (GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.5) then
call KillUnit(GetFilterUnit())
set K = Knockback.create(GetFilterUnit(), GetRandomReal(100, 150), GetRandomReal(0.5, 0.8), B.face)
call SetUnitAnimation(GetFilterUnit(), "spell slam")
call SetUnitFacing(GetFilterUnit(), ModuloReal(B.face-180, 360))
return true
endif
endif
endif
endif
return false
endfunction
struct ball
implement List
real xv //x, y, and z vectors
real yv
real zv
real last_z
real ang
real face
unit u
private static timer ticker
static method create takes real x, real y, real tar_x, real tar_y returns ball
local thistype this = thistype.allocate()
local real dx = tar_x - x
local real dy = tar_y - y
local real dist = SquareRoot(dx * dx + dy * dy)
local real ang = 0.5*(Asin((G*dist)/(VEL*VEL))* bj_RADTODEG)
local real f = bj_RADTODEG * Atan2(tar_y - y, tar_x - x) //angle between start and target coordinates
local real z
local real z_diff
local unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'h015', x, y, f)
call .listAdd()
if .count == 1 then
call TimerStart(.ticker, INTERVAL, true, function thistype.moveballs)
endif
call MoveLocation(LOC, tar_x, tar_y)
set z = GetLocationZ(LOC)
call MoveLocation(LOC, x, y)
set z_diff = GetLocationZ(LOC)-z
set .face = f
set .ang = (90-Atan((0.5*G*dist)/(VEL*VEL)) * bj_RADTODEG)-(Asin(z_diff/dist)*bj_RADTODEG)
set .u = u
set .last_z = GetLocationZ(LOC)
set .xv = VEL*Cos(.face*bj_DEGTORAD)*Sin(.ang*bj_DEGTORAD)
set .yv = VEL*Sin(.face*bj_DEGTORAD)*Sin(.ang*bj_DEGTORAD)
set .zv = VEL*Cos(.ang*bj_DEGTORAD)
set u = null
return this
endmethod
private static method moveballs takes nothing returns nothing
local thistype this = .first
local group damage = NewGroup()
local real z_diff
local real x
local real y
loop
exitwhen this == 0
set x = GetUnitX(.u)
set y = GetUnitY(.u)
call MoveLocation(LOC, x, y)
set z_diff = .last_z-GetLocationZ(LOC) //this is where the height correction comes in. I substract the current Z coordinate from the last..
set .last_z = GetLocationZ(LOC) //and then sets last coordinate to current, for the next loop.
set .zv = .zv-G //substracts gravity from Z vector.
call SetUnitX(.u, x+.xv)
call SetUnitY(.u, y+.yv)
call SetUnitFlyHeight(.u, GetUnitFlyHeight(.u)+.zv+z_diff, 0)
set bj_forLoopAIndex = this
call GroupEnumUnitsInRange(damage, x, y, 65., Filter(function BallDoDamage))
if (GetUnitFlyHeight(.u) < 1) then
if (.zv < 0) then
call KillUnit(.u)
call .destroy()
else
call .bounce()
endif
endif
if .count < 1 then
call PauseTimer(.ticker)
endif
set this = .next
endloop
call ReleaseGroup(damage)
endmethod
method bounce takes nothing returns nothing
//some code here that is being replaced, nothing important
endmethod
method onDestroy takes nothing returns nothing
set this.u = null
call .listRemove()
endmethod
private static method onInit takes nothing returns nothing
set .ticker = CreateTimer()
endmethod
endstruct
endlibrary
Also, The_Reborn_Devil was so nice as to help me with the formula for calculating required launch angle for the ball to reach target x/y, but sadly, it does not compensate for target height (that is why i added the "-(Asin(z_diff/dist)*bj_RADTODEG)" ).
If someone can come up with ideas for making a viable formula for this, please tell me! It would be great to have some nice accurate cannonballs going!