Вопрос, какая система снарядов будет наиболее производительной?
Хочу рассмотреть вообще абсолютно все варианты, под Bullet Hell я имею ввиду стадию босса когда миллион снарядов летит от 1 или нескольких источников и игрок должен уклоняться от всего этого месива.

Какие я знаю варианты:

  1. Дефолтный скилл рексара стадо ящериц, он там проблемы с углом поворота и настройками в целом, самый примитивный но норм
  2. Система снарядов:
    • 1 таймер на движение всех снарядов
    • перебор группы в которой ищется враг вокруг снаряда в определённом радиусе
  3. Система снарядов для 1 игрока
    • тот же перебор таймером
    • но столкновение определяется через IsunitInrange (снаряд, наш герой)
  1. Система снарядов + аура жара (мой фаворит):
  • снаряды снова летят на таймере
  • в качестве столкновения используется событие получения урона 131 патча, сами же снаряды излучают жар преисподни (постоянный)
  1. Медленные волны силы/ тёмные стаи:
  • 1 дамми кастует заклинание в указанную точку
  • к сожелению период урона в таком случае странный и снаряд не будет умирать при столкновении с героем
Из требований будут скорее всего такие параметры:
  • одновременное число снарядов от 10 до 300
  • скорость снарядов от 200 до 1000
Я понимаю, что работать будет прекрасно даже если каждый из 100 снарядов посадить на отдельный таймер, но всё же... какой способ самый оптимальный для слабых пк.
Если есть другие варианты реализации - пишите в комменты

то скорость разная, то вылетают не из героя а из какой то псевдо центральной точки
в общем я полностью добился желаемого результата, никакого прерывания, ни каких лагов и странных поведений (то что снаряды врезаются в трупы так и задумано =))
вот мой код
//! beginusercode

--какие то общие функции
function MoveX (x,  Dist,  Angle)
    return x+Dist*Cos(Angle*0.0175)
end
function MoveY (x,  Dist,  Angle)
    return x+Dist*Sin(Angle*0.0175)
end
function AbilityId(id)
    return id:byte(1) * 0x1000000 + id:byte(2) * 0x10000 + id:byte(3) * 0x100 + id:byte(4)
end

function Out(x,y)
    return ( ( GetRectMinX(bj_mapInitialPlayableArea) <= x ) and ( x <= GetRectMaxX(bj_mapInitialPlayableArea) ) and ( GetRectMinY(bj_mapInitialPlayableArea) <= y ) and ( y <= GetRectMaxY(bj_mapInitialPlayableArea) ) ) or IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) == false
end

GetTerrainZ_location = Location(0, 0)
function GetTerrainZ(x,y)
    MoveLocation(GetTerrainZ_location, x, y);
    return GetLocationZ(GetTerrainZ_location);
end

function ehandler( err )
    print( "ERROR:", err )
end
--/////// глобалки (хотя какая разница где объявить то)
perebor=CreateGroup()

--/////// триггер

    local trigger = CreateTrigger()
    for i = 0, bj_MAX_PLAYER_SLOTS - 1, 1 do
        TriggerRegisterPlayerUnitEvent(trigger, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT)
    end
    TriggerAddCondition(trigger, Condition(function() return
        GetOwningPlayer(GetTriggerUnit()) == Player(0)
    end))
local d=0
TriggerAddAction(trigger, function()
    local u=GetTriggerUnit()
    local z=GetTerrainZ(GetUnitX(u),GetUnitY(u))
        print("perodstart")
        TimerStart(CreateTimer(), 0.1, true, function()
        d=d+1

 --print("abiclick "..d)
 -- будущая фукция запуска снаряда
 local x=GetUnitX(u)
 local y=GetUnitY(u)
 local eff=AddSpecialEffect("Abilities\\Weapons\\DemolisherFireMissile\\DemolisherFireMissile.mdl", x, y)
 local d2=1000
 local a=GetUnitFacing(u)

 TimerStart(CreateTimer(), 0.032, true, function()
 d2=d2-10
 x=MoveX(x,25,a)
 y=MoveY(y,25,a)
 BlzSetSpecialEffectPosition(eff, x, y, GetTerrainZ(x,y)+30)
-- урон
local e=nil
GroupEnumUnitsInRange(perebor,x,y,80,null)
while true do
	e = FirstOfGroup(perebor)
	if e == nil then break end
if IsUnitEnemy(e, GetOwningPlayer(u)) then
    UnitDamageTarget( u, e, BlzGetUnitBaseDamage(u, 1), false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, WEAPON_TYPE_WHOKNOWS )
   -- print("наносим урон")
    DestroyEffect(eff)
    eff=nill 
end

	GroupRemoveUnit(perebor,e)
end

--print(d2)

 if d2<=0 or  Out(x,y)==false or eff==nil then
  --  print("УМРИ!")
    DestroyEffect(eff)
    DestroyTimer(GetExpiredTimer())
 end

 end)

    end)
end)





//! endusercode
а вот и карта
Выражаю огромную благодарность NazarPunk, и Prog за оказанную помощь и наставления
Выводы:
Более навороченные (в техническом плане) способы не всегда самые оптимальные
Точно также можно двигать эффекты и на мемхаке, так что 126 пат так же может удостоится высокой производительностью для огромного количества снарядов
Мой комп держит на 1 экране около 700 объектов в режиме 60+ FPS (с отключенной вертикальной синхронизацией, это когда макс фпс за 200)
Загруженные файлы
`
ОЖИДАНИЕ РЕКЛАМЫ...
30
Из детекта, мне тоже больше нравится аура жара
А таймеры я бы создавал на группу снарядов, например: кольцо снарядов, линия снарядов, змейка и т.д. Так меньше мороки с кодом и по хэндлу таймера например, можно менять поведение всей группе, не заморачиваясь с лишними переборами.
28
Из детекта, мне тоже больше нравится аура жара
Мой опыт показывает, что GroupEnumUnitsInRange() показывает себя лучше, меньше лагов. А также, насколько мне изветстно, жары от одинаковых способностей не складываются.
C остальным согласен.
Медленные волны силы/ тёмные стаи
Не используй это, из-за скорости снаряда урон иногда может вообще не проходить или наноситься там, где его раньше не было. Поставь скорость на 2048, длину на 448, пусти сначала одну волну, через 0.4 секунды вторую - вторая не нанесёт урона. Снизь скорость до 1050 - вторая волна нанесёт урон.
21
Насколько знаю, большое количество Жаров может приводить к фаталу.
33
ScopteRectuS, с этого момента по подробней, мб они поэтому и фаталят, потому что какие то лимиты в движке, например связаны с частым тиком урона
30
Bergi_Bear, всё никак немогу привыкнуть, что в новом патче эффекты можно в трёх плокостях вращать. Можно ещё оптимизировать и икать столкновения таймером помедленнее, держа координаты эффектов в таблице.
11
Bergi_Bear, могли бы объяснить механику снарядов через жар преисподней?
33
PT153, ну волны конечно не собирался использовать, но спасибо за инфу, очень прошу NazarPunk, сделать такую систему на луа
wetalq, Как-то так
Каждый снаряд излучает ауру жара, она же аура соприкосновения с ним, и как только снаряд нанесёт урон, значит врезался, новое событие позволяет отследить этот момент соприкосновения, и можно изменить урон, отследить сам снаряд (уничтожит его или отклонить траекторию полёта)
28
А также, насколько мне изветстно, жары от одинаковых способностей не складываются.
Это так или нет?
30
очень прошу NazarPunk, сделать такую систему на луа
Сделаем, с движением снарядов на lua я уже разобрался)
16
я давным-давно пытался скилл тинкера на гоблинов закодить, лагает жутко, на двух кастах юнит уже ходить не может - предел двигаемых юнитов за одного игрока. В новых патчах лимит подняли, там зависать не должно. А еще в новых можно на эффектах, но коллизии самостоятельно регистрировать нужно как-то. Очевидно, что узкое место будет именно это.
15
А как вы выяснили, что Жар Преисподней оптимальный по производительности вариант? Каким алгоритмом игра ищет юнитов вокруг ауры?
28
Мой опыт показывает, что GroupEnumUnitsInRange() показывает себя лучше, меньше лагов.
Это логично хотя бы по той причине, что скорее всего жар и GroupEnumUnitsInRange() ищут юнитов вокруг одинаковым способом, но жар ещё и урон наносит.
Для оптимизации, кол-во юнитов вокруг можно считать в фильтре GroupEnumUnitsInRange(), а в группу ничего не добавлять.
33
JackFastGame, это и собираемся выяснить, ещё не тестировалось особо, но жар перебирает юнитов движком игры, а не таймером+группой
Maniac_91, точно я забыл просто как называется =)
32
Юнитов в качестве снарядов лучше не юзать, большая нагрузка на движок. Юзайте даммика который стреляет по площади или по цели.
16
нет, для оптимизации групп нужно не использовать фильтр (ставить нулл), а перебирать её через loop-firstOfGroup
жар преисподней будет оптимальнее с той точки зрения, что он собирает группы по заданным критериям целей без подключения жасс-машины. Однако он же будет тратить время на создание, вручение, уборку бафа и анимаций урона, создание объектов нанесения урона, а также саму работу абилки на даммике. Короче, и так, и так тяжело будет.
а в игре разве не было баллист, которые стреляют по прямой и снаряд разрушается при соприкосновении с первой целью?
33
а мы не будет использовать урон и вешать какой либо бафф, важен лишь факт соприкосновения, первый тик, после этого дамми снаряд будет уничтожен
DracoL1ch, но ведь если в фильтре гонять будет бытрее?
лично я использую да тот самый
loop-firstOfGroup
call GroupEnumUnitsInRange(perebor,x,y,80,null)
loop  
set e=FirstOfGroup(perebor)
exitwhen e==null 

//ACTIONS

call GroupRemoveUnit(perebor,e)
set e=null
endloop
DracoL1ch, не помню чтобы балиста била насквозь =(, но это бы очень подошло
quq_CCCP:
Юнитов в качестве снарядов лучше не юзать, большая нагрузка на движок. Юзайте даммика который стреляет по площади или по цели.
точно не подойдёт, визуально может быть и да, но с таким снарядом не столкнуться заранее
16
зачем ты пишешь e==null , если оно всегда будет нулл в итоге?
фильтр ни разу не быстрее и требует создание потока для каждого юнита, поэтому все китайцы и перешли на null - firstOfGroup, где это возможно
33
e==null - условие выхода из цикла, значит группа пуста, иначе он будет бесконечно гонять loop , что вызовет дикий лаг на пару секунд
28
Bergi_Bear, он про обнуление в самом конце, оно бесполезно.
33
DracoL1ch, напиши как надо конструкцию в 2019 писать
PT153, а то, случайно попало =)
28
Почти как ты и сделал.
function f takes something returns something
    local group g = CreateGroup()
    local unit u
    // ...
    call GroupEnumUnitsInRange(g, x, y, 80, null)
    loop  
        set u = FirstOfGroup(g)
        exitwhen u == null
        call GroupRemoveUnit(g, u)
        // ACTIONS
    endloop
    call DestroyGroup(g)
    set g = null
    // ...
endfunction
33
PT153, почти нет =) группу же лучше глобальную одну и туже 1 раз создать и просто наполнять её, уж локальная группа точно лишнее
Чтобы оставить комментарий, пожалуйста, войдите на сайт.