Как сделать, чтобы дальнобойные атаки юнитов не били сквозь препятствия?

Принятый ответ

код
не весь
globals
    constant group TempG = CreateGroup( )

    constant timer TempTimer = CreateTimer( )
    constant real timerPeriodic = 0.01
    
    boolean AbilityDamage = false
    
    integer max = 0

    unit array dummy
    unit array target
    
    real array startx
    real array starty
    real array startz
    real array midx
    real array midy
    real array midz
    real array endx
    real array endy
    real array endz
    
    real array time
    real array maxTime
    real array damage
    
    constant location LFZ = Location( 0.00, 0.00 )
endglobals

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

function IsEven takes integer a returns boolean
    return a / 2 * 2 == a
endfunction

function move takes nothing returns nothing
    local real x
    local real y
    local real z
    local integer i
    
    set i = 1
    loop
        set endx[i] = GetUnitX( target[i] )
        set endy[i] = GetUnitY( target[i] )
        set endz[i] = GetLocZ( endx[i], endy[i] ) + 50.00
    
        set x = startx[i] + ( ( 2.00 * ( midx[i] - startx[i] ) ) + ( startx[i] - 2.00 * midx[i] + endx[i] ) * time[i] ) * time[i]
        set y = starty[i] + ( ( 2.00 * ( midy[i] - starty[i] ) ) + ( starty[i] - 2.00 * midy[i] + endy[i] ) * time[i] ) * time[i]
        set z = startz[i] + ( ( 2.00 * ( midz[i] - startz[i] ) ) + ( startz[i] - 2.00 * midz[i] + endz[i] ) * time[i] ) * time[i]
        
        call SetUnitFacing( dummy[i], Atan2( y - GetUnitY( dummy[i] ), x - GetUnitX( dummy[i] ) ) * bj_RADTODEG )
        
        call SetUnitX( dummy[i], x )
        call SetUnitY( dummy[i], y )
        call SetUnitFlyHeight( dummy[i], z - GetLocZ( x, y ), 0.00 )
        
        set time[i] = time[i] + timerPeriodic / maxTime[i]
        
        if time[i] >= 1.00 or GetUnitFlyHeight( dummy[i] ) < 30.00 then
            if time[i] >= 1.00 then
                set AbilityDamage = true
                call UnitDamageTarget( dummy[i], target[i], damage[i], false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null )
                set AbilityDamage = false
            endif
        
            call KillUnit( dummy[i] )
            
            if i != max then
                set dummy[i]  = dummy[max]
                set target[i] = target[max]
                
                set startx[i] = startx[max]
                set starty[i] = starty[max]
                set startz[i] = startz[max]

                set endx[i] = endx[max]
                set endy[i] = endy[max]
                set endz[i] = endz[max]
                
                set midx[i] = midx[max]
                set midy[i] = midy[max]
                set midz[i] = midz[max]
                
                set time[i] = time[max]
                set maxTime[i] = maxTime[max]
                set damage[i] = damage[max]
            endif
            
            set dummy[max]  = null
            set target[max] = null
            
            set i = i - 1
            set max = max - 1
            
            if max <= 0 then
                call PauseTimer( TempTimer )
            endif
        endif
        
        set i = i + 1
        exitwhen i > max
    endloop
endfunction

function DamageEvent_Actions takes nothing returns boolean
    local unit attacker
    local unit damaged
    local real dmg = GetEventDamage( )
    local real x
    local real y
    local real angle
    local real angleOffset
    local real distance
    local real distanceOffset
    local real height
    local integer i
    
    if not AbilityDamage and dmg > 0.00 then
        set attacker = GetEventDamageSource( )
        set damaged  = GetTriggerUnit( )
        set x = GetUnitX( damaged )
        set y = GetUnitY( damaged )
        
        call NegateDamage( damaged, dmg )
        
        set dmg = dmg / 2.00
        set height = 50.00
        set angleOffset = 5
        set distanceOffset = 0.00
        set i = 0
        loop
            set max = max + 1
            
            set startx[max] = GetUnitX( attacker )
            set starty[max] = GetUnitY( attacker )
            set startz[max] = GetLocZ( startx[max], starty[max] ) + height
            
            set endx[max] = x
            set endy[max] = y
            set endz[max] = GetLocZ( endx[max], endy[max] ) + 50.00
            set angle     = Atan2( endy[max] - starty[max], endx[max] - startx[max] )
            set distance  = SquareRoot( ( endx[max] - startx[max] ) * ( endx[max] - startx[max] ) + ( endy[max] - starty[max] ) * ( endy[max] - starty[max] ) )
            
            set target[max] = damaged
            set dummy[max] = CreateUnit( GetOwningPlayer( attacker ), 'u000', startx[max], starty[max], angle * bj_RADTODEG )
            
            call UnitAddAbility( dummy[max], 'Arav' )
            call UnitRemoveAbility( dummy[max], 'Arav' )
            call SetUnitPathing( dummy[max], false )
            call SetUnitX( dummy[max], startx[max] )
            call SetUnitY( dummy[max], starty[max] )
            call SetUnitFlyHeight( dummy[max], startz[max], 0.00 )
            
            set distance = distance + distanceOffset
            
            if IsEven( i ) then
                set midx[max] = startx[max] + ( distance / 2.00 ) * Cos( angle + angleOffset * bj_DEGTORAD )
                set midy[max] = starty[max] + ( distance / 2.00 ) * Sin( angle + angleOffset * bj_DEGTORAD )
            else
                set midx[max] = startx[max] + ( distance / 2.00 ) * Cos( angle - angleOffset * bj_DEGTORAD )
                set midy[max] = starty[max] + ( distance / 2.00 ) * Sin( angle - angleOffset * bj_DEGTORAD )
            endif
            
            set midz[max] = 0.00
            
            if startz[max] < endz[max] then
                set midz[max] = midz[max] + endz[max]
            else
                set midz[max] = midz[max] + startz[max]
            endif
            
            set midz[max] = midz[max] + height
            
            if not IsEven( i ) then
                set distanceOffset = distanceOffset + 50.00
                set angleOffset = angleOffset + 180.00 / 16.00
                set height = height + 20.00
            endif
            
            set time[max] = 0.00
            set maxTime[max] = distance * 0.25 * timerPeriodic
            set damage[max] = dmg
            
            if max == 1 then
                call TimerStart( TempTimer, timerPeriodic, true, function move )
            endif
            
            set i = i + 1
            exitwhen i > 15
        endloop
        
        set damaged  = null
        set attacker = null
    endif
    
    return false
endfunction

//===========================================================================
function Regist takes unit u returns nothing
    if GetUnitAbilityLevel( u, 'Aloc' ) == 0 then
        call TriggerRegisterUnitEvent( gg_trg_DamageEvent, u, EVENT_UNIT_DAMAGED )
    endif
endfunction

function RegistCond takes nothing returns boolean
    call Regist( GetTriggerUnit( ) )
    return false
endfunction

function RegistCond_1 takes nothing returns boolean
    call Regist( GetFilterUnit( ) )
    return false
endfunction

function RegistEvent takes nothing returns nothing
    if gg_trg_DamageEvent != null then
        call DestroyTrigger( gg_trg_DamageEvent )
    endif
    
    set gg_trg_DamageEvent = CreateTrigger( )
    
    call GroupEnumUnitsInRect( TempG, bj_mapInitialPlayableArea, Condition( function RegistCond_1 ) )
    call TriggerAddCondition( gg_trg_DamageEvent, Condition( function DamageEvent_Actions ) )
    call TimerStart( GetExpiredTimer( ), 600.00, false, function RegistEvent )
endfunction

function InitTrig_DamageEvent takes nothing returns nothing
    local trigger t = CreateTrigger( )
    local region rectRegion = CreateRegion( )
    
    call RegionAddRect( rectRegion, bj_mapInitialPlayableArea )
    call TriggerRegisterEnterRegion( t, rectRegion, null )
    call TriggerAddCondition( t, Condition( function RegistCond ) )
    call TimerStart( CreateTimer( ), 0.00, false, function RegistEvent )
    
    set t = null
    set rectRegion = null
endfunction
Загруженные файлы
`
ОЖИДАНИЕ РЕКЛАМЫ...
2
27
2 года назад
Отредактирован MpW
2
изменить тип атаки? тогда не будут стрелять через ограды. Когда обойдет ограду, то снимай/выдай классификацию, и вау-ля можно снова атаковать.
или нужен блок? можно сделать триггерно движение снарядов, когда снаряд врезается об щит ментально, делаем отскок, удаляем. если это атака, то проще сделать триггерно атаку, у одного мастера можно узнать. xgm.guru/user/rsfghd если если эта какая то способность, то мб проще сделать триггерно абилку снарядов.
1
27
2 года назад
1
МрачныйВорон, с каких пор я стал мастером? а так с ответом согласен, обычно я реализовывал это через мгновенную атаку у юнита и триггерами с регистрацией получения урона делал кастомные снаряды, сам урон с автоатаки блочил этой либой, сохраняя для повторного нанесения при достижении цели
большие минусы (которые лично мне никогда не были минусами), это то, что весь урон нужно делать триггерным, т.е. яды, скиллы из ро и прочая ерунда у юнита с такой атакой будут вызывать кастомные снаряды, тут поможет мемхак либо damage engine
0
1
2 года назад
0
МрачныйВорон, rsfghd, cпасибо, товарищи, будем посмотреть!
1
27
2 года назад
1
Dmitry85, могу наклепать простой пример второго варианта если интересно
2
27
2 года назад
2
Dmitry85, могу наклепать простой пример второго варианта если интересно
давай))
0
27
2 года назад
0
код
не весь
globals
    constant group TempG = CreateGroup( )

    constant timer TempTimer = CreateTimer( )
    constant real timerPeriodic = 0.01
    
    boolean AbilityDamage = false
    
    integer max = 0

    unit array dummy
    unit array target
    
    real array startx
    real array starty
    real array startz
    real array midx
    real array midy
    real array midz
    real array endx
    real array endy
    real array endz
    
    real array time
    real array maxTime
    real array damage
    
    constant location LFZ = Location( 0.00, 0.00 )
endglobals

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

function IsEven takes integer a returns boolean
    return a / 2 * 2 == a
endfunction

function move takes nothing returns nothing
    local real x
    local real y
    local real z
    local integer i
    
    set i = 1
    loop
        set endx[i] = GetUnitX( target[i] )
        set endy[i] = GetUnitY( target[i] )
        set endz[i] = GetLocZ( endx[i], endy[i] ) + 50.00
    
        set x = startx[i] + ( ( 2.00 * ( midx[i] - startx[i] ) ) + ( startx[i] - 2.00 * midx[i] + endx[i] ) * time[i] ) * time[i]
        set y = starty[i] + ( ( 2.00 * ( midy[i] - starty[i] ) ) + ( starty[i] - 2.00 * midy[i] + endy[i] ) * time[i] ) * time[i]
        set z = startz[i] + ( ( 2.00 * ( midz[i] - startz[i] ) ) + ( startz[i] - 2.00 * midz[i] + endz[i] ) * time[i] ) * time[i]
        
        call SetUnitFacing( dummy[i], Atan2( y - GetUnitY( dummy[i] ), x - GetUnitX( dummy[i] ) ) * bj_RADTODEG )
        
        call SetUnitX( dummy[i], x )
        call SetUnitY( dummy[i], y )
        call SetUnitFlyHeight( dummy[i], z - GetLocZ( x, y ), 0.00 )
        
        set time[i] = time[i] + timerPeriodic / maxTime[i]
        
        if time[i] >= 1.00 or GetUnitFlyHeight( dummy[i] ) < 30.00 then
            if time[i] >= 1.00 then
                set AbilityDamage = true
                call UnitDamageTarget( dummy[i], target[i], damage[i], false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null )
                set AbilityDamage = false
            endif
        
            call KillUnit( dummy[i] )
            
            if i != max then
                set dummy[i]  = dummy[max]
                set target[i] = target[max]
                
                set startx[i] = startx[max]
                set starty[i] = starty[max]
                set startz[i] = startz[max]

                set endx[i] = endx[max]
                set endy[i] = endy[max]
                set endz[i] = endz[max]
                
                set midx[i] = midx[max]
                set midy[i] = midy[max]
                set midz[i] = midz[max]
                
                set time[i] = time[max]
                set maxTime[i] = maxTime[max]
                set damage[i] = damage[max]
            endif
            
            set dummy[max]  = null
            set target[max] = null
            
            set i = i - 1
            set max = max - 1
            
            if max <= 0 then
                call PauseTimer( TempTimer )
            endif
        endif
        
        set i = i + 1
        exitwhen i > max
    endloop
endfunction

function DamageEvent_Actions takes nothing returns boolean
    local unit attacker
    local unit damaged
    local real dmg = GetEventDamage( )
    local real x
    local real y
    local real angle
    local real angleOffset
    local real distance
    local real distanceOffset
    local real height
    local integer i
    
    if not AbilityDamage and dmg > 0.00 then
        set attacker = GetEventDamageSource( )
        set damaged  = GetTriggerUnit( )
        set x = GetUnitX( damaged )
        set y = GetUnitY( damaged )
        
        call NegateDamage( damaged, dmg )
        
        set dmg = dmg / 2.00
        set height = 50.00
        set angleOffset = 5
        set distanceOffset = 0.00
        set i = 0
        loop
            set max = max + 1
            
            set startx[max] = GetUnitX( attacker )
            set starty[max] = GetUnitY( attacker )
            set startz[max] = GetLocZ( startx[max], starty[max] ) + height
            
            set endx[max] = x
            set endy[max] = y
            set endz[max] = GetLocZ( endx[max], endy[max] ) + 50.00
            set angle     = Atan2( endy[max] - starty[max], endx[max] - startx[max] )
            set distance  = SquareRoot( ( endx[max] - startx[max] ) * ( endx[max] - startx[max] ) + ( endy[max] - starty[max] ) * ( endy[max] - starty[max] ) )
            
            set target[max] = damaged
            set dummy[max] = CreateUnit( GetOwningPlayer( attacker ), 'u000', startx[max], starty[max], angle * bj_RADTODEG )
            
            call UnitAddAbility( dummy[max], 'Arav' )
            call UnitRemoveAbility( dummy[max], 'Arav' )
            call SetUnitPathing( dummy[max], false )
            call SetUnitX( dummy[max], startx[max] )
            call SetUnitY( dummy[max], starty[max] )
            call SetUnitFlyHeight( dummy[max], startz[max], 0.00 )
            
            set distance = distance + distanceOffset
            
            if IsEven( i ) then
                set midx[max] = startx[max] + ( distance / 2.00 ) * Cos( angle + angleOffset * bj_DEGTORAD )
                set midy[max] = starty[max] + ( distance / 2.00 ) * Sin( angle + angleOffset * bj_DEGTORAD )
            else
                set midx[max] = startx[max] + ( distance / 2.00 ) * Cos( angle - angleOffset * bj_DEGTORAD )
                set midy[max] = starty[max] + ( distance / 2.00 ) * Sin( angle - angleOffset * bj_DEGTORAD )
            endif
            
            set midz[max] = 0.00
            
            if startz[max] < endz[max] then
                set midz[max] = midz[max] + endz[max]
            else
                set midz[max] = midz[max] + startz[max]
            endif
            
            set midz[max] = midz[max] + height
            
            if not IsEven( i ) then
                set distanceOffset = distanceOffset + 50.00
                set angleOffset = angleOffset + 180.00 / 16.00
                set height = height + 20.00
            endif
            
            set time[max] = 0.00
            set maxTime[max] = distance * 0.25 * timerPeriodic
            set damage[max] = dmg
            
            if max == 1 then
                call TimerStart( TempTimer, timerPeriodic, true, function move )
            endif
            
            set i = i + 1
            exitwhen i > 15
        endloop
        
        set damaged  = null
        set attacker = null
    endif
    
    return false
endfunction

//===========================================================================
function Regist takes unit u returns nothing
    if GetUnitAbilityLevel( u, 'Aloc' ) == 0 then
        call TriggerRegisterUnitEvent( gg_trg_DamageEvent, u, EVENT_UNIT_DAMAGED )
    endif
endfunction

function RegistCond takes nothing returns boolean
    call Regist( GetTriggerUnit( ) )
    return false
endfunction

function RegistCond_1 takes nothing returns boolean
    call Regist( GetFilterUnit( ) )
    return false
endfunction

function RegistEvent takes nothing returns nothing
    if gg_trg_DamageEvent != null then
        call DestroyTrigger( gg_trg_DamageEvent )
    endif
    
    set gg_trg_DamageEvent = CreateTrigger( )
    
    call GroupEnumUnitsInRect( TempG, bj_mapInitialPlayableArea, Condition( function RegistCond_1 ) )
    call TriggerAddCondition( gg_trg_DamageEvent, Condition( function DamageEvent_Actions ) )
    call TimerStart( GetExpiredTimer( ), 600.00, false, function RegistEvent )
endfunction

function InitTrig_DamageEvent takes nothing returns nothing
    local trigger t = CreateTrigger( )
    local region rectRegion = CreateRegion( )
    
    call RegionAddRect( rectRegion, bj_mapInitialPlayableArea )
    call TriggerRegisterEnterRegion( t, rectRegion, null )
    call TriggerAddCondition( t, Condition( function RegistCond ) )
    call TimerStart( CreateTimer( ), 0.00, false, function RegistEvent )
    
    set t = null
    set rectRegion = null
endfunction
Загруженные файлы
Принятый ответ
Чтобы оставить комментарий, пожалуйста, войдите на сайт.