Знаете, обычно я не участвую в джемах, потому что … зачем? Ну то есть концепт “сделай игру за два дня” или за неделю сам по себе прикольный, но я уже прошла через этап, когда любая сделанная игра – лучше, чем не сделанная. Мне хочется делать что-то большее. Не просто игру на 30 минут, а игру, которую будут помнить годами. Поэтому и делаю я игры тоже годами теперь)

Впрочем, ближе к делу. Что за Вастрик? Что за джем? Что за клуб – вы, думаю, сами посмотрите, если не знаете. А джем там родился из нескольких тредов, посвященных этому делу. Идея джема появилась где-то на майских, но проведение назначили почему-то на рабочую неделю. Конец немного предсказуем. Всего зарегистрировалось 14 участников и было очевидно, что 14 игр мы не увидим. То есть вполне можно было допустить, что моя игра вообще единственная до релиза дойдет, если я буду что-то делать.

Почему я вписалась в авантюру, которая мне не так уж нравится? Вообще я сейчас не могу точно ответить на этот вопрос, но могу рассказать как это выглядело у меня в голове. Примерно вот это: “Ну, посмотрим что за тема выпадет а дальше я уже подумаю буду участвовать или нет, денег за запись никто не берет”. После того, как выпала тема про бусы, мне прямо совсем расхотелось участвовать. Но я начала думать что я могу сделать. Конечно первыми в голову пошли игры, которые мне давно хочется сделать: тактика а-ля Advance Wars и карточная игра, вдохновленная сборкой танчиков из Warzone 2100. Однако, зайдя в хорошо мне знакомый Multimedia Fusion, я поняла что ни в одном из этих вариантов игра за неделю мне не светит. Собственно, если бы я не была в отпуске, я бы вообще не стала даже задумываться о том, чтобы сделать какую-то игру (наверное).

Проработка концепта

Раз сделать что-то амбициозное в срок сложно, я подумала над созданием игры в своем традиционном жанре: мы как-то передвигаемся, вокруг что-то спавнится, мы в это стреляем, получаем экспу и прокачиваемся. Столько раз работало, не может не заработать в этот раз. В общем, запилила я быстренько основной фон, объект, которым управляет игрок и стала думать как в этом что-то спавнить. И придумала что с концов дорожек будет ехать полиция. А чтобы интереснее было она научится еще поворачивать случайным образом. Делала я эту штуку, делала, и в итоге пришла к тому что это превратится в автомобильную катастрофу, когда все машинки по кругу друг в дружку врежутся. Это было бы забавно, но играть в это было бы нельзя. Но я сразу придумала как это обойти. Надо чтобы они всегда либо поворачивали направо, либо ехали вверх. Тогда оробороса не будет. Но эта мысль вызвала следом другую: “А как это сделать интересным-то?”. И мне показалось, что никак. Да и вообще, я куда-то сильно торопилась. Мне хотелось поскорее сделать игру, чтобы этот кошмар просто поскорее закончился и я могла дальше заниматься своими делами. Поняв, что тут что-то не так, и если мне не интересно делать игру, то вряд ли кому-то будет в нее интересно играть, я пошла в интернет смотреть как люди переживают джемы вообще.

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

И обнаружила, что в первый день даже в 48-часовых джемах мало кто делает игру. У них целый день отводится под концепт. И я поняла, что это может все заметно улучшить. Я подумаю что я могу сделать, а если не придумаю – то и не буду делать. Размышления мои пошли в сторону выживалок а-ля Out There. Я подумала сделать клон этой игры. И начала прорабатывать концепт. Дизайн будущей игры получился таким, который практически 1-в-1 повторяет источник вдохновения. То есть в машинку перетаскиваются ресурсы, которые в разных городах и локациях просто добываются. Какое-то время я всерьез хотела так и сделать. Но потом мне подумалось, что делать точную копию не интересно. Особенно, копию игры, которая мне не очень нравится)

С этими мыслями первый день джема и закончился. Но у меня уже был второй вариант – карточный выживач, в котором нужно разобрать колоду. Идея мне понравилась, но вот ее реализация на MMF2, который оказался не таким удобным и приятным, каким я его помню, могла вызвать очень большие сложности. Карточная игра подразумевает большую долю математической составляющей и тексты с циферками. Как все это сделать на движке, редактор для которого выглядит вот так:

Слева – условия, сверху – объекты. В пересечениях строк и столбцов размещаются операции, которые нужно выполнить

