XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

Ответ
 
Variecs

offline
Опыт: 2,508
Активность:
Система приоритетов
Собственно, запилил вот такое вот добро. Находит наиболее подходящую цель для данной башни. Часть приоритетов привязана к моей карте, часть универсальна. Больше подробностей в комментариях к коду.
Хотелось бы узнать, где я оплошал, где код лишний и где есть гораздо более простой способ это сделать. В любом случае не хочется применять на практике нечто сырое и несуразное, даже если в своей собственной карте.
» раскрыть
Код:
function Checker_Filter takes nothing returns boolean
    return ( GetOwningPlayer( GetFilterUnit() ) == Player(4) ) && ( GetUnitState( GetFilterUnit(), UNIT_STATE_LIFE ) > 0 ) && ( GetUnitTypeId( GetFilterUnit() ) != 'h004' )
endfunction

function Checker_Red takes nothing returns boolean
    return ( GetUnitY( GetFilterUnit() ) < BORDER_TOP ) && Checker_Filter()
endfunction

function Checker_Blue takes nothing returns boolean
    return ( GetUnitX( GetFilterUnit() ) < BORDER_RIGHT ) && Checker_Filter()
endfunction

function Checker_Teal takes nothing returns boolean
    return ( GetUnitY( GetFilterUnit() ) > BORDER_BOTTOM ) && Checker_Filter()
endfunction

function Checker_Purple takes nothing returns boolean
    return ( GetUnitX( GetFilterUnit() ) > BORDER_LEFT ) && Checker_Filter()
endfunction

//---------------------------------------------------------------------------------------------------------------------------------------------
//Вначале идут функции для выбора юнита из группы различными способами.
//Затем функция Intersection, используемая для того, чтобы найти пересечение групп допустимых и потенциальных целей.
//Последняя функция, самая большая, служит для выбора конкретного способа нахождения цели и, собственно, находит её. 
//Именно последнюю функцию надо использовать для нахождения приоритета.

//Ближайший юнит
function DCheck takes unit tower, group g returns unit
    local unit u
    local unit cur = FirstOfGroup( g )
    local group temp = CreateGroup()
    call GroupAddGroup( g, temp )
    loop
        exitwhen CountUnitsInGroup( temp ) == 0
        set u = FirstOfGroup( temp )
        if ( SquareRoot( ( GetUnitX( u ) - GetUnitX( tower ) )*( GetUnitX( u ) - GetUnitX( tower ) ) + ( GetUnitY( u ) - GetUnitY( tower ) )*( GetUnitY( u ) - GetUnitY( tower ) ) ) < SquareRoot( ( GetUnitX( cur ) - GetUnitX( tower ) )*( GetUnitX( cur ) - GetUnitX( tower ) ) + ( GetUnitY( cur ) - GetUnitY( tower ) )*( GetUnitY( cur ) - GetUnitY( tower ) ) ) ) then
            set cur = u
        endif
        call GroupRemoveUnit( temp, u )
    endloop
    call DestroyGroup( temp )
    set temp = null
    set u = null
    return cur
endfunction

//Самый левый
function XCheck_Left takes group g returns unit
    local unit u
    local unit cur = FirstOfGroup( g )
    local group temp = CreateGroup()
    call GroupAddGroup( g, temp )
    loop
        exitwhen CountUnitsInGroup( temp ) == 0
        set u = FirstOfGroup( temp )
        if ( GetUnitX( u ) < GetUnitX( cur ) ) then
            set cur = u
        endif
        call GroupRemoveUnit( temp, u )
    endloop
    call DestroyGroup( temp )
    set temp = null
    set u = null
    return cur
endfunction 

//Самый правый
function XCheck_Right takes group g returns unit
    local unit u
    local unit cur = FirstOfGroup( g )
    local group temp = CreateGroup()
    call GroupAddGroup( g, temp )
    loop
        exitwhen CountUnitsInGroup( temp ) == 0
        set u = FirstOfGroup( temp )
        if ( GetUnitX( u ) > GetUnitX( cur ) ) then
            set cur = u
        endif
        call GroupRemoveUnit( temp, u )
    endloop
    call DestroyGroup( temp )
    set temp = null
    set u = null
    return cur
endfunction

