Всем привет! На связи Андрей, Елена и Дмитрий, в этой статье мы расскажем, как нам работалось над дипломным проектом, как выбирали идею и что получилось в итоге. Мы все познакомились на курсе «Мидл-фронтенд разработчик», а в конце обучения нас объединили в команду.

Наш диплом — игра в формате «захват территорий»: чтобы победить, игрокам необходимо уничтожить планеты противников. Можно сразиться против нескольких ботов или отправить их рубиться между собой. Также частью проекта являлись и более привычные задачи: авторизация через OAuth, SSR, создание форума, таблицы лидеров и профиля пользователя.

Знакомство с командой

Андрей Шторк

Пошёл учиться для разнообразия и встряски мозга. Курсы фронтенда проходил за счёт компании, в которой работает по сей день. В разработке уже 5 лет. Интересный факт: всегда работал на Angular’е и понятия не имел, что проект будет на React — сюрприз-сюрприз!

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

Елена Леванова

Высшее образование в IT, всегда работала в этой сфере, но программированием занималась мало. Когда решила работать удалённо, перешла в фронтенд-разработку — занимается ей уже 3 года. Пока была в поиске новой работы, пошла на курсы, чтобы не простаивать и углубить знания. 

Искала (и нашла) идеи для дизайна, реализовала страницы чата, списка победителей, форума — для него полностью написала бэкенд. Написала тесты для небольшой части функционала.

Дмитрий Гасилов

5 лет во фронтенде, но все эти 5 лет в одной компании и на одном проекте. Появилось желание пройти курсы, чтобы освежить теорию и разнообразить опыт.

Продумал и реализовал механики игрового процесса, делал главную страницу с описанием и правилами игры, серверную и клиентскую часть реакций (эмодзи) на форуме.

Как выбирали идею для проекта

Нам предоставлялась полная свобода — никаких критериев и ограничений. Все решения принимали самостоятельно: обсудили несколько возможных вариантов, а потом объединили и доработали. В финал вышли три идеи: Крокодил, какая-нибудь настолка или «захват территорий».

Андрей: Мне не понравилась идея с настолками: кто вообще играет в настолки онлайн?! Вроде они как раз для социализации сейчас используются. Ещё мне не нравились идеи, которые связаны со сложной логикой, но минимальным кодом. Ко всему остальному я был открыт. 

Елена: Я была среди тех, кому перенести настолки в компьютер не казалось скучным. Но мне хотелось чего-то новенького — делать очередную «три в ряд» не интересно. Идея Димы и его запал были очень к месту — все сразу согласились. Зато идея сделать из игры именно «звёздные войны» и космическую тематику была моей! Покидала ребятам в чат картинки для вдохновения.

Много разных картинок из поиска, которыми мы вдохновлялись
Много разных картинок из поиска, которыми мы вдохновлялись

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

Сначала я предложил сделать игру в стиле Vampire Survivors, но положительного отклика эта идея не получила — реализовать её было бы трудно. Позже я предложил игру в стиле «захват территорий», подобную Mushroom Wars. Разработка такой игры уже ощущалась выполнимой задачей, но при этом и достаточно интересной. Эту идею все приняли уже более тепло.

Изначально сеттингом игры предполагались «замки — пешие армии», но к такому сложно подобрать хорошее оформление. В процессе обсуждения визуала приложения и игры Елена скинула прикольные картинки с инопланетянами и предложила космос. Сеттинг «планеты — космические корабли» оказался более удачным и отлично лёг на механики игры.

Как выглядела игра на самом старте:

Как построили командную работу

Преимущественно мы общались в чате и в комментариях к пуллреквестам на GitHub. Были созвоны, инициированные куратором, но в большей мере на них обсуждалось планирование.

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

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

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

В конце проекта снова добавили четвертого участника. Мы назначили ему важную задачу — задеплоить проект для сдачи дипломной работы. Новый участник откладывал всё на завтра, в итоге Андрей заподозрил неладное и задеплоил сам. Получается, весь проект делали всё же втроём.

