WarCraft 3: 5. Функции в jass

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

5. Функции в jass

Что такое функция? Функция, это фрагмент кода, в который можно передавать параметры, который может возвращать один параметр и производить определенные действия. Не очень понятно, но вспомни в предыдущем сообщении, как для определения выполняется ли условие i=1 создавалась специальная функция.
Кроме того, ты наверное замечал, что при переводе триггера в jass, в итоге создаются несколько функций. Обычно, функция для действий триггера, для условия, а также функция для присоединения события. Но об этом я еще напишу позже.
Самое главное, что функции можно использовать, чтобы сделать код более удобным и коротким. Синтаксис функции выглядит следующим образом:
function <ИМЯ ФУНКЦИИ> takes <ПЕРЕЧЕНЬ ПАРАМЕТРОВ, которые функция БЕРЕТ> returns <тип параметра, который функция ВОЗВРАЩАЕТ>
...
<ПЕРЕЧЕНЬ ДЕЙСТВИЙ ФУНКЦИИ>
...
endfunction
Все это может быть выглядит страшно, но мы разберем на примерах. Самый простой вид функций - та которая ничего не берет и ничего не возвращает. К примеру, создадим функцию с именем property, которая при каждом ее запуске дает игроку1 1000 золотых.
Такая функция будет выглядеть следующим образом:
function property takes nothing returns nothing
    call AdjustPlayerStateBJ( 1000, Player(0), PLAYER_STATE_RESOURCE_GOLD )
endfunction
Несколько замечаний. Во-первых действие добавления денег взято путем перевода такого действия из триггеров в jass. Я сказал, что деньги даются игроку1, а в коде написано Player(0) - это потому что в jass игроки начинают нумероваться с нуля. Т.е. 0 - номер первого игрока, 1 - второго и т.д. PLAYER_STATE_RESOURCE_GOLD - кодовое слово, которое означает, что прибавляется именно золото, а не скажем лес.
Вместо перечня параметров, которые берутся и вместо типа параметра, который возвращается функцией стоит слово nothing - на английском означает ничего. Т.е. функция ничего не берет и ничего не возвращает. Она просто делает действие - добавляет деньги игроку1.
Для того, чтобы вызвать эту функцию на исполнение, достаточно написать команду
call property()
() - это скобки, в которых указывается список параметров для функции, но в нашем случае он пуст.
Ты можешь вставить эту команду в триггеры (в виде custom script) или в jass. Когда триггер запущен и очередь дойдет до этой команды, будет запущена функция и выполнены все ее действия. И при каждом запуске игрок1 будет получать 1000 золота.
Конечно, функция состоящая из одного действия не имеет смысла, но действий может быть и больше. Если в триггерах или коде имеются часто повторяющиеся фрагменты, то имеет смысл создать функцию и заменять фрагмент на вызов функции.
Пока что я не рассказал, а куда нужно вставлять текст функции. Это нельзя делать куда попало. Нельзя вставлять функцию внутрь другой функции. Функцию можно вставить в пустое пространство между другими функциями в триггере или в специально отведенное место (второй вариант предпочтительнее, позже расскажу почему).
Путь к этому специальному месту: открой редактор триггеров. Слева в окне найди дерево триггеров (список папок и самих триггеров). Самая высокая позиция этого дерева - иконка карты. Щелкни на нее. Справа откроется окно "Нестандартный код". Вот в него и нужно вставлять функции.
Вставь в это окно текст функции property. Затем сделай триггер с событием Map Initialization и действием: cs call property()
Запусти сценарий и проверь, что функция действительно работает.
Итак, первая и самая простая функция сделана. Но функции очень удобны тем, что они могут принимать определенные параметры, которые влияют на действие функции. К примеру, модернизируем функцию property, чтобы она давала 1000 золота не первому игроку, а игроку, которого мы укажем в параметре. Т.е. в функцию мы будем передавать параметр номер игрока (типа integer). В итоге, функция будет выглядеть так
function property takes integer n returns nothing
    call AdjustPlayerStateBJ( 1000, Player(n-1), PLAYER_STATE_RESOURCE_GOLD )
