Зона, с которой игрок чаще всего взаимодействует в карточной игре — это его рука (не путать с рукой в играх с 18+ контентом). Рука — это набор карт, которые игрок может разыграть в текущий ход. И раз это одно из самых важных мест, я решил уже на этапе прототипа сделать руку приятной и красивой.

Дисклеймер: я тут описываю свой говнокод. Программировать я совсем не умею, так что не советую использовать как инструкцию.

Вот как раз во время работы с рукой (не путать с «во время работы рукой») я понял отличие качественной игры от поделки на уровне прототипа для тестирования геймплея. Все дело в мелочах и деталях. Посмотрите, как ведут себя карты в руке в Slay the Spire:

Теперь посмотрите на те же карты на видосе у чела, который пишет в названии ролика, что он сделал Slay the Spire за неделю (9:11):

Теперь у меня это название вызывает горький смех, потому что как раз из-за таких небольших фишек с анимациями запрограммировать всё из Slay the Spire не удастся за неделю, даже при условии, что у тебя будет готов абсолютно весь арт, геймдизайн и другой контент.

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

Как я делал руку с картами

Первую руку я сделал по туториалу, с которого делал первый прототип. В нём за формирование руки отвечал компонент Grid, который расставляет объекты по сетке. Grid лишает вас необходимости писать код, который отвечает за расстановку карт: вы просто задаете настройки и карты сами встают ровно при любом количестве, когда попадают в нужный родительский объект.

Интерфейс компонента: как видите, все отступы, расположение и расстояния можно настроить тут, не нужно писать код
Интерфейс компонента: как видите, все отступы, расположение и расстояния можно настроить тут, не нужно писать код

Проблема с Grid была в том, что делалось это некрасиво: карты телепортировались в сетку, а мне хотелось, чтобы они плавно переходили.

Недолго погуглив, я нашёл в Ассет Сторе бесплатный ассет Smooth Grid. Там были желанные плавные переходы. Если я вытаскивал карту, она потом вставала в конец — ну да и ладно, решил я.

В настройках все то же самое, только еще есть плавность: насколько быстро карты переходят в свое место в сетке
В настройках все то же самое, только еще есть плавность: насколько быстро карты переходят в свое место в сетке

Проблемы со Smooth Grid появились, когда я решил сделать руку похожей на руку в реальной жизни и в других карточных играх — чтобы карты слегка наезжали друг на друга — и после этого стал думать, как мне сделать выделение карты по наведению курсора. Сначала карты просто не хотели выезжать. Когда я разобрался с выездом, понял, что карта не хочет выходить на передний план. Всплыла проблема с тем, что эта плавная сетка перемещала карты влево или вправо в зависимости от положения объекта с картой в инспекторе. А значит, если я буду выводить карту на передний план с помощью перемещения в инспекторе, карта будет перескакивать со своей позиции в самую крайнюю в руке. Такое мне точно не подходило.

Я понял, что в 2D в Unity не было способов перетащить объект на задний и передний план кроме свойства Sorting Layer. Вот только применить его можно только к объектам с компонентом Sprite Renderer. Он отвечает, например, за то, чтобы у карточки выводилась нужная картинка. А у меня все объекты имели компонент Image — я выводил изображение карточки с помощью него.

Так вот, чтобы выводить карточку на передний план, мне нужно было менять компонент Image на компонент Sprite. И это привело к своим сюрпризам. Оказывается, все объекты внутри Canvas с компонентом Image будут перекрывать любой другой объект. И когда я создаю объект Background, который задумывал как фон, он перекрывает спрайты карточек, и поверх фона ничего не видно. И это довольно логично: любой объект внутри Canvas Unity распознает как часть интерфейса: а интерфейс как бы должен быть поверх всего остального в игре. Но…на осознание этих правил у меня ушло много времени. А еще много времени на то, чтобы разобраться, как выставить настройки у спрайтов, поправить поехавшую камеру и сделать кучу мелких действий.