Елена: Задачи распределялись примерно равномерно по трудозатратам, каждый брал то, что ему по душе. Например, ребятам не хотелось задач, которых и так много на работе, — вёрстка, тесты. А я люблю в профессии именно наличие визуальной части, плюс нужно было на новом месте работы изучить срочно MUI и Styled components, которые мы решили взять и тут.

Роли очень хорошо сразу распределились. Я отвечала за визуал и основной фронтенд, Дима взялся за игру и canvas, а из Андрея вышел отличный тимлид. Он же очень заинтересовался настройкой окружения и обязанностями DevOps-инженера.

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

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

Дмитрий: Преимущественно я занимался игрой. Ранее опыта работы с canvas не имел, рад, что это оказалось весьма увлекательной задачей. Первые несколько дней уделял разработке игры всё свободное время.

По итогу удалось реализовать:

  • алгоритм размещения планет;

  • игровой цикл с изменением состояния игры и постоянной перерисовкой этого на экране;

  • перемещение космических кораблей, логику и расчёты увеличения численности юнитов на планетах и произведение расчётов при нападениях кораблей на планеты;

  • алгоритм бота (4 разные сложности) и возможность запускать игру между ботами без участия игрока.

Когда базовая часть механик была реализована и немного оттестирована, я подключился к прочим задачам. 

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

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

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

Обычно это были любые задачи на инфраструктуру. Например, пока я не подключу базу данных, не накидаю каркас на node и не запушу это все в ветку, остальные ребята не смогут делать свои задачи на бэке. Соответственно, такие задачи нужно выполнять как можно быстрее.

Так же было и с каркасом фронта. Чтобы приступить к разработке фич, сначала нужно создать React-приложение, добавить туда линтеры, TypeScript, тесты и только потом уже начинать основную разработку. Пока это всё делается, остальные либо принимают участие в развёртывании, либо отдыхают и ждут, когда инфра попадет в Git, чтобы приступить к разработке.

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

Меня мотивировали работа в команде и желание довести дело до конца. К тому же курс оплачивала компания, и мне нужно было показать им диплом :) Первое время было тяжело, но последовательные повторения приводят к привычке. Когда уже привык что-то делать, продолжать легко, поэтому после 1–2 месяцев это уже было как попить кофе с утра.

За время учёбы я натренировал свою дисциплину до высшего уровня. Мы закрывали на 100% почти все демо, так что мы молодцы.

Как выглядела игра на первом демо:

Правила и описание игры

Делимся правилами и описанием в том виде, в котором мы презентовали их во время учёбы.

const gameRules = [

'Вы являетесь участником галактического сражения, условием победы является полное уничтожение оппонентов.',

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

'- На старте игры каждому участнику конфликта подконтрольна одна планета, остальные планеты нейтральны, количество юнитов на нейтральных планетах не растёт.',

'- Для захвата новой планеты направьте на неё армию с планеты, подконтрольной вам. Если количество захватчиков превышает количество защитников планеты, то она будет захвачена.',

'- Сразу же после захвата на планете начнинают генерироваться юниты в армию для нового владельца.',

'- Чем больше планет под вашим контролем, тем быстрее пополняется ваша армия, что является ключевой механикой для победы.',

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

'Удачных завоеваний!',

  ]

  const gameSettings = [

'- Перед стартом необходимо определить количество участников, количество планет и выставить ботам сложность.',

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

'- Планеты каждый раз размещаются случайным образом, фиксированы только стартовые позиции (2 оппонента – слева и справа по центру, 3 – треугольник, 4 – квадрат).',

'- У ботов есть 4 сложности, чем выше сложность, тем быстрее боты совершают действия, тем больше действий они могут производить одновременно и тем коварнее они выбирают цели для атаки.',

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

'- Есть возможность ставить паузу – кнопка в правом верхнем углу во время игры, либо клавишей "пробел".',

'- В случае победы определяется кол-во баллов (оценивается, как долго длилась игра, сколько юнитов и планет было подконтрольно игроку на момент завершения игры). Результаты доступны на странице "Таблица лидеров".',

  ]

Теперь, когда вы знаете правила, можете сами понажимать все кнопочки и попробовать сыграть: https://starconquest.netlify.app/ Для статьи игра размещена отдельно от прочей части дипломного проекта. В нём были авторизация через OAuth Яндекса, форум, таблица лидеров и профиль пользователя, которые были зависимы от недоступного сейчас учебного сервиса.

