Как делать мелкую игру сто лет

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

К счастью, не убийцу WoW, а мелкую, мобильную ММО. И хоть я сам в мобилки не играю, мобильная платформа мне нравится возможностью купить там инсталлы - т.е. я знаю, что игра хотя бы не выйдет мертворожденной с пустыми серверами. Решил сделать MVP (minimum viable product), выпустить где-нибудь в Тайланде/Беларуси, купить инсталлы и посмотреть как пойдет.

В плане геймдизайна тоже казалось, что есть хорошая идея. Когда-то в школьном возрасте рубился в МУДы в конце девяностых и начале нулевых, и тот геймдизайн старой школы запал мне в душу. Ультима Онлайн, Еверквест 1, Анархия Онлайн, все эти ММО были основаны на мадах, а их системы часто были похожи на адаптацию AD&D, и вообще настолок тех времен. К тому же, сейчас есть такой феномен как OSR (old school renaissance), запрос на ваниллу ВоВ, Линейки, и даже Лольца, да и вообще культурное тяготение к тем временам, например рождение Ретровейва (или Синтвейва). Таким образом, я решил сделать ММОшку старой школы и познакомить зумерское поколение с тем, что они упустили.

Арт я делать не умею, поэтому купил спрайты и тайлсеты, и накидал первый прототип. Авторитативный сервер - на Go, клиент - на Unity. Сервер на Go был логичным решением, т.к. его го-рутины это что-то, почти не имеющее аналогов.

Го-рутины - это как треды в других языках, но в go их можно запускат тысячами, для CPU это почти бесплатно, а в результате мы получаем такое распараллеливание игровой логики, что можно арендовать один 20+ корный сервак и все коры будут загружаться в равной степени.

Такой сервак мог бы выдерживать тысячи игроков без малейших проблем. Выглядело это так:

Геймплей первого прототипа (извиняюсь за музыку)

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

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

Это было то решение, которое я искал все пол года. Игра должна будет стать менюшной, а бой - текстовым. Это позволяло развить мад как жанр, но в ином направлении от 2д и 3д ММО. И это было великолепно.

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

А затем, я совершил две большие ошибки, которые аукаются мне по сей день.

Первая - это то, что я оставил сервер на Go, даже не задумавшись об этом. Хотя геймдизайн я весьма пересмотрел и на сервере должно было играть уже не 2000 человек, а не больше 200 одновременно. Но Go я почему-то оставил.

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

А вторая ошибка - мне очень понравился нативный дизайн и ощущения от нативных менюшек в Pocket Combats, поэтому я отложил Unity подальше и стал изучать нативную разработку под мобилы.

Именно нативную я отбросил почти сразу, потому что я не хотел ограничивать себя Android'ом или iOS'ом, ведь у меня не было опыта продажи игр на этих платформах. Но из почти-нативных были Flutter и React Native, и они были кросс-платформенными.

Помимо этого, еще были и весьма странные решения, вроде разработки на Vue.js. Сама по себе, Vue - это фреймворк для создания сайтов, с использованием HTML + CSS + JS. Однако, оберни проект на Vue в WebView и вот твой сайт уже существует как апп. Естественно, это ударит по производительности, т.к. фактически ты будешь запускать урезанный браузер и в нём открывать свой "сайт".

Из около-нативных, Flutter выглядел самым производительным, плюс он основывается на типизированном языке Dart, который очень похож на более современный C#, в отличии от React Native, где используется JS. А я как раз люблю типизацию и изучать новые языки.

На удивление, Flutter оказался очень сложным в изучении. У меня годы опыта Unreal и Unity, я умею делать фронт на Vue и бэк на Nodejs, да и просто работал с кучей фреймворков на разных языках. Вообще, геймдевы часто являются универсалами и часто знакомы с кучей различных технологий. Но ни одна технология еще не давалась мне так сложно как Flutter.

Плюс я писал фактически игровой движок на Go. Единственное, что отличало его от полноценного движка - отсутствие рендеринга. Но это слихвой компенсировалось необходимостью реплицировать всё происходящее в мире. А фактический рендерер, которым выступал Flutter, вставлял палки в колёса, т.к. являлся крайней неудобным UI-китом. В нем сложная система sizes & constraints, кардинально отличающаяся от интуитивно понятной системы верстки HTML'а. С версткой каждого мелкого виджета можно биться головой об стенку весь день.

В результате выбора технологий, с начала разработки прошло 600+ дней и было написано 24 тысячи строк кода. А MVP у меня нет и по сей день, и до него еще как до внеземных цивилизаций.

Подсчет строк кода в проектах с помощью tokei
Подсчет строк кода в проектах с помощью tokei

Как можно заметить по скрину выше, весь проект - это 5 кодовых проектов. Как так вышло?

Дело в том, что в студиях мне приходилось работать с геймдизайнерами и писателями, и весь их вклад часто сводился практически на нет их невозможностью пушать изменения в репозиторий. Чтобы избежать бесконечные коннекты по тимвьюверу и исправление их неверных действий в Git, я решил написать все редакторы в виде сайтов. Таким образом, дизайнеру достаточно уметь пользоваться браузером.

Редактор предметов/монстров написан на Vue + Nodejs и с ним вообще всё предельно просто. Это обычный сайт:

Редактор мира (на скрине ниже) - с ним немножко посложнее, т.к. тут нужен был редактор с узлами, с возможностью их двигать, соединять/разъединять, и каждому узлу (клетке в мире) присваивать описание, мобов и пр. Было два варианта, 1) писать на JS, либо 2) не запариваться и написать на Unity, сбилдив как WebGL. Так я и поступил. Любые изменения сразу посылаются на сервер на Nodejs.

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

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

После работы в редакторах, я запускаю батник, который просто скачивает весь мир, монстров и предметы в виде JSON. А клиент и сервер умеют их читать.

Редактор мира
Редактор мира

Всего на редакторы ушло пол года. На игру - полтора. Однако из игры у меня почти ничего так и нет.

Есть следующее:

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

А нет следующего:

  • нет системы абилок, спеллов, бафов/дебафов как в бою, так и вне боя
  • нет пати
  • нельзя прыгнуть на помощь другим игрокам и даже смотреть за их боем
  • нет ИИ у мобов, все что они делают, это авто-атаки
  • нет экрана экипировки
  • нет экрана статсов, хотя бы чтоб раскидывать статсы при левл-апе
  • нет магазинов
  • нет аукциона / рынка, где можно оставлять запросы на покупку предметов
  • нет гильдий
  • нет ПВП механик (флаги мести, флаги убийцы как в Линейке, и чтоб стражи в городах нападали)
  • нет квестовой системы
  • нет экрана создания персонажа
  • нет персистенса - сохранения/получения персонажей из ДБ
  • нет игрового контента как такового, только механики

Осталось сделать еще так много, что до MVP как минимум года два, а то и три. А еще три года на разработку, казалось бы, мелкой мобильной ММО, это просто с ума сойти. Хочется орать и выть.

Если бы не моё решение о Flutter и Go, я думаю я мог бы справиться с проектом на чистом Unity и C# сервере за пол года (умножай любые эстимейты на два, значит за год). Но как известно, в разработке нельзя начинать с начала. Выбрав стек, нужно идти с ним до конца.

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

49
30 комментариев