Первые пару снарядов летят в нужные точки, а другие улетают в основном вверх в разные стороны. При том если кидать в центр мапы всё отлично работает. Ставил дебаг, иногда 0 показывает в EndX, EndY, но даже когда не 0, то всё равно летят не как надо.
3-й день разобраться пытаюсь, скорее всего в глаза долблюсь, и допустил супер банальную ошибку )
function IsLocOnMap takes rect r, real x, real y returns boolean
    return GetRectMinX( r ) <= x and x <= GetRectMaxX( r ) and GetRectMinY( r ) <= y and y <= GetRectMaxY( r )
endfunction

function GetLocZ takes real x, real y returns real
    call MoveLocation( Loc, x, y )
    return GetLocationZ( Loc )
endfunction

function Parabola takes real startZ, real targetZ, real maxZ, real maxDist, real curDist returns real
    return ( ( 4 * maxZ / maxDist ) * ( maxDist - curDist ) + targetZ - startZ ) * ( curDist / maxDist ) + startZ
endfunction

function SetUnitZ takes unit u, real z returns nothing
    call SetUnitFlyHeight( u, z - GetLocZ( GetUnitX( u ), GetUnitY( u ) ), 0 )
endfunction

function Lerp takes real a, real b, real t returns real
    return a * ( 1 - t ) + b * t
endfunction

globals
    constant integer Rockets_AbilityId = 'A000'
    constant integer Rockets_Count = 8
    constant real Rockets_TimerPeriod = 0.03
    constant real Rockets_Speed = 800
    constant real Rockets_FullRange = 300
    constant real Rockets_Range = 100
    constant real Rockets_Damage = 30
    constant real Rockets_StartHeight = 75
    constant real Rockets_MaxHeightCoefficient = 0.4
    constant real Rockets_MaxHeightCoefficientRandom = 0.1

    hashtable HT = InitHashtable()
    group Group = CreateGroup()
    location Loc = Location( 0, 0 )
    group RocketsGroup = CreateGroup()
    player CasterOwner

    timer Timer
    integer TimerId
    integer Tick
    integer HandleId
    integer Count

    unit Caster
    unit Dummy
    unit Target
    
    real DummyX
    real DummyY

    real StartX
    real StartY

    real CastX
    real CastY

    real NewX
    real NewY

    real EndX
    real EndY

    real DeltaX
    real DeltaY

    real Angle
    real MaxDist
    real Time
    real Range
endglobals

native UnitAlive takes unit id returns boolean

function Rockets_Group takes nothing returns nothing
    set Target = GetEnumUnit()

    if IsUnitInRangeXY( Target, DummyX, DummyY, Rockets_Range ) and UnitAlive( Target ) and IsUnitEnemy( Target, GetOwningPlayer( Caster ) ) and not IsUnitType( Target, UNIT_TYPE_STRUCTURE ) then
        call UnitDamageTarget( Caster, Target, Rockets_Damage, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS )
    endif
endfunction

function Rockets_Move takes nothing returns nothing
    set Dummy = GetEnumUnit()
    set HandleId = GetHandleId( Dummy )

    set EndX = LoadReal( HT, TimerId, HandleId + 'endX' )
    set EndY = LoadReal( HT, TimerId, HandleId + 'endY' )
    set MaxDist = LoadReal( HT, TimerId, HandleId + 'dist' )

    set Time = ( Tick * Rockets_TimerPeriod ) / ( MaxDist / Rockets_Speed )
    set NewX = Lerp( StartX, EndX, Time )
    set NewY = Lerp( StartY, EndY, Time )

    set DeltaX = NewX - StartX
    set DeltaY = NewY - StartY
    call SetUnitZ( Dummy, Parabola( LoadReal( HT, TimerId, 'strZ' ), LoadReal( HT, TimerId, HandleId + 'endZ' ), LoadReal( HT, TimerId, HandleId + 'maxZ' ) * MaxDist, MaxDist, SquareRoot( DeltaX * DeltaX + DeltaY * DeltaY ) ) )

    if IsLocOnMap( bj_mapInitialPlayableArea, NewX, NewY ) then
        call SetUnitFacing( Dummy, bj_RADTODEG * Atan2( EndY - NewY, EndX - NewX ) )
        call SetUnitX( Dummy, NewX )
        call SetUnitY( Dummy, NewY )
    endif

    if Time >= 1 then
        call GroupRemoveUnit( RocketsGroup, Dummy )
        call RemoveUnit( Dummy )
    endif
endfunction

function Rockets_Timer takes nothing returns nothing
    set Timer = GetExpiredTimer()
    set TimerId = GetHandleId( Timer )

    set Caster = LoadUnitHandle( HT, TimerId, 'cstr' )
    set StartX = LoadReal( HT, TimerId, 'strX' )
    set StartY = LoadReal( HT, TimerId, 'strY' )

    set Tick = LoadInteger( HT, TimerId, 'tick' ) + 1
    call SaveInteger( HT, TimerId, 'tick', Tick )
    call ForGroup( RocketsGroup, function Rockets_Move )

    if FirstOfGroup( RocketsGroup ) == null then
        call PauseTimer( Timer )
        call DestroyTimer( Timer )
        call FlushChildHashtable( HT, TimerId )
    endif
endfunction

function Rockets_Act takes nothing returns nothing
    if GetSpellAbilityId() == Rockets_AbilityId then
        set Caster = GetTriggerUnit()
        set StartX = GetUnitX( Caster )
        set StartY = GetUnitY( Caster )

        set CastX = GetSpellTargetX()
        set CastY = GetSpellTargetY()
        set Angle = Atan2( CastY - StartY, CastX - StartX )

        set Timer = CreateTimer()
        set TimerId = GetHandleId( Timer )
        set CasterOwner = GetOwningPlayer( Caster )

        set Count = 0
        loop
            set Range = GetRandomReal( 0, Rockets_FullRange / 2 )
            set Angle = GetRandomReal( 0, 2 * bj_PI )

            set EndX = CastX + Range * Cos( Angle )
            set EndY = CastY + Range * Sin( Angle )

            set DeltaX = EndX - StartX
            set DeltaY = EndY - StartY

            set Dummy = CreateUnit( CasterOwner, 'h000', StartX, StartY, Atan2( EndY - StartY, EndX - StartX ) )
            set HandleId = GetHandleId( Dummy )

            call SetUnitZ( Dummy, Rockets_StartHeight )
            call GroupAddUnit( RocketsGroup, Dummy )

            call SaveReal( HT, TimerId, HandleId + 'dist', SquareRoot( DeltaX * DeltaX + DeltaY * DeltaY ) )
            call SaveReal( HT, TimerId, HandleId + 'endX', EndX )
            call SaveReal( HT, TimerId, HandleId + 'endY', EndY )

            call SaveReal( HT, TimerId, HandleId + 'endZ', GetLocZ( EndX, EndY ) )
            call SaveReal( HT, TimerId, HandleId + 'maxZ', GetRandomReal( Rockets_MaxHeightCoefficient - Rockets_MaxHeightCoefficientRandom, Rockets_MaxHeightCoefficient + Rockets_MaxHeightCoefficientRandom ) )

            set Count = Count + 1
            exitwhen Count >= Rockets_Count
        endloop

        call SaveUnitHandle( HT, TimerId, 'cstr', Caster )
        call SaveReal( HT, TimerId, 'strX', StartX )
        call SaveReal( HT, TimerId, 'strY', StartY )
        call SaveReal( HT, TimerId, 'strZ', GetLocZ( StartX, StartY ) + Rockets_StartHeight ) 
        call TimerStart( Timer, Rockets_TimerPeriod, true, function Rockets_Timer )
    endif
endfunction

function InitTrig_Rockets takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0

    loop
        call TriggerRegisterPlayerUnitEvent( t, Player( i ), EVENT_PLAYER_UNIT_SPELL_EFFECT, null )
        set i = i + 1
        exitwhen i >= 16
    endloop

    call TriggerAddAction( t, function Rockets_Act )
    set t = null

    call FogMaskEnable( false )
    call FogEnable( false )
