Добавлен , опубликован

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

Содержание:

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

Локальные переменные – это воистину первый шаг в освоении jass. И это очень важный шаг. Умея работать с локальными переменными, ты сможешь заметно упростить себе решение многих триггерных задач.
Читатель, прежде чем начнем изучение, я советую тебе скачать файл sample locs.w3x, который приложен к данной статье. Скачай, затем открой в редакторе и запусти на исполнение. Суть примера в том, что если стрельнуть заклинанием файербол, над головой жертвы появляется спецэффект «восклицательный знак», который через несколько секунд исчезнет. Действие сделано на триггерах с применение локальных переменных.
С одной стороны можно задать вопрос – а зачем тут вообще нужны триггеры? Этого же эффекта можно достичь в редакторе объектов. Да, можно. Но главное не это. Вместо спецэффекта мы можем навесить и любое другое действие. Например, при ударе файербола, на юните будет появляться череда сменяющих друг друга спецэффектов. Такого в редакторе объектов уже не сделаешь.
А можно ли сделать этот эффект при помощи обычных триггеров? Конечно. Для одного юнита, это легко сделать. Например, запустил юнит файербол, мы:
  1. Помещаем цель заклинания в переменную u типа юнит.
  2. Ждем время, пока файербол долетит (которое равно расстояние до цели делить на скорость полета).
  3. Создаем спецэффект на юните u, который записываем в переменную se типа спецэффект.
  4. Через несколько секунд уничтожаем спецэффект 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 уже сделан.

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

Закрепим то, что узнали. Чтобы создать локальную переменную, нужно вставить команду:
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 
Локальные переменные очень хорошо решают проблему хранения данных при отсроченных действиях, как мы разобрали в прошлом примере. Существует способ решения задач при помощи локальных переменных: способ движения от частного к общему. Алгоритм такой:
  1. Создай обычный не универсальный триггер, который решает задачу для одного запуска.
  2. Добавь локальные переменные и запиши в них все, что должно сохраниться во время паузы.
  3. Помести данные обратно в глобальные переменные и делай нужные действия.
Локальные переменные выступают как хранилища на время пауз в триггере, глобальные переменные нужны для каких-то мгновенных действий. См. пример sample locs. Мы не можем угадать, что будет храниться в переменной unit в какой-то момент времени. Ее значение будет постоянно меняться в зависимости от игровых событий. Мы не можем помещать в эту переменную ДАННЫЕ ДЛЯ СОХРАНЕНИЯ, но можем использовать ее для мгновенных действий. В нашем случае работает только одно триггерное заклинание, но мы могли бы использовать ту же самую переменную unit для сотни точно таких же заклинаний.
Если хотите обойтись одними локальными переменными, то нужно либо весь триггер переводить в jass, либо переводить в cs те строки, где имеются ссылки на эти переменные.
Чтобы посмотреть, как выглядит та или иная команда в jass, можно использовать такой прием: создаем новый пустой триггер, создаем внутри него нужную команду и переводим триггер в текст. Затем этот текст можно будет вставить в cs один в один. Так что нет необходимости запоминать все команды на jass.
Итак, Читатель, ты уже достаточно узнал, чтобы создать свой собственный jass код. Правда, есть определенные тонкости который тебе нужно узнать. Во-первых, если в jass допущена ошибка, то при попытке сохранить карту или запустить ее будут выданы ошибки. При этом триггер тут же отключится и ты не сможешь его включить, пока не исправишь ошибки.
А теперь представь, что на данный триггер ссылается еще один. Что произойдет? Триггер отключился из-за ошибки и все триггерные команды, которые ссылались на него тоже отключатся.
Еще одна ситуация. Допустим, имеется триггер на jass или с cs, в котором идет ссылка на глобальную переменную unit. Затем, мы берем и меняем название глобальной переменной на unit2. Во всех нормальных триггерных действиях название старой переменной на новую произойдет автоматически. Но не в jass-коде! Там все названия останутся старыми. Т.е. нам нужно вручную менять везде udg_unit на udg_unit2, иначе будет выдана ошибка.
Поэтому при создании jass кода надо всегда соблюдать осторожность. Тем более что ошибки в jass не всегда бывают безобидными. Некоторые из них приводят к тому, что редактор вылетает без сохранения карты. Так что когда работаете с jass-кодом – ЧАЩЕ СОХРАНЯЙТЕСЬ!
Итак, Читатель, если есть время и желание, поработай над реализацией какой-нибудь из задач на jass. К примеру:
  1. Заклинание разговор: когда применяешь его на юнит, на две секунды над ним появляется фраза плавающего текста «Привет».
  2. Заклинание banish (триггерный аналог): на 20 секунд юниту-цели дается способность ethereal (дух).

