ГлавнаяБлогКарты Warcraft 3Гайды для первой ДотыГайды для Доты 2 [ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
Зарегистрированные пользователи не видят всплывающей рекламы
Страница 1 из 11
Модератор форума: Goodie 
Форум » Картостроение в Warcraft 3 » Статьи » Локальные переменные (jass)
Локальные переменные
Дата: Вторник, 04.10.2011, 23:15 | Сообщение # 1
Генералиссимус
Заблокированные
Сообщений: 2263
Награды: 8
Репутация: 85
Не советую полностью превращать триггер в текст, досаточно использовать триггер "нестандартный код" (Custom Code)
И в него вписывать какой либо код.

Если вам интересно, как на Жасс записать тот или иной триггер - создайте тригер, задайте ему действие и через меню преобразуйте в текст.

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

Локальные переменные

Локальные переменные – это воистину первый шаг в освоении jass. И это очень важный шаг. Умея работать с локальными переменными, ты сможешь заметно упростить себе решение многих триггерных задач.

Читатель, прежде чем начнем изучение, я советую тебе скачать файл sample locs.w3x, который приложен к данной статье. Скачай, затем открой в редакторе и запусти на исполнение. Суть примера в том, что если стрельнуть заклинанием файербол, над головой жертвы появляется спецэффект «восклицательный знак», который через несколько секунд исчезнет. Действие сделано на триггерах с применение локальных переменных.

С одной стороны можно задать вопрос – а зачем тут вообще нужны триггеры? Этого же эффекта можно достичь в редакторе объектов. Да, можно. Но главное не это. Вместо спецэффекта мы можем навесить и любое другое действие. Например, при ударе файербола, на юните будет появляться череда сменяющих друг друга спецэффектов. Такого в редакторе объектов уже не сделаешь.

А можно ли сделать этот эффект при помощи обычных триггеров? Конечно. Для одного юнита, это легко сделать. Например, запустил юнит файербол, мы:
Помещаем цель заклинания в переменную u типа юнит.
Ждем время, пока файербол долетит (которое равно расстояние до цели делить на скорость полета).
Создаем спецэффект на юните u, который записываем в переменную se типа спецэффект.
Через несколько секунд уничтожаем спецэффект se.

Все просто, но... Насколько такой триггер будет универсален? Предположим, несколько юнитов имеют заклинание файербол, и поочередно друг за другом применяют его, так что два триггерных действия (создание спецэффекта) выполняются в короткий промежуток времени. Тогда у нас произойдет триггерный конфликт. Ведь в одни и те же переменные u и se будут писаться параметры для разных файерболов. В итоге у нас могут появиться 2 спецэффекта над одним и тем же юнитом и один из этих спецэффектов останется навсегда. Все это произойдет из-за того, что без переменных вообще обойтись нельзя, а для разных запусков нельзя использовать одни и те же переменные.

Есть способ исправить эту проблему: для каждого запуска файербола помещать значения не в переменные, а в ячейку массива. Для каждого запуска сохранять значения в свои ячейки, каким-то образом отслеживать, что пришел момент создать спецэффект для такого-то юнита из массива или удалить такой-то спецэффект из другого массива. Это не очень удобный и достаточно громоздкий способ. В итоге, простая по сути задача – становится очень тяжелой.
В то же время, в том примере sample locs, эта задача решена очень легко. Чтобы узнать как – рассмотрим, что же такое локальные переменные.

Читатель, ты уже знаком с переменными в редакторе. Ты умеешь создавать их при помощи редактора переменных. Так вот, все переменные, которые создаются в редакторе переменных, будем отныне называть глобальными переменными. Глобальные переменные можно использовать во всех триггерах игры.
Оказывается, что кроме глобальных переменных, существует еще один вид – локальные переменные. Локальные переменные – это переменные, которые работают только внутри определенного триггера. Локальные переменные создаются при запуске триггера и уничтожаются после того, как выполнение триггера закончено. Если триггер запущен на исполнение несколько раз, то при каждом запуске создается свой набор локальных переменных, никак не связанный с другими наборами.

В каждом триггере можно определить набор локальных переменных. Для этого нужно применить команду из jass. В редакторе есть возможность вставить в триггер команду из jass – так называемый Custom Script (в дальнейшем cs). Читатель, давай посмотрим, как это сделано в примере – см триггер «Cast fireball method 1».
В самом начале триггера идут команды
Код:

cs: local unit u
cs: local effect e


Это объявление того, что при запуске этого триггера будут созданы 2 локальные переменные: u типа юнит и e типа спецэффект. Создавать локальные переменные можно всех тех же типов, что и глобальные и в любом количестве. Можно даже создавать массивы локальных переменных.
Далее идет обычная триггерная команда:
Код:

Set unit = (Target unit of ability being cast)


В глобальную переменную unit помещается юнит - цель нашего заклинания.
Дальше идет еще одна jass-команда:
Код:

cs: set u = udg_unit


Что это значит? Дело в том, что в jass есть такое правило: перед глобальными переменными ставится приставка udg. udg_unit - это наша глобальная переменная unit. Что касается локальных переменных, то их имена пишутся непосредственно без всяких приставок. Что же означает наша команда, записанная выше? u – локальная переменная, udg_unit – глобальная, set – это оператор присвоения.
Ответ таков: мы в локальную переменную u поместили то, что было записано в глобальную переменную unit (а в ней у нас был юнит-цель заклинания).
Оставим пока вопрос зачем, просто посмотрим, что будет дальше. А дальше идет команда
Код: [Выделить]

Wait ((Distance between (Position of (Casting unit)) and (Position of (Target unit of ability being cast))) / 1000.00) game-time seconds

- ждать время, равное отношению расстояния между кастонувшим юнитом и юнитом-целью к 1000 (1000 – это скорость снаряда файербола). Т.е. ждать время полета. Далее идет команда на jass:
Код:

cs: set udg_unit = u

Догадаетесь, что она означает? В глобальную переменную unit помещаем то, что записано в локальной переменной.
Далее проделана аналогичная схема с созданием спецэффекта. Созданный спецэффект помещается в глобальную переменную se, затем в локальную переменную e помещается что, что записано в se. Затем ждем период 3 игровых секунды и делаем обратное: записываем в se то, что записано в e. И уничтожаем спецэффект.
Итого, весь триггер напоминает тот, который мы создали бы, чтобы реализовать появление спецэффекта для одного юнита. Разница лишь в нескольких jass вставках. Но без этих вставок триггер НЕ УНИВЕРСАЛЕН, а со вставками – УНИВЕРСАЛЕН. Почему?

Давай вспомним про локальные переменные, которые мы создали. При каждом запуске триггера «Cast fireball method 1» будет создаваться набор из двух локальных переменных u и e. Причем для каждого запуска свой набор – не зависящий от других наборов. Запустим триггер 1000 раз – будет создано 1000 локальных переменных u типа юнит и e типа спецэффект.

В локальную переменную u мы поместили юнит-цель заклинания (сначала в глобальную unit, затем в локальную u). Через несколько секунд мы не можем гарантировать, что значение глобальной переменной unit не изменится. Ведь другой юнит может запустить файербол по другой цели – тогда значение переменной unit будет перезаписано. НО ЗНАЧЕНИЕ ЛОКАЛЬНОЙ ПЕРЕМЕННОЙ ДЛЯ ДАННОГО ЗАПУСКА НЕ ИЗМЕНИТСЯ. Ведь при следующем запуске триггера будет создан новый набор локальных переменных, а старые наборы не будут затронуты.

Итак, при помощи локальных переменных мы можем сохранить юнит-цель для каждого запуска заклинания файербол. А через некоторое время, равное времени полета файербола, мы должны создать на юните спецэффект. Мы делаем нужную паузу и затем помещаем в глобальную переменную unit ссылку на юнит из переменной u. И создаем спецэффект над юнитом из переменной unit.

Таким приемом мы можем гарантировать, что сколько бы файерболов не было выпущено, спецэффект будет создаваться над юнитом-целью и только над ним. Никаких сбоев не будет. Точно такой же прием с удалением спецэффекта через 3 секунды после создания. Все эти три секунды ссылка на спецэффект будет храниться в локальной переменной e. А затем мы перебросим ее значение в глобальную переменную se и удалим спецэффект.

Итак, как показывает пример, локальные переменные очень удобны для реализации УНИВЕРСАЛЬНЫХ отсроченных действий. Это свойство локальных переменных делает их незаменимыми при создании триггерных заклинаний. Причем добавить локальные переменные в триггер, как ты убедился, совсем не сложно.

Этот пример я специально сделал наиболее простым. jass команды, которые в нем используются – создать локальную переменную и присвоить значение переменной. Локальные переменные только для хранения данных. Для конкретных действий мы используем глобальные переменные unit и se. Также мы используем их как посредники – для переброски в них значений из локальных переменных и наоборот. Вообще говоря, в нашем примере можно обойтись и без глобальных переменных – одними локальными. Но проблема в том, что использование локальных переменных не предусмотрено в редакторе. Чтобы использовать эти переменные необходимо записывать команды на jass.

Теперь, Читатель, используй команду Правка->Конвертировать в текст, чтобы перевести весь триггер в «Cast fireball method 1» в jass. Не вдаваясь пока в устройство триггеров, обрати внимание на фрагмент, в который превратились наши триггерные действия. Каждая строчка триггерных команд превратилась в какую-то строчку jass-кода. Что касается строчек из custom script, они не изменились, т.к. они уже были написаны на jass. Теперь посмотри на триггер «Cast fireball method 2». Похоже? Да, это почти то же самое, только во втором примере я уже не использую глобальные переменные.
Обрати внимание на то, что в jass-код можно вставлять комментарии (любой текст)

Если нужно отключить какую-то строчку кода, не обязательно ее стирать. Можно превратить ее в комментарий. Второй пример на самом деле не работает, т.к. я превратил в комментарий строчку, которая отвечает за события триггера.
Еще обрати внимание, что названия спецэффектов в jass-коде записываются немного иначе - вместо одного \, записывается два:
"Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl"
Любой триггер можно конвертировать в jass-код, но обратную процедуру выполнить невозможно. Хотя есть такое действие – отменить последнюю команду редактора: ctrl-z. Если нужно, можно посмотреть, как выглядит код триггера, а затем вернуть триггер обратно.

Наконец, посмотри на третий триггер «Cast fireball method 3». Он делает то же самое, что и первые два. Но этот третий пример является как бы смесью первых двух. Как и во втором примере, здесь не используются глобальные переменные, но все команды, в которых используются локальные – пришлось переписать в виде cs.
Итак, первый шаг в мире jass уже сделан.

Применение локальных переменных

Закрепим то, что узнали. Чтобы создать локальную переменную, нужно вставить команду:
Код:

local <тип переменной> <имя переменной>


Типы переменных – это строки. В некоторых случаях они совпадают с названием переменных в Редакторе переменных. Например unit, integer, real, string. Но иногда не совпадают как в случае с effect, который означает спецэффект.
Если вы не знаете, как называется такой-то тип переменных в jass, как это узнать? Можно использовать такой способ: создаете глобальную переменную нужного типа. Затем используете команду редактора Файл->Экспорт кода – сохраняете код сценария в файл. Затем смотрите содержание этого файла при помощи блокнота. Находите пункт
* Global Variables
- он будет в самом верху.
Там перечислены все глобальные переменные в сценарии и рядом записан их тип.
Можно еще использовать такой способ: сделать какую-то ошибку в jass-коде, после чего игра отключить и подключить триггер с ошибкой (disable/enable). Игра выдаст ошибку и в окне с ошибкой будет виден код сценария. Так что там же можно найти раздел Globals.

Примечания: попробуйте посмотреть таким способом как в jass называются типы «тип юнита», «тип предмета», «способность» или «бафф». И обнаружите, что они преобразуются к... типу integer. Тут нет никакой ошибки. Эти типы переменных существуют только в редакторе триггеров. В jass они представляют собой тип integer. Типы юнитов, способности и т.п. кодируются числами. Хотя, у них имеется и другой способ кодирования – специальными константами ‘hfoo’- означает тип юнита footman. Подобные названия объектов можно узнать переводя триггеры в jass или в редакторе объектов (если поставите галочку «Вид->Показывать названия переменных»
Команды по созданию локальных переменных всегда должны располагаться в самом верху триггерных действий (за исключением только комментариев), иначе будет выдана ошибка.
Можно создавать массивы локальных переменных при помощи команды
Код:

local <тип переменной> array <имя переменной>


Например, массив юнитов:
Код:

local unit array u

Обращение к элементам этого массива такое же как в триггерах:
Код:

Set u[1] = …

- записываем в первый элемент массива такое-то значение. И т.п.
При создании переменных, можно сразу же записывать в них какое-то значение.
Код:

local integer i =1

создаст переменную i и присвоит ей значение 1.
Предупреждение. Когда мы создаем глобальную числовую переменную, то ее значение автоматически приравнивается к нулю. Но для локальных переменных это не так. При создании локальной переменной ее значение не определено. Попытка их использования до того, как вы поместите в них какое-либо значение приводит к сбою. Пример ошибочного кода:
Код:

local integer i
set i = i +1


Чтобы не было ошибки, сначала прировняйте значение переменной i к нулю.
Код:

local integer i = 0
set i = i +1


Локальные переменные очень хорошо решают проблему хранения данных при отсроченных действиях, как мы разобрали в прошлом примере. Существует способ решения задач при помощи локальных переменных: способ движения от частного к общему. Алгоритм такой:
Создай обычный не универсальный триггер, который решает задачу для одного запуска.
Добавь локальные переменные и запиши в них все, что должно сохраниться во время паузы.
Помести данные обратно в глобальные переменные и делай нужные действия.
Локальные переменные выступают как хранилища на время пауз в триггере, глобальные переменные нужны для каких-то мгновенных действий. См. пример sample locs. Мы не можем угадать, что будет храниться в переменной unit в какой-то момент времени. Ее значение будет постоянно меняться в зависимости от игровых событий. Мы не можем помещать в эту переменную ДАННЫЕ ДЛЯ СОХРАНЕНИЯ, но можем использовать ее для мгновенных действий. В нашем случае работает только одно триггерное заклинание, но мы могли бы использовать ту же самую переменную unit для сотни точно таких же заклинаний.

Если хотите обойтись одними локальными переменными, то нужно либо весь триггер переводить в jass, либо переводить в cs те строки, где имеются ссылки на эти переменные.

Чтобы посмотреть, как выглядит та или иная команда в jass, можно использовать такой прием: создаем новый пустой триггер, создаем внутри него нужную команду и переводим триггер в текст. Затем этот текст можно будет вставить в cs один в один. Так что нет необходимости запоминать все команды на jass.

Итак, Читатель, ты уже достаточно узнал, чтобы создать свой собственный jass код. Правда, есть определенные тонкости который тебе нужно узнать. Во-первых, если в jass допущена ошибка, то при попытке сохранить карту или запустить ее будут выданы ошибки. При этом триггер тут же отключится и ты не сможешь его включить, пока не исправишь ошибки.
А теперь представь, что на данный триггер ссылается еще один. Что произойдет? Триггер отключился из-за ошибки и все триггерные команды, которые ссылались на него тоже отключатся.

Еще одна ситуация. Допустим, имеется триггер на jass или с cs, в котором идет ссылка на глобальную переменную unit. Затем, мы берем и меняем название глобальной переменной на unit2. Во всех нормальных триггерных действиях название старой переменной на новую произойдет автоматически. Но не в jass-коде! Там все названия останутся старыми. Т.е. нам нужно вручную менять везде udg_unit на udg_unit2, иначе будет выдана ошибка.
Поэтому при создании jass кода надо всегда соблюдать осторожность. Тем более что ошибки в jass не всегда бывают безобидными. Некоторые из них приводят к тому, что редактор вылетает без сохранения карты. Так что когда работаете с jass-кодом – ЧАЩЕ СОХРАНЯЙТЕСЬ!
Итак, Читатель, если есть время и желание, поработай над реализацией какой-нибудь из задач на jass. К примеру:
Заклинание разговор: когда применяешь его на юнит, на две секунды над ним появляется фраза плавающего текста «Привет».
Заклинание banish (триггерный аналог): на 20 секунд юниту-цели дается способность ethereal (дух).
 
Дата: Пятница, 14.10.2011, 20:50 | Сообщение # 2
Генерал-лейтенант
Проверенные
Сообщений: 522
Награды: 5
Репутация: 26
а про обнуление???
 
Дата: Пятница, 14.10.2011, 21:29 | Сообщение # 3
Генералиссимус
Заблокированные
Сообщений: 2263
Награды: 8
Репутация: 85
Действительно.. хоть отдельной темой пиши)
Будет время - напишу статью про обнуление и про то как Заменять BJ функции на свои и на сколько близзард криворукие говнокодеры.
 
Дата: Пятница, 14.10.2011, 21:35 | Сообщение # 4
Генерал-лейтенант
Проверенные
Сообщений: 522
Награды: 5
Репутация: 26
DonLaonda, проще дополнить)

