Особенности прототипирования игр

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!


Думаю, во многих компаниях есть свои R&D-команды, которые ищут новые продукты. Такую решили организовать и в нашей студии, и меня туда пригласили. Конечно же, поначалу мы все были окрылены идеей, что сейчас мы в команде экспериментальных проектов и будем писать ПРОТОТИПЫ. Звучит-то как! Мы будем экспериментировать с новыми библиотеками, так сказать «щупать» новые технологии и вообще делать что-то новое почти каждый месяц! Значит, нам не только не надоест какой-то проект, но и можно не заботиться о долгосрочной поддержке кода. Ведь это начальство разрешает забить на качество написания кода в угоду скорости разработки, ведь всё потом полетит в мусорку и будет переписываться с нуля. Но так ли всё радужно? 

Меня зовут Андрей, я программист в студии IT Territory/My.Games, работаю в команде экспериментальных проектов. И хочу рассказать вам об особенностях нашего прототипирования игр. 

Делай просто, но элегантно


Разработка прототипов немного отличается от обычной разработки. В этой сфере необходимость быстрой модификации намного важнее, чем качество кода, потому что мы должны как можно скорее проверить различные игровые гипотезы. При этом нужно помнить, что нельзя быть в чём-то абсолютно уверенным. Если при разработке прототипа мы принимаем какое-то решение, то на следующей неделе оно уже может поменяться. 

До того, как меня позвали в команду, у меня уже был опыт создания прототипов. Но он касался, в основном, разработки проектов на различных GameJam’ах. Если кто-то не в курсе, то GameJam — это хакатон, но про разработку игр. Происходит это так: тебе описывают какую-то идею, дают двое суток, ты ночами не спишь, работаешь вместе с командой, и когда программируешь, то совершенно не думаешь о качестве кода. Главное — успеть сделать то, что можно показать жюри. А в IT Territory у нас иная задача: не просто сделать какой-то один прототип, в который поиграли и забыли (или начали готовить к Soft-launch), а поставить разработку прототипов на поток, чтобы можно было проверять различные гипотезы наших гейм-дизайнеров без особых затрат на создание полноценных проектов. 

В общих чертах зависимость качества кода от времени разработки можно представить так:

Наша задача — попасть в середину графика. У команды есть два месяца на разработку прототипа, значит, мы можем немного времени выделить на то, чтобы подумать о качестве кода и удобстве разработки всего проекта. Более того, при создании прототипа необходимо пережить несколько итераций, чтобы посмотреть на проект с разных сторон, попробовать разные игровые механики, которые, возможно, лучше подойдут. Так что тут на костылях и велосипедах далеко не уедешь, придётся хоть немного, но задумываться о качестве кода для возможности его модификации и расширения.

Но увы, это идеалистическое представление. Реальность совершенно иная:


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

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

Так было на нашем первом прототипе, и это могло бы стать тенденцией в последующих проектах, но мы сделали выводы из проблем, с которыми столкнулись. И этими выводами я хотел бы с вами поделиться.

Не доверяй никому


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


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

В какой-то момент мы поняли, что нам необходимо вращать камеру. Но тогда придётся постоянно перерисовывать спрайты под разные углы, и вообще имелось несколько других нюансов, связанных с распределением нагрузки по участником команды. В итоге проект перешёл в 3D и постепенно стал таким:


Всё может полететь в мусорку 


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

Делай универсальные компоненты


У нас в больших проектах гейм-дизайнеры заранее продумывают, что им нужно настраивать. Они вместе с программистами долго думают над тем, как создать внутренний редактор, на основе которого можно будет собирать различные игровые сущности. Программист просто отдает гейм-дизайнеру код, а тот собирает из него важный объект, который программист порой не предусматривал. Но с прототипами так не получится. Сложно взять и сходу придумать отдельные части некой сущности, из которых всё будет собираться. И всё же нужно пытаться выделять какие-то атомарные элементы. Например, можно выделить сущность логики поведения, чтобы гейм-дизайнеры или аниматоры могли просто накинуть этот компонент. 

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


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


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

Важный момент — заимствование универсальных компонентов из других проектов. Мы перетягиваем из предыдущих игр много других сущностей. Даже создали отдельный проект, в который перемещаем все наработки, чтобы использовать их в будущих прототипах.

Дифференцируй всю разработку в целом


Это касается не только разделения на отдельные компоненты в коде, но и работы с отдельными префабами. В прототипе очень мало пространства для манёвра, поэтому пока проект ещё не разросся, два человека могут обрабатывать одну сущность, что потом приведёт к конфликту при коммитах. Мы столкнулись с этим в первую же неделю работы над прототипами, так как то и дело случайно затирали правки друг друга. Решили, что нужно как можно чаще использовать prefab variant/nested prefab, то есть максимально отдалять отдельные элементы. 


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

Думай о дизайнерах


Гейм-дизайнеры придумывают какие-то механики, которые им нужно настраивать. Для этого в больших проектах с длинным жизненным циклом можно даже написать качественный редактор. Например, при работе над одним из наших боевых (Hawk: Freedom Squadron) мы потратили где-то неделю на создание редактора самолетов. В нём достаточно было ввести имя и требуемые параметры, нажать «ок», и редактор за пару минут собирал крутой самолёт, на сборку которого вручную у дизайнера мог уйти день, а то и два. 

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