`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
26
10 лет назад
0
RiseD_Konst:
nvc123, то-есть локалки создаются отдельно внутри каждой функции? А что насчет моей попытки сравнить Jass c паскалем? я мыслю в том направлении?
nvc123, тогда получается что хоть весь код можно писать прямо в шапке карты?
Buulichkaa, извини, я недавно взялся учить это дело - ничего не понимаю. Ты имел ввиду что хоть весь код спихни в триггер и он будет работать, но если работаешь в команде приходится делать код осмысленным не только для себя. Да?
да х3
1
28
10 лет назад
1
RiseD_Konst, зачем сравнивать Jass с паскалем?)
Локалки создаются отдельно внутри каждой функции. Чтобы значение переменной переносилось в другие функции, нужно на мгновение присваивать ей глобальную переменную, а потом очищать (ну или не очищать в зависимости от надобностей.
nvc123, тогда получается что хоть весь код можно писать прямо в шапке карты?
В шапке карты, кажется, указывается загрузочный код.
извини, я недавно взялся учить это дело - ничего не понимаю. Ты имел ввиду что хоть весь код спихни в триггер и он будет работать, но если работаешь в команде приходится делать код осмысленным не только для себя. Да?
Да. Как коллеги говорят: лезть в чужой код без комментов, сродни копанию в чужих фекалиях в поисках полезных ископаемых =)
0
28
10 лет назад
0
RiseD_Konst, джасс непохож на паскаль
триггер это объект в джасс который имеет мало общего с тем триггером о котором ты говоришь
то что ты называешь триггером лишь иллюзия которую создаёт редактор для того чтобы непосвящённые не потерялись в куче кода
Jusper, в шапке карты можно весь код(я так делал) но только если ты 1 кодер который работает над мапой
Jusper, присваивать глобалкам?
а то что функции могут брать и возвращать параметры эт ничё?
другое дело если надо между потоками передать данные,там без глобалок не обойтись
1
28
10 лет назад
1
другое дело если надо между потоками передать данные,там без глобалок не обойтись
Потоки имел ввиду.
0
21
10 лет назад
0
Ясно. Спасибо. Еще меня интересует что бы делала эта функция:
function somefunction take nothing return boolean
Может я и сделал ошибку, но что она должна бы делать по-идее? Что означает "брать" параметр и "возвращать" параметр? Хорошо. Слишком много вопросов. nvc123, твоя школа еще открыта?
1
26
10 лет назад
1
вы из холодильника колбасу можете достать? а положить?
0
21
10 лет назад
0
Hate:
вы из холодильника колбасу можете достать? а положить?
Ладно, попробую положить колбасу в холодильник, но если не влезет, Hate, прячтесь)
0
28
10 лет назад
0
RiseD_Konst, школа открыта для тех кто прочитал следующие статьи
Этот комментарий удален
1
6
10 лет назад
Отредактирован VovkaShyt
1
Большое спасибо за статью. До прочтения думал что фигня эти локальные переменные и почему они не работают и как их сделать чтоб работали... Прочитал понял всё куда проще оказалось))
1
12
10 лет назад
1
VovkaShyt, ну да, прочитал статью и ты теперь уже тру-кодер! Иди пили модные карты и забудь навсегда про ГУИ, господин археолог)))
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.