Пытаюсь сделать споосбнось, как у Катарины Танцующий клинок, но столкнулся с рядом проблем в анимации: то, одно клинок улетает в неизвестность, невзирая на условия, то летит нормально; то клинок приземляется куда нужно, но оказывается, что только под определённым углом, то сильно мимо, можете помочь с тем, как правильно сделать анимацию?
Код способности
function MoveBlade takes nothing returns nothing
    local timer Timer = GetExpiredTimer()
    local integer TimerId = GetHandleId(Timer)
    local unit Target = LoadUnitHandle(udg_hash, TimerId, StringHash("Target"))
    local effect Blade = LoadEffectHandle(udg_hash, TimerId, StringHash("Blade"))
    local real a = LoadReal(udg_hash, TimerId, StringHash("a"))
    local real TargetX = GetEffectX(Blade)
    local real TargetY = GetEffectY(Blade)
    local real FallBladeX = GetUnitX(Target) + 300 * Cos(a * bj_DEGTORAD)
    local real FallBladeY = GetUnitY(Target) + 300 * Sin(a * bj_DEGTORAD)
    local integer AngleBlade = LoadInteger(udg_hash, TimerId, StringHash("Blade Pitch Angle"))
    
    if SquareRoot((FallBladeX - TargetX) * (FallBladeX - TargetX) + (FallBladeY - TargetY) * (FallBladeY - TargetY)) <= 0 then
        call DestroyTimer(Timer)
        call FlushChildHashtable(udg_hash, TimerId)
        call SetEffectPitch(Blade, 90)
        call SetEffectY(Blade, GetEffectY(Blade) - 10)
    elseif SquareRoot((FallBladeX - TargetX) * (FallBladeX - TargetX) + (FallBladeY - TargetY) * (FallBladeY - TargetY)) >= 150 then
        call SetEffectPosition(Blade, TargetX + 2 * Cos(a * bj_DEGTORAD), TargetY + 2 * Sin(a * bj_DEGTORAD), GetEffectZ(Blade) + 5)
    elseif SquareRoot((FallBladeX - TargetX) * (FallBladeX - TargetX) + (FallBladeY - TargetY) * (FallBladeY - TargetY)) <= 150 then
        call SetEffectPosition(Blade, TargetX + 2 * Cos(a * bj_DEGTORAD), TargetY + 2 * Sin(a * bj_DEGTORAD), GetEffectZ(Blade) - 4)
    endif
    
        if AngleBlade == 60 then
            set AngleBlade = 0
        else
            set AngleBlade = AngleBlade + 1
        endif
        
        call SaveInteger(udg_hash, TimerId, StringHash("Blade Pitch Angle"), AngleBlade)
endfunction

function CreateBlade takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer id = GetHandleId(t)
    local unit Caster = LoadUnitHandle(udg_hash, id, StringHash("Caster"))
    local unit Target = LoadUnitHandle(udg_hash, id, StringHash("Target"))
    local real CasterX = GetUnitX(Caster)
    local real CasterY = GetUnitY(Caster)
    local real TargetX = GetUnitX(Target)
    local real TargetY = GetUnitY(Target)
    local real a = bj_RADTODEG * Atan2(TargetY - CasterY, TargetX - CasterX)
    local effect Blade =  AddSpecialEffect("Weapon_2.mdl", TargetX, TargetY)
    local effect Alarm =  AddSpecialEffect("Alarm.mdl", TargetX + 235 * Cos(a * bj_DEGTORAD), TargetY + 235 * Sin(a * bj_DEGTORAD))
    local timer Timer = CreateTimer()
    local integer TimerId = GetHandleId(Timer)
    
    call SetEffectColourR(Alarm, 255)
    call SetEffectColourG(Alarm, 0)
    call SetEffectColourB(Alarm, 0)
    
    call SaveEffectHandle(udg_hash, GetHandleId(Caster), StringHash("Alarm Voracity"), Alarm)
    call SaveEffectHandle(udg_hash, GetHandleId(Caster), StringHash("Blade"), Blade)
    
    call TimerStart(Timer, 0.01, true, function MoveBlade)
    call SaveUnitHandle(udg_hash, TimerId, StringHash("Target"), Target)
    call SaveEffectHandle(udg_hash, TimerId, StringHash("Blade"), Blade)
    call SaveReal(udg_hash, TimerId, StringHash("a"), a)
    
    set t = null
    set Caster = null
    set Target = null
    set Blade = null
    set Alarm = null
    set Timer = null