В редакторе нет даже удобного редактора формул, а у объектов нет произвольных параметров с именами, только Alterable Value A-Z. Сорцы тут нарисованы для первого прототипа). При этом плагины для написания скриптов в движке… очень плохие. Это в основном Lua и C#. Первый я знаю по написанию скриптов для гомункулов в Ragnarok Online (и не очень хочу на нем писать), а второй просто знаю. Проблема в том, что там очень старая версия .NET и самого языка, поэтому писать в нем код было бы мучительно. В итоге я пошла по другому пути. В MMF2 есть (по-моему, даже встроенный) плагин для работы с DLL. Можно заимпортить функции из библиотеки, которую я напишу на C# или C++ (на самом деле на любом языке, где можно экспортить си-функции). Пользоваться этим плагином не супер-удобно, он почему-то не позволяет вызывать функции с аргументом за одно действие, а просит сначала выставить аргументы, а потом звать. Но жить можно. Утром второго дня у меня уже были готовы тесты всего этого дела. Заработало! Теперь оставалось только написать код и сделать интерфейс.

Реализация

С кодом проблем не было, он вообще моментально пишется. Многие почему-то боятся плюсов, но на них тоже можно писать код быстро, оверхед относительно c# практически незаметен. Но я писала на плюсах, потому что тестировала работу DLL на них. Так просто вышло, мог бы быть и шарп. На работу в IDE у меня ушло меньше половины времени. Часов 12-16, может быть. Проблемы были снова с MMF. Как обеспечить последовательную логику в сеточке событий и не сильно страдать от количества ручного труда? То есть, нам нужно обновлять несколько разных штук на экране на каждом действии и подгружать информацию несколькими вызовами из DLL. В MMF нет функций. Есть объект функции в виде плагина, но, попробовав его, мне расхотелось им пользоваться. Он нарушает логику MMF, так как вызванная функция выполняется до того, как выполнится строчка события. Я бы скорее всего не разгребла все баги, если бы делала с использованием этого плагина. Поэтому мне пришлось, хоть и не хотелось, использовать на стороне MMF конечный автомат. Выглядит это вот так:

  1. Если статус = 0 и игрок кликает на колоду – выставляем статус в 1;
  2. Если статус = 1 – играем звук, выставляем статус в 2;
  3. Если статус = 2 – пишем в массив карт возврат функции DrawCard из DLL, выставляем статус в 3;
  4. Если статус = 3 – достаем из массива карт по номеру свободной позиции id карты, выставляем его в качестве аргумента, пишем возвраты GetCardResource и GetCardCost в массив карт, выставляем статус в 30;
  5. Если статус >= 30 и <35, обходим позиции в руке и находим следующий свободный слот. Если слот занят – добавляем к статусу 1, если свободен – выставляем в 100;
  6. Если статус = 35, выставляем статус в 100. Позиция в руке будет выше размера руки игрока)
  7. Если статус = 100, обновляем интерфейс, смотрим жив ли игрок и так далее, вы поняли суть.
Вот так это все выглядит на практике. Коды разбиты по группам, чтобы я не сломалась на поиске багов

По такой логике в игре работает все. MMF ничего об игре не знает. В нем прописано только несколько тултипов. Вся логика игры и остальная часть текстов находится в Engine.dll. Благодаря такому решению, мне не нужно править фронтенд на каждое изменение баланса. Раз уж на то пошло, было несколько скриншотов MMF, но скриншотов Visual Studio не было. Надо исправиться. Вот вам те самые экспорты (не все), коих довольно много:

Экспортируются нативные си-функции с built-in типами. Поэтому вся работа идет по id и индексам. В основном все функции имеют от нуля до одного аргумента, но есть функции с двумя аргументами.
А так выглядит обычная логика игры. Почти все на мапах и switch-стейтментах. Чисто процедурного кода довольно мало.

В целом я написала в cpp намного больше фигни, чем надо было. Например, изначально Card была классом, но позднее я оставила только enum class с типами, а логику использования карт – в игроке. Так код получился проще. Сами сорцы я возможно куда-нибудь выложу потом…

Все, больше прогромирования не будет, тем кто глазки закрыл от ужаса – можно открывать обратно. Давайте напоследок пройдемся по самой игре. Что было добавлено, что было удалено и всякое такое. На самом деле, фичаката не было. Было изменение механик. Я, тем не менее, думала удалить из игры воду, например. Зачем два ресурса, которые нужно меинтейнить? Практически низачем, на самом деле. Можно было убрать ее, но я не убрала. Также, я добавила в игру сувениры, которые изначально не планировались, друзяшек, которые были большую часть времени закомментированы и пикники, которые связаны с друзяшками. Все это добавление фич мне практически ничего не стоило, вообще игра очень легко масштабируется, ведь я хороший программист и пишу легкий в поддержке код)

Тестирование и допиливание

