Добавлен NCrashed,
опубликован
[vJass] Создание moving system
Содержание:
Теперь осталось научиться добавлять тело в этот стек. Для этого в структуру 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 юнита прибавлять разницу высот. Тогда главная часть движка примет вид:
Последний штрих – сделать пространство объемным. Для этого к z юнита прибавлять разницу высот. Тогда главная часть движка примет вид:
globals
body array mvs_Sb [1000]
integer mvs_si = -1 // при первой записи, элемент запишется в ячейку 0
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 // Опа! Нашли удаленный с помощью body.Remove() элемент массива. Приговор: удалить и закрыть дырку последним элементом.
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
// нам таймер в глобалку сохранять незачем, так как он работает всю игру
// периoд 0.025 выбран в результате практики, при 0.05 видны "рывки"
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
// Параметры системы, обычно их сюда помещают для удобства настройки системы
// private - переменная будет доступна только внутри библиотеки
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 // на этой оси еще действует mg
endif
...
globals
private real maxX
private real maxY
private real minX
private real minY
endglobasl
function IniMove takes nothing returns nothing
// нам таймер в глобалку сохранять незачем, так как он работает всю игру
// периoд 0.025 выбран в результате практики, при 0.05 видны "рывки"
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
...
Заключение
Скелет системы готов, теперь на него можно наращивать остальные части, например: притяжение к земле, трение, столкновения с другими телами. В карте примере находится эта система, но уже с сухим трением и притяжением к земле. Для примера я сделал на основе этой системы способность «Прыжок», чтобы показать систему в действии. Теперь, освоив эту статью, вы можете легко делать реалистичные заклинания. Идеи черпал из моей физической библиотеки «Fisics Dynamik System», по сути, это та же система, но усложненная.
Пример: MoveSys.w3x (28.1 Кбайт)
Содержание
`
ОЖИДАНИЕ РЕКЛАМЫ...
Комментарии пока отсутcтвуют.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.