Game Maker Language
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 . У GMS2 вбудований механізм конвертації дій, заданих «кнопками», в код GML і назад, що дозволяє новачкам швидше перейти на GML і покращує розуміння того, як працюють стандартні дії.
Синтаксис і семантика GML
GML структурно схожий на мову С своїми блоками коду, викликами функцій, привласненням змінних, синтаксисом операторів і так далі. GML розрізняє оператори і вирази. Наприклад,
g < 1;
не є правильним оператором і викличе помилку. Також, присвоювання змінних - це завжди оператор, і тому не може бути використаний в виразах. Наприклад, наступний рядок завжди генерувала б помилку тому, що вона б обчислювала вкладене вираз як true або false, а потім порівнювала б булевий результат з рядком «Yes» (неправильне порівняння):
if ((answer = get_string("Yes or No?", "")) == "Yes")
Варто пам'ятати, що знак рівності «=» є оператором присвоєння і булевих оператором порівняння в виразах, тоді як в С ++ у виразах пишуть подвійний знак «==». Проте, подвійний знак одно «==» буде правильно інтерпретований в разі використання його в виразах. Використання такого знака в якості оператора присвоєння викличе помилку виконання. GML також підтримує оператори інкремента :
g ++; // підтримується як Постфіксний, так і префиксная запис
і
g += 1;
те ж саме, що і
g = g + 1;
Також існують оператори: - =, * =, / =, | =, & = і ^ =. Починаючи з GMS2 введена підтримка тернарного оператора?:. Оператори в GML можуть бути розділені крапкою з комою, однак це не є обов'язковою умовою (хоча і може привести до помилки в деяких специфічних випадках).
Функції
Game Maker містить велику бібліотеку вбудованих функцій для забезпечення основної функціональності. Програміст може створювати свої власні скрипти, які викликаються точно таким же способом, як і функції. Функції малювання в Game Maker використовують Direct3D API . При необхідності Game Maker також дозволяє викликати нативний код платформи за допомогою розширень (DLL на Windows, Java на Android, JS на HTML5 і т. п).
Використання
Зазвичай, GML не потрібно попередньо оголошувати змінну, як це робиться в деяких інших мовах. Мінлива створюється автоматично, відразу після присвоєння їй жодного значення:
foo = "bar";
В Game Maker є багато вбудованих змінних і констант. Кожен екземпляр об'єкта містить багато локальних змінних, наприклад «х» і «у». Також існує кілька вбудованих глобальних змінних, наприклад «score». Ці змінні існують незалежно від примірників об'єктів. Ці змінні не містять префіксу «global.», На відміну від глобальних змінних, зазначених програмістом. Одномірні і двовимірні масиви також підтримуються.
Структури даних
У GML є функції для створення і редагування структур даних шести типів: стек, чергу, список, карта (асоціативний масив), пріоритетна чергу і сітка. До сітці, списку і карті також є можливість доступу за допомогою аксессор, що надають синтаксис, подібний масивів:
var value = list[| 0]; // вместо ds_list_find_value(list, 0)
map[? "name"] = "Username"; // вместо ds_map_add(map, "name", "Username")
var value = map[? "name"]; // вместо ds_map_find_value(map, "name");
Типи
У GML підтримуються наступні типи даних:
- string (рядок) - послідовність символів, укладених в одинарні або подвійні лапки (починаючи з GMS2 слід використовувати подвійні лапки).
- real (число) - ціле або з плаваючою комою. Хоча все значення, створені в GML, зберігаються як числа з плаваючою комою подвійної точності, для роботи з розширеннями можна використовувати і інші типи
- array (масив) - змінна, яка використовує індекси для доступу до елементів. Можуть містити будь-які дані - числа, рядки, інші масиви, дескриптори інших структур даних і т.п. Їх також можна передати як параметр у функцію, і вони можуть бути повернуті функцією як результат.
- boolean - може приймати значення true або false. Майте на увазі, що в даний час GML не підтримує «справжні» булеві значення і насправді приймає як false будь-які числа менше 0.5, а все, що дорівнює або більше - як true.
- pointer (покажчик) - покажчик на область пам'яті. Використовується в деяких специфічних функціях на кшталт buffer_get_address () і ін.
- enum (перерахування) - задана користувачем колекція констант, що зберігаються в змінної.
- undefined (не задано) - спеціальне значення, що повертається у випадках, коли запитувані дані не знайдені.
Область дії змінних
Хоча GML і можна розглядати як об'єктно-орієнтована мова, природа об'єктів і примірників об'єктів в Game Maker створює деякі важливі відмінності в способі розмежування змінних. Існує два типи локальності: локальність в об'єкті і локальність в скрипті (або іншому шматку коду, що міститься в окремому контейнері). Те, що змінна є локальною для екземпляра об'єкта, означає, що змінна прив'язана до конкретного екземпляру об'єкта і ззовні цього примірника може бути використана тільки з приставкою, яка визначає цей екземпляр; то, що змінна є локальною для скрипта, означає, що ця змінна може бути використана тільки в цьому скрипті (і знищується після закінчення скрипта). Далі термін «локальний» означатиме локальність в об'єкті. За замовчуванням, змінна локальна для об'єкта, але не локальна для скрипта, в якому вона використовується. Для того щоб зробити змінну доступною всім екземплярам об'єктів, вона може бути визначена через глобальний простір імен:
global.foo = "bar";
Також існує можливість оголошувати глобальні змінні використовуючи ключове слово globalvar:
globalvar foo, bar;
Але такого способу слід уникати, так як це може легко призвести до складно виявляються помилок, через перетину областей видимості змінних (те ж саме рекомендують і безпосередньо розробники GMS, більше того, можливо, що в майбутньому це ключове слово буде повністю прибрано з мови - в даний момент воно залишено виключно з міркувань забезпечення сумісності). Для того, щоб зробити змінну локальної для скрипта, її потрібно визначати так:
var foo, bar;
Областю видимості локальної змінної є скрипт, всередині якого вона оголошена. Це має на увазі, що при перемиканні контексту (c використанням with) вона як і раніше буде доступна. наприклад:
var foo = "bar";
with other
{
show_message (foo); // змінна foo доступна
}
Доступ до локальних змінних об'єкта можна отримати, використовуючи ідентифікатор екземпляра об'єкта як приставку
instance.varname
але, тим не менше, таким чином неможливо отримати локальні змінні одного скрипта з іншого, поки вони не передаються як параметри функції. Поточне простір імен об'єкта може бути змінено за допомогою конструкції «with». Наприклад, наступний скрипт, якщо його помістити в подію зіткнення, знищить інший екземпляр об'єкта, залучений в цю подію (зауважимо, що у події зіткнення Game Maker автоматично встановлює змінну other на другий примірник об'єкта, з яким сталося зіткнення):
with other
{
instance_destroy();
}
Розподіл пам'яті
GML автоматично розподіляє пам'ять під змінні на ходу, і використовує динамічні типи, тому присвоювання змінним значення різних типів також можливо. Наприклад, спочатку можна створити целочисленную змінну, а потім змінити її на строкову:
intNumber = 1;
intNumber = "Ця змінна тепер містить рядок";
У GML немає спеціального функціоналу, що дозволяє звільняти пам'ять, зайняту під змінну, однак при необхідності можна привласнювати змінної нове значення, меншого розміру. Наприклад, якщо у вас є змінна, в якій зберігається великий текст, то, присвоївши змінної значення порожнього рядка, можна домогтися вивільнення пам'яті. Те ж саме стосується і масивів:
data = [1, 2, 3, 4, 5]; // створили масив (такий синтаксис створення масивів доступний починаючи з GMS2)
data = 0; // знищили масив (тепер це просто змінна)
При знищенні об'єкта також знищуються всі змінні, локальні для нього, а будь-які глобальні змінні існують незалежно від них. Тому перевагу потрібно віддавати локальним змінним, а глобальні змінні використовувати тільки в разі реальної необхідності цього. Для зберігання великих обсягів інформації більш ефективно, в Game Maker є підтримка декількох структур даних - таких, як стек, чергу, список, карта, пріоритетна чергу і сітка. Ці структури створюються, модифікуються і знищуються за допомогою вбудованих функцій. Також є функції практично у всіх структурах для сортування даних в них. У деяких випадках більш зручним і ефективнішим буде використання буферів, що дозволяють зберігати довільні дані і є, по суті, просто виділеними шматками пам'яті.
Об'єкти і ресурси
В основі роботи Game Maker з ресурсами лежать унікальні ідентифікатори, які служать для визначення конкретного ресурсу або примірника об'єкта. Ці ідентифікатори можуть бути використані скриптами або функціями для вказівки необхідного ресурсу. Так як створення ресурсів безпосередньо в Game Maker має на увазі вказівку імені, то це ім'я служить константою, що містить ідентифікатор ресурсу. Ідентифікатор конкретного екземпляра зберігається в локальній змінній «id». При динамічному створенні ресурсів, завжди повертається ідентифікатор створеного ресурсу, який може бути використаний в подальшому.
Приклади скриптів
Ось простий приклад скрипта, який виводить легендарну фразу «Hello, World!»:
show_message ( "Hello, World!");
Ще один приклад, який відображає той же текст, але вже у вікні програми. Зауважте, що за умовчанням Game Maker безперервно перемальовує вікно, тому в звичайному випадку цей код потрібно помістити в подія малювання.
draw_text (10, 10, "Hello, World!");
Ось фрагмент коду з гри на GML:
// це коментар
/ * Так коментарі пишуться в С ++. * /
/ * Визначення тимчасових змінних.
Ці змінні будуть видалені після закінчення скрипта.
Зауважте, що змінні не вимагають ніякого визначення типу! * /
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;
}
}
Стилі коду можна змішувати. Наприклад, попередній приклад може бути записаний так:
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
Ось приклад звичайного управління з клавіатури. Функція motion_set приймає два параметри: напрямок (в градусах) і швидкість (пікселів за крок). Виклик цієї функції призведе до зміни вбудованих локальних змінних speed і direction, які використовує Game Maker для переміщення об'єктів (об'єкти також можна зрушувати безпосередньо, використовуючи локальні змінні x і y):
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);
А ось приклад більш складного скрипта для платформної гри. Використовуючи його, гравець може ходити по опуклій поверхні:
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
Критика
Вільний синтаксис GML полегшує створення ігор в певній мірі, але може породити абсолютно нечитабельним код:
switch 0begin case 0: x = 0break}
if a = 0then begin b = 1} else if a == 0 {b: = 1end
Хоча це і не частина мови, ще одним поширеним приводом для критики старих версій Game Maker був сам процес створення EXE-файлів, які складаються з завантажувача і ресурсів GM-файлу. При запуску такої гри, код розбирається на абстрактне синтаксичне дерево (використовувалася інтерпретація коду), що полегшувало декомпіляцію і суттєво збільшувало час завантаження. Однак в більш сучасних версіях (GameMaker: Studio) механізми були змінені, тому немає ніяких проблем ні зі швидкістю запуску, ні з декомпіляцією (декомпілятори для GMS не існує).
Література
- Matthew DeLucas. GameMaker Game Programming with GML. — Packt, 2014. — 350 p. — ISBN 978-1-78355-944-2.
Див. також
- Game Maker
- Game Maker: Studio
- Мова програмування