Полноценно тестировалась игра только к пятому дню джема. До этого она была едва ли проходимой. Поэтому все правки баланса попали на последние дни. И исправлено было очень многое, начиная просто от циферок (стартовые ресурсы были раньше были равны 10, гриль готовил меньше еды и всякое такое), продолжая принципиальным изменением механик и заканчивая незаметными для игрока твиками рандомизатора.

Очень многое было поправлено уже после этого скриншота, но на самом деле игра во всех аспектах стала проще. 1078 монет – это не какие-то читы, а вполне честная циферка. Как видно, у меня даже запас хороших карт остался к концу прохождения.

Твики рандомизатора – это самое интересное! Сейчас я вам расскажу как вашу карточную игру сделать чуть менее бесящей. Вот так:

Помните, я писала что не будет больше кода? I lied.

Для непрогромистов расшифрую что на этом скриншоте нарисовано. Если вы за первые 5 карт не вытащили ни одного магазина – вытащится магазин. Если число карт, деленное на модификатор заправок или магазинов больше числа вытащенных магазинов или заправок – вытащится заправка или магазин. Если вытащилась карта, которая уже есть в руке – рандом бросится повторно. Это очень крутые quality-of-life улучшения, которые делают большую долю игровых сессий проходимыми. И это не все. Например, в магазине всегда есть один из артефактов, которых у вас нет. Изначально вам всю игру мог не падать гриль в магазине, например. Также, ресурс в магазине выбирался случайным образом. Сейчас в магазин всегда попадает тот ресурс, которого у игрока меньше. Подобные хаки уменьшают вариативность ситуаций, но делают игру приятнее (особенно, на первых этапах освоения механик).

Помимо этого, лопата в игре давала намного больше ресурсов, но работала случайным образом в лесах, а выкапывания нефти вообще не было. Выкапывание минимального ресурса сделало лопату очень полезным инструментом для прохождения, а леса – особенными. Ими можно подстраховаться на любую ситуацию. Карты со штрафами были изначально фиксированными, но в начале игры они были слишком серьезными, поэтому я добавила формулы увеличения штрафов постепенно, по ходу игры. Это также мотивирует не держать штрафные карты в руке подолгу. А друзяшки начали снижать штрафы на воду и еду, потому что с ними было адово сложно и нужно было придумать какую-то мотивацию для их кормления. Сейчас с ними игра проходится довольно просто. В итоге получилось так, что игру можно проходить по-разному. Не все способы одинаково простые, но по-моему они все интересные и хотелось бы добавить в игру список ачивок на прохождение с разными челленджами, но эта идея мне только к концу джема пришла в голову.

Чего игре по-прежнему не хватает – так это прозрачности. Стоило бы показывать игроку почему он проиграл. Стоило бы показывать изменения циферок на каждом обновлении (такие всплывающие циферки с нижней части с ресурсами можно было сделать) и стоило бы найти возможность отменять выбор карты локации. Это все мне уже было лень делать, я очень сильно задолбалась. На игру ушло где-то 40-50 часов разработки, и это довольно много для недельного джема. Пару дней я вставала в 8 часов утра и делала игру до 11 вечера с перерывами на еду. В последний день я только добавила желтую рамочку для элемента, которым сейчас предполагается пользоваться. Но и эта фича не доделана. Стоило бы сделать желтую рамку и у колоды. Но это было чуть сложнее сделать, потому что это переключение между тремя вариантами вместо двух. А еще потому что у колоды нет бэкграунда, есть только сама колода.

Особый баттхерт у меня вызвал поиск ассетов. Практически весь интерфейс я нарисовала самостоятельно, исключением являются только картинки карт. Искать royalty-free картинки по всему интернету – неудобина. Наверное, у людей, ходящих на джемы, есть свои запасы ресурсов на любой случай, но мне было стрессово осознавать что я могу не успеть сделать картинки для всех карт. Хотя, надо признать, что бесплатных ассетов в интернете сейчас очень много. Кстати…

Узнаете человечков? )

Так что в итоге? Пойду я на следующий джем? Знаете, если он будет недельным – вряд ли. Это слишком стрессово и я не думаю что я смогу снова так окунуться на 50 рабочих часов в свое свободное время. Я хочу делать качественные продукты, а не клепать хоть что-то на коленочке. А эта потребность быстрыми джемами не покрывается. Если же джем будет подлиннее – то я подумаю. Но для тех, кто хочет испытать в себе геймдизайнера, джемы – хорошая штука. Рекомендую попробовать. По этому посту можно увидеть, что я тоже узнала много нового за это время.

P.S. The VAN Journey получила первое место на джеме)

P.P.S. Поиграть во все игры с джема вы можете вот тут. А тут можно посмотреть как в них играет один из участников)

Метки: