XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов> Jass
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

Закрытая тема
 
Preveder
StarCraft II® Inside
offline
Опыт: 1,927
Активность:
Лагает спелл, нужна помощь
Написал намедни триггерный близнец стандартного близзарда, чтобы колбасить юнитов не в конкретных значениях, а в процентах к текущему хп каждого юнита и персонально вешать замедление 70% на 6 сек.

Протестировал с помощью многократных одновременных вызовов по мобам, и значение фпс за считанные секунды падало с 65 до 18 за 5-10 применений. Видимо, есть утечки. Нужна помощь, копал немало, но обычно добавление удаления точки сразу после создания или ещё где-либо, кроме как в конце, ломало спелл, т.е. заклинание переставало действовать вообще. Судя по всему, подвисал поток. Заюзал кэш впервые, в джассе новичок. Видимо, совсем индийский код получился. Может быть, траббл в том, что цикл для EnumUnit() не удаляет даммиков-слоуверов? Если ставить ремувюнит без слипэкшн, то никакого слоу не наложится. Если проблема действительно в удалении, то стоит ли добавить Expiration Timer каждому даммику? Нужен совет разбирающихся в джассе людей.
ЗЫ: Спеллкаст вызывается другим динамическим триггером, который отслеживает способ запуска спелла (есть активный скилл - с обычными параметрами и пассивный скилл - более мощный, но с малым шансом, естественно, параметры передаются в запускающую функцию).

Код:
//GroupDamage From Blizzard Spell
function SpellBlizzardTarget takes nothing returns nothing
    local unit Caster = GetObjectUparam(null, "caster")
    local real DamagePercent = GetObjectRparam(null, "damagepercent")
    local unit u = CreateUnitAtLoc(GetOwningPlayer(Caster), 'u002', GetUnitLoc(GetEnumUnit()),bj_UNIT_FACING)
    local real Damage = GetUnitStateSwap(UNIT_STATE_LIFE,GetEnumUnit())
    call IssueTargetOrder( u, "slow", GetEnumUnit() )
    set Damage = Damage * DamagePercent
    call UnitDamageTarget(Caster, GetEnumUnit(), Damage, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
    call TriggerSleepAction(0.2)
    call RemoveUnit(u)
    set u = null
    set Caster = null
    set DamagePercent = 0.00
    set Damage = 0.00
endfunction

function SpellBlizzardRuntime takes nothing returns nothing
    local trigger t = GetTriggeringTrigger()
    local integer Waves = GetObjectIparam(t, "waves")
    local integer Angle = GetObjectIparam(t, "angle")
    local integer MaxTimes = GetObjectIparam(t, "maxtimes")
    local integer Times = GetObjectIparam(t, "times")
    local real Radius = GetObjectRparam(t, "radius")
    local unit Caster = GetObjectUparam(t, "caster")
    local real DmgPerTimePercentLife = GetObjectRparam(t, "damagepercent")
    local location TargetPoint = GetObjectLparam(t, "location")
    local integer TempAngle = 0
    local string Model = "Abilities\\Spells\\Human\\Blizzard\\BlizzardTarget.mdl"
    local location WavePoint
    local integer WavesSpawned = 0
    local group Group = CreateGroup()
    local sound Effect = CreateSound("Abilities\\Spells\\Human\\Blizzard\\BlizzardTarget1.wav", false, true, true, 10, 10, "SpellsEAX")
    if Times == MaxTimes then
        call FlushObject(t)
        call FlushObject(null)
        call DestroyGroup(Group)
        call RemoveLocation(WavePoint)
        call DestroyTrigger(t)
        return
    else
        loop //Circle Effects
        exitwhen WavesSpawned == Waves
        set WavesSpawned = WavesSpawned + 1
        set TempAngle = Angle*WavesSpawned
        set WavePoint = PolarOffset(TargetPoint, (Radius*0.35), I2R(TempAngle))
        call AddSpecialEffectLoc(Model, WavePoint)
        call DestroyEffect(GetLastCreatedEffectBJ())
        endloop
    call SetSoundParamsFromLabel(Effect, "BlizzardTarget")
    call SetSoundDuration(Effect, 4000)
    call SetSoundVolume(Effect, 127)
    call SetSoundPosition(Effect, GetLocationX(TargetPoint), GetLocationY(TargetPoint), 0)
    call StartSound(Effect)
    call KillSoundWhenDone(Effect)
    call SetObjectIparam(null, "caster", H2I(Caster))
    call SetObjectRparam(null, "damagepercent", DmgPerTimePercentLife)
    call GroupEnumUnitsInRangeOfLoc(Group, TargetPoint, Radius, Condition(function IsGroundAndBelongToCreeps))
    if IsGroupEmpty(Group) != true then
    call ForGroup(Group, function SpellBlizzardTarget)
    call DestroyGroup(Group)
    else
    call DestroyGroup(Group)
    endif
    call FlushObject(null)
    set Times = Times + 1
    call SetObjectIparam(t, "times", Times)
    endif
set Effect = null
set Group = null
set WavePoint = null
set Model = null
set TempAngle = 0
set Caster = null
set Times = 0
set t = null
set Radius = 0.00
set WavesSpawned = 0
set TargetPoint = null
set DmgPerTimePercentLife = 0.00
set MaxTimes = 0
set Angle = 0
set Waves = 0
call RemoveLocation(WavePoint)
call RemoveLocation(TargetPoint)
endfunction

// Blizzard Rain Spell
function SpellBlizzard takes location TargetPoint, unit Caster, real Radius, integer Waves, real DmgPerTimePercentLife, integer NumTimes returns nothing
    local trigger t = CreateTrigger()
    local integer Angle = 360/Waves
    call TriggerRegisterTimerEvent(t, 0.90, true)
    call TriggerAddAction(t, function SpellBlizzardRuntime)
    call EnableTrigger(t)
    call SetObjectIparam(t, "waves", Waves)
    call SetObjectIparam(t, "maxtimes", NumTimes)
    call SetObjectIparam(t, "times", 0)
    call SetObjectRparam(t, "radius", Radius)
    call SetObjectIparam(t, "angle", Angle)
    call SetObjectIparam(t, "caster", H2I(Caster))
    call SetObjectRparam(t, "damagepercent", DmgPerTimePercentLife)
    call SetObjectIparam(t, "location", H2I(TargetPoint))
    set t = null
    set Angle = 0
    call RemoveLocation(TargetPoint)
endfunction


Preveder добавил:
Тему можно закрыть, уже разобрался сам в этом ужасном потоке кода :)
Старый 18.04.2009, 00:21
Hellfim
Новичок
offline
Опыт: 79,880
Активность:
Preveder, лагает из-за кеша. Я бы посоветовал тебе использовать таймеры, а не триггеры. И аттачить через кэш нельзя, при малых периодах. Например создай по массиву для всех твоих аттачей (Waves,NumTimes...) и для таймера. Потом просто находишь индекс истекшего таймера и достаешь соответствующие ему значение из остальных массивов.
Старый 18.04.2009, 00:29
Preveder
StarCraft II® Inside
offline
Опыт: 1,927
Активность:
Цитата:
Сообщение от Hellfim
Preveder, лагает из-за кеша. Я бы посоветовал тебе использовать таймеры, а не триггеры. И аттачить через кэш нельзя, при малых периодах. Например создай по массиву для всех твоих аттачей (Waves,NumTimes...) и для таймера. Потом просто находишь индекс истекшего таймера и достаешь соответствующие ему значение из остальных массивов.

Период вроде бы не совсем малый... 0.90 сек. Видел спеллы, где кэш использовали и на 0.05 (притягивания вские) и вроде бы не лагало.
Мне помогли следующие преобразования:
к даммикам подставил
Код:
call SetUnitExploded(u,true)
   call UnitApplyTimedLife(u,0,1.00)


спецэффекты заменил более элегантной конструкцией
Код:
call DestroyEffect(AddSpecialEffectLoc(Model, WavePoint))


Ну и убрал обнуление не-хендловых переменных по совету из статьи http://xgm.guru/forum/showthread.php?t=18742


Если проблема в кэше, то это танцы с бубном, конечно, но помогло, как ни странно! Теперь фпс падает только во время самого действа и ненамного (с 65 до 58 примерно) и восстанавливается полностью после окончания спелла. Проверял даже восьмикратным одновременным запуском. Причем суть, видимо, была в неудалявшихся даммиках и эффектах, т.к. проседал фпс только в том случае, если камера висела над местами, где происходил многократный запуск спелла.

В итоге код запуска спелла получился такой:
Код:
function SpellBlizzardTarget takes nothing returns nothing
    local unit Caster = GetObjectUparam(null, "caster")
    local real DamagePercent = GetObjectRparam(null, "damagepercent")
    local unit u = CreateUnitAtLoc(GetOwningPlayer(Caster), 'u002', GetUnitLoc(GetEnumUnit()),bj_UNIT_FACING)
    local real Damage = GetUnitStateSwap(UNIT_STATE_LIFE,GetEnumUnit())
    call IssueTargetOrder( u, "slow", GetEnumUnit() )
    call SetUnitExploded(u,true)
    call UnitApplyTimedLife(u,0,1.00)
    set Damage = Damage * DamagePercent
    call UnitDamageTarget(Caster, GetEnumUnit(), Damage, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
    set u = null
    set Caster = null
 endfunction

function SpellBlizzardRuntime takes nothing returns nothing
    local trigger t = GetTriggeringTrigger()
    local integer Waves = GetObjectIparam(t, "waves")
    local integer Angle = GetObjectIparam(t, "angle")
    local integer MaxTimes = GetObjectIparam(t, "maxtimes")
    local integer Times = GetObjectIparam(t, "times")
    local real Radius = GetObjectRparam(t, "radius")
    local unit Caster = GetObjectUparam(t, "caster")
    local real DmgPerTimePercentLife = GetObjectRparam(t, "damagepercent")
    local location TargetPoint = GetObjectLparam(t, "location")
    local integer TempAngle = 0
    local string Model = "Abilities\\Spells\\Human\\Blizzard\\BlizzardTarget.mdl"
    local location WavePoint
    local integer WavesSpawned = 0
    local group Group = CreateGroup()
    local sound Effect = CreateSound("Abilities\\Spells\\Human\\Blizzard\\BlizzardTarget1.wav", false, true, true, 10, 10, "SpellsEAX")
    if Times == MaxTimes then
        call FlushObject(t)
        call FlushObject(null)
        call DestroyGroup(Group)
        call RemoveLocation(WavePoint)
        call DestroyTrigger(t)
        return
    else
        loop //Circle Effects
        exitwhen WavesSpawned == Waves
        set WavesSpawned = WavesSpawned + 1
        set TempAngle = Angle*WavesSpawned
        set WavePoint = PolarOffset(TargetPoint, (Radius*0.35), I2R(TempAngle))
        call DestroyEffect(AddSpecialEffectLoc(Model, WavePoint))
        endloop
    call SetSoundParamsFromLabel(Effect, "BlizzardTarget")
    call SetSoundDuration(Effect, 4000)
    call SetSoundVolume(Effect, 127)
    call SetSoundPosition(Effect, GetLocationX(TargetPoint), GetLocationY(TargetPoint), 0)
    call StartSound(Effect)
    call KillSoundWhenDone(Effect)
    call SetObjectIparam(null, "caster", H2I(Caster))
    call SetObjectRparam(null, "damagepercent", DmgPerTimePercentLife)
    call GroupEnumUnitsInRangeOfLoc(Group, TargetPoint, Radius, Condition(function IsGroundAndBelongToCreeps))
    if IsGroupEmpty(Group) != true then
    call ForGroup(Group, function SpellBlizzardTarget)
    call DestroyGroup(Group)
    else
    call DestroyGroup(Group)
    endif
    call FlushObject(null)
    set Times = Times + 1
    call SetObjectIparam(t, "times", Times)
    endif
set Effect = null
set Group = null
set WavePoint = null
set Model = null
set Caster = null
set t = null
set TargetPoint = null
call RemoveLocation(WavePoint)
call RemoveLocation(TargetPoint)
endfunction

Отредактировано Preveder, 18.04.2009 в 11:24.
Старый 18.04.2009, 11:14
Артте
Open up your eyes
offline
Опыт: 24,373
Активность:
Сразу виден прогресс, молодец, раз разобрался
Старый 18.04.2009, 11:33
Sunn
To feel joy, not be blue
offline
Опыт: 4,975
Активность:
Код:
set WavePoint = null
set TargetPoint = null
call RemoveLocation(WavePoint)
call RemoveLocation(TargetPoint)

Убейте меня ап стену, если после обнуления указателя при его помощи можно удалять обьект, на который он указывал
Старый 18.04.2009, 13:54
Артте
Open up your eyes
offline
Опыт: 24,373
Активность:
Xenosapien
я скажу почему на это никто не указал..никто не читал код, ибо он слишком громоздкий
Старый 18.04.2009, 14:09
Preveder
StarCraft II® Inside
offline
Опыт: 1,927
Активность:
Цитата:
Сообщение от Xenosapien
Код:
set WavePoint = null
set TargetPoint = null
call RemoveLocation(WavePoint)
call RemoveLocation(TargetPoint)

Убейте меня ап стену, если после обнуления указателя при его помощи можно удалять обьект, на который он указывал

Если ставить ремувы выше обнуления, спелл перестаёт работать. 1 раз польёт дождичком и всё. Вообще, если эти ремувы поставить где-либо, кроме как в самом конце, работать он не будет.
Старый 18.04.2009, 18:22
MF
Что-то вокруг не так
offline
Опыт: 26,594
Активность:
Preveder а если так то утечек у тебя до фига. Если не работает, значит что-то в корне не правильно
Старый 18.04.2009, 18:30
agentex

offline
Опыт: 34,534
Активность:
Цитата:
Цитата:Сообщение от Xenosapien
Код:
set WavePoint = null
set TargetPoint = null
call RemoveLocation(WavePoint)
call RemoveLocation(TargetPoint)

Убейте меня ап стену, если после обнуления указателя при его помощи можно удалять обьект, на который он указывал


Если ставить ремувы выше обнуления, спелл перестаёт работать. 1 раз польёт дождичком и всё. Вообще, если эти ремувы поставить где-либо, кроме как в самом конце, работать он не будет.

извини, но производить операции с обьектом после обнуления его хендла - полный бред)