Следующее открытие: Event Trigger, компонент, с помощью которого я делал выведение карточек на передний план при наведении мыши и разыгрывании карточек, не хотел работать со спрайтами. Один и тот же скрипт у меня работал на объекте с Image и переставал работать на объекте со Sprite Renderer. Оказалось, есть еще один способ регистрировать наведение мышки: с помощью методов MouseEnter, MouseExit и MouseOver.

Дальше меня ждали новые проблемы. Я использовал метод Lerp, чтобы карточки красиво залетали в руку и красиво выдвигались, когда наводишь на них курсор. Все отлично работало ровно до тех пор, пока я не совмещал анимации карточек с их добавлением в Smooth Grid. Тогда начиналась котовасия.

Дело в том, что Smooth Grid тоже построен на Lerp. А Lerp — это такая функция, которая как резиночка тянет объект на родительское место. И вот проблема была в том, что Lerp в сетке и мой Lerp спорили между собой, а карточки в итоге трясло и кидало в разные стороны. Я пытался это решить попеременным отключением Lerp’ов — не сработало. Все начинало ехать еще больше.

В итоге пришлось отказаться от компонента Grid совсем: и от Smooth, и от обычного. Я сам сделал простенький вывод на нужную позицию с помощью цикла for, максимально костыльно.

Смотрю и даже стыдно смотреть...
Смотрю и даже стыдно смотреть...

Вот что у меня получилось в итоге

Скорее всего, прокатит для трейлера. Но для реальной игры нужно будет править, чтобы, например, карточки выравнивались по центру и расстояние между ними менялось, когда карточек в ряду становится больше или меньше. А еще наведение курсора не всегда регистрируется, и при желании порядок выдачи и улетания карт в сброс можно сломать.

Что думаю про сишарп

Несмотря на кучу проблем, мне нравится работать с сишарпом. Но по сравнению со всякими JS и Python синтаксис у него выглядит более избыточным:

Не напоминает ли это вам этот момент из «Кролика ДжоДжо» (0:18):

Хотелось бы конечно сделать так же сочно, как в Slay the Spire, но это капец сколько ещё ковыряться. Вообще при разработке стараюсь максимально отсекать всё лишнее. Например, когда я понял сейчас, что надо много всего перепиливать, я отсек вообще всю логику, которая не нужна была для той задачи, которую я поставил себе здесь, в телеге. Этим путём я следую и при разработке части игры для трейлера: максимальный говнокод (даже по моим меркам, а я тот ещё программист), максимум бутафорских штук. Например, у меня карточки тупо вылазят из края экрана, а там они изначально лежат перед запуском экрана.

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

Этот пост входит в цикл постов про игру, которую я потихоньку делаю уже несколько месяцев. Я делюсь всем производственным процессом: какие решения я принимаю в разработке, геймдизайне, интерфейсе, арте и других сферах. В моем телеграм-канале вы можете посмотреть другие посты и узнать, когда ждать следующие: @nigylamchan.