endfunction

function Trig_Bouncing_Blade_Actions takes nothing returns nothing
    local unit Caster = GetTriggerUnit()
    local unit Target = GetSpellTargetUnit()
    local real CasterX = GetUnitX(Caster)
    local real CasterY = GetUnitY(Caster)
    local real TargetX = GetUnitX(Target)
    local real TargetY = GetUnitY(Target)
    local real a = bj_RADTODEG * Atan2(TargetY - CasterY, TargetX - CasterX)
    local trigger Voracity = CreateTrigger()
    local timer t = CreateTimer()
    local integer id = GetHandleId(t)
    local real time = SquareRoot((CasterX - TargetX) * (CasterX - TargetX) + (CasterY - TargetY) * (CasterY - TargetY)) / 1500
    
    if GetSpellAbilityId() == 'A001' then        
        call TimerStart(t, time, false, function CreateBlade)
        call SaveUnitHandle(udg_hash, id, StringHash("Caster"), Caster)
        call SaveUnitHandle(udg_hash, id, StringHash("Target"), Target)
        
        call TriggerRegisterEnterRectSimple( Voracity, Rect( TargetX + 235 * Cos(a * bj_DEGTORAD) - 100 * 0.5, TargetY + 235 * Sin(a * bj_DEGTORAD) - 100 * 0.5, TargetX + 235 * Cos(a * bj_DEGTORAD) + 100 * 0.5, TargetY + 235 * Sin(a * bj_DEGTORAD) + 100 * 0.5 ))
        call TriggerAddAction(Voracity, function VoracityAction)
        call SaveTriggerHandle(udg_hash, GetHandleId(Caster), StringHash("Destroy Voracity"), Voracity)
    endif
    
    set Caster = null
    set Target = null
    set Voracity = null
    set t = null
endfunction

//===========================================================================
function InitTrig_Bouncing_Blade takes nothing returns nothing
    set gg_trg_Bouncing_Blade = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Bouncing_Blade, EVENT_PLAYER_UNIT_SPELL_CAST )
    call TriggerAddAction( gg_trg_Bouncing_Blade, function Trig_Bouncing_Blade_Actions )
endfunction

ArhiMEN, работаю над этим, немного осталось

в общем я поленился и не добавил все настройки, но оставил комменты по которым ты быстро сориентируешься что к чему и сам доделаешь как надо
то что я бы посоветовал переделать, это выбирать юнитов вокруг точки падения, которая регистрируется после первого пораженного юнита, а не вокруг последней пораженной цели, в видео ты можешь посмотреть пример как глупо полёт смотрелся (0:24)
раскрыть
library mylib
globals
    constant hashtable H = InitHashtable()
    private group TempG = CreateGroup()
    private group TempG1
    private unit bj_lastFilterUnit
    private unit TempUnit
    private unit CUEX
    private real TempReal
    private real MaxX
    private real MinX
    private real MaxY
    private real MinY
endglobals

// воспомогательные фукнции
native UnitAlive takes unit id returns boolean

private function SetUnitPositionEx takes unit u, real x, real y returns nothing
    if x > MaxX then
        set x = MaxX
    elseif x < MinX then
        set x = MinX
    endif
    if y > MaxY then
        set y = MaxY
    elseif y < MinY then
        set y = MinY
    endif
    call SetUnitX(u,x)
    call SetUnitY(u,y)
endfunction

private function CreateUnitEx takes player id, integer unitid, real x, real y, real face returns unit
    set CUEX = CreateUnit(id,unitid,x,y,face)
    call UnitAddAbility(CUEX,'Arav')
    call SetUnitPathing(CUEX,false)
    call SetUnitPositionEx(CUEX,x,y)
    return CUEX
endfunction

private function ParabolaZ takes real h, real d, real x returns real
    return (4 * h / d) * (d - x) * (x / d)
endfunction

private struct Spell
    unit caster
    unit target
    unit dummy
    unit dummy1
    real speed
    real angle
    real dmg
    real fly
    real fly1
    real time
    real dist
    real dist1
    real radius
    real x
    real y
    integer dummyid
    boolean b = true
    integer count
    group g
endstruct

private function cond takes nothing returns boolean // выбор ближайших целей для кинжала
    set bj_lastFilterUnit = GetFilterUnit()
    return UnitAlive(bj_lastFilterUnit) and IsUnitEnemy(bj_lastFilterUnit,GetOwningPlayer(TempUnit)) and not IsUnitInGroup(bj_lastFilterUnit,TempG1)
endfunction

private function DamageCond takes nothing returns boolean // кому наносить урон
    set bj_lastFilterUnit = GetFilterUnit()
    if UnitAlive(bj_lastFilterUnit) and IsUnitEnemy(bj_lastFilterUnit,GetOwningPlayer(TempUnit)) then
        call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl",bj_lastFilterUnit,"chest"))
        call UnitDamageTarget(TempUnit,bj_lastFilterUnit,TempReal,false,false,null,null,null)
    endif
    return false
endfunction

private function casterr takes nothing returns boolean // это для кинжала, выбор кастера когда кинжал упал
    return GetFilterUnit() == TempUnit
endfunction

private function move1 takes nothing returns nothing //это для эффекта кругового удара
    local timer t = GetExpiredTimer()
    local integer i = GetHandleId(t)
    local unit u = LoadUnitHandle(H,i,0)
    local unit u1 = LoadUnitHandle(H,i,1)
    local real tm = LoadReal(H,i,2)-.01
    
    call SetUnitPositionEx(u1,GetUnitX(u),GetUnitY(u))
    
    if tm <= 0. then
        call KillUnit(u1)
        call PauseTimer(t)
        call DestroyTimer(t)
        call FlushChildHashtable(H,i)
    else
        call SaveReal(H,i,2,tm)
    endif
    
    set t = null
    set u = null
    set u1 = null
endfunction

// периодическая проверка кастера у кинжала
private function checkcaster takes nothing returns nothing
    local Spell A = LoadInteger(H,GetHandleId(GetExpiredTimer()),0)
    local timer t
    set A.time = A.time-.01
    set TempUnit = A.caster
    call GroupEnumUnitsInRange(TempG,A.x,A.y,100,Condition(function casterr))
    if A.time <= 0. or FirstOfGroup(TempG) != null then
        if FirstOfGroup(TempG) != null then
            set t = CreateTimer()
            call SaveUnitHandle(H,GetHandleId(t),0,A.caster)
            call SaveUnitHandle(H,GetHandleId(t),1,CreateUnitEx(Player(0x0F),'u002',GetUnitX(A.caster),GetUnitY(A.caster),GetRandomReal(0,360)))
            call SaveReal(H,GetHandleId(t),2,.10)
            call SetUnitFlyHeight(CUEX,50,0)
            call SetUnitScale(CUEX,2,2,2)
            call TimerStart(t,.01,true,function move1)
            set t = null
            
            call GroupClear(TempG)
            set TempReal = A.dmg
            call GroupEnumUnitsInRange(TempG,GetUnitX(A.caster),GetUnitY(A.caster),A.radius*0.8,Condition(function DamageCond))
        endif
        
        call KillUnit(A.dummy)
        call KillUnit(A.dummy1)
        call RemoveUnit(A.dummy1)
        call DestroyGroup(A.g)
        set A.g = null
        set A.caster = null
        set A.dummy = null
        call A.destroy()
        call FlushChildHashtable(H,GetHandleId(GetExpiredTimer()))
        call PauseTimer(GetExpiredTimer())
        call DestroyTimer(GetExpiredTimer())
    endif
endfunction

// перемещение кинжала когда он падает
private function setpos takes nothing returns nothing
    local Spell A = LoadInteger(H,GetHandleId(GetExpiredTimer()),0)
    local real x = GetUnitX(A.dummy)+A.speed*Cos(A.angle)
    local real y = GetUnitY(A.dummy)+A.speed*Sin(A.angle)
    
    set A.dist = A.dist-A.speed
    call SetUnitPositionEx(A.dummy,x,y)
    call SetUnitFlyHeight(A.dummy,ParabolaZ(A.fly,A.dist1,A.dist)+A.fly1,0)
    
    if A.dist <= 0. then
        set A.x = x
        set A.y = y
        set A.dummy1 = CreateUnitEx(GetOwningPlayer(A.caster),A.dummyid,x,y,GetRandomReal(0,360))
        call SetUnitScale(A.dummy1,.5,.5,.5)
        call TimerStart(GetExpiredTimer(),.01,true,function checkcaster)
    endif
