Пятница, 03.05.2024, 17:43


Главная
Регистрация
Вход
Dota Allstars ✪ World of WarCraft Приветствую Вас Гость | RSS  
Меню сайта

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Главная » Статьи » Dota Allstars » Полезные статьи

WarCraft 3: [vJass]:Последние шаги
WarCraft 3: [vJass]:Последние шаги                                                                                                                               

  • Последние шаги
Теперь осталось научиться добавлять тело в этот стек. Для этого в структуру 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 // при первой записи, элемент запишется в ячейку 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
...

Заключение

Скелет системы готов, теперь на него можно наращивать остальные части, например: притяжение к земле, трение, столкновения с другими телами. В карте примере находится эта система, но уже с сухим трением и притяжением к земле.
Категория: Полезные статьи | Добавил: TRACTOR (29.05.2012)
Просмотров: 584 | Рейтинг: 0.0/0
Вход на сайт

Поиск

Copyright MyCorp © 2024Сделать бесплатный сайт с uCoz