Или посмотрите демо и репозиторий на GitHub’е. Сам дипломный проект находится в другом репозитории, он более полный — заглядывайте на GitHub.

Как мы почти закончили, но что-то пошло не так

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

Для плавного движения кораблей игровой цикл и перерисовка состояния игры были реализованы с помощью метода window.requestAnimationFrame(), при котором количество обновлений соответствует частоте обновления дисплея, обычно это не менее 60 кадров в секунду. Оказалось, элементов на сanvas слишком много, их не получалось перерисовывать с такой частотой.

Очевидными решениями было ограничение количества кадров или игровых элементов, но нашлось другое решение. Все элементы на одном canvas мы разбили на четыре группы и разместили их друг над другом. Теперь они обновлялись по отдельности, и не на всех была потребность в частом обновлении. 

Частота обновления canvas’ов:

  • Полоса соотношения сил оппонентов — 1 кадр в секунду, либо при нападении на планету.

  • Планеты — 1 кадр в секунду, либо при нападении на планету.

  • Корабли — по частоте обновления дисплея.

  • Фон -— 30 кадров в секунду.

Благодаря такому разделению удалось преодолеть лаги и не сокращать задуманные масштабы игры. 

Была ещё одна проблема, но мы пришли к выводу, что это не баг, а фича :) Дело в том, что алгоритм бота не анализирует ситуации, когда на его планеты направляется вражеский флот. Поэтому возможны ситуации, когда игрок нападает на бота, а он направляет свою армию в ответ.

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

Как защищали проект

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

Часть интерфейса с настройками игры
Часть интерфейса с настройками игры

Большое количество идей не были реализованы: сетевой режим, заранее подготовленные уровни, разные виды и типы планет, добавление апгрейдов (как в рамках одной сессии, так и глобальных).

Защищали проект на созвоне в Zoom, участвовали мы и ещё три команды. Все по очереди презентовали проекты друг другу, а затем отвечали на вопросы. По итогу всех презентаций было голосование за приз зрительских симпатий. 

Кому-то проект показался оригинальным и интересным сам по себе, кто-то просто предпочёл нас в сравнении с прочими проектами. В итоге мы победили с приятным отрывом.

Распределение голосов
Распределение голосов

Дмитрий: Презентовать игру предстояло мне. Публичные выступления не особо мне нравятся, так что я почти целый день потратил на репетицию. Несколько раз зрителями пришлось быть Елене и Андрею, а ещё несколько раз — моей девушке. Страх презентовать самый слабый проект, к счастью, не сбылся :) 

Андрей:
Может, я не волновался на защите, потому что не я рассказывал про функционал. Но мне кажется, что я не волновался потому, что мы сделали всё, что было нужно, всё работало, недоработок никаких не было.

Елена: Мы сделали всё необходимое для защиты. Я лично постаралась навести красоту на сайте перед презентацией. Дима — большой молодец, тренировался, мы даже репетицию проводили. Страхов не было, мы не могли не сдать — все демо на 100% почти.

Выводы: чему научились и что советуем

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

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

Андрей: Практикум — среда, где каждый может почувствовать себя своим. Я даже в других командах себя чувствовал своим, так как законнектился с некоторыми ребятами до распределения команд, а потом, в проектных работах, помогал некоторым командам с авторизацией или настройкой server side rendering. Было интересно.

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

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

Если хотите в мидлы, советую изучать не только JS, но и инфраструктуру вокруг него. Разберитесь, как работает сервер, как правильно покрывать код тестами, как всё деплоить. Изучите устройство и принципы фреймворка, на котором пишете, а также сборщики кода (Webpack, Vite). Написать компонент может любой человек, а покрыть его тестами, по одной кнопке автоматически протестировать, собрать и развернуть код — уже не каждый.

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

Если хотите дорасти до мидла — учитесь. Делайте пет-проекты и не забивайте на самообразование, даже если нашли работу.

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

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

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


  1. onets
    17.06.2024 12:19
    +4

    Немного ностальгии по детству