WarCraft 3: 4. Условия и циклы в jass

Осваиваем jass (0-1)

4. Условия, циклы в jass

Рассмотрим такой пример: имеется фрагмент триггерного действия
For each (Integer i) from 1 to 10, do (Actions)
    Цикл
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            Условие
                i равно 1
            Действие
                Set s = (s + 2)
            Иначе
                Set s = (s + 1)
Цикл по i от 1 до 10 и условие внутри цикла. Во что превратится это действие, когда мы переведем его в jass? Создай в редакторе такой триггер и проверь.
Действие превратится в следующий фрагмент
    set udg_i = 1
    loop
        exitwhen udg_i > 10
        if ( Trig_____________________________________001_Func001Func001C() ) then
            set udg_s = ( udg_s + 2 )
        else
            set udg_s = ( udg_s + 1 )
        endif
        set udg_i = udg_i + 1
    endloop
Думаю, что пока не очень понятно, что здесь за что отвечает. Начнем с оператора if. Очевидно, он превратился в строки:
        if ( Trig_____________________________________001_Func001Func001C() ) then
            set udg_s = ( udg_s + 2 )
        else
            set udg_s = ( udg_s + 1 )
        endif
Все что ниже первой строки - понятно, но почему вместо нормального условия в первой строке стоит "( Trig_____________________________________001_Func001Func001C() )"? Дело в том, что редактор триггеров довольно глупо переводит условия из триггеров или триггерных действий. После такого перевода часто приходится исправлять и оптимизировать код. В нашем случае, редактор создал специальную функцию с именем Trig_____________________________________001_Func001Func001C() для того, чтобы проверить нужное нам условие, что i=1. Эту функцию ты можешь увидеть вверху триггера:
function Trig_____________________________________001_Func001Func001C takes nothing returns boolean
    if ( not ( udg_i == 1 ) ) then
        return false
    endif
    return true
endfunction
Пока не будем вдаваться в то, что это за функция и что она делает. Самое главное - эта функция возвращает значение true (истина) если i=1, или ложь, если i не равно 1. Возникает вопрос: что же, при каждом применении оператора if нам придется создавать какую-то функцию? Ничего подобного - можно обойтись и без нее! Стираем эту ненужную функцию, а в строчку вносим изменения:
if (udg_i == 1) then
И все. остальное оставляем неизменным. У нас получится фрагмент кода:
    set udg_i = 1
    loop
        exitwhen udg_i > 10
        if (udg_i == 1) then
            set udg_s = ( udg_s + 2 )
        else
            set udg_s = ( udg_s + 1 )
        endif
        set udg_i = udg_i + 1
    endloop
Теперь ты знаешь, что такое оптимизация :).
Но остается открытым вопрос: что же такое мы вставили в условие оператора if. Это просто проверка, равна ли переменная i единице. В jass есть специальные значки для проверки условий равенства или неравенства:
== (два знака равно) переводится как равно
!= переводится как не равно
< меньше
> больше
<= меньше или равно
>= больше или равно.
Т.е. если мы хотим записать условие **i[.b] не равно 10, то оно будет выглядеть
i!=10
Теперь ты можешь сам разобраться с условным оператором в jass:
        if (udg_i == 1) then
            set udg_s = ( udg_s + 2 )
        else
            set udg_s = ( udg_s + 1 )
        endif
Переводится как "Если i=1 то делать то-то иначе делать то-то".
Хорошо, с условным оператором разобрались. А как насчет циклов?
К оператору цикла относятся следующие строки:
    set udg_i = 1
    loop
        exitwhen udg_i > 10
        ...
        set udg_i = udg_i + 1
    endloop
... - это могут быть любые действия, которые происходят внутри цикла
Итак, перед началом цикла переменной i присваивается значение 1 - это начальное значение для нашего цикла.
loop - ключевое слово, означающее начало цикла
endloop - конец цикла
Т.е. действия между loop и endloop будут повторяться. Но сколько раз они должны повторяться? Вообще говоря, 10. Но в jass все циклы устроены более универсально, чем в триггерах. Тут циклы повторяются не ОПРЕДЕЛЕННОЕ ЧИСЛО РАЗ, а ДО ТЕХ ПОР, ПОКА НЕ БУДЕТ ВЫПОЛНЕНО ТАКОЕ-ТО УСЛОВИЕ. За проверку этого условия отвечает строка:
exitwhen <УСЛОВИЕ> - переводится как выйти из цикла, когда выполнено УСЛОВИЕ.
exitwhen udg_i > 10 - переводится как выйти из цикла, когда переменная i станет больше 10.
Мы могли бы к примеру написать условие
exitwhen udg_i == 10- выйти из цикла, когда iстанет равно 10. Тогда в цикле будет выполнено на одно действие меньше.
Итак, вся наша структура
    set udg_i = 1
    loop
        exitwhen udg_i > 10
        ...
        set udg_i = udg_i + 1
    endloop