С первого раза тут очень сложно понять, что за чем идёт и как это настраивать. Всё вперемешку, глаза разбегаются, трудно найти какие-то группы элементов, которые дизайнер будет настраивать в первую очередь. В итоге приходилось тратить достаточно много времени на настройку всего этого добра. А в качестве положительного примера приведу другой наш прототип, в котором геймплей был сильно связан с работой искусственного интеллекта. Дизайнеру необходимо было иметь возможность настраивать достаточно сложные логические цепочки в поведении юнитов.


Здесь мы учли прошлые ошибки и старались максимально упростить настройки механик, разделяя их на логические группы. То есть сделали набор конечных операций, вроде «прийти к точке», «прицелиться в противника», «выстрелить» и т.п. Эти действия помещали в отдельные группы, а какое действие нужно совершить, определяли через веса переменных, которые юнит считывал из окружающего мира. Конкретные группы выбирались точно так же, как и операции, в соответствии с переменными окружающего мира. Так дизайнер мог выделить отдельные группы действий вроде бега или стрельбы, а уже в самих группах определить их конкретные реализации. Например, бежать от укрытия к укрытию или же идти на пролом к врагу.

Расширяй багаж знаний


Это необходимо не только для быстрого написания прототипов, а в целом полезная привычка по жизни. Но при прототипировании она играет одну из решающих ролей. Если знаний не хватает, то нужно стараться изучать всё, что только можно, даже в свободное время, чтобы когда тебе поставят нестандартную задачу, ты знал, как её решить. 

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


О важности такого подхода мы вспомнили на одном из первых прототипов. Он представлял из себя шутер с видом сверху, в котором персонаж путешествовал по миру, а карта состояла из отдельных тайлов. По-хорошему, нужно было взять тайловую систему Unity или любой другой движок из asset store, но у нас с ними ранее никто не работал. Сейчас мы понимаем, что стоило выделить время и предварительно изучить доступные варианты, поскольку у такого подхода очень широкие возможности, которые позволили бы собирать уровни быстрее. Но на тот момент мы решили не рисковать и в конечной реализации прототипа просто использовали отдельный набор игровых объектов, на которые накинуты компоненты sprite renderer, а они отрисовывали квадратные спрайты. Мы взяли неопытного дизайнера-стажёра, из-за чего скорость сборки уровня была очень низкая, при этом во время сборки эти объекты даже не вытаскивались в отдельные префабы. И когда по результатам игровых тестов нам сказали, что тайлы карты выглядят «не очень», для их изменения нам пришлось «вручную» менять каждый спрайт, вместо того, чтобы просто подсунуть карте новую тайловую палитру. 

Поддерживай баланс кода


В разработке очень часто появляется возможность немножечко «наговнокодить» и забить в угоду скорости работы. Особенно в «незначительных» мелочах. Но эти мелочи потом могут отстрелить тебе ногу. Даже если есть возможность писать плохой код, старайся избегать этого всеми силами, с учётом выделенного времени стремись писать хороший, качественный код. 

Сюда же можно отнести тему с паттернами. Например, может показаться, что какой-то паттерн идеально подходит под ваш прототип. Но внедрив его, начинаешь понимать, что он каким-то образом тебя ограничивает. Поэтому прежде чем применять паттерн нужно продумать, не придётся ли делать дополнительную работу и подстраиваться под него в дальнейшем, потому что скорость — самое главное в разработке игровых прототипов.

Итоги


  • Всё в прототипе может перевернуться с ног на голову.
  • Необходимо иметь возможность быстро включать и выключать отдельную функциональность без вреда для проекта.
  • Максимально унифицируй компоненты.
  • Дифференцируй разработку.
  • Старайся постоянно расширять багаж знаний для работы «на передовой».
  • Поддерживай баланс кода.
Источник: https://habr.com/ru/company/mailru/blog/573298/


Интересные статьи

Интересные статьи

В 2009 году мы заехали в гражданское бомбоубежище при заводе, которое давным-давно сняли с боевого дежурства. Внутри было сухо, почти чисто, стояли окрашенные бронедвери, и терпеливо жд...
Добрый день, сообщество. В этой статье хочу поговорить о Postfix – о том, каковы принципы его работы, и о возможностях диагностики проблем. В силу специфики работы приходится с ни...
Как-то у нас исторически сложилось, что Менеджеры сидят в Битрикс КП, а Разработчики в Jira. Менеджеры привыкли ставить и решать задачи через КП, Разработчики — через Джиру.
Несмотря на то, что “в коробке” с Битриксом уже идут модули как для SOAP (модуль “Веб сервисы” в редакции “Бизнес” и старше), так и для REST (модуль “Rest API” во всех редакциях, начиная с...
Как обновить ядро 1С-Битрикс без единой секунды простоя и с гарантией работоспособности платформы? Если вы не можете закрыть сайт на техобслуживание, и не хотите экстренно разворачивать сайт из бэкапа...