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

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

Ответ
 
ARHUI

offline
Опыт: 3,341
Активность:
Ворота глючат.
Ниже приведу много кода, я запарился, не понимаю в чем ошибка, но иногда ворота не работают должным образом.

Описание функций:


Код:
function Initialization takes nothing return nothing
*
    set udg_gates[0] = gg_dest_LTg4_1004
    set udg_gates[1] = gg_dest_LTg2_1003
    set udg_gates[2] = gg_dest_LTg4_1005
    set udg_gates[3] = gg_dest_LTg2_1002
    set udg_open_gates[0] = gg_rct_open_gates_TR
    set udg_open_gates[1] = gg_rct_open_gates_BR
    set udg_open_gates[2] = gg_rct_open_gates_BL
    set udg_open_gates[3] = gg_rct_open_gates_TL
*
    local trigger t = CreateTrigger(  )
    call TriggerRegisterEnterRectSimple( t, udg_open_gates[0] )
    call TriggerRegisterLeaveRectSimple( t, udg_open_gates[0] )
    call TriggerAddAction( t, function gate0 )
    t = CreateTrigger(  )
    call TriggerRegisterEnterRectSimple( t, udg_open_gates[1] )
    call TriggerRegisterLeaveRectSimple( t, udg_open_gates[1] )
    call TriggerAddAction( t, function gate1 )
    t = CreateTrigger(  )
    call TriggerRegisterEnterRectSimple( t, udg_open_gates[2] )
    call TriggerRegisterLeaveRectSimple( t, udg_open_gates[2] )
    call TriggerAddAction( t, function gate2 )
    t = CreateTrigger(  )
    call TriggerRegisterEnterRectSimple( t, udg_open_gates[3] )
    call TriggerRegisterLeaveRectSimple( t, udg_open_gates[3] )
    call TriggerAddAction( t, function gate3 )
*
endfunction


как видно при входе и выходе юнита из области вызываются функции:

Код:
function gate0 takes nothing returns nothing
    local unit u = GetTriggerUnit()
    if IsPlayerAlly(GetOwningPlayer(u),Player(9))==true then
        call GatesActions(0,u)
    endif
endfunction

function gate1 takes nothing returns nothing
    local unit u = GetTriggerUnit()
    if IsPlayerAlly(GetOwningPlayer(u),Player(9))==true then
        call GatesActions(1,u)
    endif
endfunction

function gate2 takes nothing returns nothing
    local unit u = GetTriggerUnit()
    if IsPlayerAlly(GetOwningPlayer(u),Player(9))==true then
        call GatesActions(2,u)
    endif
endfunction

function gate3 takes nothing returns nothing
    local unit u = GetTriggerUnit()
    if IsPlayerAlly(GetOwningPlayer(u),Player(9))==true then
        call GatesActions(3,u)
    endif
endfunction


так много похожих функций из-за того что TriggerAddAction( t, function gate3 ) не берет параметры, а вообще нужна одна вот эта функция:

Код:
function GatesActions takes integer i, unit u returns nothing
    local integer a = NumberOfBuildersNearGate(i)
    if ( GetUnitTypeId(u) == 'H024' ) then
        if ( udg_IsGateDead[i] == false ) then
            if ( GetDestructableLife(udg_gates[i]) > 0.00 ) then
                call DisableTrigger( gg_trg_MarkDeadGates )
                set udg_GatesLife[i] = GetDestructableLife(udg_gates[i])
                call ModifyGateBJ( bj_GATEOPERATION_OPEN, udg_gates[i] )
                call SetDestructableLife( udg_gates[i], 0.00 )
                call EnableTrigger( gg_trg_MarkDeadGates )
            elseif (a == 0)
                call ModifyGateBJ( bj_GATEOPERATION_CLOSE, udg_gates[i] )
                call SetDestructableLife( udg_gates[i], udg_GatesLife[i] )
            endif
            call MoveForce()
        endif
    endif
