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


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

Статистика

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

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

Stomp спелл:Функция обработки движения
Stomp спелл:Функция обработки движения                                                                              
 


Функция обработки движения

Теперь, когда главная функция, которая наносит урон и запускает таймер, сделана, мы приступаем к следующему этапу: созданию циклической функции движения.
А начнем мы с извлечения из кеша данных, сохраненных другой функцией:
function Stomp_Move takes nothing returns nothing
local string s = I2S(H2I(GetExpiredTimer()))
local gamecache gc = udg_AbilityCache
local real x = GetStoredReal(gc, s, "x")
local real y = GetStoredReal(gc, s, "y")
local integer i = GetStoredInteger(gc, s, "level")
local group g = Stomp_CopyGroup(I2G(GetStoredInteger(gc, s, "group")))
...
Вам следует обратить особое внимание на некоторые участки этого фрагмента кода.
Во-первых, мы не записываем истекший таймер в отдельную переменную, мы напрямую используем значение, сохраненное в кэше (за исключением единственного случая, когда нам надо будет уничтожить таймер), так как он будет нужен нам только один раз при каждом выполнении функции. Мы не записываем группу в отдельную переменную по тем же причинам. Мы берем значение из кэша и копируем его в переменную g.
Загрузка из кэша оригинала группы и его модифицирование, является очень распространенной ошибкой JASS спеллов, вроде этого. Некоторые думают, что при следующем срабатывании таймера, загрузится та же группа, содержащая тех же юнитов, даже если они удаляют юнитов из группы и уничтожаю ее. Но это далеко не так.
Например, если вы убьете юнита, прикрепленного к таймеру, юнит будет мертв и при следующем срабатывании этого таймера. То же самое происходит и с группами и всеми другими объектами.
Спелл отталкивает юнита назад, в течении определенного промежутка времени, таким образом, чтобы отследить сколько времени спелл уже отталкивает юнита, нам потребуется еще одна переменная.
function Stomp_Move takes nothing returns nothing
local string s = I2S(H2I(GetExpiredTimer()))
local gamecache gc = udg_AbilityCache
local real x = GetStoredReal(gc, s, "x")
local real y = GetStoredReal(gc, s, "y")
local integer i = GetStoredInteger(gc, s, "level")
local group g = Stomp_CopyGroup(I2G(GetStoredInteger(gc, s, "group")))
local real dur = GetStoredReal(gc, s, "dur")+0.05
if dur < 1+0.5*i then
else
endif
...
Я добавил переменную dur типа real. В нее загружается значение, прикрепленное к таймеру с меткой 'dur' и затем ее значению увеличивается на +0.05 (временной интервал таймера).
Если вы загружаете НЕ сохраненное значение из кэша, то загруженное значение всегда будет равно 0/0.0/"" или null, в зависимости от типа.
Этот спелл толкает юнитов на протяжении 1+0.5*i (i – уровень спелла) секунд, так что нам требуется добавить блок if/then/else.
Ну что ж, давайте, добавим часть кода, которая непосредственно двигает юнитов, на которых действует спелл. Для этого добавим следующие переменные: real ux, real uy, real a, unit f.
function Stomp_Move takes nothing returns nothing
local string s = I2S(H2I(GetExpiredTimer()))
local gamecache gc = udg_AbilityCache
local real x = GetStoredReal(gc, s, "x")
local real y = GetStoredReal(gc, s, "y")
local integer i = GetStoredInteger(gc, s, "level")
local group g = Stomp_CopyGroup(I2G(GetStoredInteger(gc, s, "group")))
local real dur = GetStoredReal(gc, s, "dur")+0.05
local real ux
local real uy
local real a
local unit f
if dur < 1+0.5*i then
loop
set f = FirstOfGroup(g)
exitwhen f == null
set ux = GetUnitX(f)
set uy = GetUnitY(f)
set a = Atan2(uy-y, ux-x)
call SetUnitPosition(f, ux+40*Cos(a), uy+40*Sin(a))
call GroupRemoveUnit(g, f)
endloop
call StoreReal(gc, s, "dur", dur)
else
endif
...
Как и в главной функции, мы циклически перебираем всех юнитов группы, используя функцию FirstOfGroup().
Для начала, нам нужно сохранить координаты юнита.
Затем мы вычисляем угол (в радианах) между эпицентром спелла и позицией юнита, используя функцию Atan2.
Я не буду рассказывать, как эта функция устроена, я лучше расскажу, как нам ее правильно использовать.
Попросту используйте конструкцию вида Atan2(otherPointY-centerPointY, otherPointX-centerPointX), чтобы получить угол (в радианах) между точками centerPoint и otherPoint.
Спелл должен передвигать юнита. Существует два различных (лучших) способа передвигать юнита:
SetUnitPosition – Эта native функция передвигает юнита в точку с координатами X и Y. Пока юнит передвигается, он не может двигаться и кастовать канальные (channeling) спеллы и вообще ведет себя как будто остановлен. Эта функция не требует дополнительных проверок, и она полностью безопасна.
SetUnitX/Y – Native функции SetUnitX и SetUnitY также меняют X и Y координаты юнита. Однако, юнит не прекращает двигаться, кастовать канальные спеллы и так далее, во время движения. Эти функции работают быстрее, чем SetUnitPosition, но если вы используете координаты за пределами карты, игра вылетит.
Здесь я использую функцию SetUnitPosition для передвижения юнита на 40 единиц, всякий раз, когда таймер срабатывает. Это значит, что скорость движения будет 40*100*0.05 = 800. Применение именно этой функции, в данном случае, проще, так как не требует дополнительных проверок, но главной причиной, по которой я использую эту функцию, является то, что юниты не могут двигаться, пока таймер толкает их, и все возможные касты канальных спеллов, будут остановлены. Следовательно, эта функция идеальна для этого спелла.
Я также сохраняю переменную dur, значение которой увеличивается и сохраняется в кэш всякий раз, когда таймер срабатывает. Иначе действие спелла длилось бы бесконечно долго.
Когда время действия спелла истекает, он должен остановится. Так что нам требуется добавить код, который очистит значения в кэше, уничтожит группу и остановит таймер.
function Stomp_Move takes nothing returns nothing
local string s = I2S(H2I(GetExpiredTimer()))
local gamecache gc = udg_AbilityCache
local real x = GetStoredReal(gc, s, "x")
local real y = GetStoredReal(gc, s, "y")
local integer i = GetStoredInteger(gc, s, "level")
local group g = Stomp_CopyGroup(I2G(GetStoredInteger(gc, s, "group")))
local real dur = GetStoredReal(gc, s, "dur")+0.05
local real ux
local real uy
local real a
local unit f
if dur < 1+0.5*i then
loop
set f = FirstOfGroup(g)
exitwhen f == null
set ux = GetUnitX(f)
set uy = GetUnitY(f)
set a = Atan2(uy-y, ux-x)
call SetUnitPosition(f, ux+40*Cos(a), uy+40*Sin(a))
call GroupRemoveUnit(g, f)
endloop
call StoreReal(gc, s, "dur", dur)
else
call DestroyGroup(I2G(GetStoredInteger(gc, s, "group")))
call FlushStoredMission(gc, s)
call DestroyTimer(GetExpiredTimer())
endif
...

