Глобальные переменные
Вы уже знаете о том как создавать глобальные переменные и как их использовать в гуи. Также в прошлых уроках мы говорили о том как их использовать в коде, но не создавали их. В этом уроке мы изучим их практически полностью, не затронем только массивы.
В jass можно создать глобальные переменные только в одном месте, внутри блока кода globals-endblobals, который должен находится выше всех функций (по сути в начале файла скрипта). Для создания глобальной переменной нужно написать её декларацию с новой строки внутри блока globals-endblobals: тип имя. Сейчас просто посмотрите на пример:
globals
integer udg_Var1
string Var2
endglobals
В данном случае будет создано две глобальные переменные: udg_Var1 с типом integer и Var2 с типом string. Как видим, приставка "udg_" необязательна.
При создании глобальных переменных через редактор триггеров, он всегда будет добавлять приставку "udg_" к началу имени переменной. В джассе вы можете назвать её и без приставки, она ни на что не повлияет. Также, глобальные переменные созданые с помощью джасса не будут добавлены в список глобальных переменных гуи-триггеров, их можно будет использовать только в скриптах.
А теперь проблема. В обычном джассе, блок с глобальными переменными может быть только один и его создает редактор триггеров. Доступ к нему мы можем получить только двумя путями:
- Создавать глобальные переменные через редактор триггеров. Все они будут с приставкой "udg_". Вписать туда код нам не дадут.
- Влезть внутрь файла с картой и вручную вписать код.
Первый вариант не открывает никаких новых возможностей, а второй сверх неудобный и бредовый. Вот и получается, что возможность есть, а использовать её мы не можем. Тут то к нам на помощь и приходит vJass.
В vJass можно создавать сколько угодно блоков globals и где угодно (только не внутри globals блоков, это как минимум тупо). Во время компиляции, независимо от места нахождения блоков, все они будут перенесены в основной блок в самом верху кода. На нашем восприятии это никак не отобразится, наши отдельные блоки globals так и будут визуально отдельными блоками globals. На этом отличия vJass и Jass в плане глобальных переменных заканчиваются.
Создавая глобальные переменные в них можно положить стартовое значение. Если этого не сделать, то в ней ничего не будет и до тех пор, пока мы не присвоим ей какое-либо значение, функция или триггер будет прекращать роботу доходя до места где используется пустая переменная. Например:
globals
integer A = 5
integer B
endglobals
function Test takes nothing returns nothing
call BJDebugMsg("Start")
call BJDebugMsg("A = " + I2S(A))
call BJDebugMsg("B = " + I2S(B))
call BJDebugMsg("End")
endfunction
На старте игры А = 5, а в В ничего нет. Если до выполнения функции Test ничего не положить в В, то функция дойдет до вывода на экран строки "А = 5", а дальше прекратит свою работу, и работу триггера, который её вызвал.
Присвоение самого первого значения для переменной зовется инициализацией переменной. Инициализация переменных может происходить как сразу после создания переменной, так и во время инициализации карты, или любого другого момента игры. Но важно инициализировать глобальную пременную хоть каким-то значением до её первого использования. Глобальные переменные созданные через редактор триггеров всегда имеют стартовое значение.
В качестве стартовых значений отлично подойдут следующие варианты: 0 - для real и integer, false - для boolean и null для остальных типов. Null не вызывает ошибок, хоть и является ссылкой на несуществующий объект.
Глобальная переменная может быть константой, то есть не менять своего значения. Да, тут нарушена логика, но суть в том, что в остальном константа ведет себя так же, как и глобальная переменная. Для создания константы нужно к уже знакомой декларации глобальной переменной дописать в начале слово constant. Пример:
globals
constant real Pi = 3.14
endglobals
Нами была создана константа с типом real, именем Pi и значением 3.14.
Значение у констант должно быть присвоено обязательно в момент создания, иначе произойдет ошибка компиляции. Если где-то в коде попытаться изменить значение константы, то также будет ошибка компиляции.
Конечно, мы могли бы и просто создать глобальную переменную и нигде не менять её. Но константа позволяет гарантировать то, что мы не сможем её поменять. В программировании вообще много таких штук, которые просто что-то гарантируют, это позволяет избежать многих ошибок. Наиболее ярким примером использования констант будут различные настройки, которые должны меняться только через редактор, но не во время игры.
В прошлом уроке мы уже присваивали значения переменным в коде, просто напомню вам как это делать:
globals
integer Number = 0
endglobals
function Count takes nothing returns nothing
set Number = Number + 1
call BJDebugMsg(I2S(Number))
endfunction
По итогу, сначала строчка кода set Number = Number + 1 увеличит переменную Number на единицу, а следующая строка выведет на экран число, которое сейчас хранит переменная Number. Если вызывать эту функцию в триггере по таймеру, то он будет считать от 1 и до тех пор, пока не отключим триггер.
Для инициализации глобальных переменных и констант в момент их создания, можно использовать выражения и функции. Но использовать ваши функции не выйдет, так как они всегда будут ниже по коду чем блок глобальных переменных, подходят только стандартные функции. Также можно использовать другие глобальные переменные и константы, но только те, которые находятся выше по коду. Пример:
globals
integer A = 10
integer Number = 5 + A + GetRandomInt(1, 5)
endglobals
Здесь функция GetRandomInt возвращает случайное число от 1 до 5. По итогу в переменную Number будет положено случайное значение от 16 до 20.
Важно! Для инициализации глобальных переменных в момент их объявления, можно использовать не все стандартные функции. Большинство из них сработает нормально, но есть проблемы с теми функциями, которые создают игровые объекты. У вас никак не получится создать юнита, предмет, декорацию в блоке с глобальными переменными. Все переменные в следующем примере будут содержать в себе null:
globals
unit u = CreateUnit(p, 'hfoo', 0,0,0)
item i = CreateItem('ratc', 0, 0)
destructable d = CreateDestructable('ATtr', 500, 500, 0, 1, 0)
endglobals
А некоторые функции будут приводить к критическим ошибкам во время запуска карты. Например, создание эффектов или деформаций ландшафта:
globals
effect e = AddSpecialEffectLoc("units\\human\\Peasant\\Peasant.mdx", Location(0, 0))
terraindeformation t = TerrainDeformCrater(0, 0, 128, 64, 10, true)
endglobals
Любая из этих двух строчек кода приведет к критической ошибке во время запуска карты в игре.
Всех этих проблем можно легко избежать перенеся инициализацию глобальных переменных таких типов в функции или триггеры. Создание точек, хеш-таблиц, областей, груп юнитов, груп игроков и т.д. работает без таких проблем.
Я не буду приводить никаких практических примеров потому, что вы уже наверняка использовали глобальные переменные в триггерах. Мы обязательно будем их использовать, но в других более сложных примерах.
Ред. avuremybe
Тест показывает, что обращение к непроинициализированной ячейке массива прекращения работы ф-ции не вызывает.
Или что для них сделано исключение?
Или проблемы все же могут возникнуть и следует стараться инициализировать глобальные массивы?