endfunction


данная функция считает количество героев в области, чтобы не открывать ворота два раза:

Код:
function NumberOfBuildersNearGate takes integer i returns integer a
    local integer a = 0
    local group g = CreateGroup()
    local unit u
    call GroupEnumUnitsInRect(g, udg_open_gates[i], null)
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        if (GetUnitTypeId(u) == 'H024') then
            set a = a + 1
        endif
        call GroupRemoveUnit(g, u)
    endloop
    call DestroyGroup(g)
    set u = null
    return a
endfunction



'H024' - это герой на которого ворота должны реагировать, если ворота живы... Чтобы открыть ворота их надо убить но при этом сохранить переменную что их не убивали, и значение их жизни перед открытием... Убитые ворота помечаются триггером:

Код:
function Trig_MarkDeadGates_Actions takes nothing returns nothing
    local integer a = 0
    local destructable d = GetTriggerDestructable()
    loop
        exitwhen a > 3
        if ( udg_gates[ a ] == d ) then
            set udg_IsGateDead[ a ] = true
        endif
        set a = a + 1
    endloop
    set d = null
    call MoveForce()
endfunction

//===========================================================================
function InitTrig_MarkDeadGates takes nothing returns nothing
    set gg_trg_MarkDeadGates = CreateTrigger(  )
    call TriggerRegisterDeathEvent( gg_trg_MarkDeadGates, gg_dest_LTg2_1002 )
    call TriggerRegisterDeathEvent( gg_trg_MarkDeadGates, gg_dest_LTg2_1003 )
    call TriggerRegisterDeathEvent( gg_trg_MarkDeadGates, gg_dest_LTg4_1004 )
    call TriggerRegisterDeathEvent( gg_trg_MarkDeadGates, gg_dest_LTg4_1005 )
    call TriggerAddAction( gg_trg_MarkDeadGates, function Trig_MarkDeadGates_Actions )
endfunction



Также ворота можно починить, и вслучае починки их надо отметить как не убитые:

Код:
function Trig_GatesRecovery_Actions takes nothing returns nothing
    if ( GetSpellAbilityId() == 'Ahrp' ) then
        local integer a = 0
        loop
            exitwhen a > 3
            if (udg_IsGateDead[a] = false) then
                return
            endif
            if ( (udg_IsGateDead[a] == true) && ( GetDestructableLife(udg_gates[a]) > 0.00 ) && (DistanceBetweenPoints(GetUnitLoc(GetSpellAbilityUnit()), GetDestructableLoc(udg_gates[a])) < 600) ) then
                set udg_IsGateDead[a] = false
                call SetDestructableLife(udg_gates[a],500.00)
                set udg_GatesLife[a]=GetDestructableLife(udg_gates[a])
                if ( NumberOfBuildersNearGate(a)!=0 ) then
                    call DisableTrigger( gg_trg_MarkDeadGates )
                    call ModifyGateBJ( bj_GATEOPERATION_OPEN, udg_gates[a] )
                    call SetDestructableLife( udg_gates[a], 0.00 )
                    call EnableTrigger( gg_trg_MarkDeadGates )
                else
                    call ModifyGateBJ( bj_GATEOPERATION_CLOSE, udg_gates[a] )
                    call SetDestructableLife( udg_gates[a], udg_GatesLife[a] )
                endif
            endif
            set a = a + 1
        endloop
        call MoveForce()
    endif
endfunction

//===========================================================================
function InitTrig_GatesRecovery takes nothing returns nothing
    set gg_trg_GatesRecovery = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_GatesRecovery, EVENT_PLAYER_UNIT_SPELL_FINISH )
    call TriggerAddAction( gg_trg_GatesRecovery, function Trig_GatesRecovery_Actions )
endfunction



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

Я понимаю что вывалил кучу кода, но у меня уже руки опускаются...
Старый 24.04.2011, 11:58
AiDSeller
За здоровый образ жизни
offline
Опыт: 6,094
Активность:
ARHUI, так что именно надо сделать? А то из кода я, если честно, не вижу.
Старый 24.04.2011, 12:56
ARHUI

