Game Maker Language

Материал из Циклопедии
Перейти к навигации Перейти к поиску
Game Maker Language
Тип исполнения:объектно-ориентированный, событийно-ориентированный, скриптовый
Появился в:1999
Автор(ы):Маркус Овермарс
Расширение файлов:.gml, .gmk, .gm6, .gmd, .gm8, .gm81
Сайт:yoyogames.com

Game Maker Language (GML) — это интерпретируемый язык программирования, разработанный для использования вместе с программой для разработки компьютерных игр называемой Game Maker. Изначально поддержка языка была внедрена в Game Maker Марком Овермарсом для дополнения системы кнопочных событий, однако, в последних версиях программы, все кнопочные события были включены в GML, позволяя программисту избежать использования кнопочных функций. GML очень сильно связан со средой Game Maker. Game Maker организован так, чтобы не было необходимости программирования вручную таких вещей, как управление событиями, дизайн уровней и настройка объектов. Существует заблуждение, что GML поддерживает вставки фрагментов кода на других языках, таких как Pascal, Assembler или C++. Заблуждение возникло из-за частичной схожести синтаксиса GML с Pascal и C++. (Например, оператор «&&» может быть заменен на «and»).

Библиотеки[править]

В Game Maker совокупность кнопочных событий образует библиотеку. В интерфейсе программы библиотеки отображаются как закладки, в которых находятся различные иконки событий. Каждое такое событие — это GML-скрипт или функция, которую пользователь может использовать в игре. В поставку Game Maker входят несколько стандартных библиотек, которые содержат основные события, используемые в большинстве игр; Так же существует возможность создавать свои собственные библиотеки, используя Library Maker.

Синтаксис и семантика GML[править]

GML структурно похож на язык С своими блоками кода, вызовами функций, присваиванием переменных, синтаксисом операторов и так далее. GML различает операторы и выражения. Например,

  g < 1;

не является правильным оператором и вызовет ошибку. Также, присваивание переменных — это всегда оператор, и поэтому не может быть использован в выражениях. Например, следующая строка всегда генерировала бы ошибку потому, что она бы вычисляла вложенное выражение как true или false, а затем сравнивала бы булевский результат со строкой «Yes» (неправильное сравнение):

  if ((answer = get_string("Yes or No?", "")) == "Yes")

Стоит помнить, что знак равно «=» является оператором присвоения и булевским оператором сравнения в выражениях, тогда как в С++ в выражениях пишут двойной знак «==». Тем не менее, двойной знак равно «==» будет правильно интерпретирован в случае использования его в выражениях. Использование такого знака в качестве оператора присваивания вызовет ошибку исполнения. GML также поддерживает операторы инкремента:

  g += 1;

то же самое, что и

  g = g + 1;

Так же существуют операторы: -=, *= и /=. Game Maker не поддерживает оператор ?:. Операторы в GML могут быть разделены точкой с запятой, однако это не является обязательным условием.

Функции[править]

Game Maker содержит обширную библиотеку встроенных функций для обеспечения основной функциональности. Программист может создавать свои собственные скрипты, которые вызываются точно таким же способом, как и функции. Функции рисования в Game Maker используют Direct3D API. В Game Maker так же есть функции для использования внешних DLL. Любая возможность, которой нет в Game Maker может быть добавлена посредством DLL.

Переменные[править]

Обычно, GML не нужно предварительно определять переменную, как это делается во многих языках. Переменная создается автоматически, сразу после присваивания ей какого-либо значения, то есть сразу после

  foo = "bar";

В Game Maker есть множество встроенных переменных и констант. Каждый образец объекта содержит множество локальных переменных, например «х» и «у». Также существует несколько встроенных глобальных переменных, например «score». Эти переменные существуют независимо от образцов объектов. Эти переменные не содержат приставку «global.», в отличие от глобальных переменных, указанных программистом. Одномерными и двумерные Массивы также поддерживаются в GML. В действительности, это не новый тип данных, а способ использования переменных. Массивы могут содержать как числа, так и строки, но не другие массивы. Их нельзя передать как параметр в функцию, и они не могут быть возвращены функцией как результат. Общее количество элементов массива не может быть выше 10 млн, причём каждое измерение допускает индекс от 0 до 31999 включительно. На самом деле, простые переменные хранятся, как двумерные массивы: указание имени переменной без индексов p равносильно обращению к первому элементу массива p[0,0], а с одним индексом p[10] — к его первой строке p[0,10].

Структуры данных[править]

В GML есть функции для создания и редактирования структур данных шести типов. Эти функции доступны только в Pro-версии Game Maker. Доступные структуры данных: стек, очередь, список, отображение, очередь с приоритетами и решётка (которая представляет собой эффективную замену массивам).

Типы[править]