Дополнение:
чтобы обнулить переменную, достаточно прописать:
set X=null

где Х естественно название переменной
 
Дата: Пятница, 14.10.2011, 21:46 | Сообщение # 5
Генералиссимус
Заблокированные
Сообщений: 2263
Награды: 8
Репутация: 85
Нет.
т.к. если это тип юнит, то ты удалишь его хендл не больше.
И не все типы переменных обнуляются через null.
Я и хотел указать все типы и по поводу юнита и эффекта объяснить.
Да и если используешь BJ функции утечки не побороть, к сожалению =\


Сообщение отредактировал DonLaonda - Пятница, 14.10.2011, 21:48
 
Дата: Пятница, 14.10.2011, 22:39 | Сообщение # 6
Генерал-лейтенант
Проверенные
Сообщений: 522
Награды: 5
Репутация: 26
Quote (DonLaonda)
Да и если используешь BJ функции утечки не побороть, к сожалению =\

я вот тоже непойму зачем создавать глобалBJ переменные??? создавались бы лучше локальные...
и меня бесит как близард триггеры переводит >(
вначале функцию создают (в которой вызывается другая функция), а потом вызывают ту же функцию. такое чувство как-будто там стадо баранов сидит >( >(
 
Дата: Понедельник, 17.10.2011, 13:37 | Сообщение # 7
Генералиссимус
Заблокированные
Сообщений: 2263
Награды: 8
Репутация: 85
Quote (TOTKTO3HAETBCE)
такое чувство как-будто там стадо баранов сидит >( >(

ахаха +100500
Quote (TOTKTO3HAETBCE)
я вот тоже непойму зачем создавать глобалBJ переменные???

Да это ерунда))
Вот в BJ функциях используются переменные локальные и не обнуляются, а для создания юнита используются 2 цикла и 3 функции, хотя на самом деле нужна 1 строчка в 4 слова.
Если карта типа доты, то масса утечек произойдет даже при правильно поставленном ГУИ из-за BJ функций стандартных.
 
Дата: Воскресенье, 06.11.2011, 11:51 | Сообщение # 8
Генерал-лейтенант
Проверенные
Сообщений: 522
Награды: 5
Репутация: 26
не ну удалять её было слишком, ведь не сам писал
 
Форум » Картостроение в Warcraft 3 » Статьи » Локальные переменные (jass)
Страница 1 из 11
Поиск: