ребята привет, слушайте не могли вы бы проверить мой код и дать пару советов по использованию vJass'a может есть какие то фишки или какие то собственные функции без которых вы не пишете код
library Chidory initializer Init

globals
    private integer SpellID = 'A001'// Код способности
endglobals

private struct SpellStruct
    unit Caster
    unit Target
    real Damage
    real Speed
    real Angle
    method Destroy takes nothing returns nothing
        set this.Caster = null
        set this.Target = null
        call this.destroy()
    endmethod
endstruct

private function Distance takes unit A, unit B returns real
    return SquareRoot((GetUnitX(B) - GetUnitX(A)) * (GetUnitX(B) - GetUnitX(A)) + (GetUnitY(B) - GetUnitY(A)) * (GetUnitY(B) - GetUnitY(A)))
endfunction

private function Chidory_Action takes nothing returns nothing
    local timer Timer = GetExpiredTimer()
    local SpellStruct s = LoadInteger(Hash,GetHandleId(Timer),StringHash("Struct"))
    local real x
    local real y

    if Distance(s.Caster,s.Target) > 165 and GetWidgetLife(s.Caster) > 0.405 and GetWidgetLife(s.Target) > 0.405 then

        set x = GetUnitX(s.Caster) 
        set y = GetUnitY(s.Caster)
        set s.Angle = bj_RADTODEG * Atan2(GetUnitY(s.Target) - y, GetUnitX(s.Target) - x)
        call SetUnitX(s.Caster,x + s.Speed * Cos(s.Angle * bj_DEGTORAD))
        call SetUnitY(s.Caster,y + s.Speed * Sin(s.Angle * bj_DEGTORAD))

    else

        call PauseTimer(Timer)
        
        call SetUnitAnimation(s.Caster,"spell channel one")
        
        call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl",GetUnitX(s.Target),GetUnitY(s.Target))) 
        
        call UnitDamageTarget(s.Caster,s.Target,s.Damage,false,false,AT_Chaos,DT_Magic,null)
        
        call FlushChildHashtable(Hash,GetHandleId(Timer))
        call DestroyTimer(Timer)
        call s.Destroy()

    endif
    
    set Timer = null

endfunction

private function Chidory_Variable takes nothing returns nothing
    local timer Timer = CreateTimer()
    local SpellStruct s = SpellStruct.create()
    
    set s.Caster = GetTriggerUnit()
    set s.Target = GetSpellTargetUnit()
    set s.Speed = 35.0
    set s.Damage = (70 * GetUnitAbilityLevel(s.Caster,SpellID)) + (GetHeroAgi(s.Caster,true) * 1.2)
    
    call SaveInteger(Hash,GetHandleId(Timer),StringHash("Struct"),s)
    
    call TriggerSleepAction(0.5)
    
    call DestroyEffect(AddSpecialEffect("wind.mdx",GetUnitX(s.Caster),GetUnitY(s.Caster))) 
    
    call TimerStart(Timer,0.01,true,function Chidory_Action)
    
    set Timer = null
endfunction

private function Chidory_Condition takes nothing returns boolean
    return GetSpellAbilityId() == SpellID
endfunction

private function Init takes nothing returns nothing
    local trigger Chidory = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( Chidory, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( Chidory, Condition( function Chidory_Condition ) )
    call TriggerAddAction( Chidory, function Chidory_Variable )
    set Chidory = null
endfunction

endlibrary

Здесь вы переводите из радианов в градусы, а потом при использовании данной переменной снова переводите её в радианы:
        set s.Angle = bj_RADTODEG * Atan2(GetUnitY(s.Target) - y, GetUnitX(s.Target) - x)
        call SetUnitX(s.Caster,x + s.Speed * Cos(s.Angle * bj_DEGTORAD))
        call SetUnitY(s.Caster,y + s.Speed * Sin(s.Angle * bj_DEGTORAD))
Лучше заменить на :
        set s.Angle = Atan2(GetUnitY(s.Target) - y, GetUnitX(s.Target) - x)
        call SetUnitX(s.Caster,x + s.Speed * Cos(s.Angle))
        call SetUnitY(s.Caster,y + s.Speed * Sin(s.Angle))
`
ОЖИДАНИЕ РЕКЛАМЫ...
21
Здесь вы переводите из радианов в градусы, а потом при использовании данной переменной снова переводите её в радианы:
        set s.Angle = bj_RADTODEG * Atan2(GetUnitY(s.Target) - y, GetUnitX(s.Target) - x)
        call SetUnitX(s.Caster,x + s.Speed * Cos(s.Angle * bj_DEGTORAD))
        call SetUnitY(s.Caster,y + s.Speed * Sin(s.Angle * bj_DEGTORAD))
Лучше заменить на :
        set s.Angle = Atan2(GetUnitY(s.Target) - y, GetUnitX(s.Target) - x)
        call SetUnitX(s.Caster,x + s.Speed * Cos(s.Angle))
        call SetUnitY(s.Caster,y + s.Speed * Sin(s.Angle))
Принятый ответ
14
ScopteRectuS:
Здесь вы переводите из радианов в градусы, а потом при использовании данной переменной снова переводите её в радианы:
        set s.Angle = bj_RADTODEG * Atan2(GetUnitY(s.Target) - y, GetUnitX(s.Target) - x)
        call SetUnitX(s.Caster,x + s.Speed * Cos(s.Angle * bj_DEGTORAD))
        call SetUnitY(s.Caster,y + s.Speed * Sin(s.Angle * bj_DEGTORAD))
Лучше заменить на :
        set s.Angle = Atan2(GetUnitY(s.Target) - y, GetUnitX(s.Target) - x)
        call SetUnitX(s.Caster,x + s.Speed * Cos(s.Angle))
        call SetUnitY(s.Caster,y + s.Speed * Sin(s.Angle))
щет, спасибо!
15
С технической точки зрения ничего не скажу, но одним из важных аспектов программирования является соблюдение единого стиля кода и написание легко читаемого кода. Поэтому дам пару советов.
Следует избегать подобных названий:
private struct SpellStruct
Если вы объявляете переменную типа Spell, то и так понятно, что это структура, поэтому суффикс Struct здесь лишний.
Разделяйте логические блоки кода пустой строкой:
	private struct SpellStruct
    unit Caster
    unit Target
    real Damage
    real Speed
    real Angle
    method Destroy takes nothing returns nothing
        set this.Caster = null
        set this.Target = null
        call this.destroy()
    endmethod
endstruct
В этом примере явно не хватает пустой строки между полем Angle и методом Destroy. Набор полей структуры и тело метода — два логических блока, которые нам гораздо легче отделять друг от друга, если между ними пустая строка.
Здесь проблема с именованием локальных переменных:
local timer Timer = CreateTimer()
local SpellStruct s = SpellStruct.create()
timer объявлен в PascalCase, а SpellStruct в camelCase. Определите для себя единую конвенцию именования переменных. Как правило, локальные переменные в функциях и приватные поля структур именуются в camelCase, а публичные поля структур и функции именуются в стиле PascalCase.
Подобные расхождения в стиле написания кода тоже стоит избегать:
call TriggerRegisterAnyUnitEventBJ( Chidory, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( Chidory, Condition( function Chidory_Condition ) )
и
call UnitDamageTarget(s.Caster,s.Target,s.Damage,false,false,AT_Chaos,DT_Magic,null)
Пробелы между аргументами во всех вызовах должны соблюдаться одинаково. Либо вы не ставите пробелы везде, либо ставите везде. Лучше, конечно, ставить, т.к. это читабельнее. Старайтесь придерживаться одного стиля написания кода, тогда он будет легко читаем, т.к. мозг хорошо распознаёт закономерности.
Также избегайте такого:
globals
    private integer SpellID = 'A001'// Код способности
endglobals
Во-первых, комментарии следует оставлять на пустой строке, а не впихивать в конец какой-то инструкции. Во-вторых, комментарии необходимы для пояснения каких-то сложных моментов в коде. Здесь пример плохого комментария: он поясняет очевидное. По названию переменной и так понятно, что это айди способности, поэтому и нужды что-либо комментировать нет. Называйте свои переменные, функции и методы так, чтобы их не приходилось комментировать.
Успехов.
28
JackFastGame, с читаемостью проблем вообще нет, помимо комментов выше я бы только GetWidgetLife на UnitAlive заменил, а угол в структуре убрал бы вообще, заменив на локалку, в самом методе Destroy смысла нет, ибо вызывается метод лишь из одной функции и выполняет действия, которые можно сделать непосредственно в функции уничтожения таймера
Чтобы оставить комментарий, пожалуйста, войдите на сайт.