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

[Solved] Bug when "jumping" over water

Status
Not open for further replies.
Level 12
Joined
Jan 2, 2016
Messages
973
Today I made this jumping system, and it working quite well, with one exception: when the unit is jumping above terrain with different level - the movement isn't smooth. The unit starts going down, then up again, and it's really bothering me.
Here is the library:
JASS:
library Jumping

  globals
  public constant real Tick = 0.05
  constant real Acceleration = 98.1*Tick
  private timer Ticker = CreateTimer()
  private boolean On = false
  public real X
  public real Y
  public unit Unit
  public boolean End = false
  public integer Index
  private real sqDist
  endglobals

  struct Jumper
  unit u
  real array x[2]
  real array y[2]
  real array z[2]
  real a
  real array Vz[2]
  real speed
  trigger tr

  readonly thistype next
  readonly thistype prev
  static method operator first takes nothing returns thistype
  return thistype(0).next
  endmethod
  static method operator last takes nothing returns thistype
  return thistype(0).prev
  endmethod

  static method create takes nothing returns thistype
  local thistype this = thistype.allocate()
  set thistype(0).next.prev = this
  set this.next = thistype(0).next
  set this.prev = thistype(0)
  set thistype(0).next = this
  if not On then
  call TimerStart(Ticker, Tick, false, function thistype.jump)
  set On = true
  endif
  return this
  endmethod

  method onDestroy takes nothing returns nothing
  if this.first == this.last then
  set On = false
  endif
  set this.next.prev = this.prev
  set this.prev.next = this.next
  endmethod

  static method jump takes nothing returns nothing
  local thistype this = thistype.first
  loop
  exitwhen this == 0
  set sqDist = (this.x[1] - this.x[0])*(this.x[1] - this.x[0]) + (this.y[1] - this.y[0])*(this.y[1] - this.y[0])
  set End = sqDist <= this.speed*this.speed
  if End then
  set this.x[0] = this.x[1]
  set this.y[0] = this.y[1]
  set this.z[0] = this.z[1]
  set sqDist = 0
  else
  set this.x[0] = this.x[0] + this.speed*Cos(this.a)
  set this.y[0] = this.y[0] + this.speed*Sin(this.a)
  set this.z[0] = this.z[0] + this.Vz[0] + (this.Vz[1] - GetTerrainCliffLevel(this.x[0], this.y[0]))
  set this.Vz[0] = this.Vz[0] - Acceleration
  endif
  call SetUnitX(this.u, this.x[0])
  call SetUnitY(this.u, this.y[0])
  call SetUnitFlyHeight(u, this.z[0], 100000)
  if this.tr != null then
  set Unit = this.u
  set X = this.x[0]
  set Y = this.y[0]
  set sqDist = (this.x[1] - X)*(this.x[1] - X) + (this.y[1] - Y)*(this.y[1] - Y)
  set Index = this
  call TriggerEvaluate(this.tr)
  endif
  if End then
  call PauseUnit(this.u, false)
  call thistype.destroy(this)
  endif
  set this = this.next
  endloop
  if On then
  call TimerStart(Ticker, Tick, false, function thistype.jump)
  endif
  endmethod
  endstruct

  function Jump takes unit u, real x, real y, real speed, trigger tr returns Jumper
  local Jumper jump = Jumper.create()
  local real distance
  call UnitAddAbility(u, 'Arav')
  call UnitRemoveAbility(u, 'Arav')
  //call PauseUnit(u, true)
  set jump.u = u
  set jump.x[1] = x
  set jump.y[1] = y
  set jump.x[0] = GetUnitX(u)
  set jump.y[0] = GetUnitY(u)
  set jump.Vz[1] = GetTerrainCliffLevel(jump.x, jump.y)
  set jump.z[0] = GetUnitFlyHeight(u) + jump.Vz[1]
  set jump.z[1] = GetTerrainCliffLevel(x,y)
  set jump.speed = speed*Tick
  set distance = SquareRoot((jump.x[1] - jump.x[0])*(jump.x[1] - jump.x[0]) + (jump.y[1] - jump.y[0])*(jump.y[1] - jump.y[0]))
  set jump.Vz[0] = ((distance/jump.speed)*Acceleration/2) + ((jump.z[1] - jump.z[0])/(distance/jump.speed))
  set jump.a = Atan2(jump.y[1] - jump.y[0], jump.x[1] - jump.x[0])
  set jump.tr = tr
  return jump
  endfunction

