Хотелось бы поделиться с вами историей разработки моей игры.
Итак, всё началось около 4 лет назад, когда я решил попробовать свои силы в программировании игр. Собравшись в кучку из трёх человек, мы решили галопом освоить Enreal Engine 3. По своей неопытности, мы бросились делать MMO с крутым графоном. Чтобы там и звуки, и пушки, и лазеры, и открытый мир и т.д. Естественно, всё это не принесло результатов: запал угас, проект почил в бездне игродева.
Однако, страсть к программированию у меня осталась, идеи копились, а полученный опыт подтолкнул к правильному (на тот момент) решению.
Хочешь сделать игру — делай всё сам.
Часть 0. Почему программисту легче сделать PvP игру?
Друг: В этой игре маги фотм! Если бы у тебя была PvP игра, это было бы весело, а так скучно
Я: Ок, я попробую уменьшить магам урон
Друг: Не надо, сейчас я сделаю команду из 4 магов и порву этого медведя…
Прикинув в голове варианты игр, я понял, что мой проект должен быть RPG. Это мой любимый жанр, а создание его игровой механики как торт для любого программиста. Также я решил, что игра должна стать пошаговой, чтобы давать простор для тактики и отлаженной стратегии, а не для безумного закликивания врагов. Сеттингом послужило привычное фэнтези с орками и эльфами. Идея игры заключалась в следующем: отряд героев в составе 4 человек проходят локацию за локацией и крошат группы монстров, иногда даже боссов. Выбор языка пал на C#, т.к. он довольно известный и популярный. Кроме того, в универе нам преподавали C++, и переход на C# прошёл для меня достаточно легко.
И вот, спустя 6 месяцев, у меня уже была игра на C#, в которой можно создать команду и начать качаться. Но что-то внутри подсказывало, что это не интересно и скучно. В ходе анализа проекта я выделил следующие недостатки:
Контент. Пробираться через толпы монстров – это очень в духе RPG. Но монстров требуется немало и у каждого должен быть портрет, ну и хотя бы 1-2 уникальных способности. К тому же, противникам нужно прописать AI, чтобы они правильно распоряжались своими умениями. Ограничиться 5-10 монстрами, значит сделать очень скучную игру. Для большего количества потребуется тонна времени и сил, которые могли бы уйти на качественные, а не на количественные изменения.
Прокачка – неотъемлемый атрибут RPG, но он превращает балансировку классовых способностей в ад. Сделал способность, проверил, на 1-м уровне — бьёт сносно, на 100-м – не достаточно. Подкрутил шаг увеличения урона способности в формуле: на 1-м стало нормально и на 100-м тоже, но теперь на 50-м мало! И по новой! Вот так и сидишь, крутишь часами цифры.
Инвентарь и снаряжение – те же проблемы, что и у прокачки. На 1-м уровне прибавка некоторых характеристик у меня составляла 0,00012%, зато на 100-м шансы критического удара могли составлять 70-80%.
Скукота. Бесконечный забег по локациям и одевание/прокачка группы не меняют сути игрового процесса. На 99-м уровне ты будешь делать то же самое, что и на 1-м, только цифры выше и монстры толще.
Прототип игры на C#
Все эти размышления привели меня к задумке о создании PVP-ориентированной игры. Прикинув в голове, как моя игра выглядела бы в другом формате, я ещё раз пересмотрел предыдущие пункты и вот что получил:
Контент. Если взять противостояние команда на команду, то всё можно свести к созданию большого количества персонажей или их способностей. В новой игре я решил реализовать несколько классов и предоставить им выбор умений, которые можно взять в бой. Таким образом, создание контента сводится к введению только новых способностей, ведь ими пользуются оппоненты с обеих сторон. Кроме того, отпадает необходимость писать AI.
Прокачка. От системы опыта и левелинга я решил отказаться. С одной стороны, это приводит к проблеме того, что игрок не наблюдает результата своих действий и прогресса. С другой, ставит всех игроков в равное положение. Тот, кто только зашёл в игру, будет иметь столько же шансов на победу, что и игрок, который уже провёл там какое-то время.
Инвентарь и снаряжение. Проблема отсутствия прогресса всё же одолевала меня, так что я решил исправить ситуацию, введя в игру снаряжение. Однако представил я всё это в немного необычном виде. В тот момент мне вспомнилась игра Blade&Sword (китайская копия Diablo), где амуниция персонажа не менялась, а в неё лишь вставлялись драгоценные камни, изменяющие характеристики доспехов. Теперь игрок, участвуя в боях получает некую валюту, на которую способен прикупить для своих персонажей новые камешки и улучшить ими характеристики. Рост присутствует, однако он оказывает прямое действие лишь на количественные показатели персонажа, поэтому догнать «крутых папок» в игре не так уж сложно.
Фан. Сразу стоит отметить, что каким бы грамотным не был AI, он всё же и в подмётки не годится иррациональному мышлению игроков, которые бьются друг с другом. Популярность всяческих MOBA и карточных игр держится на ЧСВ, противостоянии живым людям, миллионе ситуаций и уловок, которые способен сгенерировать мозг твоего противника в бою. Большое количество тактических ходов и настроек команды только добавляет реиграбельности и заставляет вас сыграть «ещё одну катку».
PvP-направление игры привело меня в точку невозврата – в WEB. Недолго думая, я стал изучать основы HTML и CSS. Пара простеньких сайтов и мне уже стало понятно, в каком направлении двигаться дальше. После прочтения нескольких страниц в гугле по запросу «Создание браузерной игры», я понял, что нужно покопаться в загадочном Node.js. На тот момент все новые языки и фреймворки казались невероятно сложными, особенно после C#. По большей части выбор технологий за меня сделал Илья Кантор, по урокам которого я осваивал этот новый мир. Таким образом, получилась связка Node.js, Express.js, MongoDB, Socket.io. Оставался открытым лишь вопрос клиентской части. Я лишь немного знал JQuery и представить, как на нём можно будет реализовать свою задумку, я так и не смог. Вся backend часть как бы указывала мне пальчиком в сторону Angular.js, который, сперва, показался мне магией. Магия – это весело, выбор был сделан!
Итак, стек технологий найден, начался процесс работы над игрой.
Часть 1. Шишел-мышел-зашёл-вышел
Я: Я кинул тебе ссылку, нажимаешь на регистрацию и заполняешь свои данные
Друг: Ок, сейчас пробну…
Я: Ну как там?
Друг: Имя не могу придумать…
Я: Да вводи любое
Друг: Всё, зарегался
Я: А что не входишь?
Друг: Пароль забыл…
Каким бы сильным не было желание с наката начать делать экраны создания персонажей и клепать для них характеристики и способности, мне всё равно приходилось разбираться с проблемами маршрутизации, сессий, работы с базой данных. Хотелось создать красивые ссылки в адресной строке, сделать так, чтобы кнопка «назад» в браузере возвращала меня туда, куда нужно мне, а не ей. Если персонаж «Вася» сейчас в игре, что будет, если с другого хоста зайдёт ещё один «Вася»? Нужно будет либо не пустить нового «Васю», либо выкинуть старого. Пришлось остановиться на втором варианте, реализация которого заняла у меня не меньше 2 недель! Потом я постигал дзен WebSockets: кто кому broadcast, кто куда emit, кто в какой room, что есть io, а что socket.
Форма регистрации с валидацией средствами angular.js
Минимальная задача на этом этапе – реализация правильно работающего (хотя бы с виду) процесса регистрации и входа. После этого – попадание в комнату на сервере, где видны другие пользователи. Помню день, когда я показал своему другу результат всех этих трудов. Он зарегистрировался, залогинился и … попал на экран, на котором написано, что он сейчас единственный человек на сервере. Результат 2-х месячной тяжёлой работы.
Часть 2. Heavy-metal
Я: У меня будет игра про ангелов и демонов
Друг: Жаль, если бы были эльфы, я бы тебе такой ЛОР сочинил!
Следующей малой (как на тот момент мне казалось) задачей планировалась реализация процесса создания команды и персонажей.
Когда ты поглощён разработкой своей игры мысли о сеттинге, характеристиках, способностях, расах, классах и механиках взрывают твой мозг.
Многие задумки я записывал в блокнот.
Чаще всего вдохновение накатывало ночью, не давая спать. Количество ролей и рас по 150 раз прокручивалось в голове и обтесывалось в удобоваримый вариант. В итоге я начал делать всё тех же орков и эльфов.
На этапе, когда экран создания персонажа уже был готов, на меня снизошло озарение.
Экран создания персонажа
Как сейчас помню: иду по улице и слушаю песню Judas Priest «Demonizer». В тот момент, когда под конец песни Роб начинает пищать “demonizeeeeeer”, я подумал: «Это же отличное название для класса! Звучит брутально, митольненько, создавая темную атмосферу». Круговорот мыслей привёл меня к идее «металлизации» сеттинга. Как результат, все названия классов, обмундирования и способностей, так или иначе, связались с рок-музыкой. Всё это прекрасно уместилось в обёртку из ангело-демонического противостояния.
Demonizer
Класса Demonizer я так и не ввёл, но зато появились Sentinel, Ripper и Redeemer. Спасибо, Роб!
Стоит отметить, что чем дальше я залезал в дебри angular.js, тем больше влюблялся в него. За время работы с игрой я так и не выявил недостатков, за которые стоило бы поругать этот framework.
Часть 3. Да здравствует тригонометрия!
Я: С помощью треугольника можно будет мага раскачать полностью на силу
Друг: н@й не нужен такой маг
Наконец-то, я подобрался к «сладенькому» – рождению механик и характеристик. Предполагалось, что манипуляции над персонажем заключаются в выборе способностей и клепанию новых камешков для доспехов, однако я решил пойти дальше. Вдохновлённый треугольниками настройки цвета кожи из генератора персонажей в MMO Rift, я решил сделать нечто подобное с базовыми характеристиками каждого персонажа. Представьте, по трём углам треугольника расположены максимально возможные показатели Силы, Ловкости и Интеллекта персонажа. Настоящее (или текущее) значение этих характеристик определяется положением белой точки, которая изначально находится в центре фигуры. Чем ближе к одному из углов эта точка, тем больше текущее значение соответствующего показателя, и наоборот. Например, передвинув её в угол силы, мы получим персонажа с максимально возможным показателем силы, но его ловкость и интеллект будут равны 0.
Вооружившись «википедией», я стал вспоминать школьный курс тригонометрии, чтобы понять, в каком соотношении точка пересечения трёх чевиан будет делить каждую из них. Параллельно с этим я составлял таблицы в Excel, в которых расписывал зависимости характеристик от обмундирования. Финальный результат очень порадовал и меня охватила гордость за реализованную «фичу».
Часть 4. Встречают по одёжке, а провожают one-shot’ом
Друг: в твою игру поиграть-то можно уже? Или ты всё статы крутишь?
Я: Пока не особо, там только один спел и ваншоты
Друг: ну так и в WoW также, но люди-то играют
Инвентарь создавался довольно долго и кропотливо. Например, сложно далась реализация drag’n’drop’а. Кстати, выбор инструмента для этой механики пал на модуль нашего соотечественника. Интереснее другое: до работы над инвентарём о системе крафта у меня не было ни единой мысли. Идея создания рандомных камешков разной ценности сразу перекочевала из головы в код. Мгновенно под неё была переделана и система валюты.
Чем сидеть и по сто раз перелопачивать всё в голове, иногда стоит сразу начать писать код, а аппетит придёт во время еды.
Инвентарь, аммуниция, система крафта, характеристики персонажа
Когда я подобрался к способностям персонажей, у меня сложилась уже довольно чёткая картина, как всё должно выглядеть. Препятствием стало то, что я не знал точно, как будет происходить бой. Первой способностью в игре стал обычный “Strike”, наносящий n урона персонажу противника. На этом создание способностей приостановилось и началось конструирование боевой комнаты (или арены).
К моему удивлению, арена оформилась очень быстро и без серьёзных заминок. И раз уж мы дошли до битвы, то я немного расскажу вам о ней поподробнее. Бой происходит между двумя командами в формате «3х3» на поле 10х10 клеток. Персонажи ходят по очереди согласно специальной шкале (примерно как в «HoMM 5»). В свой ход игрок может совершить несколько действий, на использование которых тратится энергия. Как только одна команда полностью гибнет или сдаётся, бой завершается. В целом получается арена 3х3 из WoW, но только с примесью шахмат.
Первый матч в моей игре выглядел так: две команды набегают друг на друга и способностью “Strike” ваншотят своих противников. Кто промазал – тот и проиграл. Этого было достаточно, чтобы начать реализовывать сложные механики и вернуться к созданию способностей.
Часть 5. Все скилы в пятёрочку
Я: Ну вот и потестили, что скажешь про игру?
Друг: Срочно нерфить Потрошителей и Искупителей, ибо они вообще лютые. Оракула я не понял, он слишком зависит от ситуации. Еретик мало дотает. Танк с Клериком скучные, надо им хил порезать, а дамаг прибавить. Малефика не трогай, он в самый раз. А ещё, снизь КД на всех абилках у Палача.
Я: Это по балансу, а игра-то как?
Друг: Норм
Идея вариативности каждой способности была оформлена в моей голове ещё на очень ранних этапах создания игры. Смысл её в том, чтобы не делать навыки «маленький ожог» и «огромный лавовый метеор», а оставить навык «огненный шар» с 5-ю вариантами использования:
1-й – наносит мало урона, но стоит дёшево и используется каждый ход.
5-й – наоборот, бьёт много, но редко и дорого.
2,3,4й – поиск золотой середины.
Блок редактирования способностей
Кроме того, некоторые навыки кардинальным образом меняют своё поведение в зависимости от варианта, т.е. не просто привязаны к формуле.
Процесс генерации новых способностей я бы назвал самым увлекательным в разработке (хотя в прошлой игре он бесил донельзя). По ходу работы над следующими навыками приходилось добавлять новые механики. Наложение эффектов, заклинания по области, оглушение, невидимость, наскоки, иммунитеты, восстановление маны и другие особенности расширяли функционал и открывали путь к придумыванию новых. На данный момент на каждый из 8 классов персонажей приходится по 8 заклинаний.
Помню тот вечер, когда мы с другом уже по-настоящему рубились в мою игру. Я не мог в это поверить! Совсем недавно я с гордостью показывал ему форму входа в игру, и вот мы уже спорим о том, что Палач слишком скучный, а Потрошитель крут и рвёт всех магов в щепки. В этот момент меня тревожила мысль, что какой-нибудь критичный баг начнёт рушить игру посреди боя. Но игра решительно отказывалась сыпать ошибками в консоль, и первый же тест прошёл «без единого разрыва».
Часть 6. Что это сейчас было?
Я: Смотри, в логе же написано, что я на тебя молчанку кинул
Друг: Там на английском всё, я туда не смотрю…
Следующим этапом работы стала реализация того, что я всё время откладывал в дальний ящик из-за желания поскорее увидеть прототип.
Прежде меня заботил приятный внешний вид игры только на моём мониторе. Пришло время заняться адаптивной вёрсткой. Сфокусировав все свои знания в области css, я добился удовлетворительного вида на всех разрешениях.
Все, кому я показывал игру, требовали локализации на русский язык. На тот момент это мне казалось неприподъёмной задачей. Тщательно изучив вопрос интернационализации, я пришёл к модулю getText и программке PoEdit. С их помощью удалось решить задачу полного перевода игры на русский примерно за неделю.
Главный экран команды Meets the Russian
Встал вопрос звукового оформления игры. Для реализации звукового сопровождения был выбран модуль ngAudio, с которым возникли некоторые трудности. Я запланировал использовать в бою более 50 звуков. Для этого я создал именованный массив звуковых объектов и воспроизводил отдельные элементы. Поначалу всё шло хорошо, но как только бой затягивался, начинались жуткие зависания. Стало очевидно, по ходу игры что-то переполняется. Так я и подошёл к вопросу оптимизации моего творения, перейдя к изучению digest цикла и $$watchers в angular.js.
Работы по оптимизации всего клиента отняли довольно много времени и сил, хотя окупились сполна. Игра забегала гораздо шустрее, а количество $$watchers сократилось примерно на 40%.
После ряда тестов также были выявлены общие недостатки игры. Изначально предполагалось, что у игрока в распоряжении может быть сразу несколько команд (такой менеджер гладиаторов). Однако система оказалась практически бесполезной, т.к. увеличивала количество данных в базе, а создание дополнительной команды не имело смысла. Игра перешла к виду игрок--->команда--->3 персонажа. Поверх этого легла система сжиганий и воскрешений за трату ресурсов. Также решилась проблема наказания за проигрыш или просто за закрытие вкладки браузера во время боя.
Введение такой системы без каких-либо изменений поставило бы игрока в тупик, т.к. он мог остаться без ресурсов с дохлой командой. Поэтому я придумал дополнительный источник заработка. Им стала мини-игра «кинуть кости» — обычная рулетка, которая есть в большинстве социальных игр.
Встроенная мини-игра «Бросить кости»
К этому моменту игра казалась мне уже сформировавшейся для того, чтобы показать её кому-то ещё. Так я завёл свой профиль на Git и перенёс всё туда. Знай бы я раньше, что такое система контроля версий, сэкономил бы немало времени. Помимо этого встал вопрос о «заливании» игры на внешнее хранилище. Выбор пал на PaaS-платформу Heroku, благо у неё есть бесплатный тариф. Тут тоже не обошлось без трудностей, пришлось поближе познакомиться с npm и bower, переменными среды node.js.
До момента показа надо было воплотить остальные смелые идеи, которые аккуратно и методично возникали в тетрадке. Звуковое сопровождение хоть и добавило интерактивности в игру, напрашивалась идея всплывающего над полем боя текста, отражающего урон, исцеление и промахи. Написание директивы и указание направлений «отлёта» текста вылилось в несколько дней кропотливой разработки и отладки. Даже сейчас в этой системе есть небольшие огрехи, над которыми я не стал заморачиваться в пользу других нереализованных возможностей.
Всплывающие цифры урона поверх поля боя
Воплощение перевода, озвучивания и всплывающего текста позволило мне и моему главному критику лучше понимать ситуацию в бою и взаимодействовать с игрой. Эти этапы работы оказались для меня весьма непростыми, хотя и сами задачи подразумевали использование всех приобретённых до этого умений и впитывание новых знаний.
Каждая трудность преодолевалась с всё большим разгоном и нацеленностью на результат.
Часть 7. You are not prepared!
Друг: В твоей игре никто ничего не поймёт, переведи её…
***
Друг: Теперь всё на русском, но всё равно никто ничего не поймёт. Пиши мануал…
***
Друг: Я глянул твой мануал, там ничего не понятно. Сделай лучше видеогайд…
***
Друг: Слушай, ты непонятно чем занимаешься, это никому не нужно! Сделай лучше всем по 9 способностей…
Последнее глобальное нововведение из моей тетради – организация препятствий на поле боя. Удивительным образом я смог их реализовать за 2 дня. Причём преграды мешали не только передвижению, но и применению способностей. Появилась возможность прятаться за колоннами и убивать противников, которые убегали слишком далеко от своего лекаря.
Дальше следовала череда множественных исправлений багов и правок баланса. Казалось, всё уже готово и пора показывать игру массам, чтобы они сами решали, чего не хватает. Но мой перфекционизм меня всё время останавливал. Хотя нет, даже боязнь того, что твоё детище осмеют, раскритикуют, закидают какахами и прочим непотребством.
Чтобы хоть как-то отложить момент открытого теста, я начал придумывать новые задания. Была поставлена цель — написать руководство пользователя к игре. У всех же игр есть руководства. Я даже не догадывался, что это будет настолько трудной задачей! Все нюансы, которые тебе, как создателю, кажутся элементарными, людям приходится разжёвывать и пояснять. В итоге моих 3-х дневных мучений я родил талмуд правил на 40! страниц. 40, Карл!
С чувством выполненного долга я создал группу ВК для того чтобы принять людей, которые заинтересуются моим творением. Кажется, что всё готово и пора начинать. Но как бы ни так! Придут люди, а как я за ними буду следить? Как узнаю, кто какую команду создал? Какие самые популярные способности в игре?
На создание админки и статистики на сервере у меня ушла почти неделя, хотя ничего сверхсложного в этом не было. Я создал удобное визуальное представление всех игроков на сервере, что-то вроде «оружейной» в WoW. Потом сделал разные графики при помощи Chart.js, которые смогут отслеживать популярность классов, способностей, уровней способностей и камешков (кто во что точится). Также была реализована вкладка Ladder (таблица рейтингов), которую можно показывать в конце каждой недели всем игрокам. Далее я быстро прикрутил Google Analytics к angular.js. Мне важно лишь следить за текущим онлайном не из игры.
Админка: графики статистики на сервере
На данный момент я морально готов к тому, чтобы весь мир смог увидеть результат моей кропотливой, но очень интересной работы. С того момента, как мы с другом в первый раз зашли вместе на сервер прошло уже больше года. Надеюсь, мой опыт будет полезен другим начинающим игроделам.