endfunction
Смотри, в первой строке вместо takes nothing теперь стоит takes integer n. Это означает, что функция имеет 1 параметр типа integer. Чтобы запустить функцию с параметром, нужно будет вставить строку
call property(<какое-то число>)
И это самое число будет передано в функцию при запуске и записано в локальную переменную n. Вот такой фокус. Мы можем вводить номер игрока, которому мы хотим дать 1000 золота и этот номер будет передан в функцию. А для того, чтобы дать 1000 золота игроку с этим номером, мы переделали вторю строку:
call AdjustPlayerStateBJ( 1000, Player(n-1), PLAYER_STATE_RESOURCE_GOLD ) 
Т.е. дать 1000 золоту игроку с индексом n-1. Я нарочно поставил не n, а n-1, т.к. мы привыкли нумеровать игроков с 1, а в jass нумерация идет с 0.
Итак, если у нас имеется указанная функция, то чтобы дать игроку1 1000 золота, мы можем набрать команду
call property(1) 
Еще несколько слов о параметрах. Во-первых, параметров может быть любое число и они могут быть любого типа. Если параметров более одного, то они идут перечислением через запятую. Например, вот модернизированная функция, в которую мы в качестве параметров передаем не только номер игрока, но и количество золота.
function property takes integer n, integer gold returns nothing
    call AdjustPlayerStateBJ( gold, Player(n-1), PLAYER_STATE_RESOURCE_GOLD )
endfunction
Но сколько параметров у функции, столько должно передаваться и при ее вызове. Т.е. для вызова нужно использовать строку
call property(1,1000) 
Во-вторых, параметры, как я и говорил, передаются в локальные переменные. Но в любой функции могут быть и другие локальные переменные. Просто нужно объявить их в начале функции
function property takes integer n, integer gold returns nothing
    **local real r**
    call AdjustPlayerStateBJ( gold, Player(n-1), PLAYER_STATE_RESOURCE_GOLD )
endfunction
Ну и еще одно замечание. В большинстве языков программирования имеется разделение понятий процедура и функция. Процедура - фактически тоже самое что и функция, но она ничего не возвращает в качестве параметра. Все примеры, рассмотренные нами выше - брали или не брали параметры, но все равно ничего не возвращали. Т.е. грамотнее было бы назвать их процедурами.
И переходим к последнему - самому общему варианту, когда функция что-то возвращает. Раньше мы везде писали returns nothing, но если мы хотим, чтобы функция что-то вернула, нужно указать какой-нибудь тип. Скажем returns integer (возвратить параметр типа integer). Например, если мы хотим создать функцию, которая будет возвращать нам сумму чисел от 1 до n, где n - параметр, передаваемый в функцию. Функция выглядит так:
function summa takes integer n returns integer
local integer i
local integer s
    set i = 1
    set s = 0
    loop
        exitwhen i > n
        set s = s + i
        set i = i + 1
    endloop
return s
endfunction
Попытайся разобраться с действием этой функции. Внутри есть цикл, который нужен для нахождения суммы 1+2+...+n. Далее есть ключевое слово return - это одновременно команда прекратить выполнение функции, и способ заставить функцию вернуть значение.
return s означает, что функция вернет значение из переменной s, т.е. искомую сумму.
Как же обратиться к такой функции для ее вызова? Функции, возвращающие определенное значение, вызываются по-особому. Их можно использовать в каких-то выражениях или равенствах. К примеру, если у тебя есть глобальная переменная i, ты можешь вызвать функцию summa следующим образом:
cs set udg_i = summa(10) 
И тогда РЕЗУЛЬТАТ ФУНКЦИИ, то что она возвращает - сумма, будет помещен в переменную i. Или можно сделать так:
cs set udg_i = summa(9+1)+2
Тогда в переменную i будет помещена сумма чисел от 1 до 10 плюс еще 2 единицы.
В этом и состоит смысл функций, с возвращаемым значением.
Примечания:
  1. Тип данных, возвращаемых функцией должен совпадать с переменной, куда мы пишем это значение. integer-integer или real-real.
  2. Вообще говоря, даже если функция возвращает значение, ее можно запустить методом
call <Функция> (<параметры>)
Но понятное дело, значение функции, которое оно возвращает, не будет никуда записано.
  1. Команда return представляет определенный интерес сама по себе. Если ты проверишь, во что превратится команда skip remaining actions в jass - она превратится в return. Т.е. это команда, которая прерывает исполнение функции.
  2. Допускается запуск одной функции из другой. К примеру, в функцию summa можно вставить строчку
call property(1,1000) 
Но может возникнуть ошибка. Обращаться можно только к функции, которая записана выше данной (т.е. создана раньше). Т.е. если функция property будет ниже чем summa - то обращаться к property из summa нельзя.
Кстати, код в специальном месте для триггерных функций расположен ВЫШЕ чем код всех игровых триггеров. Поэтому к функциям записанным здесь можно обращаться из любого триггера.
  1. Если внимательно приглядеться, то кроме функций, определенных пользователем (т.е. тобой) существуют еще и встроенные функции. К примеру, глянь команду