endlibrary

I will also post the map, in case you want to see how it looks like.
You just need to press "M" and choose where to jump :p
It looks how it's supposed to when jumping on even terrain, but when jumping above "holes" or "pools" - that's when it becomes problematic..
 

Attachments

  • New Era BETA v0,2,0,2.w3x
    2.4 MB · Views: 34
Level 39
Joined
Feb 27, 2007
Messages
5,015
I believe problem is your use of GetTerrainCliffLevel(). That function only outputs how many levels of cliffs (x,y) is situated on (the things you can make with the terrain palette), not the actual height of (x,y). To do that you need to use
JASS:
native GetLocationZ takes location whichLoc returns real
Yes you have to use a location to get the Z height-- I would recommend just making 1 location for your whole system and moving it around when you need to:

JASS:
call MoveLocation(TMP_LOC, X, Y)
set ZGround = GetLocationZ(TMP_LOC)

//Never call this
//call RemoveLocation(TMP_LOC)
 
Level 12
Joined
Jan 2, 2016
Messages
973
Turning off collision did indeed make it look a bit better, tho it's still noticable.
I tried out the GetLocationZ, but it kind a gave too "grand" results - whenever the unit was going above a hole - instead of "falling" - it was rocketing upwards :D
 
Level 39
Joined
Feb 27, 2007
Messages
5,015
You just need to put them in the right places:
JASS:
location xyloc
//in jump method
set this.x[0] = this.x[0] + this.speed*Cos(this.a)
set this.y[0] = this.y[0] + this.speed*Sin(this.a)
call MoveLocation(this.xyloc, this.x[0], this.y[0])
set this.z[0] = this.z[0] + this.Vz[0] + (this.Vz[1] - GetLocationZ(this.xyloc))
//in Jump function
//unnecessary
//set jump.Vz[1] = GetTerrainCliffLevel(jump.x, jump.y) also you're missing the [0]s
local real fly = GetUnitFlyHeight(u)
call MoveLocation(jump.xyloc, jump.x[0], jump.y[0]) 
set jump.z[0] = fly + GetLocationZ(jump.xyloc)
call MoveLocation(jump.xyloc, jump.x[1], jump.y[1])
set jump.z[1] = fly + GetLocationZ(jump.xyloc)
 