offline
Опыт: 3,341
Активность:
Чтобы ворота не начинали работать наоборот. Тоесть может кто-то увидит последовательность которая приводит к этому... Я вот уже не первый день смотрю и не вижу, однако в игре нет нет да и заглючит воротина(не все обычно одна)...
Старый 24.04.2011, 12:58
AiDSeller
За здоровый образ жизни
offline
Опыт: 6,094
Активность:
ARHUI, я посмотрел на код и решил.
Смотри. Ворота начинают реагировать только тогда, когда нужный юнит ближе, чем в радиусе 600. Выход из этой ситуации один:
  1. Когда юнит приближается ближе, чем на 600 к воротам, давать ему способность "Скачок" (Дальность работы скила должна быть больше или равна 1200);
  2. Отслеживать применение "Скачка";
  3. Если в результате он оказался дальше 600 от ворот, то забирать способность "Скачок".
Всё просто!
Старый 24.04.2011, 13:03
ARHUI

offline
Опыт: 3,341
Активность:
А я не понял, зачем способность давать? Единственное место в коде где отслеживается дистанция, это при ремонте, чтобы привязать вхождение цикла к конкретным воротам возле которых стоит герой.
Старый 24.04.2011, 13:11
AiDSeller
За здоровый образ жизни
offline
Опыт: 6,094
Активность:
ARHUI, ну раз ворота не открываются, то ведь надо же их как-то пройти! Вот тебе и способность "Скачок". Всё просто!
Старый 24.04.2011, 13:14
ARHUI

offline
Опыт: 3,341
Активность:
Нормально -
герой подошел к воротам - открылись,
герой отошел от ворот и возле ворот не других героев - закрылись.
герой закончил починку ворот - открылись.

Ошибка
герой подошел к воротам - закрылись,
герой отошел - открылись

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

Я вот не понимаю как эта ошибка возникает из вышеприведенного кода...
Старый 24.04.2011, 13:25
Gudfree
гуи (V)_( Oo )_(V)
offline
Опыт: 8,233
Активность:
AiDSeller:
ARHUI, ну раз ворота не открываются, то ведь надо же их как-то пройти! Вот тебе и способность "Скачок". Всё просто!
Абузить будут же// если карта мультиплеерная// мб при входе в120 рэнж давать скачок?
Старый 24.04.2011, 14:13
AiDSeller
За здоровый образ жизни
offline
Опыт: 6,094
Активность:
xak12, со "Скачком" мой метод слишком муторный. Можно как сделать: Давать спеллбук, в котором есть "Скачок" и скрывать его с самого начала игры. А при приближении к воротам снова показывать. Всё просто!
Хотя... Твой метод тоже ничего! Хотя, стоп. Какова вероятность того, что юнит будет проходить мимо ворот просто так? Нулевая! Если юнит хотел пройти при радиусе 600, он захочет пройти и при радиусе 120, так что твой алгоритм никак мой не упрощает. Так-то!
Старый 24.04.2011, 14:17
Hanabishi
COOL STATUS
offline
Опыт: отключен
ARHUI, раздели триггеры открытия и закрытия
Старый 24.04.2011, 16:34
ARHUI

offline
Опыт: 3,341
Активность:
Может не в тему но чтобы решить вопрос надо - как в jass закончить петлю цикла? аналог next() для for?
Старый 24.04.2011, 21:29
Hanabishi
COOL STATUS
offline
Опыт: отключен
ARHUI, в jass нет такой функции, есть только exitwhen
Старый 24.04.2011, 21:51
ARHUI

offline
Опыт: 3,341
Активность:
Jass вроде событийно ориентированный язык, тогда почему если в область входят юниты, то события путаются местами? Глюк с открытием закрытием ворот случается когда несколько юнитов выходят из области ворот, первое срабатывание закрывает ворота, второе открывает, при том что при предпоследнем срабатывании один юнит ещё был в области, а значит если ворота закрылись ясс в ту предпоследнюю функцию вернул количество юнитов 0.

ARHUI добавил:
а в последнюю 1

ARHUI добавил:
Если делать вот так:

Код:
function Initialization
    set udg_gates[0] = gg_dest_LTg4_1004
    set udg_gates[1] = gg_dest_LTg2_1003
    set udg_gates[2] = gg_dest_LTg4_1005
    set udg_gates[3] = gg_dest_LTg2_1002
    set udg_gates_reg[0] = gg_rct_TRGates
    set udg_gates_reg[1] = gg_rct_BRGates
    set udg_gates_reg[2] = gg_rct_BLGates
    set udg_gates_reg[3] = gg_rct_TLGates

local trigger t = CreateTrigger(  )
call TriggerRegisterEnterRectSimple( t, udg_open_gates[0] )
call TriggerRegisterLeaveRectSimple( t, udg_open_gates[0] )
call TriggerAddAction( t, function gate0 )
t = CreateTrigger(  )
call TriggerRegisterEnterRectSimple( t, udg_open_gates[1] )
call TriggerRegisterLeaveRectSimple( t, udg_open_gates[1] )
call TriggerAddAction( t, function gate1 )
t = CreateTrigger(  )
call TriggerRegisterEnterRectSimple( t, udg_open_gates[2] )
call TriggerRegisterLeaveRectSimple( t, udg_open_gates[2] )
call TriggerAddAction( t, function gate2 )
t = CreateTrigger(  )
call TriggerRegisterEnterRectSimple( t, udg_open_gates[3] )
call TriggerRegisterLeaveRectSimple( t, udg_open_gates[3] )
call TriggerAddAction( t, function gate3 )

endfunction

function gate0 takes nothing returns nothing
    local unit u = GetTriggerUnit()
    if (IsPlayerAlly(GetOwningPlayer(u),Player(9))==true)&&(udg_IsWorkingOnGates[0]==false) then
        call GatesActions(0,u)
    endif
endfunction

function gate1 takes nothing returns nothing
    local unit u = GetTriggerUnit()
    if (IsPlayerAlly(GetOwningPlayer(u),Player(9))==true)&&(udg_IsWorkingOnGates[1]==false) then
        call GatesActions(1,u)
    endif
endfunction

function gate2 takes nothing returns nothing
    local unit u = GetTriggerUnit()
    if (IsPlayerAlly(GetOwningPlayer(u),Player(9))==true)&&(udg_IsWorkingOnGates[2]==false) then
        call GatesActions(2,u)
    endif
endfunction

function gate3 takes nothing returns nothing
    local unit u = GetTriggerUnit()
    if (IsPlayerAlly(GetOwningPlayer(u),Player(9))==true)&&(udg_IsWorkingOnGates[3]==false) then
        call GatesActions(3,u)
    endif
endfunction


function GatesActions takes integer i, unit u returns nothing
    local integer a = NumberOfBuildersNearGate(i)
    call DisplayTextToPlayer(Player(0),0,0,"\n\r\n Trigger start\nnumber of builders near gate "+I2S(i)+" is " +I2S(a))
    if (udg_IsWorkingOnGates[i]==false) then
        call DisplayTextToPlayer(Player(0),0,0,"gate "+I2S(i)+" is not in job list working with it")
        set udg_IsWorkingOnGates[i]=true
        if ( GetUnitTypeId(u) == 'H024' ) then
            call DisplayTextToPlayer(Player(0),0,0,"Trigger unit is "+GetUnitName(u))
            if(a==0)then
                call DisplayTextToPlayer(Player(0),0,0,"Number of builders near gate "+I2S(i)+" is 0")
                if ( udg_IsGateDead[i] == false ) then
                    call DisplayTextToPlayer(Player(0),0,0,"number of gate to work on = "+I2S(i)+" this gate is not dead")

                    if ( udg_IsGateClosed[i]==true )&&(udg_IsGateOpened[i]==false) then
                        call DisplayTextToPlayer(Player(0),0,0,"gate "+I2S(i)+" is closed so attempting to open it")
                        set udg_GatesLife[i] = GetDestructableLife(udg_gates[i])
                        call DisplayTextToPlayer(Player(0),0,0,"last life is stored")
                        call KillDestructable(udg_gates[i])
                        call SetDestructableAnimation(udg_gates[i], "death alternate")
                        call DisplayTextToPlayer(Player(0),0,0,"gate animation modified to death alternate")
                        set udg_IsGateDead[i] = false
                        set udg_IsGateClosed[i]=false
                        set udg_IsGateOpened[i]=true
                        call SetDestructableLife( udg_gates[i], 0.00 )
                        call DisplayTextToPlayer(Player(0),0,0,"gate destroyed")
                    elseif ( udg_IsGateClosed[i]==false )&&(udg_IsGateOpened[i]==true) then
                        call DisplayTextToPlayer(Player(0),0,0,"gate "+I2S(i)+" is not dead, and has life 0.0, so attempting to close it")
                        call SetDestructableAnimation(udg_gates[i], "stand")
                        call DisplayTextToPlayer(Player(0),0,0,"gate animation modified to stand")
                        call SetDestructableLife( udg_gates[i], udg_GatesLife[i] )
                        set udg_IsGateDead[i] = false
                        set udg_IsGateClosed[i]=true
                        set udg_IsGateOpened[i]=false
                        call DisplayTextToPlayer(Player(0),0,0,"last life is restored")
                    endif
                    
                    call DisplayTextToPlayer(Player(0),0,0,"gate open/close related actions ended calling AntiStuck()")
                    call AntiStuck()
                else
                    call DisplayTextToPlayer(Player(0),0,0,"gate "+I2S(i)+" is dead so no need to open/close it")
                endif
            else
                call DisplayTextToPlayer(Player(0),0,0,"near gate "+I2S(i)+" more than one builder founded ("+I2S(a)+")")
            endif
        endif
        set udg_IsWorkingOnGates[i]=false
    else
        call DisplayTextToPlayer(Player(0),0,0,"gate "+I2S(i)+" is already in job list")
    endif
    call DisplayTextToPlayer(Player(0),0,0,"End GatesActions function \n\r\n")
endfunction



порядок функций конечно обратный, но бывают сбои, хотя на гуи:

на вход юнита

Код:
function Trig_____________________________________008_Func004001 takes nothing returns boolean
    return ( CountUnitsInGroup(GetUnitsInRectAll(gg_rct_open_gates_TL)) == 0 )
endfunction

function Trig_____________________________________008_Func004002 takes nothing returns boolean
    return ( IsPlayerAlly(GetOwningPlayer(GetEnteringUnit()), Player(0)) == true )
endfunction

function Trig_____________________________________008_Conditions takes nothing returns boolean
    if ( not ( udg_IsGateDead[3] == false ) ) then
        return false
    endif
    if ( not GetBooleanAnd( Trig_____________________________________008_Func004001(), Trig_____________________________________008_Func004002() ) ) then
        return false
    endif
    if ( not ( GetDestructableLife(gg_dest_LTg2_1002) > 0.00 ) ) then
        return false
    endif
    return true
endfunction

function Trig_____________________________________008_Actions takes nothing returns nothing
    set udg_GatesLife[3] = GetDestructableLife(gg_dest_LTg2_1002)
    call DisableTrigger( gg_trg_MarkDeadGates )
    call ModifyGateBJ( bj_GATEOPERATION_OPEN, gg_dest_LTg2_1002 )
    call EnableTrigger( gg_trg_MarkDeadGates )
endfunction