Сначала, мы уничтожаем группу юнитов, сохраненную в кэше.
Затем полностью очищаем категорию s в кэше. Это действие очищает все данные, которые мы 'прикрепили' к таймеру, таким образом, мы исключаем повторное использование этих данных другими спеллами в дальнейшем.
И в завершении, мы уничтожаем истекший таймер.
Теперь все что нам осталось сделать в этой функции – устранить утечки памяти. Давайте сделаем это:
function Stomp_Move takes nothing returns nothing
local string s = I2S(H2I(GetExpiredTimer()))
local gamecache gc = udg_AbilityCache
local real x = GetStoredReal(gc, s, "x")
local real y = GetStoredReal(gc, s, "y")
local integer i = GetStoredInteger(gc, s, "level")
local group g = Stomp_CopyGroup(I2G(GetStoredInteger(gc, s, "group")))
local real dur = GetStoredReal(gc, s, "dur")+0.05
local real ux
local real uy
local real a
local unit f
if dur < 1+0.5*i then
loop
set f = FirstOfGroup(g)
exitwhen f == null
set ux = GetUnitX(f)
set uy = GetUnitY(f)
set a = Atan2(uy-y, ux-x)
call SetUnitPosition(f, ux+40*Cos(a), uy+40*Sin(a))
call GroupRemoveUnit(g, f)
endloop
call StoreReal(gc, s, "dur", dur)
else
call DestroyGroup(I2G(GetStoredInteger(gc, s, "group")))
call FlushStoredMission(gc, s)
call DestroyTimer(GetExpiredTimer())
endif
set gc = null
call DestroyGroup(g)
set g = null
set f = null
endfunction


Вот и все! Вы успешно завершили создании своего собственного stomp спелла.
Вот полный код нашего триггера:

function Trig_Stomp_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction
function Stomp_Filter takes nothing returns boolean
return IsPlayerEnemy(GetOwningPlayer(GetTriggerUnit()), GetOwningPlayer(GetFilterUnit())) and GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING)
endfunction
function Stomp_CopyGroup takes group g returns group
set bj_groupAddGroupDest = CreateGroup()
call ForGroup(g, function GroupAddGroupEnum)
return bj_groupAddGroupDest
endfunction
function Stomp_Move takes nothing returns nothing
local string s = I2S(H2I(GetExpiredTimer()))
local gamecache gc = udg_AbilityCache
local real x = GetStoredReal(gc, s, "x")
local real y = GetStoredReal(gc, s, "y")
local integer i = GetStoredInteger(gc, s, "level")
local group g = Stomp_CopyGroup(I2G(GetStoredInteger(gc, s, "group")))
local real dur = GetStoredReal(gc, s, "dur")+0.05
local real ux
local real uy
local real a
local unit f
if dur < 1+0.5*i then
loop
set f = FirstOfGroup(g)
exitwhen f == null
set ux = GetUnitX(f)
set uy = GetUnitY(f)
set a = Atan2(uy-y, ux-x)
call SetUnitPosition(f, ux+40*Cos(a), uy+40*Sin(a))
call GroupRemoveUnit(g, f)
endloop
call StoreReal(gc, s, "dur", dur)
else
call DestroyGroup(I2G(GetStoredInteger(gc, s, "group")))
call FlushStoredMission(gc, s)
call DestroyTimer(GetExpiredTimer())
endif
set gc = null
call DestroyGroup(g)
set g = null
set f = null
endfunction
function Trig_Stomp_Actions takes nothing returns nothing
local unit c = GetTriggerUnit()
local real x = GetUnitX(c)
local real y = GetUnitY(c)
local integer i = GetUnitAbilityLevel(c, 'A000')
local boolexpr b = Condition(function Stomp_Filter)
local group g = CreateGroup()
local group n
local unit f
local gamecache gc = udg_AbilityCache
local timer t = CreateTimer()
local string s = I2S(H2I(t))
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl", x, y))
call GroupEnumUnitsInRange(g, x, y, 100+50*i, b)
set n = Stomp_CopyGroup(g)
loop
set f = FirstOfGroup(n)
exitwhen f == null
call UnitDamageTarget(c, f, 25*i, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)
call GroupRemoveUnit(n, f)
endloop
call StoreInteger(gc, s, "level", i)
call StoreInteger(gc, s, "group", H2I(g))
call StoreReal(gc, s, "x", x)
call StoreReal(gc, s, "y", y)
call TimerStart(t, 0.05, true, function Stomp_Move)
set c = null
call DestroyBoolExpr(b)
set b = null
set g = null
call DestroyGroup(n)
set n = null
set f = null
set gc = null
set t = null
endfunction
//===========================================================================
function InitTrig_Stomp takes nothing returns nothing
set gg_trg_Stomp = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Stomp, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Stomp, Condition( function Trig_Stomp_Conditions ) )
call TriggerAddAction( gg_trg_Stomp, function Trig_Stomp_Actions )
call Preload("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl")
endfunction
Категория: Полезные статьи | Добавил: TRACTOR (24.04.2012)
Просмотров: 520 | Рейтинг: 0.0/0
Вход на сайт

Поиск

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