Разработка карточной игры в Game Maker
Всем привет! Меня зовут Яков, и я разработчик игр. Возможно, вы играли в мои предыдущие проекты: Dom Rusalok, Loretta и Anoxia Station. Сейчас я заканчиваю работу над новой игрой — Bonereader. И, поскольку я много думаю сейчас о балансе игры, я решил поделиться опытом, в свободной форме порассуждать обо разработке, и дать, надеюсь, полезные советы, которые помогут другим разрабам.
Bonereader — карточная игра с механикой покера на костях. Вас поджаривают на электрическом стуле, и вы оказываетесь в Чистилище, вдохновлённом романами Карлоса Кастанеды и Кормака Маккарти, где вынуждены играть в кости с разными духами за призрачный шанс на перерождение.
В основе механики лежит костяной покер (yatzy). В детстве мы с братом часто играли в одну из его вариаций. Когда работа над Anoxia Station подходила к концу, я, как и многие, увлёкся Balatro. А мне за короткое время нужно было придумать концепт для новой игры. И я вспомнил про покер "на костях".
Я не программист, а врач по образованию. Несмотря на то что занимаюсь этим уже лет восемь. Моя главная проблема в том, что у меня нет систематических знаний и я не знаю ни одного языка программирования, кроме GML. Если я нахожу элегантное решение какой-то проблемы в чужом проекте на GitHub, я, конечно же, «заимствую» его, но всегда существенно переписываю. Хотя сейчас в коде для меня нет задачи, которая могла бы поставить меня в тупик. В крайнем случае, я всегда могу обратиться за советом к бесплатной версии Claude.
Пожалуй, единственное, чего я не освоил — сетевой код, но лишь потому, что такая задача никогда передо мной и не стояла. В остальном есть лишь два ограничения: невозможность работать в 3D и фантазия.
Код и механики
По сути, в моём проекте есть три главных объекта: obj_dice, obj_combination и obj_controller, который отвечает за global.game_state (то есть за всё происходящее в игре).
После короткой беседы с тем или иным духом вам открывается магазин, в котором вы можете приобрести предметы и кости, продать или купить карты-комбинации. У каждого монстра есть «правило дома» — специальное условие, которое необходимо выполнять.
С каждым противником вы играете четыре партии, последняя проходит под случайным «Знамением» — по сути, дебаффом. Наконец, на каждый ход или бросок на случайную карту из вашей руки накладывается случайное: есть как выгодные, так и не очень, так и что-то между.
Математика подсчёта примерно такая:
Затем мы накладываем проклятие карты, если оно есть:
Затем проверяем татуировки — перманентные баффы, награды за повышение уровня. Ну и наконец, считаем результат:
Короче говоря, мы суммируем значения кубиков, умножаем на уровень карты и накидываем остальные эффекты.
Предметы работают по принципу:
Где add_bonus_per_dice_value ():
Конечно, таких функций ещё очень много, но суть у них примерно одинаковая: предметы влияют либо на сумму значений кубиков, либо на множитель.
Баланс
Поскольку в проекте я работаю один, то не веду таблиц (кроме локализации) и документации. У меня есть файл _Balance (раньше в GM это называлось script, но я не хочу никого путать, и когда-то он мог нести в себе только одну функцию, но сейчас туда можно записывать сколько угодно функций), куда я в виде #macro записал основные показатели: например, базовое количество очков, которое даёт карта, её цена покупки/продажи и так далее.
В игре два режима: сюжетный и роглайт. Если сюжетный более выверен с геймдизайнерской точки зрения — враги идут по очереди, мы примерно представляем себе кривую прогрессии, определяем пул бонусов для того или иного уровня игрока, — то в роглайт-режиме многое зависит от рандома.
Сет врагов определяется случайно, колоду игрок может взять любую, предметы и награды тоже. Детерминировано, пожалуй, только количество требуемых очков, но и оно может меняться в зависимости от того, взял ли игрок татуировку, уменьшающую очки, или использовал ли предмет для смены дебаффа.
Вот как подсчёт требуемых очков очки для противника. Для своего удобства я использовал термин «анте», который взял из Balatro и который и в самом Balatro, на самом деле, означает не своё первое смысловое значение, но мы это опустим.
Другие технические сложности, вроде смены разрешений, локализации, системы визуальных настроек, системы сохранений, управления геймпадом для меня сегодня уже не представляют такого уж большого вызова. Я использую наработки из предыдущих проектов, оптимизируя под текущий и, по возможности, улучшая.
В Bonreader же я гораздо больше потратил времени на создание "ощущения" от карт и кубиков. Их анимаций, наведения, шейдеров для проклятий.
Советы разработчикам
Из раза в раз я создаю определённую подборку советов для себя в будущем и, быть может, для других разработчиков, которые могут найти их полезными. Почти каждый раз я их в той или иной мере нарушаю, но искренне стремлюсь их соблюдать, а потому не стесняюсь повторить!
Если вы тоже хотите создать игру на GM, вот немного сермяжной правды:
- Используйте минимум шрифтов, при этом по возможности заранее подыскивайте аналоги в CJK-шрифтах, чтобы стиль текста и дизайна игры был похожим для всех игроков.
- Продумывайте текстурные и аудиогруппы заранее. Вообще, продумывайте архитектуру проекта (систему сохранений, контроллер). Это сэкономит много времени при создании уровней. Учитывайте ограничения выбранного движка и свои навыки ещё на этапе планирования.
- Создавать игры с поддержкой геймпада выгоднее.
- Не создавайте «hard-сoded» текст. Используйте .csv-таблицы. Если не знаете, как это сделать, обязательно научитесь.
- Сохраняйте лицензии на все используемые звуки и музыку. Делайте это сразу, чтобы потом не терять время на поиск источников.
- Не используйте внутри игры видео. Кодеки — это отдельная головная боль, которая вряд ли стоит результата.
- По возможности используйте меньше шейдеров. Особенно если вы не пишете их сами, а покупаете или находите и внедряете. Нет гарантии, что шейдер на одной платформе будет работать так же хорошо, как на другой. Keep it simple.
- Чаще рассказывайте о своей игре. Общайтесь с аудиторией, делитесь процессом и идеями.
- Я бы советовал держать код для API-разных магазинов в пределах одного участка кода. Ну, к примеру, ачивки я делаю так:
В апреле вышла бесплатная демка Bonereader, в которую я приглашаю вас сыграть и поделиться со мной своими мыслями! Мы находимся на финишной прямой. Мне осталось дописать финальные тексты, перевести их на японский и два вида китайского, вставить звуки в концовки, которых в игре будет несколько, к слову. А Даше, моему партнеру и художнице, осталось закончить артбук и несколько больших и не очень артов.
И спасибо за внимание! :)