//Самый нижний
function YCheck_Down takes group g returns unit
    local unit u
    local unit cur = FirstOfGroup( g )
    local group temp = CreateGroup()
    call GroupAddGroup( g, temp )
    loop
        exitwhen CountUnitsInGroup( temp ) == 0
        set u = FirstOfGroup( temp )
        if ( GetUnitY( u ) < GetUnitY( cur ) ) then
            set cur = u
        endif
        call GroupRemoveUnit( temp, u )
    endloop
    call DestroyGroup( temp )
    set temp = null
    set u = null
    return cur
endfunction

//Самый верхний
function YCheck_Up takes group g returns unit
    local unit u
    local unit cur = FirstOfGroup( g )
    local group temp = CreateGroup()
    call GroupAddGroup( g, temp )
    loop
        exitwhen CountUnitsInGroup( temp ) == 0
        set u = FirstOfGroup( temp )
        if ( GetUnitY( u ) > GetUnitY( cur ) ) then
            set cur = u
        endif
        call GroupRemoveUnit( temp, u )
    endloop
    call DestroyGroup( temp )
    set temp = null
    set u = null
    return cur
endfunction

//С наименьших количеством хп
function HCheck_Up takes group g returns unit
    local unit u
    local unit cur = FirstOfGroup( g )
    local group temp = CreateGroup()
    call GroupAddGroup( g, temp )
    loop
        exitwhen CountUnitsInGroup( temp ) == 0
        set u = FirstOfGroup( temp )
        if ( GetUnitState( u, UNIT_STATE_LIFE ) > GetUnitState( cur, UNIT_STATE_LIFE ) ) then
            set cur = u
        endif
        call GroupRemoveUnit( temp, u )
    endloop
    call DestroyGroup( temp )
    set temp = null
    set u = null
    return cur
endfunction

//С наибольшим количеством хп
function HCheck_Down takes group g returns unit
    local unit u
    local unit cur = FirstOfGroup( g )
    local group temp = CreateGroup()
    call GroupAddGroup( g, temp )
    loop
        exitwhen CountUnitsInGroup( temp ) == 0
        set u = FirstOfGroup( temp )
        if ( GetUnitState( u, UNIT_STATE_LIFE ) < GetUnitState( cur, UNIT_STATE_LIFE ) ) then
            set cur = u
        endif
        call GroupRemoveUnit( temp, u )
    endloop
    call DestroyGroup( temp )
    set temp = null
    set u = null
    return cur
endfunction

function Intersection takes group g1, group g2 returns group
    local group temp = CreateGroup()
    local group g = CreateGroup()
    local unit u
    call GroupAddGroup( g1, temp )
    loop
        exitwhen CountUnitsInGroup( temp ) == 0
        set u = FirstOfGroup( temp )
        if IsUnitInGroup( u, g2 ) then
            call GroupAddUnit( g, u )
        endif
        call GroupRemoveUnit( temp, u )
    endloop
    call DestroyGroup( temp )
    set u = null
    set temp = null
    return g
endfunction

