
Как ты уже мог прочитать ранее, Game Maker содержит встроенный язык программирования.
Этот язык программирования дает тебе намного больше гибкости в управлении чем стандартные
действия. Этот язык мы назовем как GML (Game maker Language). Имеются три различных места,
где ты можешь напечатать программы на этом языке. Прежде всего, когда ты определяешь
сценарии. Сценарий - программа на GML. Во-вторых, когда ты добавляешь действие кода в
событие. В действии кода ты снова должен представить программу на GML. Наконец, везде,
где ты должен определить значение в действии, ты можешь также использовать выражения на
GML. Выражение, как мы увидем ниже - не законченная программа, а часть результирующая в
значении (value).
В этой главе я опишу основную структуру программ на GML. Когда ты хочешь использовать
программы на GML, имеется пара нюансов, на которые ты должен обратить свое внимание.
Прежде всего, для всех твоих ресурсов (спрайты, объекты, звуки и т.д.) ты должен
использовать названия, которые начинаются с символа и состоят только из символов, цифр
и символа подчеркивания '_' . Иначе ты не cможешь обратиться к ним изнутри программы.
Также будь осторожен и не назвай ресурсы как self, other, global, или all - потому что
все они имеют специальное назначение в данном языке. Также ты не должен использовать ни одно
из ключевых слов, обозначенных ниже.
Программа
Программа состоит из блока. Блок состоит из одной или большего количества инструкций,
заключенных в символы '{' и '}'. Инструкции должны быть разделены символом ';'.
Так выглядит глобальная структура каждой программы:
{
<инструкция>;
<инструкция>;
...
}
Инструкция (statement) может снова быть блок инструкций. Имеется множество различных типов
инструкций, которые будут обсуждены ниже.
Переменные (Variables)
Как и любой другой язык программирования GML содержит переменные. Переменные могут хранить
любые реальные значения (values) или строки (strings). Переменные не должны быть объявлены.
Существует большое количество встроенных переменных. Некоторые общие (general), такие как
mouse_x и mouse_y, указывают текущую позицию мыши, тогда как все другие являются локальными
к образцу объекта, для которого мы выполняем программу, подобно x и y которые указывают
текущую позицию образца. Переменная имеет название, которое должно начинаться с символа и
может содержать только символы, числа и символ подчеркивания '_'. (Максимальная длина - 64
символа). Когда ты используешь новую переменную, она локальна к текущему образцу и не известна
в программах для других образцов (даже того же самого объекта). Хотя ты можешь, обращаться к
переменным в других образцах; смотри ниже.
Присваивания (Assignments)
Присваивание назначает значение выражения (expression) для переменной (variable). Присваивание
имеет форму:
<переменная> = <выражение>;
Прежде чем присваивать значение переменной, ты можешь его также прибавлять используя +=,
вычитать используя -=, умножать используя *= или делить используя /=. (Это работает
только для реальных оцененных переменных и выражениях, но не для строк.)
Выражения (Expressions)
Выражениями могут быть вещественные числа (например 3.4), строки между одиночными или
двойными кавычки (например 'hello' или "hello") или более сложные выражения. Для выражений,
существуют следующие бинарные операторы (в порядке приоритета):
- &&, ||: &&, ||: комбинация Булевых значений (&& означает и, || означает или)
- <, <=, ==, !=, >, >=: сравнение, результат истинный (1) или ложный (0)
- +, -: сложение, вычитание
- *, /, div, mod: умножение, деление, целочисленное деление, и по модулю
Также, существуют следующие одноместные операторы:
- !: нет, поворачивает истину в ложь и ложь в истину
- -: отрицает следующее значение
В качестве значений ты можешь использовать числа, переменные или функции, которые
возвращают значение. Суб-выражения могут быть помещены между скобками. Все
операторы работают для реальных значений. Сравнение также работает для строк и
+ связывает строки.
Пример
Далее приведен пример с некоторыми бесполезными присваиваниями.
{
x = 23;
str = 'hello world';
y += 5;
x *= y;
x = 23*((2+4) / sin(y));
str = 'hello' + " world";
b = (x < 5) && !(x==2 || x==4);
}
Дополнительные переменные (Extra variables)
Ты создаешь новые переменные, определяя значение для них (объявлять их сначала не
требуется). Если ты просто используешь имя переменной, переменная будет сохранена
только с образцом текущего объекта. Так что, не дожидаясь его нахождения, она
работает с другим объектом (или другим образцом этого объекта) следующей. Ты можешь
также устанавливать и читать переменные в других объектах, помещая название объекта
с точкой перед именем переменной.
Чтобы создать глобальные переменные (global variables), которые являются видимыми
для всех образцов объекта, перед переменной пишем слово global и точку.
Ты например можешь записать так:
{
if (global.doit)
{
// do something
global.doit = false;
}
}
Адресование переменных в других образцах (Addressing variables in other instances)
Как описано выше, ты можешь устанавливать переменные в текущих инструкциях
используя подобный оператор:
Но в большинстве случаев ты захочешь адресовать переменные в другом образце. Например,
ты захотел остановить движение всех шариков, или ты захотел переместить основного
персонажа в специфическую позицию, или в событии столкновения, ты захотел установить
спрайт для другого вовлеченного образца. Это может быть достигнуто, если перед именем
переменной поставить название объекта и точку. Так например, ты можешь написать:
Это изменит скорость всех образцов объекта шарика. Существует множество специальных
"объектов" ("objects").
- self: Текущий образец, для которого мы выполняем действие
- other: Другой образец, вовлеченный в событие столкновения
- all: Все образцы
- noone: Вообще нет образцов
- global: Вообще нет образцов, но контейнер сохраняет глобальные переменные
Так для примера, ты можешь использовать инструкции следующего вида:
other.sprite_index = sprite5;
all.speed = 0;
global.message = 'A good result';
global.x = ball.x;
Ты мог бы задаться вопросом, что же делает последнее присваивание, когда
существует множество шариков. Что-ж - первое принимает значение x и назначает
его глобальному значению.
Но если ты хочешь установить скорость одного определенного шарика, а не сразу
всех шаров. Сделать это немного сложнее. Каждый образец имеет уникальный
идентификатор. Когда ты помещаешь образцы в комнату в проектировщике, данный
идентификатор образца отображается, при наведении на образец курсора мыши.
Он представляется в виде числа, которое больше или равно 100000. Такое число
ты можешь использовать также, подставив его слева от точки. Но будь осторожен.
Точка интерпретируется как десятичная точка в числе. Чтобы избежать путаницы,
помести по краям числа круглые скобки. Так например, допустим идентификатор
шарика - 100032, его ты можешь записать так:
Когда ты создаешь образец в программе, запрос возвращает идентификатор. Вот
конкректная часть программы:
{
nnn = instance_create(100,100,ball);
nnn.speed = 8;
}
Она создает шарик и устанавливает его скорость. Обрати внимание, что мы
назначили идентификатор образца как переменную и использовали эту переменную
как указание перед точкой. Данное использование полностью допустимо. Позволь
мне попробовать сделать это более точно. Точка фактически считается оператором.
Она берет значение (value) как левый операнд и переменную (адрес) как правый
операнд, и возвращает адрес этой специфической переменной в указанном объекте
или образце. Все имена объекта и специальные объекты, указанные выше, просто
представляют значения, и с ними можно иметь дело как и с любым значением.
Например, следующая программа является правильной:
{
obj[0] = ball;
obj[1] = flag;
obj[0].alarm[4] = 12;
obj[1].id.x = 12;
}
Последняя инструкция должна читаться следующим образом. Мы берем идентификатор
(id) первого флага. Для образца с этим идентификатором мы устанавливаем x
координату на 12.
Название объекта, специальные объекты и идентификаторы образца могут также
использоваться во множестве функций.
Массивы (Arrays)
Ты можешь использовать 1 и 2х мерные массивы в GML. Просто помести индекс между
квадратными скобками для 1-мерного массива и второй индекс с запятой между
ними для 2-размерных массивов. В настоящее время ты используешь индекс,
сгенерированного массив. Каждый массив начинается с индекса 0. То есть будь
внимателен при использованием больших индексов, потому что память для большого
массива будет зарезервирована. Никогда не используй отрицательные индексы.
Система устанавливает ограничение 32000 для каждого индекса и 1000000 для
общего размере. Так например ты можешь записать следующее:
{
a[0] = 1;
i = 1;
while (i < 10) { a[i] = 2*a[i-1]; i += 1;}
b[4,6] = 32;
}
Оператор Если (If)
Оператор If имеет форму
if (<выражение>) <инструкция>
или
if (<выражение>) <инструкция> else <инструкция>
Инструкция также может быть блоком. Выражение будет оценено. Если (округленное)
значение <=0 (ложно) инструкция после else выполняется, иначе (истинно) выполняется
другая инструкция. Лучше всего, взять за правило - инструкцию в условном операторе
всегда заключать в фигурные скобки. Вот пример правильного использования
if (<выражение>)
{
<инструкция>
}
else
{
<инструкция>
}
Пример
Следующая программа перемещает объект в середину экрана.
{
if (x<200) {x += 4} else {x -= 4};
}
Оператор Повторения (Repeat)
Оператор Repeat имеет форму
repeat (<выражение>) <инструкция>
Оператор повторяется число раз, соответствующее значению, указанному выражением
заключенному в круглые скобки.
Пример
Следующая программа создает пять шариков, в произволных позициях.
{
repeat (5) instance_create(random(400),random(400),ball);
}
Оператор Тогда как (While)
Оператор While имеет форму
while (<выражение>) <инструкция>
Пока выражение истинно, оператор (который также может быть блоком) выполняется.
Будь осторожен с использованием 'while' циклов. Ты легко можешь сделать такие
циклы бесконечными, и тогда твоя игра зависнет и не будет реагировать ни на какие
действия пользователя (игрока).
Пример
Следующая программа пробует поместить текущий объект в свободную позицию (аналогично
действию, перемещения объекта в случайную позицию).
{
while (!place_free(x,y))
{
x = random(room_width);
y = random(room_height);
}
}
Оператор Для (For)
Оператор (For) имеет форму
for (<инструкция1> ; <выражение> ; <инструкция2>) <инструкция3>
Это работает следующим образом. Сначала выполняется инструкция .
Затем оценивается выражение . Если оно истинно, инструкция
выполняется; затем инструкция и затем выражение
оценивается снова. Это продолжается, пока выражение не будет ложно.
Возможно все это звучит несколько запутанно. Все вышеизложенное следует
интерпретировать следующим образом. Первая инструкция инициализирует for-цикл.
Выражение проверяет, должен ли цикл быть закончен. Statement2 - шаговая (step)
инструкция, которая ведет к следующему оценочному циклу.
Наиболее часто - используют в счетчике, проходящем некоторый диапазон.
Пример
Следующая программа инициализирует массив длиной 10 со значениями 1-10.
{
for (i=0; i<9; i+=1) list[i] = i+1;
}
Оператор Выход (Exit)
Оператор (Exit) имеет форму
Он просто завершает выполнение данной программы. (Он не завершает выполнение
игры! Для этого тебе необходима функция game_end(); смотри ниже).
Функции (Functions)
Функция имеет форму - имя функции, сопровождаемое нулем или большим количеством
параметров между скобками, отделенными запятыми.
<функция>(<arg1>,<arg2>,...)
Существуют два типа функций. Во первых, доступна большая коллекция встроенных
функций, для контроля за всеми аспектами игры. Во-вторых, любой сценарий, который
ты определяешь в своей игре, может использоваться как функция.
Обрати внимание, что для функции без параметров ты также должен использовать
скобки. Некоторые функции возвращают значения и могут использоваться в
выражениях. Другие просто выполняют команды.
Сценарии (Scripts)
Когда ты создаешь сценарий, ты хочешь иметь доступ в пройденным (passed) параметрам
из него (или при использовании действия сценария, или при вызове сценария в
качестве функции из программы (или из другой, или даже того же самого сценария).
Эти параметры сохраняются в переменных argument0, argument1, ¦, argument9. Таким
образом могут быть определены максимум 10 параметров. (Обратите внимание, что
при вызове сценария из действия, определены могут быть только первые 3 параметра).
Сценарии также могут возвращать значения, так чтобы они могли быть использованы в
выражениях. Для этого ты используешь инструкцию возвращения (return):
Выполнение сценария заканчивается оператором возвращения (return)!
Пример
Вот определение для небольшого сценария, который вычисляет квадрат параметра:
{
return (argument0*argument0);
}
Конструкции С (With)
Как было сказано выше, существует возможность читать и изменять значение
переменных в других образцах. Но в большинстве случаев ты захочешь сделать
с другими образцами что-то более существенное. Например - предположим, что ты
хочешь переместить все шарики вниз на 8 пикселов. Ты мог бы предположить, что
добится этого можно следующей частью кода
Но это не верно. Правая сторона присваивания получает значение y-координаты
первого шарика и добавляется к нему 8. Затем это новое значение установливается
как y-координата для всех шариков. Таким образом, в результате все шарики
получают ту же самую y-координату. Инструкция
будет иметь точно такой же эффект, потому как это - просто сокращение первой
инструкции. Так, каким же образом сделать это? Для этой цели имеется инструкция
with. Его глобальная форма
with (<выражение>) <инструкция>
Выражение указывает один или большее количество образцов. Для
этого ты можешь использовать идентификатор (id) образца, имя объекта (чтобы
указать все образцы этого объекта) или один из специальных объектов (all, self,
other, noone). Инструкция теперь выполняется для каждого из
обозначенных образцов, как будто этот образец - текущий (self) образец.
Таким образом, чтобы переместить все шарики на 8 пикселов вниз, ты можешь
напечатать.
Если ты хочешь выполнить многочесленные (multiple) инструкции, помести вокруг
них фигурные скобки. Так например, чтобы переместить все шарики в случайную
позицию, ты можешь использовать
with (ball)
{
x = random(room_width);
y = random(room_height);
}
Обрати внимание, что в пределах инструкции(ий), обозначенный образец стал
самостоятельным (self) образцом. В пределах инструкций оригинал самостоятельного
образца стал другим (other) образцом. Так например, чтобы переместить все
шарики в позицию текущего образца, ты можешь напечатать
with (ball)
{
x = other.x;
y = other.y;
}
Использование инструкции (with) является чрезвычайно мощным инструментом.
Позволь привести еще несколько примеров. Чтобы уничтожить все шарики, ты
печатаешь
with (ball) instance_destroy();
если взрывается бомба и ты хочешь уничтожить все образцы рядом с собой, можно
использовать:
with (all)
{
if (distance_to_object(other) < 50) instance_destroy();
}
Комментарий (Comment)
Ты можешь добавлять в свои программы комментарии. Все что находится в строке
после символа // не читается программой. Данный символ используется внутренне и
указывает конец строки.
Стиль Паскаль (Pascal style)
Интерпретатор в действительности довольно слаб. Но ты также можешь использовать
программы, подобные написанным на Паскале. Ты можешь использовать, (begin) и
(end) для разграничивания блоков, := для присваивания, и даже добавлять слово
(word) в операторе if или do в цикле (while). Например, следующая программа
также допустима:
begin
x := 10;
while x>0 do
begin
if x=5 then x:=x-5 else x:=x-1;
end;
end;
Функции (functions) и переменные (variables) в GML
GML содержит большое количество встроенных функций и переменных. С их помощью
ты можешь управлять любой частью игры. Для всех действий имеются соответствующие
функции, так что тебе не понадобится применять какие-либо действия, если ты
предпочитаешь использовать код. С использованием функций и переменных, для
управления игрой, можно добится значительно большего, нежели при использовании
только одних дейстивий. Так что, если ты хочешь расширить возможности своей
игры, я настоятельно рекомендую тебе просмотреть следующие главы, чтобы
получить общее представление о том что вообще возможно будет сделать. Обрати
внимание, что указанные переменные и функции могут также использоваться при
обеспечении значений для действий. Следовательно, даже если ты и не планируешь
использовать в дальнейшем код или писать сценарии, тем не менее ты получишь
полезные данные для дальнейшей работы.
Ниже используется следующие соглашение.
Имена переменных помеченных значком * являются доступными только для чтения
(read-only), то есть их значения не могут быть изменены. Имена переменной с
[0..n] после имени - являются массивами. Диапазон возможных индексов приводится.
© 2001 Simple Life & World
|