endfunction

private function move takes nothing returns nothing
    local Spell A = LoadInteger(H,GetHandleId(GetExpiredTimer()),0)
    local real x = GetUnitX(A.dummy)+A.speed*Cos(A.angle)
    local real y = GetUnitY(A.dummy)+A.speed*Sin(A.angle)
    local real x1 = GetUnitX(A.target)
    local real y1 = GetUnitY(A.target)
    local unit u
    local real r
    local real r1
    
    set A.angle = Atan2(y1-y,x1-x)
    call SetUnitPositionEx(A.dummy,x,y)
    
    if SquareRoot((x-x1)*(x-x1)+(y-y1)*(y-y1)) <= 50. then
        call SetUnitX(A.dummy,x1)
        call SetUnitY(A.dummy,y1)
        call UnitDamageTarget(A.caster,A.target,A.dmg,false,false,null,null,null)
        if A.b then // установление дистанции падения кинжала после первой цели
            set A.x = x1+A.radius*Cos(A.angle)
            set A.y = y1+A.radius*Sin(A.angle)
            set A.b = false
        endif
        set A.count = A.count-1
        set TempUnit = A.dummy
        set TempG1 = A.g
        call GroupEnumUnitsInRange(TempG,x1,y1,A.radius,Condition(function cond))
        if A.count <= 0 or FirstOfGroup(TempG) == null then
            // настройки для падения кинжала
            set A.dist = SquareRoot((x-A.x)*(x-A.x)+(y-A.y)*(y-A.y))
            set A.dist1 = A.dist // (для параболы)
            set A.angle = Atan2(A.y-y1,A.x-x1)
            set A.speed = SquareRoot((x-x1)*(x-x1)+(y-y1)*(y-y1))*.1
            call TimerStart(GetExpiredTimer(),.01,true,function setpos)
        else
            // выбор ближней цели
            set r = A.radius*2
            loop
                set u = FirstOfGroup(TempG)
                exitwhen u == null
                set r1 = SquareRoot((GetUnitX(u)-x1)*(GetUnitX(u)-x1)+(GetUnitY(u)-y1)*(GetUnitY(u)-y1))
                if r1 < r then
                    set r = r1
                    set A.target = u
                endif
                call GroupRemoveUnit(TempG,u)
            endloop
            call GroupAddUnit(A.g,A.target)
        endif
    endif
    
endfunction

private function Trig_Spell_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local Spell A = Spell.create()
    local integer lvl
    set A.caster = GetTriggerUnit()
    set A.target = GetSpellTargetUnit()
    set A.angle = Atan2(GetUnitY(A.target)-GetUnitY(A.caster),GetUnitX(A.target)-GetUnitX(A.caster))
    set A.dummy = CreateUnitEx(GetOwningPlayer(A.caster),'u000',GetUnitX(A.caster)+50*Cos(A.angle),GetUnitY(A.caster)+50*Sin(A.angle),A.angle*bj_RADTODEG)
    set A.g = CreateGroup()
    set lvl = GetUnitAbilityLevel(A.caster,'A000')
    
    if lvl == 1 then
        set A.dmg = 100.00
        set A.count = 3
        set A.speed = 25.00
        set A.radius = 300.00 // радиус поиска целей а так же дистанция падения кинжала от первой пораженной цели
        set A.fly = 300.00 // максимальная высота кинжала
        set A.fly1 = 50.00 // постоянная высота кинжала
        set A.time = 5.00 // время существования кинжала
        set A.dummyid = 'u001' // какого юнита спавнить для отображения радиуса подбора кинжала
    //elseif lvl == 2 then
    endif
    call GroupAddUnit(A.g,A.target)
    call SetUnitFlyHeight(A.dummy,A.fly1,0)
    call SaveInteger(H,GetHandleId(t),0,A)
    call TimerStart(t,.03125,true,function move)
    set t = null
endfunction

//===========================================================================
private function mycond takes nothing returns boolean
    if GetSpellAbilityId() == 'A000' then
        call Trig_Spell_Actions()
    endif
    return false
endfunction
function InitTrig_Spell takes nothing returns nothing
    set gg_trg_Spell = CreateTrigger(  )
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x00), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x01), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x02), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x03), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x04), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x05), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x06), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x07), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x08), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x09), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x0A), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x0B), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x0C), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x0D), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x0E), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x0F), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
    call TriggerAddCondition( gg_trg_Spell, Condition(function Trig_Spell_Actions) )
    
    set MaxX = GetRectMaxX(GetWorldBounds())
    set MinX = GetRectMinX(GetWorldBounds())
    set MaxY = GetRectMaxY(GetWorldBounds())
    set MinY = GetRectMinY(GetWorldBounds())
endfunction
endlibrary





а насчёт вращения юнита, если мемхак не помогает, можешь найти дамми модель 360 градусов и прикрепить к ней кинжал как эффект, устанавливая нужную анимацию модели в соответствии с таким-то градусом, костыльно, но работает без проблем
Загруженные файлы
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
32
Чет совсем не то, надо будет с юнитом попробовать.

Совсем забыл, в 1.4 не полная реализация вращения, еще и с ошибками. Только в 1.5 завезли все эти фишки, вот...
Загруженные файлы
11
quq_CCCP:
Чет совсем не то, надо будет с юнитом попробовать.
а он не крутиться в 1.4 а дурацкий эффект крутиться вокруг рукояти видимо

если подойти точно справа от юнита, то попадёт в цель, в других случаях мимо

но я совсем не понимаю, почему вообще может пролететь мимо, я вращаю его вдоль оси, но с неё же он не сходит (как мне казалось) Однако он умудряется промахнуться.
14
quq_CCCP:
Чет совсем не то, надо будет с юнитом попробовать.

Совсем забыл, в 1.4 не полная реализация вращения, еще и с ошибками. Только в 1.5 завезли все эти фишки, вот...
"Катарина мечет во врага кинжал, который рикошетом поражает еще несколько целей, после чего падает на землю."
вот что он пытается сделать
11
quq_CCCP:
Чет совсем не то, надо будет с юнитом попробовать.

Совсем забыл, в 1.4 не полная реализация вращения, еще и с ошибками. Только в 1.5 завезли все эти фишки, вот...
спасибо
28
но столкнулся с рядом проблем в анимации: то, одно клинок улетает в неизвестность, невзирая на условия, то летит нормально; то клинок приземляется куда нужно, но оказывается, что только под определённым углом, то сильно мимо, можете помочь с тем, как правильно сделать анимацию?
у тебя проблемы с анимацией или с движением кинжала? не понятно что ты хочешь

если именно технические проблемы, а не визуальные (по которым ты мемхак юзаешь для вращения по yaw/pitch/roll), то я могу сделать эту абилку и скинуть тебе
11
rsfghd:
но столкнулся с рядом проблем в анимации: то, одно клинок улетает в неизвестность, невзирая на условия, то летит нормально; то клинок приземляется куда нужно, но оказывается, что только под определённым углом, то сильно мимо, можете помочь с тем, как правильно сделать анимацию?
у тебя проблемы с анимацией или с движением кинжала? не понятно что ты хочешь

если именно технические проблемы, а не визуальные (по которым ты мемхак юзаешь для вращения по yaw/pitch/roll), то я могу сделать эту абилку и скинуть тебе
У меня проблема в том, что при повороте по оси кинжал смещается и это выглядит криво, да и в целом он находится не в нужной мне точке. И не совсем придумал, как правильно в техническом плане повернуть мест, чтобы его полёт выглядел более естественно.
14
вот что можно сделать если бы у модели была анимация вращения движется к цели и задевает окружающих

все удалил с твоей карты чтоб не мозолила глаза

вот иконка которая подойдет

вот еще пару иконок
28
Гуванч, нафига ему иконки?)
он спрашивает почему кинжал себя так странно ведёт)

через час примерно скину спелл
14
rsfghd:
Гуванч, нафига ему иконки?)
он спрашивает почему кинжал себя так странно ведёт)

через час примерно скину спелл
rsfghd:
Гуванч, нафига ему иконки?)
он спрашивает почему кинжал себя так странно ведёт)

через час примерно скину спелл
Это если он использует мой пример у себя я и сказал что ему надо анимка вращения если найдет то поставит и я пытаюсь помочь чем могу а не втирать всякую дичь про мемори хак имхо мемори хак это дно!

Прилепить к моего примеру систему параболы и отскока(которые я не в силах сделать) и спелл готов щас снаряд поражает рядом стоящих без эффекта отскока и нет эффекта приземления на землю
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.