//Приоритеты 2 и 3 ищут соответственно первого и последнего юнита в волне. 
//Приоритет 4 ищет последнего, только если текущая цель недоступна или умерла.
//Эти приоритеты работают только в циклических ТД вроде CreenCircle, и для них в функциях Checker_Red и т.п. нужно установить константы
//BORDER_TOP, BORDER_RIGHT и т.д. координат внутренних сторон круга. Эти приоритеты будут работать правильно при движении
//противников против часовой стрелки, но наоборот при движении по часовой. Впрочем, чтобы это исправить, достаточно поменять местами
//два участка кода: где выбирается приоритет 2 и где выбираются приоритеты 3 и 4.
//Остальные приоритеты работают в любой карте, даже для движущихся целей. 
function Target_Picking takes unit u, unit curTarget, integer state, group targets returns unit
    local integer i = 0
    local group g = CreateGroup()
    local unit target = null
    if ( CountUnitsInGroup( targets ) == 0 ) then
        return null
    endif
    //Вычисляем атакующего
    if ( state == 2 )
        //Выбираем игрока
        if ( GetOwningPlayer( u ) == Player(0) )
            //Берём всех юнитов после поворота
            call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Red ) )
            set g = Intersection( g, targets )
            if ( CountUnitsInGroup( g ) != 0 ) then
                //Ищем первого
                set target = YCheck_Down( g ) 
            else
                //Выбираем остальных и ищем первого
                call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Filter ) )
                set g = Intersection( g, targets )
                set target = XCheck_Left( g )
            endif
        endif
        if ( GetOwningPlayer( u ) == Player(1) )
            call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Blue ) )
            set g = Intersection( g, targets )
            if ( CountUnitsInGroup( g ) != 0 ) then
                set target = XCheck_Left( g ) 
            else
                call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Filter ) )
                set g = Intersection( g, targets )
                set target = YCheck_Up( g ) 
            endif
        endif
        if ( GetOwningPlayer( u ) == Player(2) )
            call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Teal ) )
            set g = Intersection( g, targets )
            if ( CountUnitsInGroup( g ) != 0 ) then
                set target = YCheck_Up( g ) 
            else
                call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Filter ) )
                set g = Intersection( g, targets )
                set target = XCheck_Right( g ) 
            endif
        endif
        if ( GetOwningPlayer( u ) == Player(3) )
            call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Purple ) )
            set g = Intersection( g, targets )
            if ( CountUnitsInGroup( g ) != 0 ) then
                set target = XCheck_Right( g ) 
            else
                call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Filter ) )
                set g = Intersection( g, targets )
                set target = YCheck_Down( g ) 
            endif
        endif
    endif
    if ( ( state == 3 ) or ( ( state == 4 ) && not ( IsUnitInRange( u, curTarget, GetUnitAcquireRange( u ) ) && GetUnitState( curTarget, UNIT_STATE_LIFE ) > 0 ) ) )
        //Выбираем игрока
        if ( GetOwningPlayer( u ) == Player(0) )
            //Берём всех юнитов до поворота
            call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Purple ) )
            set g = Intersection( g, targets )
            if ( CountUnitsInGroup( g ) != 0 ) then
                //Ищем последнего
                set target = XCheck_Right( g ) 
            else
                //Выбираем остальных и ищем последнего
                call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Filter ) )
                set g = Intersection( g, targets )
                set target = YCheck_Up( g ) 
            endif
        endif
        if ( GetOwningPlayer( u ) == Player(1) )
            call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Red ) )
            set g = Intersection( g, targets )
            if ( CountUnitsInGroup( g ) != 0 ) then
                set target = YCheck_Down( g ) 
            else
                call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Filter ) )
                set g = Intersection( g, targets )
                set target = XCheck_Right( g ) 
            endif
        endif
        if ( GetOwningPlayer( u ) == Player(2) )
            call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Blue ) )
            set g = Intersection( g, targets )
            if ( CountUnitsInGroup( g ) != 0 ) then
                set target = XCheck_Left( g ) 
            else
                call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Filter ) )
                set g = Intersection( g, targets )
                set target = YCheck_Down( g ) 
            endif
        endif
        if ( GetOwningPlayer( u ) == Player(3) )
            call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Teal ) )
            set g = Intersection( g, targets )
            if ( CountUnitsInGroup( g ) != 0 ) then
                set target = YCheck_Up( g ) 
            else
                call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Filter ) )
                set g = Intersection( g, targets )
                set target = XCheck_Left( g ) 
            endif
        endif
    endif
    if ( state == 5 )
        //Ищем ближайшего юнита
        call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Filter ) )
        set g = Intersection( g, targets )
        set target = DCheck( u, g ) 
    endif
    if ( state == 6 )
        //Ищем юнита с наибольшим количеством здоровья
        call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Filter ) )
        set g = Intersection( g, targets )
        set target = HCheck_Up( g ) 
    endif
    if ( state == 7 )
        //Ищем юнита с наименьшим количеством здоровья
        call GroupEnumUnitsInRange( g, GetUnitX( u ), GetUnitY( u ), GetUnitAcquireRange( u ), Condition( function Checker_Filter ) )
        set g = Intersection( g, targets )
        set target = HCheck_Down( g ) 
    endif
    call DestroyGroup( g )
    set g = null
    return target
endfunction


UPD: ещё момент. В карте каждый игрок имеет право строить юнитов только в своём углу. Это позволяет просчитывать некоторые приоритеты, т.к. мы точно знаем, что башня этого игрока будет находиться в конкретном углу. В противном случае пришлось бы считать самому, в каком углу находится башня.

Отредактировано Variecs, 02.07.2013 в 18:15.
Старый 02.07.2013, 18:08
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 16:57.