Ради упрощения GML, в нём есть только два типа переменных. Каждая переменная может быть любого типа без какого-либо определения оного. Строки — набор символов любой длины. Размер ограничен только размером доступной памяти. Числа с плавающей точкой — знаковые числа с плавающей точкой. Начиная с версии 6.1, Game Maker может обрабатывать числа, заданные в шестнадцатеричном представлении (начинающиеся со знака «$»). В 6-ой версии в управлении такими числами есть ошибка, из-за которой теряется точность вычислений (что приводит к неверным результатам при вычислении больших чисел). Эта ошибка все ещё присутствует в седьмой версии, но она была смягчена увеличением точности в общем. Так как в GML нет булевского типа, выражения, в которых используются такие значения, например «if», определяют значения большие 0.5 как true, а все остальное как false. Константы true и false могут быть использованы вместо 1 и 0 соответственно.

Область действия переменных[править]

Хотя GML рассматривается как объектно-ориентированный язык, природа объектов и образцов объектов в Game Maker создает некоторые важные отличия в способе разграничения переменных. Существует два типа локальности: локальность в объекте и локальность в скрипте (или другом куске кода, содержащемся в отдельном контейнере). То, что переменная является локальной для образца объекта, означает, что переменная привязана к конкретному образцу объекта и может быть использована только с приставкой, определяющей этот образец; то, что переменная является локальной для скрипта, означает, что эта переменная может быть использована только в этом скрипте (и уничтожается после окончания скрипта), так как скрипты не имеют идентификаторов, к которым можно было бы обратиться. Далее термин «локальный» будет означать локальность в объекте. По умолчанию, переменная локальна для объекта, но не локальна для скрипта, в котором она используется. Для того чтобы сделать переменную доступной всем образцам объектов, она может быть или определена через глобальное пространство имен

  global.foo = "bar";

или определена следующим способом:

  globalvar foo, bar;

В первом случае переменная должна быть использована с приставкой global., а во втором без этой приставки. Для того чтобы сделать переменную локальной для скрипта, её нужно определять так: var foo, bar; Доступ к локальным переменным объекта можно получить, используя идентификатор образца объекта как приставку

  instance.varname

но, тем не менее, таким образом невозможно получить локальные переменные одного скрипта из другого, пока они не передаются как параметры функции. Текущее пространство имен объекта может быть изменено с помощью конструкции «with». Например, следующий скрипт, если его поместить в событие столкновения, уничтожит другой образец объекта, вовлеченный в это событие (Заметим, что в событии столкновения Game Maker автоматически устанавливает переменную other на второй образец объекта, с которым произошло столкновение):

  with (other) { instance_destroy(); }

Локальная переменная скрипта становится полностью независимой от текущего образца. Например, следующий код будет работать нормально, хотя переменная foo не определена в образце someOtherInstance:

  var foo;
  foo = "bar";
  with (someOtherInstance) { show_message(foo); }

Распределение памяти[править]

GML автоматически распределяет память под переменные на ходу, и использует динамические типы, поэтому присваивание переменным значения различных типов также возможно. Например, сначала можно создать целочисленную переменную, а потом изменить её на строковую:

  intNumber = 1;
  intNumber = "Эта переменная теперь содержит строку" 

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

Объекты и ресурсы[править]

Game Maker не поддерживает использования указателей на память, поэтому каждый ресурс имеет уникальный идентификатор, который служит для определения конкретного ресурса или образца объекта. Эти идентификаторы могут быть использованы скриптами или функциями для указания необходимого ресурса. Так как создание ресурсов непосредственно в Game Maker подразумевает указание имени, то это имя служит константой, содержащей идентификатор ресурса (для объектов это идентификатор первого образца). Идентификатор конкретного образца хранится в локальной переменной «id». При динамическом создании ресурсов, всегда возвращается идентификатор созданного ресурса, который может быть использован в дальнейшем.

Примеры скриптов[править]

Вот простой пример скрипта, который выводит легендарную фразу «Hello, World!»:

  show_message('Hello, World!');

Ещё один пример, который отображает тот же текст, но уже в окне программы. Заметьте, что по умолчанию Game Maker непрерывно перерисовывает окно, поэтому в обычном случае этот код нужно поместить в событие рисования.

  draw_text(10,10,'Hello, World!');

Вот фрагмент кода из игры на GML:

  <source lang="c">// это комментарий

/* Так комментарии пишутся в С++. */

/* определение временных переменных.

  Эти переменные будут удалены после окончания скрипта.
 Заметьте, что переменные не требуют никакого определения типа! */

var xx, yy, nn;

