JASS – триггеры в виде кода. Недавно я подумал, что уже довольно давно не писал статей и решил написать статью на тему триггеры в понимании JASS. Собственно, вот то, что из этого вышло. Итак, триггер. Вспомним, из чего он состоит. - События.
- Условия.
- Действия.
И начнём мы с общего анализа триггера в текстовом виде. Для примера создадим триггер с названием Sample. Добавим в него событие Игрок красный выигрывает ( Игрок - Victory). Теперь – условие: Игрока красного контролирует человек ( Player Controller Comparison). Ну и в качестве действия выведем на экран строку: « Вы выиграли!!!» (действие Игра – Text Message). Теперь у нас есть триггер. Переведя его в текст, мы получим это: | Code | | function Trig_Sample_Conditions takes nothing returns boolean <br /> if ( not ( GetPlayerController(Player(0)) == MAP_CONTROL_USER ) ) then <br /> return false <br /> endif <br /> return true <br /> endfunction <p> function Trig_Sample_Actions takes nothing returns nothing <br /> call DisplayTextToForce( GetPlayersAll(), "Вы выиграли!!!" ) <br /> endfunction <p> //======================================================== <br /> function InitTrig_Sample takes nothing returns nothing <br /> set gg_trg_Sample = CreateTrigger( ) <br /> call TriggerRegisterPlayerEventVictory( gg_trg_Sample, Player(0) ) <br /> call TriggerAddCondition( gg_trg_Sample, Condition( function Trig_Sample_Conditions ) ) <br /> call TriggerAddAction( gg_trg_Sample, function Trig_Sample_Actions ) <br /> endfunction | У нас есть три функции. Начать стоит с самой последней ( InitTrig_Sample). Как видно, её название состоит из приставки InitTrig_ и названия триггера. InitTrig – инициализация триггера. В этой функции триггер регистрируется в игре. Это происходит в первой троке: | Code | | set gg_trg_Sample = CreateTrigger( ) | gg_trg_Sample – это что то вроде глобальной переменной ( ubg_), но используется она только для триггеров. То есть создаётся новый триггер, который записывается в переменную. Следующая строка – регистрация события. Собственно, чтобы добавить событие, нужно вызвать соответствующую функцию (в нашем случае TriggerRegisterPlayerEventVictory) и передать в неё все параметры ( gg_trg_Sample, Player(0)). *Примечание. Событие Map initialization – особый случай и о нём мы поговорим позднее. Далее идёт добавление условия: | Code | | call TriggerAddCondition( gg_trg_Sample, Condition( function Trig_Sample_Conditions ) ) | Здесь принцип несколько другой, чем для добавления событий. Функция добавления условий одна (TriggerAddCondition). В неё мы передаём триггер и функцию с условиями. Теперь посмотрим на саму функцию с условиями. Там всё чрезвычайно запутанно. Но ведь в этом и цель ВЕ – запутать всех и вся =). В конце концов весь этот код можно свести к одной строчке: | Code | | return GetPlayerController(Player(0)) == MAP_CONTROL_USER | *Примечание. Добавлять условия в функцию InitTrig_*** ВЕ будет только тогда, когда эти условия добавлены именно в блок с условиями триггера. Если же, например, мы использовали действие if / then / else, то функция с условиями создастся, но в функцию инициализации триггера она не добавится. В триггере можно создавать сколько угодно отдельных функций, которые не должны нигде указываться. Добавлено (19-04-2007, 11:03 Pm) ---------------------------------------------
С условиями разобрались. Посмотрим теперь на действие. Собственно, здесь всё аналогично условию (за исключением названия функции =). Так что объяснять всё подробно нет смысла. Вот вкратце об устройстве триггеров. Теперь немного поговорим об оптимизации. Я уже немного говорил об этом (условие), но теперь стоит сказать зачем это вообще надо. Ну, первый факт, это конечно удобство. Ведь если каждое условие будет создавать новую функцию, в которой будут тонны ненужных операторов… Всё это в конце концов приведёт к хронической головной боли. Далее. Лишняя нагрузка – лишний геморрой. Да и к тому же гораздо проще разобраться в триггере (постороннему человеку) когда он решит поподробней рассмотреть наработку =). Но вот хуже всего в ВЕ реализованы циклы, которые перебирают всех юнитов в определённой области. Предположим, мы хотим убить всех юнитов на карте. Опущу подробности такого сложного триггера =) и приведу его сразу на JASS: | Code | | function Trig_KillAllUnit_Func001A takes nothing returns nothing <br /> // Здесь действия цикла <br /> call KillUnit( GetEnumUnit() ) <br /> endfunction <p> function Trig_KillAllUnit_Actions takes nothing returns nothing <br /> // Здесь действия функции <br /> call ForGroupBJ( GetUnitsInRectAll(GetPlayableMapRect()), function Trig_KillAllUnit_Func001A ) <br /> endfunction | К сожалению, объединить данную конструкцию в одну функцию нельзя. Но можно сделать её несколь-ко красивее. Например, так: | Code | | function KILL takes nothing returns nothing <br /> call KillUnit(GetEnumUnit()) <br /> endfunction <p> function Trig_KillAllUnit_Actions takes nothing returns nothing <br /> call ForGroupBJ( GetUnitsInRectAll(GetPlayableMapRect()), function KILL ) <br /> endfunction | В такие функции-циклы нельзя передавать параметры. То есть, для передачи данных в них надо использовать переменные (или аналогичные способы передачи данных, о которых я расскажу в следующих статьях). Теперь отдельный разговор о событии Map Initialization. На самом деле, это даже не событие. Оно никак и нигде не регистрируется. Такие триггеры исполняются во время инициализации потоков игры. Соответственно серьёзные ошибки в таких триггерах могут привести к краху этих самых потоков. И в конце ещё одно примечание. Код из действия Custom Script остаётся неизменным при переводе с GUI на JASS. Вот я и рассказал о триггерах. Если дойдут руки до следующей части о триггерах, опишу их создание динамически (что очень часто бывает чрезвычайно полезным). А пока на этом всё. Жду комментов.
Я ведь... Сам должен командовать! © Артес Если кому-то требуется моя помощь - пишите в аську, ибо общаться через ЛС очень сложно.
|