возможно машина слабая, но врядли лаги изза кеша
Старый 18.04.2009, 19:11
Preveder
StarCraft II® Inside
offline
Опыт: 1,927
Активность:
А если убрать гордость подальше и засунуть следующее:
Код:
сall TriggerSleepAction(10.00)
call RemoveLocation(WavePoint)
call RemoveLocation(TargetPoint)
set WavePoint = null
set TargetPoint = null

Больше 10 секунд у меня ни один близзард не кастится.
ЗЫ: Лаги почти совсем пропали, остался вопрос изящности кода... Спокойно держит 15 одновременных (0.10 задержка перед каждым применением, приказ триггером 15-ти футманам) применений, фпс просаживаются на 5-6 ед. и быстро восстанавливаются обратно.

Отредактировано Preveder, 18.04.2009 в 21:11.
Старый 18.04.2009, 20:59
adic3x

offline
Опыт: 107,539
Активность:
Цитата:
сall TriggerSleepAction(10.00)

вообще то это нельзя использовать в спелах) т.е. его лучше вообще не использовать

ADOLF добавил:
локалки скалярных типов обнулять не нужно

ADOLF добавил:
SCV потенциально багаопасен, кешь можно впринципе юзать нормально, но можно его и не юзать)
Старый 19.04.2009, 13:52
Preveder
StarCraft II® Inside
offline
Опыт: 1,927
Активность:
Прочитав инфу про точки, переделал спелл под координаты ху и отпала нужда ремувить и обнулять.

Интересует принцип удаления локаций. Если мы вызываем функцию, которая создаёт эффект где-либо, а в качестве аргумента укажем следующее:

Код:
call SFXLoc("model_tralala.mdl", GetUnitLoc(u))

function SFXLoc takes string modelfile, location loc returns nothing
   call DestroyEffect(AddSpecialEffect(modelfile, GetLocationX(loc), GetLocationY(loc)))
   call RemoveLocation(loc)
endfunction

Будет ли протекать GetUnitLoc(u) в таком случае? Как я понимаю, одной функцией передаётся ссылка на определённую точку, и она же (эта самая точка с ссылкой) в другой функции удаляется. Локального хендла нет, обнулять не нужно. Так?
Из статьи-дополнения к основной статье по джассу не до конца ясно, утверждается что GetUnitLoc(u) гадит.

Отредактировано Preveder, 20.04.2009 в 10:13.
Старый 20.04.2009, 10:07
adic3x

offline
Опыт: 107,539
Активность:
удалять надо обьекты, обнулять локалки но не аргументы
Старый 20.04.2009, 13:24
agentex

offline
Опыт: 34,534
Активность:
GetUnitLoc создает точку, изза этого утечка. Но если написать так:
Код:
local location l = GetUnitLoc(...)

call RemoveLocation(l)
set l = null

утечки не будет, так как мы заносим созданную точку в локалку и в конце уничтожаем ее. Одно но- точки бред, чем тебе GetUnitX/Y не нравятся?
Старый 20.04.2009, 13:30
adic3x

offline
Опыт: 107,539
Активность:
в примере из поста №12 утечек нет к слову
Старый 20.04.2009, 13:33
Preveder
StarCraft II® Inside
offline
Опыт: 1,927
Активность:
В общем да, задница с точками, однако. Спасибо, буду юзать только координаты.
Старый 20.04.2009, 14:38
Закрытая тема

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 02:30.