- Joined
- Oct 12, 2011
- Messages
- 3,449
Here is an advanced sliding physics I made, for my new map RO2. Not very optimized atm.
Download here
Code (from the attached map above):
Download here
Code (from the attached map above):
JASS:
library SlidePhysics uses TimerUtils, UnitZ
globals
constant real SLOPE_ACCURACY = 0.1
constant real FULL_GRAVITY = 1.5
constant real SLIDER_MASS = 1.0
constant real TAU = bj_PI*2
constant real HP = bj_PI/2
endglobals
function IsInBound takes real x, real y returns boolean
return x < WorldBounds.maxX and x > WorldBounds.minX and y < WorldBounds.maxY and y > WorldBounds.minY
endfunction
struct SlideTerrain extends array
private static TableArray data
static method getFriction takes real x, real y returns real
local integer id = GetTerrainType(x, y)
if thistype.data[0].boolean[id] then
return thistype.data[1].real[id]
endif
return 0.0
endmethod
static method newTerrain takes integer id, real friction returns nothing
if not thistype.data[0].boolean[id] then
set thistype.data[0].boolean[id] = true
set thistype.data[1].real[id] = friction
endif
endmethod
private static method onInit takes nothing returns nothing
set thistype.data = TableArray[2]
endmethod
endstruct
private struct Ground extends array
static real x = 0
static real y = 0
endstruct
struct SlideUnit extends array
readonly unit slider
readonly real x
readonly real y
readonly real z
readonly real zVel
readonly boolean isFlying
real angle
real speed
private static Ground ground
implement Alloc
private static method getSlope takes real x1, real y1, real x2, real y2 returns real
return 1.571*((GetTerrainZ(x1, y1)-GetTerrainZ(x2, y2))/SLOPE_ACCURACY)
endmethod
private static method circularDifference takes real a, real b returns real
local real diff = RAbsBJ(a-b)
if diff*2 <= TAU then
return diff
else
return TAU - diff
endif
endmethod
private static method normalize takes real a returns real
loop
if a < 0 then
set a = a + TAU
elseif a > TAU then
set a = a - TAU
else
exitwhen true
endif
endloop
return a
endmethod
private static method onPeriodic takes nothing returns nothing
local real slope
local real slope2
local unit u
local real px
local real py
local real d1
local real d2
local real d3
local real sx
local real sy
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if not .isFlying then
call .getLowestGr()
set slope = getSlope(.x, .y, ground.x, ground.y)
if slope != 0 then
call slip(FULL_GRAVITY*slope, 25, Atan2(ground.y-.y, ground.x-.x), 2*bj_DEGTORAD)
endif
endif
if .speed > 0 then
if not .isFlying then
set .speed = .speed - SlideTerrain.getFriction(.x, .y)
endif
if .speed > 0 then
if IsInBound(.x, .y) then
if IsTerrainWalkable(.x, .y) then
set px = .x
set py = .y
set sx = .x + SLOPE_ACCURACY * Cos(.angle)
set sy = .y + SLOPE_ACCURACY * Sin(.angle)
set slope = getSlope(sx, sy, .x, .y)
set .x = .x + .speed * Cos(.angle)
set .y = .y + .speed * Sin(.angle)
call SetUnitX(.slider, .x)
call SetUnitY(.slider, .y)
if .isFlying then
set .z = .z + .zVel
set .zVel = .zVel - (FULL_GRAVITY+SLIDER_MASS)
call SetUnitZ(.slider, .z)
if .z <= GetTerrainZ(.x, .y) + 0.01 then
set .isFlying = false
set d1 = Atan(RAbsBJ(.zVel)/.speed)
set d2 = Atan((GetTerrainZ(.x, .y)-GetTerrainZ(px, py))/.speed)
set d3 = bj_PI-d1-d2
set .speed = .speed * (d3/HP-1)
endif
else
set sx = .x - SLOPE_ACCURACY * Cos(.angle)
set sy = .y - SLOPE_ACCURACY * Sin(.angle)
set slope2 = getSlope(.x, .y, sx, sy)
if slope > slope2 and slope - slope2 > bj_DEGTORAD*5 then
set .zVel = .speed * Sin(slope)
if .zVel > (FULL_GRAVITY+SLIDER_MASS+(GetTerrainZ(.x, .y)-GetTerrainZ(sx, sy))) then
set .isFlying = true
set .z = GetUnitZ(.slider)
endif
endif
endif
else//if .speed > stun speed then
// stun
endif
endif
else
set .speed = 0
endif
endif
set t = null
endmethod
private method getLowestGr takes nothing returns nothing
local real x
local real y
local real z
local real angle = 0
local real lowest = GetTerrainZ(.x, .y)
set ground.x = .x
set ground.y = .y
loop
exitwhen angle >= TAU
set x = .x + SLOPE_ACCURACY*Cos(angle)
set y = .y + SLOPE_ACCURACY*Sin(angle)
set z = GetTerrainZ(x, y)
if z < lowest then
set lowest = z
set ground.x = x
set ground.y = y
endif
set angle = angle + bj_DEGTORAD
endloop
endmethod
method turn takes real targetAngle, real turnRate returns nothing
if Cos(.angle - targetAngle) < Cos(turnRate) then
if Sin(targetAngle - .angle) >= 0 then
set .angle = normalize(.angle + turnRate)
else
set .angle = normalize(.angle - turnRate)
endif
else
set .angle = normalize(targetAngle)
endif
endmethod
method accelerate takes real speed, real maxspeed, real angle, real rate returns nothing
local real diff
local real turnPow
local real spdPow
set angle = normalize(angle)
if .speed <= 0 then
set .angle = angle
if .speed < maxspeed then
set .speed = speed
endif
else
set diff = circularDifference(angle, .angle)
set turnPow = RAbsBJ(circularDifference(diff, HP))
set turnPow = 1-turnPow/HP
call .turn(angle, rate*turnPow)
set spdPow = 1-diff*(2/bj_PI)
if spdPow < 0 or .speed < maxspeed then
set .speed = .speed + speed*spdPow
if .speed > maxspeed and spdPow >= 0 then
set .speed = maxspeed
endif
if .speed < 0 then
set .angle = angle
set .speed = -.speed
endif
endif
endif
endmethod
method slip takes real speed, real maxspeed, real angle, real rate returns nothing
local real diff
local real turnPow
local real spdPow
set angle = normalize(angle)
set diff = circularDifference(angle, .angle)
set turnPow = RAbsBJ(circularDifference(diff, HP))
set turnPow = 1-turnPow/HP
call .turn(angle, rate*turnPow)
set spdPow = 1-diff*(2/bj_PI)
if spdPow < 0 or .speed < maxspeed then
set .speed = .speed + speed*spdPow
if spdPow >= 0 and .speed > maxspeed then
set .speed = maxspeed
endif
if .speed < 0 then
set .angle = angle
set .speed = .speed+speed
endif
endif
endmethod
static method newSlider takes unit whichUnit returns thistype
local thistype this = allocate()
set .slider = whichUnit
set .isFlying = false
set .speed = 0
set .angle = GetUnitFacing(whichUnit)*bj_DEGTORAD
set .x = GetUnitX(whichUnit)
set .y = GetUnitY(whichUnit)
set .z = 0
call SetUnitTimeScale(whichUnit, 0.75)
call TimerStart(NewTimerEx(this), 0.0312500, true, function thistype.onPeriodic)
return this
endmethod
endstruct
endlibrary
Last edited: