Теперь осталось научиться добавлять тело в этот стек. Для этого в структуру
body добавьте такой метод:
method Start takes nothing returns boolean
if mvs_si < 1000 then
set mvs_si = mvs_si + 1
set mvs_Sb[mvs_si] = this
return true
else
return false
endif
endmethod
Теперь можно создать тело, задать ему начальные параметры и поместить в
движок с помощью этого метода.
Последний штрих – сделать пространство
объемным. Для этого к z юнита прибавлять разницу высот. Тогда главная часть
движка примет вид:
globals
body array mvs_Sb [1000]
integer mvs_si = -1
location GZL = Location(0,0)
endglobals
function GetZ takes real X, real Y returns real
call MoveLocation(GZL,X,Y)
return GetLocationZ(GZL)
endfunction
private function Engine takes nothing returns nothing
local integer i = 0
local body b
loop
exitwhen i > mvs_si
if mvs_Sb__ != 0 then
set b = mvs_Sb__
if b.m > 0 then
set b.a.x = b.f.x/b.m
set b.a.y = b.f.y/b.m
set b.a.z = b.f.z/b.m
endif
set b.f.x = 0
set b.f.y = 0
set b.f.z = 0
set b.v.x = b.v.x + b.a.x
set b.v.y = b.v.y + b.a.y
set b.v.z = b.v.z + b.a.z
call SetUnitFlyHeight(b.u,GetUnitFlyHeight(b.u) - GetZ(GetUnitX(b.u) + b.v.x*0.025,GetUnitY(b.u) + b.v.y*0.025) + GetZ(GetUnitX(b.u),GetUnitY(b.u)),0)
call SetUnitX(b.u, GetUnitX(b.u) + b.v.x*0.025)
call SetUnitY(b.u, GetUnitY(b.u) + b.v.y*0.025)
call SetUnitFlyHeight(b.u, GetUnitFlyHeight(b.u) + b.v.z*0.025,0)
else
set mvs_Sb__ = mvs_Sb[mvs_si]
set mvs_Sb[mvs_si] = 0
set mvs_si = mvs_si - 1
set i = i - 1
endif
set i = i + 1
endloop
endfunction
function IniMove takes nothing returns nothing
call TimerStart(CreateTimer(), 0.025, true, function Engine)
endfunction
А в метод уничтожения тела корректируем вот так (при удалении в стеке все
равно остается записано тело, точнее integer - номер ячейки где он хранился. ).
На самом деле все переменные, ссылающиеся на структуру, являются типом integer,
который есть номер ячейки массива, в котором вар хранит структуру:
method Destroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i > mvs_si
if mvs_Sb__ == this then
set mvs_Sb__ = mvs_Sb[mvs_si]
set mvs_Sb[mvs_si] = 0
set mvs_si = mvs_si - 1
set i = mvs_si
endif
set i = i + 1
endloop
call this.v.destroy()
call this.a.destroy()
call this.f.destroy()
call this.destroy()
endmethod
Добавляем физические явления (удар об землю, трение и т.п.)
Теперь создадим отдел параметров системы для удобства настройки:
library MoveSys initializer IniMove
// Параметры системы, обычно их сюда помещают для удобства настройки системы
globals
private real g = 14
private real Rest = 0.4
private real mu = 0.4
endglobals
..
.
endlibrary
Советую всегда при создании систем выносить коэффициенты к заголовку
библиотеки и давать пояснительные комментарии к ним. Это поможет разобраться в
собственной системе через несколько месяцев.
Теперь удары об землю и
границы карты:
private function Engine takes nothing returns nothing
local integer i = 0
local body b
local real x
local real y
loop
exitwhen i > mvs_si
if mvs_Sb__ != 0 then
set b = mvs_Sb__
if GetUnitFlyHeight(b.u) < 2 then
if b.v.z < 0 then
set b.v.z = - b.v.z*Rest
endif
endif
set x = GetUnitX(b.u)
set y = GetUnitY(b.u)
if x < minX then
call SetUnitX(b.u,minX)
elseif x > maxX then
call SetUnitX(b.u,maxX)
endif
if y < minY then
call SetUnitY(b.u,minY)
elseif y > maxY then
call SetUnitY(b.u,maxY)
endif
if b.m > 0 then
set b.a.x = b.f.x/b.m
set b.a.y = b.f.y/b.m
set b.a.z = b.f.z/b.m - g
endif
...
globals
private real maxX
private real maxY
private real minX
private real minY
endglobasl
function IniMove takes nothing returns nothing
call TimerStart(CreateTimer(), 0.025, true, function Engine)
set maxX = GetRectMaxX(bj_mapInitialPlayableArea)
set maxY = GetRectMaxY(bj_mapInitialPlayableArea)
set minX = GetRectMinX(bj_mapInitialPlayableArea)
set minY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
Сейчас добавим сухое трение:
Принцип такой, если на тело
действует сила больше mu*(mg-Fz), тогда вычитаем из вектора силы тела силу
трения, иначе отнимаем от скорости эту величину деленную на массу:
private function Engine takes nothing returns nothing
local integer i = 0
local body b
local real x
local real y
loop
exitwhen i > mvs_si
if mvs_Sb__ != 0 then
set b = mvs_Sb__
if GetUnitFlyHeight(b.u) < 2 then
if b.v.z < 0 then
set b.v.z = - b.v.z*Rest
endif
if b.m > 0 then
if SquareRoot(b.f.x*b.f.x + b.f.y*b.f.y) > mu*(b.m*g - b.f.z) then
set b.f.x = b.f.x - b.f.x*mu*(b.m*g - b.f.z)/b.f.Module()
set b.f.y = b.f.y - b.f.y*mu*(b.m*g - b.f.z)/b.f.Module()
elseif SquareRoot(b.v.x*b.v.x + b.v.y*b.v.y) < RAbsBJ(mu*(b.m*g - b.f.z))/b.m then
set b.v.x = 0
set b.v.y = 0
else
if RAbsBJ(b.v.x) > 0 then
set b.v.x = b.v.x - b.v.x*mu*(b.m*g - b.f.z)/(b.v.Module()*b.m)
endif
if RAbsBJ(b.v.y) > 0 then
set b.v.y = b.v.y - b.v.y*mu*(b.m*g - b.f.z)/(b.v.Module()*b.m)
endif
endif
endif
endif
set x = GetUnitX(b.u)
set y = GetUnitY(b.u)
if x < minX then
call SetUnitX(b.u,minX)
elseif x > maxX then
call SetUnitX(b.u,maxX)
endif
if y < minY then
call SetUnitY(b.u,minY)
elseif y > maxY then
call SetUnitY(b.u,maxY)
endif
...
Заключение
Скелет системы готов, теперь на него можно наращивать остальные части,
например: притяжение к земле, трение, столкновения с другими телами. В карте
примере находится эта система, но уже с сухим трением и притяжением к земле.