Level 12
Joined
Jan 2, 2016
Messages
973
Thanks for the replies, everyone.
I did what I could:
JASS:
library Jumping requires Misc

  globals
  public constant real Tick = 0.05
  constant real Acceleration = 98.1*Tick
  private timer Ticker = CreateTimer()
  private boolean On = false
  public real X
  public real Y
  public unit Unit
  public boolean End = false
  public integer Index
  public real sqDist
  endglobals

  struct Jumper
  unit u
  real array x[2]
  real array y[2]
  real array z[2]
  real Vz
  real a
  real speed
  integer t
  trigger tr

  readonly thistype next
  readonly thistype prev
  static method operator first takes nothing returns thistype
  return thistype(0).next
  endmethod
  static method operator last takes nothing returns thistype
  return thistype(0).prev
  endmethod

  static method create takes nothing returns thistype
  local thistype this = thistype.allocate()
  set thistype(0).next.prev = this
  set this.next = thistype(0).next
  set this.prev = thistype(0)
  set thistype(0).next = this
  if not On then
  call TimerStart(Ticker, Tick, false, function thistype.jump)
  set On = true
  endif
  return this
  endmethod

  method onDestroy takes nothing returns nothing
  if this.first == this.last then
  set On = false
  endif
  set this.next.prev = this.prev
  set this.prev.next = this.next
  endmethod

  static method jump takes nothing returns nothing
  local thistype this = thistype.first
  local real z
  loop
  exitwhen this == 0
  set sqDist = (this.x[1] - this.x[0])*(this.x[1] - this.x[0]) + (this.y[1] - this.y[0])*(this.y[1] - this.y[0])
  set End = sqDist <= this.speed*this.speed
  set this.t = this.t + 1
  if End then
  set this.x[0] = this.x[1]
  set this.y[0] = this.y[1]
  set z = this.z[1]
  set sqDist = 0
  else
  set this.x[0] = this.x[0] + this.speed*Cos(this.a)
  set this.y[0] = this.y[0] + this.speed*Sin(this.a)
  set z = this.z[1] + this.Vz*this.t - Acceleration*this.t*this.t/2 + (this.z[0] - GetLocZ(this.x[0], this.y[0]))
  endif
  call SetUnitX(this.u, this.x[0])
  call SetUnitY(this.u, this.y[0])
//call BJDebugMsg(R2S(this.z[0] - GetLocZ(this.x[0], this.y[0]))+" + "+R2S(this.z[1] + this.Vz*this.t - Acceleration*this.t*this.t/2))
  call SetUnitFlyHeight(u, z, 100000)
  if this.tr != null then
  set Unit = this.u
  set X = this.x[0]
  set Y = this.y[0]
  set sqDist = (this.x[1] - X)*(this.x[1] - X) + (this.y[1] - Y)*(this.y[1] - Y)
  set Index = this
  call TriggerEvaluate(this.tr)
  endif
  if End then
  call PauseUnit(this.u, false)
  call SetUnitPathing(u, true)
  call thistype.destroy(this)
  endif
  set this = this.next
  endloop
  if On then
  call TimerStart(Ticker, Tick, false, function thistype.jump)
  endif
  endmethod
  endstruct

  function Jump takes unit u, real x, real y, real speed, trigger tr, boolean timed returns Jumper
  local Jumper jump = Jumper.create()
  local real t
  call UnitAddAbility(u, 'Arav')
  call UnitRemoveAbility(u, 'Arav')
  call SetUnitPathing(u, false)
  //call PauseUnit(u, true)
  set jump.u = u
  set jump.x[1] = x
  set jump.y[1] = y
  set jump.x[0] = GetUnitX(u)
  set jump.y[0] = GetUnitY(u)
  set jump.z[0] = GetLocZ(jump.x[0], jump.y[0])
  set jump.z[1] = GetUnitDefaultFlyHeight(u)
  if timed then
  set jump.speed = SquareRoot((jump.x[1] - jump.x[0])*(jump.x[1] - jump.x[0]) + (jump.y[1] - jump.y[0])*(jump.y[1] - jump.y[0]))*Tick/speed
  set t = speed/Tick
  else
  set jump.speed = speed*Tick
  set t = SquareRoot((jump.x[1] - jump.x[0])*(jump.x[1] - jump.x[0]) + (jump.y[1] - jump.y[0])*(jump.y[1] - jump.y[0]))/jump.speed
  endif
  set jump.Vz = (t*Acceleration/2) + (GetLocZ(x,y) - jump.z[0])/t
  set jump.a = Atan2(jump.y[1] - jump.y[0], jump.x[1] - jump.x[0])
  set jump.t = 0
  set jump.tr = tr
  return jump
  endfunction

endlibrary
it still makes "waves" when moving above water sometimes...
Yet the debug message shows normal values. Nothing out of the ordinary, so I guess it's not the trigger's fault xP
I set the Elevation radius to 0, but that didn't help.

Anyways, the way the system is now is good enough, I guess (I'll need to add some conditions and stuff when using it tho).
 
Last edited:
Status
Not open for further replies.
Top