endfunction

Вот карта с исправленной проблемой.
По сути я просто заменил все "TimerId, HandleId +" на "HandleId," и все, готово.
Загруженные файлы
`
ОЖИДАНИЕ РЕКЛАМЫ...
23
Похожие вопросы:

ответ
Вобщем озарение как всегда пришло внезапно - понял что GetSpellAbilityUnit срабатывает на дамми и записывает в массив его, а не цель щита. Просто передвинул махинации с дамми в конец функции Actions. Всё отменно работает. Всем спасибо все свободны
ответ
XGM Bot:
Похожие вопросы:

ответ
а вопрос закрыть?
ответ
~8gabriel8:
В РО у способности есть есть строка Графика - Анимации, там указываешь ту, что хочешь видеть при её использовании. Например, для Огненных стрел Жрицы Луны используется анимация attack, для Молота бурь Горного Короля анимация spell throw, а для Покоя Хранителя Рощи анимация spell channel. Для двух последних способностей в РО указывается два слова, оба слова через пробел не работают, например, указывай отдельно spell и throw или spell и channel. Если у модели нет анимаций с таким названием, но есть анимации, которые содержат одно из этих слов, то будут проигрываться они. Там ещё есть тонкости, о которых долго печатать надо, да и они тебе могут не понадобиться. Пробуй.
ответ
quq_CCCP, Ну я на хайве видел полуджассовый вампиризм. Так мне и нужно вручать при замахе, чтоб если героя диспелят он вампиризм при атаке вернул. А утечку показывает, как я атакую, сразу хендл на один повышается. Может руна не удаляется?
ClotPh, Вообще не понял о чём ты.
Решил проблему, утечка возникала из -за не удаления руны, она почему-то не удаляется изнутри триггера, создал отдельный для удаления и нет утечки.
ответ
ALL_Remove = false
чтотооченьважное
ALL_Remove = true
как сложно то было


25
Я не пАнимать, что такое "нужная точка".
Чтобы пойти искать ошибку, надо узнать, что ты вообще хочешь, как ты видишь работу спела, со всеми его характеристиками, подробную механику. А угадывать хотелку, разбирая несколько страниц кода, такое себе...
Ответы (5)
15
konvan5, вылетает 8 снарядов которые летят по Z координате при помощи параболы, между позицией кастера (стартовая позиция), конечной позицией (разброс от позиции каста - EndX, EndY), они именно с помощью линейной интерполяции летят между этими точками. У каждого своя EndX, EndY, которая записывается по родительскому ключу - TimerId (айди таймера), и дочернему ключу - DummyId + 'endX', 'endY' (айди даммика + сам ключ).
25
LastUchiha, окей, ты же понимаешь, что HandleId + 'dist' - ненадежная запись и ты таким образом можешь случайно перетереть данные другого снаряда с другим полем.
К примеру есть снаряды 1 2 3 ... 8.
Есть поля 1 2 3.
Для 1 снаряда значение будет 1 + 1 = 2, записываем ключ 2. Таким образом еще получаем 3 и 4 ключи.
Для 2 снаряда значение будет 2 + 1 = 3 - а этот ключ уже занят первым снарядом. То есть сам хэндл снаряда то уникальный, НО твои суммы с ним уже НЕ уникальны, и ты перетираешь эти данные новыми записями.
25
LastUchiha, если у тебя уже есть уникальный HandleId для каждого снаряда, сохраненный в группе, зачем тебе вообще нужен TimerId для сохранения данных снаряда. Просто перетащи HandleId вместо TimerId, а такие значения как 'dist' пускай останутся самостоятельными без дополнительных вычислений.
25
Вот карта с исправленной проблемой.
По сути я просто заменил все "TimerId, HandleId +" на "HandleId," и все, готово.
Загруженные файлы
Принятый ответ
Чтобы оставить комментарий, пожалуйста, войдите на сайт.