call AdjustPlayerStateBJ( gold, Player(n-1), PLAYER_STATE_RESOURCE_GOLD )
Слово call тебе ни о чем не говорит? :). AdjustPlayerStateBJ - это встроенная функция с тремя параметрами. Список всех таких встроенных функций имеется в MPQ архивах. Так что получается у нас, что все триггеры устроены так, что одни функции ссылаются на другие, те на третьи и т.д. :).
На этом о функциях пока все.
В качестве примера по тому, что мы пока прошли, предлагаю изучить сценарий AR, в котором реализован достаточно простой огнемет на jass с использованием массивов, циклов и функций.

Просмотров: 24 870

Sie7eN #1 - 8 лет назад 2
Гранатомет неплохой :D
MaKoPoH #2 - 7 лет назад 2
ага ваще норм =)
Revolver_45 #3 - 7 лет назад 0
Жидко
Дмиллидан #4 - 7 лет назад 0
Отлично всё написано, чё вы паритесь?
Hares #5 - 7 лет назад 0
А если в фи-ю wait'ы вставлять, то на коде эти вэйты будут отображаться?
Rubiont_47 #6 - 6 лет назад 0
Слушай, блин, огромное тебе спасибо за эти статьи! Ты мне прям открыл глаза на Джасс!
Orlok #7 - 6 лет назад 0
лудше б пример по проще дал, а то куча неизвестного есть... =(
Inside_the_Fire #8 - 6 лет назад 0
Хорошо только примеров нет :(
Daro #9 - 5 лет назад 0
Что такое BJ, объясните
Monflame #10 - 5 лет назад -1
хм, странно, но в примере нет функций. Там только процедуры. Никто ничего никуда не возвращает
alexprey #11 - 5 лет назад 0
Monflame, гонишь.
Monflame #12 - 5 лет назад 0
BJ - Blizzard Job (наверное) :)
horr0rjkee #13 - 4 года назад 0
Как сделать глобальную функцию?
Допустим создал в инициаций мапы. И чтобы в другом триггере использовать.
Если такое возможно, помогите :).
Hate #14 - 4 года назад 0
horr0rjkee:
Как сделать глобальную функцию?
Допустим создал в инициаций мапы. И чтобы в другом триггере использовать.
Если такое возможно, помогите :).
у вас проблемы с пониманием сути работы кода. погуглите темы на форуме про код и выполнение данных, в статье одной на сайте тоже есть
lehanru #15 - 4 года назад 0
4 раза перечитал, понял )) Спасибо .
Buulichkaa #16 - 4 года назад (отредактировано ) 0
lehanru, я уже удалял ваши комментарии подобного рода, если у вас нет "особых вопросов" (которые ещё не разбирались), то не нужно оставлять комментарии с благодарностями и прочим...
Это бессмысленное воскрешение постов и забивание ленты, если вы хотите поблагодарить автора - поставьте плюсик и выпишите ему большой лист с пожеланиями добра в ЛС.
votamgen #17 - 3 года назад (отредактировано ) 0
Большущее спасибо аффтару. Очень понятно объясняете. Реально помогает.
только вот 1 вопрос. В триггере 'Fire' (29я строка):
call ForGroup( GetUnitsInRangeOfLocAll(70.00, p), function Trig_Flamethrower_Func2 )
Тут создана целая функция для того, что бы вызвать выполнить триггер:
function Trig_Flamethrower_Func2 takes nothing returns nothing
call TriggerExecute( gg_trg_Fire_damage )
endfunction
Нельзя ли, записать например так:
call ForGroup( GetUnitsInRangeOfLocAll(70.00, p), call TriggerExecute( gg_trg_Fire_damage ) )
спс.
votamgen #19 - 3 года назад 0
Дайте ссылку с подробной инфой (или хотя бы название темы). спс.
эм... нашел =)) Это описано в след. статье. ГЫыы
Artyom17 #20 - 3 года назад 0
ХМ,я сделал все также скопировал пробую...27 ошибок вылетел редактор.
mszuben #21 - 7 месяцев назад 0
Здравствуйте. Есть возможность объявления функций в функции для доступа к локальным переменным функции?
GetLocalPlayer #22 - 7 месяцев назад 0
mszuben, вложенные функции языком Jass не предусмотрены.
Clamp #23 - 7 месяцев назад 0
GetLocalPlayer, ну, есть lambda-функции в cJass.
mszuben, пользуйтесь структурами vJass.
GetLocalPlayer #24 - 7 месяцев назад (отредактировано ) 0
ну, есть lambda-функции в cJass.
Это всего лишь визуальная имитация анонимных функций. Они не дают замыканий требуемых вопрошающим.
Clamp #25 - 7 месяцев назад 0
Они не дают замыканий.
Чисто технически они там таки эмулируются. Кроме того, этой строкой я отвечал не вопрошающему, а тебе =)
GetLocalPlayer #26 - 7 месяцев назад 0
Чисто технически они там таки эмулируются.
И даже в коллбеках?