//===========================================================================
function InitTrig_____________________________________008 takes nothing returns nothing
    set gg_trg_____________________________________008 = CreateTrigger(  )
    call TriggerRegisterEnterRectSimple( gg_trg_____________________________________008, gg_rct_open_gates_TL )
    call TriggerAddCondition( gg_trg_____________________________________008, Condition( function Trig_____________________________________008_Conditions ) )
    call TriggerAddAction( gg_trg_____________________________________008, function Trig_____________________________________008_Actions )
endfunction



на выход юнита


Код:
function Trig_____________________________________009_Func004001 takes nothing returns boolean
    return ( CountUnitsInGroup(GetUnitsInRectAll(gg_rct_open_gates_TL)) == 0 )
endfunction

function Trig_____________________________________009_Func004002 takes nothing returns boolean
    return ( IsPlayerAlly(GetOwningPlayer(GetLeavingUnit()), Player(0)) == true )
endfunction

function Trig_____________________________________009_Conditions takes nothing returns boolean
    if ( not ( udg_IsGateDead[3] == false ) ) then
        return false
    endif
    if ( not GetBooleanAnd( Trig_____________________________________009_Func004001(), Trig_____________________________________009_Func004002() ) ) then
        return false
    endif
    if ( not ( GetDestructableLife(gg_dest_LTg2_1002) <= 0.00 ) ) then
        return false
    endif
    return true
endfunction

function Trig_____________________________________009_Actions takes nothing returns nothing
    call ModifyGateBJ( bj_GATEOPERATION_CLOSE, gg_dest_LTg2_1002 )
    call SetDestructableLife( gg_dest_LTg2_1002, udg_GatesLife[3] )
endfunction

//===========================================================================
function InitTrig_____________________________________009 takes nothing returns nothing
    set gg_trg_____________________________________009 = CreateTrigger(  )
    call TriggerRegisterLeaveRectSimple( gg_trg_____________________________________009, gg_rct_open_gates_TL )
    call TriggerAddCondition( gg_trg_____________________________________009, Condition( function Trig_____________________________________009_Conditions ) )
    call TriggerAddAction( gg_trg_____________________________________009, function Trig_____________________________________009_Actions )
endfunction



если выключить первые функции и оставить два триггера на гуи для 3-их ворот, то все работает, мне так и не удалось заставить их глючить сколько бы героев я в эту область не вводил/выводил.
Если оставить только первые функции то для одного героя ничего не глючит да и для двух тоже, но три и более при почти одновременном входе или выходе заставляют функцию работать некорректно.

У меня складывается ощущение что jass не по порядку обрабатывает события, а как повезет, и вот когда ему везет почти параллельно обработать события выхода для двух юнитов с приорететом на последнего вышедшего юнита (тоесть сначала он посылает на выполнение функцию для последнего вышедшего юнита, которая вычисляет что в регионе никого нет и ворота закрываются ) потом на предпоследнего (что ещё один юнит в регионе и ворота открываются) и получается что когда никого нет в регионе то ворота открыты...

Поправьте если не прав.
Старый 25.04.2011, 17:21
Faion
Noblesse Oblige
offline
Опыт: 30,395
Активность:
ARHUI, дебагами разметь место отвечающее за открытие\закрытие, выведи значения важные на экран, и смотри какие значения недопустимы, ну а далее отслеживай почему эти значения стали таковыми.
Старый 26.04.2011, 11:15
Hanabishi
COOL STATUS
offline
Опыт: отключен
ARHUI, способ реализации лучше заменить на периодический пик
Старый 26.04.2011, 14:01
ARHUI

offline
Опыт: 3,341
Активность:
Цитата:
способ реализации лучше заменить на периодический пик

Прикол в том что ещё до того как карта стала называться по новому, я так и делал, но потом решил попробовать сделать по событиям входа/выхода, с тех пор мучаюсь...

ARHUI добавил:
Оставил таймер и включил регионы...
Старый 26.04.2011, 17:44
Ответ

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

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

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

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



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