GMCheck — анонс
Немножко предыстории. Я ооочень давно познакомилась с замечательным игроконструктором Game Maker. Каждый апдейт, с 4.0 в 2001 году и до 6.1 в 2005, я встречала с нетерпением — чего же нового привнёс нам Марк Овермарс. Пусть за всё это время из-под моих лапок ни одной мало-мальски законченной игры не вышло, GM надолго стал одним из моих основных компьютерных развлечений, а скриптовый Game Maker Language — пожалуй, первым языком программирования.
Впоследствии по ряду причин — учёба, работа, другие увлечения — новые версии, созданные новыми разработчиками, прошли мимо. И когда меня на старости лет снова потянуло в геймдев, оказалось, за это время среда разработки очень сильно развилась в профессиональную сторону, похорошела, обросла множеством удобных фишечек. А вот язык остался практически на том же уровне, что и в начале нулевых. По сути, единственное крупное обновление произошло совсем недавно, в версии GMS 2.3. И даже оно, привнося несколько новых и действительно крутых возможностей, не исправляет имманентных проблем, лежащих в корне дизайна языка и его стандартной библиотеки.
Вообще говоря, даже немножко шаря в дизайне языков программирования, к Game Maker Language уже можно предъявить много объективных претензий, но это тема отдельной длинной статьи; а эта целенаправленно посвящена одному из самых больных мест — и чем проект крупнее, тем оно больнее. GML предоставляет множество способов наделать ошибок, но неохотно помогает их находить:
- Типизация в языке динамическая, что подразумевает проверки только в ходе выполнения, а выполнение за неимением юнит-тестов — это много-много пробных запусков игры, что долго и утомительно. И не факт, что эти запуски дойдут до ошибки, которая затесалась в ветке кода, срабатывающей только при очень особых условиях.
- При этом типичная реакция на ошибку — грохнуться с концами, сказав игроку «сорян» механизм исключений появился только в 2.3, а в остальном для отладки предлагается пошагово выполнять и останавливаться на брейкпойнтах, как в старых добрых 80-х.
- Разных типов, а соответственно, разных проверок — кот наплакал; даже такие вроде бы разные сущности, как булевые и целые значения, цвета, идентификаторы объектов, дескрипторы ресурсов и структур данных — это всё прикрытые фиговым листиком числа с плавающей точкой.
- Неявное объявление переменной по месту её использования массово приводит к ошибкам доступа к неинициализированной переменной, а флажок «treat as 0» — лишь уход от проблемы, лечение пульпита парацетамолом.
Я люблю игры, но не умею их делать. Зато люблю языки, и умею программировать, и хочу своими навыками помочь тем, кто тоже считает, что геймдев — это в том числе программирование. А также считаю, что самый быстрый и лучший способ исправлять ошибки — это заранее их не допускать. Поэтому с июня веду неспешную разработку GMCheck — статического анализатора кода в проектах на Game Maker Studio 2 (как более актуальной версии, но поддержку первой добавить несложно). Те, кто знаком с миром промышленного программирования, наверняка слышали о таких продуктах, как Сppcheck для C++, PVS Studio для C++ и Java, ReSharper для C#. А также о том, что старые динамические языки (PHP, Python, JavaScript) движутся в сторону опциональной типизации или ответвляются в статические диалекты (Dart, TypeScript). А если вы от всего этого далеки, то статический анализатор, вкратце — инструмент, позволяющий до запуска программы вылавливать в ней ряд потенциальных семантических (в т. ч. некоторых логических) ошибок, которые не заметил компилятор:
- Для динамического языка, коим является GML, это такой внешний тайпчекер, отслеживающий типы переменных и их возможные изменения, чтобы заранее не дать сложить строку с числом, использовать неинициализированную переменную, обратиться не тем аксессором к структуре данных или перепутать местами аргументы в развесистых функциях наподобие
draw_sprite_general
. - Причём динамические возможности — например, в рантайме поменять тип переменной, или передавать аргументом функции значения разных типов, в зависимости от чего она может вести себя по-разному — в языке-то и не используются. Все функции стандартной библиотеки имеют однозначные сигнатуры, без перегрузок. Свой скрипт можно написать каким угодно, нашпиговав внутри проверками типа
if is_real (argument0)
, но юз-кейсы такого рода сомнительны. Поэтому если одна переменная может иметь разные типы в разных участках кода или вдруг поменять его в ходе выполнения — это, возможно, и не ошибка, но как минимум предупреждение. - Поскольку типы переменных явно не указываются, их нужно выводить по контексту использования, и я не уверена, насколько полно это будет получаться. Однако несложно добавить опциональную типизацию, как в вышеупомянутых динамических языках — скажем, комментариями специального вида, которые сам GM просто игнорирует, а чекеру это будет помогать.
label /*: string*/ = <…>
- Для некоторых переменных имеет смысл отслеживать вхождение в возможный диапазон — например,
alpha
должен быть от 0 до 1, даже после всех возможных математических преобразований. - Скрипты в Game Maker — эдакие глобальные методы, которые можно вызвать из любого объекта, невзирая на его внутренности. Чекер может проверять, всё ли окружение, нужное скрипту, доступно в объекте на момент вызова, и не перетирает ли он чего-то важного.
- Не все, особенно новички, умеют грамотно пользоваться локальными переменными (
var
), из-за чего они могут висеть в объекте до скончания времён, или конфликтовать с другими (особенно при вызове скриптов). - Множество вещей, при которых программа вроде бы успешно работает, но что-то явно не так — неиспользование забытых переменных, вызов рисовательных функций вне события Draw, вызов или наследование пустых событий, обращение к
other
там, где его нет… - Структуры данных требуют ручного вызова
_create
и_destroy
, иначе можно словить утечку памяти. - Ошибки, порождаемые опечатками или копипастой — например, когда логическое выражение всегда получается истинным или ложным, в разных ветках условного выражения одинаковые конструкции, или параметрами передали
x
,y
,y
вместоx
,y
,z
. - …и много других.
Понятное дело, задача вот это всё обнаружить в общем случае неразрешима, что доказано ещё стариной Тьюрингом. Тем не менее, разнообразными эвристическими алгоритмами можно достичь очень неплохих результатов, пусть и с некоторым количеством ложноположительных срабатываний. Использование предполагается максимально простым — натравливаете программку на папочку с вашим проектом, и получаете HTML-отчёт обо всяких подозрительных местах. Интегрироваться в саму среду GM, увы, нельзя, но можно завести помощника-демона, который будет висеть в фоне и обновлять отчёт каждый раз, когда что-то добавляется в проект.
Разработка ведётся на Haskell — наилучшем языке для такого рода задач (компиляторов, трансляторов и прочих анализаторов сложноструктурированных данных). Репозиторий — здесь. На данный момент готов парсер практически всей грамматики GML в синтаксическое дерево, и растут зайчатки вывода и проверки типов. Stand-alone запускалки пока нет, разрабатываю, экспериментирую и проверяю юнит-тестами и в REPL.
Честно говоря, зная своё хроническое неумение доводить дела до конца, я совершенно не могу гарантировать, что проект дорастёт до хоть какого-то юзабельного состояния. И уж тем более не смогу своими скромными силами реализовать весь спектр возможностей, перечисленный выше. Но мне очень поможет, если буду знать, что он правда может кому-то пригодиться — любителей (и профессионалов!) Game Maker тут немало, я знаю. И кроме того, вы можете поддержать и другими способами:
- Триалка GMS2 у меня закончилась, а на лицензию раскошеливаться пока не хочу, поэтому очень полезными будут исходники маленьких проектов — например, с джемов, или просто синтетических примеров. Особенно здорово, если там действительно будут какие-нибудь загадочные ошибки, которые вы так и не смогли отловить.
- Рассказывать про самые-самые типичные и надоевшие баги, возникавшие у вас при разработке на GM.
- Проаннотировать сигнатуры всех этих бесчисленных функций стандартной библиотеки GML. Они лежат в отдельном текстовом файле с готовыми примерами, и знания хаскеля для этого не нужно.
- Просто предлагать всякие идеи и хотелки.
Stay tuned!
- 29 сентября 2020, 22:44
- 018
Товарищи гаминцы, я тут недавно, объясните одну вещь. Почему в любой теме, где речь заходит о движках и коде, обязательно образуется Кситилон и начинается поток комментов про следующее:
– я сделал GMXD, но потом подлецы выпилили execute_string;
– 14 лет жопыта;
– мне, моим знакомым и моей собачке не пригодилось – значит, никому нинужно;
– гит особенно нинужно;
– если кому-то нужно, то они тратят силы на шашечки, а могли бы игры делать;
– неча лезть в геймдев со своим программированием, он – не оно;
– инди-геймдев – особенно не оно;
– GM рулез, Unity/Godot/всёостальное сакс;
– Unity особенно сакс, потому что кватернионы;
– GM рулез, потому что на нём могут работать даже композиторы, не умеющие кодить;
– делаешь ошибки – GM не при чём, это ты дисциплинируйся и научись кодить;
– ...
Это местная традиция такая? Как вы с этим живёте?
Кажется, уже можно на его комментах обучить нейросетку и она будет его успешно заменять, пока он спит.
О, единственный человек на всём сайте, который меня заигнорил, потому что самый сноб. Чтоб не возникало вопросов с чего я взял - все остальные завсегдатаи мне отвечают на то что я написал, со знанием того что я написал.
Ну да ладно. С этого дня я пишу на Гамин только посты. Всё равно у каждого свои розовые очки и толковать с вами не о чем.
EDIT: А, так Антонка всё таки второй человек на всём сайте. Что ж. Не все способны согласиться с идеей, что их любимый движок (и другой просто популярный движок) не везде подходит, когда он якобы и 3D, и 2D, и 2.5D, и сколькохочешьD.
а_я_Д'артаньян.txt
Как самоиронично.
Если не подходит любимый движок, то есть гитхаб, чтобы скачать с него остальные движки, достойные внимания :yak:
Кватернионы вообще не трогаю, а юзаю только LocalEulerAnlges, я не особо в этом шарю, я художник,
а не программист, но пришлось учить юнити из-за доступности, по цене.
Но согласен с тем, что в юнити много гемороя.
Например, делал кастомизацию персонажа в юнити, вначале создал систему кастомизации, потом оказалось, что надо создать систему генерации кнопок списка меню, чтобы этой самой кастомизацией управлять, потом пришлось повозиться с месяц пытаясь понять как обойти все грабли
(ибо UI я не особо знаю, не люблю его использовать, потому-что вроде как внутри UI юнити нельзя или сложно использовать GameObject, мне например нужно было отображать объекты инвентаря прямо на кнопках, потому сделал систему меню просто обычными объектами), и вообще не силён в тонкостях C#)
потом пришлось прикручивать систему глобальной библиотеки, чтобы все объекты кастомизации легко находились через Dictionary по простому имени (string), гемора много было.
Добавил в черный список и вообще не парюсь. Профит.
патамушто весело
это не просто традиция, а одна из двигообразующих традиций. скрепа и основа
обучать нейросетку на комментах нейросетки такое себе
Вот ты этим и займись.
Мне пока хватает одного пет-проекта, спасибо :3
Наверное, потому что это сайт про игры, причём авторские и независимые. Статьи на тему верификации, валидации и трансляции здесь мало кому интересны. При всей их полезности, увы.
Те кто занимается здесь хоть каким-то программированием - реально игры делают. И обычно понимают что программирование как сферический конь в вакууме (сугубо скил) на игру не сильно влияет. Поэтому полезнее пообсуждать геймдизайн. Программирование можно обсудить на том же гдру в весёлой компании ненасытных троллей =)
Отчасти я не согласен с этими тезисами Кситилона, но с существенной частью могу согласиться:
Я не считаю, что правильно сводить vcs только к бэкапам. Это очень помогает следить за тем, что делаешь, и что когда сделал, то есть, экономит время в локализации проблем.
Типа, ты коммитнулся, пилишь что-то, потом вдруг смотришь - всё сломалось. В диффе unstaged commits можно увидеть, что добавлялось с последнего коммита, и быстро понять, куда смотреть.
Или работал на своей ветке, и вдруг находишь какую-то лажу, можно прыгнуть на мастер и увидеть, что её ещё не было, и этим сразу сильно локализовать проблему. В особо тяжких случаях спасает git bisect.
Если настроен CI со статиком (а может быть и тестами), то это помогает заметить разную лажу при пулл реквесте. Но даже если CI нет, тупо свежим взглядом просмотреть всё, что наделал в пулле при диффе, это уже помогает почистить.
По идее, качество кода, всякие статики и прочее как раз должны помогать меньше времени тратить на программирование и связанные с ним боли, и больше уделять созданию непосредственно игры.
Это потому что ты не понимаешь сути. Изменения никуда не проёбываются, все остаются в истории, и прошлые, и будущие. И если что-то и откатывается, то только содержимое конкретного патча, а не все патчи начиная с него и до сего дня (при этом откатанный патч тоже не проёбывается, а остаётся в системе, и потом эту часть работы можно перечитать и переделать).
Игру делает продюсер. Геймдизайнер - это перевод идей продюсера в более весёлую форму.
А программист делает движок, геймплейный код, утилиты для художника, для геймдизайнера, для продюсера и вот этот вот сайт.