имеет следующий смысл. Переменная i приравнивается к 1. На каждом витке цикла проверяется, не стала ли переменная i больше 10. Если не стала, производится какое-то действие и затем переменная i увеличивается на 1. И так до тех пор, пока не будет выполнено условие окончания цикла.
Итоги:
  1. Условный оператор при переводе триггера в jass не очень удобен, т.к. его приходится оптимизировать.
  2. Оператор цикла в jass более универсальный, т.к. действие производится не фиксированное число раз, а до тех пор, пока не выполнится условие. Кроме того, переменную цикла в триггерах можно увеличивать только на 1, а в jass - ее можно изменять произвольным образом.
Читатель, про циклы можно сказать еще следующее. Если ты попробуешь перевести в текст действие
For each (Integer A) from 1 to 10, do (Actions)
   ...
(т.е. воспользуешься одним из циклов с Integer A или Integer B, то на выходе получишь:
    set bj_forLoopAIndex = 1
    set bj_forLoopAIndexEnd = 10
    loop
        exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd
        ...
        set bj_forLoopAIndex = bj_forLoopAIndex + 1
    endloop
Что такое bj_forLoopAIndex и bj_forLoopAIndexEnd? Оказывается это специальные глобальные переменные, которые используются для проверки условий окончания такого вида цикла. Обычные переменные типа integer. Проверь сам - действие в цикле будет выполнено ровно 10 раз.
Отсюда вывод: хочешь ты того или нет, но редактор всегда вставляет в твой сценарий 4 специальных глобальных переменных:
set bj_forLoopAIndex
set bj_forLoopAIndexEnd
set bj_forLoopBIndex
set bj_forLoopBIndexEnd
В принципе они предназначены для циклов, а на самом деле при помощи jass в них можно записывать все что угодно. Кстати, подобных переменных на самом деле довольно много.

Просмотров: 22 180

» Лучшие комментарии


Orses #1 - 6 лет назад 2
Sergey респект ты хорошо учишь =)
Hares #2 - 6 лет назад 3
т. е. For он конвертирует в While, а For'a там нет. Хорошо в VB и For, и While, и Loop.
DDestyny #3 - 6 лет назад 0
Вопрос: зачем нам эти специальные глобальные если мы можем использовать вообще простые локальные переменные?
Nanopro #4 - 6 лет назад 0
DDestyny, Ты прав, если делать все целиком в jasse то можно использовать local integer i
GF RaiseD #5 - 5 лет назад 1
Давно надо было начать изучать Jass чтоб нормально сделать хоть один спелл.
Автору спасибо. . .
VMS1 #6 - 5 лет назад 0
Спс, автору, только во второй теме такую фигню нес, аж нече не понятно было:)А щас гуд:) 2 тема для профессионалов а тут для новичков:)
lehanru #7 - 3 года назад 0
Отличная статья !
VovkaShyt #8 - 3 года назад 0
Мне тоже понравилась я начал немного понимать чё за фигня этот jass)))
xANDYx #9 - 3 года назад 2
Мне тоже понравилась я начал немного понимать чё за фигня этот jass
Отсутствие запятых и логических ударений даёт возможность интерпретировать эту фразу по разному.
Artyom17 #10 - 2 года назад 2
Мда,у меня совсем по другому...
Lilop #11 - 1 год назад (отредактировано ) 0
Как сделать так вот допустим Сделал способность на основе 1 твоего урока, но теперь суть в том что когда снаряд долетает до цели он поднимает цель и под ним создается эффект будто он поднят на"буране" на торнадо, но надо еще сделать так что бы юнит кружился вокруг себя пока не закончится действие способности а то есть в течении 5 секунд??
function Trig_Trig_Spell_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'Awfb' ) ) then
return false
endif
return true
endfunction
function Trig_Trig_Spell_Actions takes nothing returns nothing
local unit u
local effect e
set u = GetSpellTargetUnit()
call PolledWait( ( DistanceBetweenPoints(GetUnitLoc(GetSpellAbilityUnit()), GetUnitLoc(GetSpellTargetUnit())) / 1000.00 ) )
call UnitAddAbilityBJ( 'Amrf', u )
call SetUnitFlyHeightBJ( u, 150.00, 500.00 )
call AddSpecialEffectLocBJ( GetUnitLoc( u ), "Abilities\\Spells\\Other\\Tornado\\TornadoElementalSmall.mdl" )
set e = GetLastCreatedEffectBJ()

call TriggerSleepAction( 3.00 )
call DestroyEffectBJ (e)
call PolledWait( 4.00 )
call SetUnitFlyHeightBJ( u, 0.00, 600.00 )
call UnitRemoveAbilityBJ( 'Amrf', u )
endfunction
===========================================================================
function InitTrig_Spell takes nothing returns nothing
set gg_trg_Spell = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spell, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Spell, Condition( function Trig_Trig_Spell_Conditions ) )
call TriggerAddAction( gg_trg_Spell, function Trig_Trig_Spell_Actions )
endfunction