Комментарии (20)


  1. AgentFire
    28.06.2023 21:24
    +1

    Сделать как в Slay the Spire не сложно, если потратить некоторое время на пристальное разглядывание КАК ИМЕННО сделано в этой игре, разбить наблюдаемый функционал на отдельные блоки (декомпозиция), их реализация уже будет сильно проще. Например, поводить мышкой неспеша влево-вправо по руке, отметить, в какие моменты фокус переключается с одной карты на другую. Отметить, насколько именно карта вылезает из руки при фокусе, можно засечь время анимации (запись экрана, подсчёт кадров), можно даже примерно определить easing function, используемую при каждой конкретной анимации.


    1. Nigylam Автор
      28.06.2023 21:24

      Да, вот этим и занимаюсь. Но на первый взгляд кажется, что различных анимаций там очень много


  1. aamonster
    28.06.2023 21:24
    +1

    На вашей анимации поведение карт в Sly the Spire выглядит ужасно (резко выпрыгивающая активная карта, после чего на фоне медленно ползут остальные – раздражает, ведь основное действие уже произошло). Интересно, это и правда так плохо или стало так выглядеть из-за низкого FPS?

    Но вы правы, анимацию надо продумывать и отлаживать. Можно даже вспомнить принципы анимации Диснея.


    1. Nigylam Автор
      28.06.2023 21:24

      Возможно, гифка все испортила, да. Хотя до этого не обращал внимание. Еще может быть, что в самом StS анимации не идеал) Я брал их за референс и детально рассматривал, потому что у остальных казалось, все сделано на порядок хуже


  1. biff_33
    28.06.2023 21:24
    -1

    А мне насрать на анимацию, реалистичность и прочий графоний. Год назад с удовольствием прошёл Inscryption — сюжет, повороты внезапные, уникальный геймплей. Хотя до этого никогда не играл в подобные "карточные" игры.


    А вот и повод перепройти, скормить охотникам кольцевого червя =)


    1. Fen1kz
      28.06.2023 21:24
      +2

      Очень плохой коммент, что StS, что Инскрипшн - образцовые игры с сочнейшим артом и анимацией, хоть сейчас в учебник стиля.

      Специально зашел и проверил - там крышесносная топовая анимация руки, которая просто истекает атмосферой. https://youtu.be/dFQaM6Hu4xs?t=2065

      Так что не надо тут понтоваться, графоний (а конкретно - артстайл) в этих играх - один из лучших в жанре.


      1. Nigylam Автор
        28.06.2023 21:24
        -1

        Вот, плюсую!


        1. Nigylam Автор
          28.06.2023 21:24

          Еще бомбит немного, когда говорят, что эти игры сделаны дешево. Да блин, вы сделайте так же дешево!


    1. Nigylam Автор
      28.06.2023 21:24

      Inscryption - это бриллиант. Тоже играл. И на самом деле если декомпозировать анимации там, то тоже поймете, что сделано все оченькруто. Важно разделять графоний и работу дизайнера в связке с фронтенд-программистом


      1. ildarin
        28.06.2023 21:24

        Фронтенд - это веб, не путайте. Ща бы верстальщик шейдеры писал, ага) Хотя, OpenGL на JS уже есть, ждем лендинги в фулл 3д на канвасе =)


        1. lexxpavlov
          28.06.2023 21:24

          Фронтенд - это не веб, и веб - не фронтенд. Фронтенд - так часть приложения, которую видит пользователь. Бэкенд - то, что пользователь не видит (например, потому что на сервере, но не обязательно). Если на js сделать СУБД и ORM-фреймворк, да запустить в браузере пользователя - это тоже фронтенд?

          Избушка, избушка, повернись ко мне фронтендом, а к лесу бэкендом...


          1. ildarin
            28.06.2023 21:24

            Эх, запахло холиваром) И фуллстеком был, и геймдевом был, и бэкэндом был) Технически, разработчик графики на C++ ближе к бэкэнду, т.к. требуется работа с памятью, оптимизация и миллисекунды, не говоря уже о стеке технологий. В то время как фронтэндер на языке программирования хтмл и цсс)

            Существует хоть одна вакансия на том же hh, где фронтенд - это НЕ веб разработчик? Есть пруфы?)


    1. mrCOTOHA
      28.06.2023 21:24

      Кейси мод, на 250, колодой с яйцами, пройди лучше :p


  1. mrCOTOHA
    28.06.2023 21:24

    Как фанат карточных игр могу еще Griftlands посоветовать.

    А вообще было очень много великолепных проектов, которые умерли вместе с Flash-ом. Часть из них в стим переехала, но большая часть просто закрылись :_(


    1. Nigylam Автор
      28.06.2023 21:24

      Приведете примеры? Я во времена Флеша был слишком молод и играл только в платформеры в основном


      1. mrCOTOHA
        28.06.2023 21:24

        Nightbanes - вампиры, оборотни, гигантские жуки, демоны, ангелы, роботы, волшебные звери, и т.п., в современном сеттинге.

        Карты атакуют "напротив", т.е. если у противника на столе 2 карты, а у тебя 3 - первые две будут атаковать друг друга, а третья будет атаковать противника (как в том же Inscryption, например).

        Несколько уникальных механик:

        • бесконечный стол

        • нет маны, за ход можно положить на стол только одну карту, но активной она становится через N ходов (от 0 до 4, в зависимости от ее "крутости"), т.е. ее атаковать можно, но если она выживет то потом кааааак даст :)

        • большинству антропоморфных юнитов можно дать оружие (тоже карты)

        Несколько лет играл в нее, меня взяли в топовый клан (в которм были, вроде как, онли донатеры), вошел в топ 3 во всех 4-х рейтингах игры (PVP, PVE, еще чего-то, не помню), пёрся от нее во весь рост... Забил на пол годика, пока переезжал в ДС1, из своего N-ска, за это время разработчик успел зайти в стим, видимо облажаться, и закрыть проект :_(

        В стиме до сих пор висит, но не думаю что возродится https://steamcommunity.com/app/338340


        1. Nigylam Автор
          28.06.2023 21:24

          Блин, звучит оч круто, спасибо!


      1. mrCOTOHA
        28.06.2023 21:24

        Ещё была игрушка, название не могу вспомнить. За час гугления найти не смог.

        В средневековом сеттинге, стол 3 ячейки. Из особенностей - были карты юнитов, gear - артефакт, который каждый ход что-нибудь делал - всем по 1 дамага, пойзон юнитов, прямой дамаг опоненту, и т.д., и карты окружения - для обоих игроков, на несколько ходов больше маны, или автоматическое сбрасывание верхней карты из колоды.

        Были ПвП турниры, с разнообразными правилами: из своих карт колода, из рандомных карт. Была очень интересная соло кампания, с разнообразными миссиями, позволяющая нафармить много наборов. Но потом разработчики перестали добавлять новые миссии, стало сложно фармить, когда выходили новые наборы - донатеры тут же их покупали и всех нагибали. А потом и флеш закончился.

        Из хорошего - помню узнал из чатика коммьюнити о группе Imagine Dragons, когда они еще не стали мейнстримом :)


        1. Nigylam Автор
          28.06.2023 21:24

          Вот совмещение PVP-режимов и PVE-кампаний в обоих примерах звучит интересно. Надо посмотреть


  1. ildarin
    28.06.2023 21:24

    В мое время - программисты руками во флеш рисовали спрайты, там же и кодили игрушки за неделю. Всякие технодемки пилили, а особо упоротые (я) - на пыхе рисовали мордочки)

    Недолго погуглив, я нашёл в Ассет Сторе бесплатный ассет Smooth Grid.

    Может теперь - это норма, скачать кучу ассетов, вставить их в проект и игра готово? Общество потребления вышло на новый уровень - потребление инструментов самореализации) Хотя, чья бы корова мычала)

    Вот так выглядит работа с анимацией в игре "здорового разраба" - построеная на системе второго порядка. Т.е. модель реального мира в виртуальном пространстве. Вот такую статью на русском языке - было бы увидеть действительно - круто.

    В свои школьные годы, в одной из первых игр я пилил 2D физику, а потом из этого уже рождалась целая игра (делал Angry Birds до того, как это стало модно ????). Т.е. сделал модель физики, а потом уже на это накрутился геймплей. Примерно так же появилась и Teradown:

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

    А у Вас: "Я хочу сделать плагиат, поэтому скачал в магазине подходящее решение и пытаюсь допилить его лобзиком". Информационно ценности не особо, но все все понимают и тыкают плюсы) Но хабр даже не столько ресурс, сколько соцсеть. Зачастую комментарии интереснее самой статьи.

    Как Вам такой кейс: сделать гибкое готовое решение для анимации карт в руке? Сделать компонент Unity, добавить возможность настраивать тип анимации, скорость, размер карт и т.д.? А потом - загрузить его в магазин. Каким бы под капотом даже ни был "говнокод": "Если это глупо, но работает - значит это не глупо." К тому же - это намного быстрее, чем делать игру, а потрогать и похвастаться можно будет намного раньше.

    И, раз уж я - гуманитарий, то добавлю: успехов Вам в Вашей песне жизни, пусть она принесет много гордости за проделанную работу) Ну и в карму тыкну плюсик, чтобы подбодрить)