Вопрос, какая система снарядов будет наиболее производительной?
Хочу рассмотреть вообще абсолютно все варианты, под 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)
Загруженные файлы
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
28
5 лет назад
0
DracoL1ch, то есть вообще не юзать фильтры?
1
32
5 лет назад
1
e==null - условие выхода из цикла, значит группа пуста, иначе он будет бесконечно гонять loop , что вызовет дикий лаг на пару секунд
1
28
5 лет назад
1
Bergi_Bear, он про обнуление в самом конце, оно бесполезно.
1
32
5 лет назад
1
DracoL1ch, напиши как надо конструкцию в 2019 писать
PT153, а то, случайно попало =)
1
28
5 лет назад
Отредактирован PT153
1
Почти как ты и сделал.
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
1
32
5 лет назад
1
PT153, почти нет =) группу же лучше глобальную одну и туже 1 раз создать и просто наполнять её, уж локальная группа точно лишнее
1
28
5 лет назад
1
Bergi_Bear, я общий вариант писал.
1
16
5 лет назад
1
ну да, это самая быстрая конструкция при входных условиях, что нам содержимое группы нигде не нужно, а все действия над ними нужно выполнить лишь 1 раз
0
32
5 лет назад
0
Кароче еще способ:
Движение: через создание и движение юнита-снаряда (приказ мув)
Столкновение: через детект урона жара
код луа
//! 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
--триггер запуска снарядов (примитивный)
MissleClick = CreateTrigger()
for i = 0, bj_MAX_PLAYER_SLOTS - 1, 1 do
     TriggerRegisterPlayerMouseEventBJ(MissleClick, Player(i), bj_MOUSEEVENTTYPE_DOWN)
end
TriggerAddCondition(MissleClick, Condition(function() return BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT end))
TriggerAddAction(MissleClick, function()
-- весь код экшена
local u=udg_Butcher
local mx=BlzGetTriggerPlayerMouseX()
local my=BlzGetTriggerPlayerMouseY()
local x=GetUnitX(u)
local y=GetUnitY(u)
local a=bj_RADTODEG*Atan2(my - y, mx - x)
--print(a)
local unit ud=CreateUnit(GetOwningPlayer(u), AbilityId('e000'), MoveX(x,30,a) ,MoveY(y,30,a) , a)

local nx=MoveX(x,2500,a)
local ny=MoveY(y,2500,a)
IssuePointOrder(ud, "move", nx, ny)

end)

-- триггер отлова урона через жар


gg_trg_DamageEvent = CreateTrigger(  )
for i = 0, bj_MAX_PLAYER_SLOTS - 1, 1 do
    TriggerRegisterPlayerUnitEvent(gg_trg_DamageEvent, Player(i), EVENT_PLAYER_UNIT_DAMAGING)
end
TriggerAddCondition( gg_trg_DamageEvent, Condition( function () return  BlzGetEventAttackType( ) == ConvertAttackType( 0 ) and  BlzGetEventDamageType( ) == ConvertDamageType( 8 ) and  BlzGetEventWeaponType( ) == ConvertWeaponType( 0 ) end))
TriggerAddAction( gg_trg_DamageEvent, function ()
BlzSetEventDamage(300)
KillUnit(GetEventDamageSource())
--print("урон от жара")

    end)
     

//! endusercode
Как же их колбасит, система дефолтного движения вызывает дикие дёрганья и неадекватность (но я её и не рассматривал, просто решил проверить на новом патче)
гифка
Загруженные файлы
0
19
5 лет назад
0
движение юнита-снаряда (приказ мув)
Так, а скорость будет 522 максимальной.. Или нет?
0
32
5 лет назад
0
да, но мб для снарядов от которых надо увернуться это достаточно, в любом случае уже сделал триггерное движение, это так экспериментик был
Кароче, пока что больше 200 юнитов снарядов не держит используется (просто не держит 200 юнитов не важно движутся ли они), использовался:
lua+ юниты +1 таймер + детект урона через жар,
Следующий на очереди:
lua + смещение позиций эффектов + loopfirstOfGroup
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.