// Условие. Оно может быть сокращено до «if (can_shoot)». if (can_shoot = true) // "=" и "==" могут быть использованы { // Начало блока кода. Вы можете также писать «begin» как в Pascal.

  /* Устанавливаем переменную в ложь. То же самое можно написать и так: «can_shoot = 0;»
     Так как Game Maker не различает булевские и целочисленные значения. */
  can_shoot = false;

  /* Здесь устанавливаем нулевой таймер на пять шагов. 
    Переменная таймера будет опускаться до 0, а когда достигнет его,
     Событие нулевого счетчика будет вызвано. */
  alarm[0] = 5;

  /* Здесь локальная переменная xx определена как целочисленная, 
     И использована функция lengthdir_x. */
  xx = x + lengthdir_x(14, direction);
  yy = y + lengthdir_y(14, direction);

  //Эта функция создает образец объекта obj_bullet и возвращает идентификатор нового объекта.
  nn = instance_create(xx, yy, obj_bullet);

  /* Оператор with позволяет вам обращаться к переменным объекта напрямую */
  with (nn)
  {
     speed = obj_tank.speed + 3;
     direction = obj_tank.direction;
  }

}</source> Стили кода можно смешивать. Например, предыдущий пример может быть записан так: <source lang="pascal"> var xx, yy, nn; if can_shoot = true then begin

  can_shoot := false
  alarm[0] := 5
  xx := x + lengthdir_x(14, direction)
  yy := y + lengthdir_y(14, direction)
  nn := instance_create(xx, yy, obj_bullet)
  with nn begin
     speed := obj_tank.speed + 3
     direction := obj_tank.direction
  end

end </source> Вот пример обычного управления с клавиатуры. Функция motion_set принимает два параметра: направление (в градусах) и скорость (пикселей за шаг). Вызов этой функции приведет к изменению встроенных локальных переменных speed и direction, которые использует Game Maker для перемещения объектов (объекты также можно сдвигать напрямую, используя локальные переменные x и y): <source lang="c"> if (keyboard_check(vk_left)) motion_set(180,4); if (keyboard_check(vk_up)) motion_set(90,4); if (keyboard_check(vk_right)) motion_set(0,4); if (keyboard_check(vk_down)) motion_set(270,4); if (keyboard_check(vk_nokey)) motion_set(0,0); </source> А вот пример более сложного скрипта для платформенной игры. Используя его, игрок может ходить по выпуклой поверхности: <source lang="c"> if !place_free(x-4,y) {

  if place_free(x-4,y-4)
  {
     x-=4
     y-=4
  }
  else if place_free(x-3,y-5)
  {
     x-=3
     y-=5
  }
  else if place_free(x-2,y-6)
  {
     x-=2
     y-=6
  }

} else

  x-=4

</source>

Критика[править]

Общая критика состоит в том, что в Game Maker всего два типа данных: вещественные числа и строки, хотя можно и объявлять массивы, но содержащие эти два типа данных. Не существует способа хранить массив в переменной; обращение к элементам массива происходит неявно, поэтому нет возможности передать массив как аргумент, но можно передать имя массива как строку, затем получив любой его элемент с помощью специальных функций. Другие структуры данных мало интегрированы в Game Maker, поэтому используются дескрипторы. При создании любого ресурса, всегда возвращается дескриптор этого ресурса. Опять же, дескриптор требует явного освобождения памяти, что может привести к утечке памяти.
Свободный синтаксис GML облегчает создание игр в определённой степени, но может породить совершенно нечитабельный код:

<source lang="pascal"> switch 0begin case 0:x=0break}

 if a=0then begin b=1}else if a==0{b:=1end

</source>

Хотя это и не часть языка, ещё одним распространенным поводом для критики является сам процесс создания EXE-файлов в Game Maker, которые состоят из загрузчика и ресурсов GM-файла. Когда пользователь запускает игру, код разбирается на абстрактное синтаксическое дерево. Это облегчает декомпиляцию и существенно увеличивает скорость загрузки.

Ссылки[править]

 
Используемые
в разработке

Ада A+ APL Atlast Forth AWL Язык ассемблера ActionScript ABAP/4 AutoIt AWK BeanShell Бейсик Си Кобол C++ C# Clarion Clojure ColdFusion Common Lisp D dBase Delphi DuAL Eiffel Erlang Euphoria F# Форт Фортран Gambas Go Groovy HAL/S Haskell IBM PL/S Icon IridiumJava JavaScript Limbo Lua Модула-3 Object Pascal Objective-C OCaml Oz Parser Паскаль Компонентный Паскаль Perl Pixilang PHP PowerBASIC Python ПЛ/1 Пролог Qi Ruby Scala Scheme Seed7 Smalltalk SQL PL/SQL Tcl TouchDesigner Vala Visual Basic (.NET) • X-Robot

Академические

Agda Clean Curry Idris Лого ML Оберон Planning C РЕФАЛ Симула

IEC 61131-3

Instruction List ST FBD Ladder Diagram (LD) • SFC

Прочие

Алгол Алгол 68 Модула-2 Миранда Hope НОРМИН Санда

Эзотерические

HQ9+/HQ9++ • INTERCAL Brainfuck Befunge Malbolge Piet Spoon Unlambda Whitespace FALSE LOLCODE Глагол

Визуальные

G (LabVIEW) • Microsoft VPL Sikuli VisSim Алиса ДРАКОН Скретч

Прочее

ДинамическиеКомпилируемыеС ключевыми словами не на английском языке С C-style синтаксисом СинтаксисYoptaScript

Категория Языки программирования