Поскольку это был мой первый опыт в подобном проекте, я извлёк для себя несколько полезных уроков и пару приятных неожиданностей. Ну а также получил игрушку, в которую можно было поиграть с коллегами в предпраздничные пятницы.
Под катом описание, как прошли интенсивные 30 дней разработки и медленные 20 дней ожидания результатов.
Примечание: статья носит повествовательный характер, с небольшим количеством технических деталей.
Пролог
Я давно хотел попробовать себя в качестве разработчика игр, а в последний год это желание становилось всё навязчивее и навязчивее. Под конец года я таки решился начать что-то делать — посещать meetup'ы по игровой разработке, читать книги и даже сделать небольшой прототип игры.
И вот в один день Селим, мой коллега, предложил поучаствовать в одном из многочисленных Game Jam и я подумал, что это наилучшая возможность изучить игровую кухню без каких-либо долговременных обязательств. Это уже не прототип, но ещё не свой долгоиграющий Проект. К тому же жёсткие сроки зачастую одни из самых лучших мотиваторов. А главным плюсом, что на выходе в любом случае получается что-то целостное и завершённое, что всегда воодушевляет на новые свершения.
Так мы и решили принять участие. Два java-разработчика, совершенно без опыта в игроделании. Но когда-то же нужно начинать?
Подготовка
Выбранный Game Jam был тематическим, и тему организаторы должны были объявить строго перед началом разработки. На создание игры конкурсантам давался 1 месяц.
Мы зарегистрировались за неделю до начала и, в связи с отсутствием темы, проводили время в томительном ожидании и бездействии. Возможно, лучше было потратить это время на выбор жанра и игровых механик. А затем обернуть это в подходящую по теме стилистику.
В час X организаторы объявили тему конкурса — Throwback (возвращение назад) и отсчёт пошёл.
У Селима было единственное пожелание к игре — наличие игрового сервера и обязательно real time. Ему было интересно познать прелести и сложности разработки серверной части. Также игра должна была быть простой, иначе мы могли не успеть её завершить.
Касаемо темы, мысли сперва были либо о ретро, либо о доисторических временах. Тема ретро мне не интересна, поэтому я пытался придумать что-то о динозаврах или древних людях. Однако, мне не удалось придумать что-то простое и многопользовательское на эту тему.
И тут мне в голову пришла идея сделать игру-песочницу, при этом в прямом смысле — отсылка к детским развлечениям на пляже. Строим замки, бегаем и кидаемся в соперников песочком (надеюсь не у всех было такое тяжёлое детство), ну а недовольные родители за это наказывают. Все это в 2D с видом сверху.
Селим посчитал, что песком в глаза это слишком жестоко и предложил заменить песок на снег, а замки на ледяные крепости. На этом варианте мы и остановились. По мере сил и времени мы могли добавлять новую функциональность и разнообразие.
Разработка. Неделя 1
Наши роли в проекте разделились сами собой. Как я уже говорил, Селиму была интересна только серверная разработка. А мне было интересно попробовать разработку UI, поскольку, на мой взгляд, она больше всего отличается от разработки бизнес приложений. Интерфейс игры планировался web.
Для работы с вебсокетами на сервере был использован микро-фреймворк Spark. А в качестве физического движка использовался box2d, как один из самых популярных. Он отвечал за расчёт физики на сервере.
Клиент писался на чистом JS, без использования каких-либо фреймворков, поскольку я в них не силён, к тому же в этом мало смысла для небольшого проекта. В качестве игрового движка использовался Phaser 2 — молодой и перспективный JS движок. В отличие от физического движка на сервере, его главным предназначением была графика и простенькие физические расчёты. Также использовался KnockoutJS для data binding.
В качестве IDE использовались продукты от JetBrains: Intellij IDEA и пробная версия WebStorm (как раз 30-дневная версия, на время Game Jam).
Разработка началась с совместной встречи в выходной день. В первые 2 часа, я подобрал «временные» спрайты и реализовал бегающего мальчика, который умел кидаться снежками. Тут могла быть картинка «было/стало», но она лишена всяческого смысла — визуально что было, то и осталось.
Имея работающий UI, оставалось лишь прикрутить серверное взаимодействие. Поэтому весь оставшийся день был посвящён интеграции: обсуждение API, настройка подключения, реализация взаимодействия. К концу дня, наш человечек мог перемещаться на 1 пиксель в сторону, при нажатии на клавишу. Это был скромный, но всё же успех.
Дальше разработка продолжалась только в свободное от работы время, при этом 6 дней в неделю раздельно по домам, и один выходной вместе. Этого было вполне достаточно благодаря простому API и жёсткому распределению ролей.
Чтобы повторить успех первого дня (бегать и кидаться снежками), но уже через сервер, нам потребовалась неделя. На это в равной степени повлияло много технических факторов, в том числе проблемы с инструментами, плохо рассчитанными на нашу клиент-серверную модель взаимодействия. Хотелось бы остановиться на этой модели подробнее.
Модель клиент-серверного взаимодействия
Изначально было решено, что за любое движение будет отвечать сервер, а клиент будет лишь отсылать команды, например нажатие клавиши, и отрисовывать то, что пришло от сервера. Позже эта философия была немного доработана, но сервер до конца оставался центральным звеном.
В первой реализации сервер отсылал обновления на клиент каждый такт. Т.е. например, если зажата клавиша, то позиция игрока изменялась каждый несколько миллисекунд и новая позиция отправлялась на клиент.
С помощью такого нехитрого алгоритма, мы реализовали движение игрока. Но стремление к лучшему побудило нас изменить алгоритм на событийный: на сервер, как и на клиент отправляются только важные события, достаточные для синхронизации.
Например, для движения игрока по карте наверх нужно 4 события:
- Клиент: нажата клавиша вверх;
- Сервер: игрок начал движение из точки [x, y1], под углом ?, со скоростью ?;
- Клиент: отжата клавиша вверх;
- Сервер: игрок закончил движение в точке [x, y2].
У такого подхода есть как плюсы, так и минусы.
Минусы
- гораздо больше логики на клиенте: клиент сам должен просчитывать движение, столкновения и т. п.;
- логика на клиенте должна очень точно повторять логику на сервере, иначе получаются скачки в движении объектов. Далее в статье будут будет несколько примеров на этот счёт;
- в случае сетевых проблем, пoзднее получение событий может привести к некорректным состояниям (выход за границы, прохождение сквозь объекты и т. п.);
- в общем случае гораздо легче получить рассинхронизацию состояния на сервере и клиенте.
Плюсы
- гораздо меньше нагрузка на I/O;
- на события можно навешивать дополнительную логику. Например при начале/окончании движения можно запускать/останавливать анимацию;
- сетевые проблемы меньше влияют на плавность движения. Пока снежок летит, задержка даже в одну секунду ни на что не повлияет, т. к. сервер ничего и не должен присылать;
- API и само взаимодействие становится прозрачнее.
Из этих списков видно, что если хорошо потрудиться над реализацией клиента, то остаются практически одни плюсы. Для нашего проекта нам удалось этого добиться и клиент-серверное взаимодействие работало без нареканий. Но нужно отдать должное, на это ушло довольно много сил и нервов.
Разработка. Недели 2 и 3
Через неделю, когда нам удалось худо-бедно освоить интеграцию и сделать поддержку нескольких типов сообщений между сервером и клиентом, настала пора добавлять в игру нечто большее, чем просто бегающего мальчика.
Поэтому мы решили добавить бегающую девочку! Попутно, для девочки пришлось сделать окно выбора персонажа. А поскольку окно все равно пришлось делать, то грех не добавить ещё и ввод имени. К тому же, пришлось сделать растягивание картинок, по аналогу с 9-patch подходом.
Так выглядел первый вариант окна логина
Из-за всего этого, такая простая и важная задача по добавлению девочки, отняла пару вечеров, но это явно того стоило. А дальше пошли серые будни с однотипными задачами: новые простые функции, исправление ошибок, мелкие визуальные улучшения.
По мере продвижения моего прогресса на клиентской части, всплыла проблема неравномерной скорости разработки сервера и UI. А поскольку сервер является центральной частью любых взаимодействий, то без готового и рабочего функционала на сервере, разработка клиента стопорилась.
Поэтому я реализовал простенький mock сервер прямо в клиенте. Многие вещи в нём были реализованы очень топорно, в т.ч. через использование глобального состояния игрового мира. Этого было достаточно, чтобы разрабатывать UI полностью независимо от сервера и сохранило мне немало времени.
У mock сервера был ещё один несомненный плюс. В нём были боты, которые не умели стрелять, поэтому был шанс хоть у кого-то выиграть.
Селим же в это время боролся с сервером. На сервере он подключил физический движок box2d для симуляции физики в игре. У этого движка много своих нюансов, и их изучение заняло немало времени. Самой большой сложностью при разработке было отсутствие визуализации игрового мира. Наш клиент отрисовывал только то, что было нужно. И некоторые элементы «серверного мира» были скрыты от клиентской части. К тому же не было полных гарантий, что клиент отрисовывает всё правильно.
Одной из важных подзадач, которые пришлось решать Селиму, была проверка столкновений объектов. На клиенте столкновения проверялись только для неподвижных элементов. На сервере же нужно было делать всё по-честному, чтобы не ущемлять права движущихся объектов.
Во время разработки столкновений мне запомнился один забавный баг, который мог претендовать на специальный функционал: когда игрок кидал снежок, его отбрасывало назад «отдачей». Это происходило, поскольку в box2d по-умолчанию каждый может столкнуться с каждым, и при этом всегда происходит отталкивание.
Эта проблема была решена введением масок, т. е. указанием классов объектов, которые не могут сталкиваться друг с другом. Например для игрока и его снежков, маска была сделана одинаковая.
Селим решил не тратить время на специальную обработку столкновений снежков друг с другом и пометил такое столкновение комментарием:
// for the unlikely event that we collide with a sibling snowball
Как показала практика, частота этого «маловероятного» события стремится к частоте кидания снежков, поскольку когда стоишь друг напротив друга, траектории снежков совпадают. Из-за этого чужие снежки постоянно отбиваются собственными. Наше мнение насчёт этого поведения разошлись, поэтому мы оставили как есть.
Пока Селим развлекался со столкновениями, я отлаживал синхронное движение объектов на сервере и клиенте. Были мелкие баги в нашей собственной реализации, но самый большой сюрприз преподнёс Phaser. В его физическом движке реальная скорость объектов подгоняется под FPS и остановки мира. Это делается, чтобы повысить плавность движений. К сожалению, такое умное поведение не согласовалось с синхронной работой относительно сервера и пришлось делать собственную реализацию перемещения объектов.
Сперва я пытался решить проблему неравномерной скорости с помощью настроек движка и физики, которую мы используем. Но, как я понял, это поведение никак не изменить. Можно было переключиться на более сложную реализацию физики, но делать это ради одной лишь скорости не хотелось. К тому же эта реализация тоже не давала абсолютно стабильную скорость.
Следующим шагом я попытался сам реализовать перемещение объектов, но от движка я взял контроль и дельту времени между каждым циклом мира. В Phaser есть несколько моделей времени и на одной из них как раз основана стандартная реализация скорости. Но, по неизвестной причине, не у одного из этих времён нет стабильности и они не могут обеспечить постоянную скорость. Это известная проблема, которая не планируется к исправлению в версии 2: github.com/photonstorm/phaser/issues/798.
На «соревнования» игрока и тени я потратил 2 дня и так и не нашёл рабочего варианта. Поэтому в конце концов я сделал полностью свою обработку скорости, основанную на стандартном времени в JS. Очень удивительно, что такая важная функция получила такую странную поддержку в движке и пришлось реализовывать собственный велосипед.
С такими шутками и прибаутками у нас незаметно прошли вторая и третья недели. При этом каждая неделя начиналась с фразы «ну уж к следующей неделе мы обязаны подготовить играбельную версию» — нам всякий раз казалось, что вот-вот и мы будем готовы. Полное отсутствие опыта и наличие огромного оптимизма — это самый плохой способ оценивать сроки.
За неделю до сдачи, на встрече разработчиков мы даже не смогли показать нормальную версию и пришлось показывать mock сервер.
Разумеется, при такой скорости разработки нечего было и мечтать об изначально задуманном списке функциональности и тем более о nice to have вещах. Поэтому нам пришлось забыть о «песочнице» и остановиться на простейшей 2D стрелялке.
Разработка. Неделя 4, последняя
В последнюю неделю разработки мы сфокусировались на исправлении ошибок. Лучше иметь что-то скромное и рабочее, чем многофункциональное, но разваливающееся. Проблем было много и большая часть из них касалась злополучной интеграции. То тут, то там выскакивали мелкие недоработки, сильно ухудшающие впечатление от игры.
Помимо исправления ошибок, на UI я также наводил окончательный лоск: добавление музыки и звуков, игру со шрифтами и улучшение мелких деталей.
Из всего функционала, в эту неделю была добавлена только система очков, а также ограничение запаса снежков и их восстановление.
В последний день Game Jam нам удалось-таки немного поиграть с коллегами. Несмотря на общие положительные отзывы, эта игровая сессия получилась неудачной из-за критического бага — полёт снежков на сервере и на клиенте происходил с разной скоростью. Из-за этого попадание в других игроков было скорее случайностью.
Надо отметить, что вплоть до этого момента, нам так и не удалось добиться полностью синхронного движения на клиенте и сервере — периодически случались скачки в движении. Изменением FPS мы пробовали увеличить отзывчивость сервера.
Когда я стал исследовать этот баг, я обнаружил 2 закономерности:
- движение игрока работало корректно и стабильно;
- движение снежка на клиенте всегда было быстрее, чем на сервере.
Значение скорости объектов приходит на клиент от сервера, т. е. это не могло быть банальным несовпадением значений. Также обратное увеличение FPS до 1000 улучшало ситуацию.
Я провёл немало времени в попытках исправить эту ошибку. Но ничего не помогало. И в итоге причина нашлась при помощи гугления — box2d косвенно ограничивает максимальную скорость, перемещая объект не более чем на 2 пикселя за один шаг мира. Т.е. при 100 FPS максимальная скорость составляет 200 пикселей/c (п/c), а при 1000 FPS — 2000 п/c. Это значение указано в константе и изменить его динамически нельзя. Это полностью объясняло причину замедления наших снежков, т. к. их скорость должна была быть 700 п/c, что требовало стабильное FPS выше 350.
Для исправления этой проблемы я увеличил FPS до 500, но не просто так. В box2d в функцию шага мира нужно передавать сколько времени прошло с момента предыдущего шага. До моего изменения мы всегда рассчитывали эту разницу перед вызовом функции. Но теперь, зная желаемую частоту, можно было всегда указывать постоянную дельту в 2мс. При сильном отставании времени мира от реального, шаги нужно было повторять друг за другом, пока время мира не нагонит отставание. Затем немного sleep и всё по-новой.
Это исправление, как и ожидалось, решило проблему скорости снежков. К тому же у нас наконец исчезла проблема с несинхронным движением на сервере и клиенте. В то время это чудесное исцеление было для нас полной неожиданностью, но сейчас я понял причину: несмотря на максимальные 1000 FPS, никто не отменял медленной работы сервера и тем более сборок мусора. Т.е. в какие-то моменты времени FPS мог свободно падать ниже необходимых 350 FPS, что и приводило к произвольным скачкам скорости.
Итак, счастливые от закрытого бага и работающей игрушки, за 2 часа до окончания сроков, мы были готовы к сдаче. Оставалось только отправить игру на сайт проекта.
Я ожидал, что выкладывание игры пройдёт гладко, и очень зря. Нужно было создать страницу проекта, сделать описание, накидать скриншотов и многое другое. Уложились мы, как и следовало ожидать, впритык. Хотя позже организаторы все равно индивидуально принимали опаздывающие проекты.
Скриншот с итоговой версией игры
Голосование
По условиям конкурса, сразу после завершения разработки, открывалось 20-дневное голосование. В этот период любой желающий мог посмотреть сданные проекты, коих набралось более 200. Голосовать за проекты разрешалось только участникам. Каждую игру можно было оценить в следующих категориях: общее, графика, звук, gameplay, инновационность и соответствие теме.
Этап голосования приготовил нам нехороший сюрприз, связанный с многопользовательской природой нашей игры. Людей, просматривающих игры, было относительно мало и шанс встретить противника стремился к нулю. Т.е. люди заходили на пустую карту, кидали пару снежков, пробегали несколько метров и разочарованно уходили.
Мы старались организовывать игровые сессии через форум проекта. Также мы с Селимом периодически заходили в игру, в надежде развлечь скучающего одинокого странника. Это всё почти не давало никаких результатов.
Мне было интересно наблюдать за тем, как некоторые люди тестируют игру. Особенно запомнился случай, когда игрок зашёл несколькими персонажами одновременно и построил пентаграмму из мальчиков. Я не знаю, что хотел сказать автор, но у меня сохранился скриншот из процесса её создания.
Другой игрок «взломал» нашу игру. У нас есть проверка длины имени, но только на стороне клиента. Соответственно он обошёл эту защиту и принялся со мной переписываться таким образом, каждый раз заходя новым персонажем, и вписывая свою фразу в имя человечка.
Одновременно с голосованием, мы с коллегами сыграли ещё раз, взяв реванш за неудачную игру в день сдачи проекта. На этот раз все прошло очень гладко и мы получили ряд идей по новым функциям, которые, однако, было уже поздно добавлять.
На мой взгляд, качество игры, особенно по части взаимодействия с сервером, получилось на очень хорошем уровне. Сколько раз мы в неё ни играли, так и не заметили никаких проблем, как и не слышали их от других игроков. Лично для меня это было сюрпризом, учитывая качество и количество ошибок за несколько дней до сдачи.
20 дней, данных на оценку игр, тянулись очень долго, но в конце концов они завершились и пришла долгожданная пора результатов.
Таким образом, мы заняли 36 место из чуть более, чем 200 участников. Что с одной стороны неплохо для первого проекта, но с другой стороны несколько неприятно для самолюбия. Особенно учитывая, что в топ 10 попали неплохие игры, но далеко не все из них заслуживали какого-то особого внимания.
Вынесенные уроки
Ради получения уроков в полу-тепличных условиях это всё и затевалось. Многие вещи мы старались изобретать сами и ограничиваться минимальным набором инструментов, чтобы ощутить проблемы и испытать плохие подходы на собственной шкуре. Зато теперь имея багаж знаний о том, как делать не надо и почему, изучать теорию будет проще.
Необходимость художника. Как показала практика (не только наша) можно сделать неплохую игру, без хорошей графики. Однако подбор нужных картинок, шрифтов и элементов пользовательского интерфейса отнимает большyю часть времени. И самое худшее, что в итоге они не совпадают между собой. От этого теряется тёплая ламповая атмосферность и игра не выглядит целостно.
Игровые тесты это очень важно. Из-за проблем со скоростью разработки, мы не могли протестировать играбельность нашей реализации бoльшую часть времени. Когда же мы смогли нормально поиграть, оставалось слишком мало времени на исправления проблемных мест. И нам очень сильно повезло, что таких проблем обнаружилось не так много.
На мой взгляд, для игр подобные тесты на реальных пользователях гораздо важнее, чем для бизнес-приложений, поскольку помимо удобства и решения проблем пользователя, ещё требуется удерживать определённый уровень эмоций и вовлеченности.
Не все библиотеки одинаково полезны. Почти никто не разрабатывает игры на собственном движке и на рынке есть движки на все случаи жизни. На дворе шёл 2017 год и можно было бы ожидать их высокого качества. Я выбрал Phaser как один из самых рекомендуемых и молодых JS движков. После всех тех проблем, которые у нас с ним были, я боюсь представить как выглядят движки похуже. Нет, в целом впечатления от работы с Phaser скорее положительные, особенно учитывая хорошую документацию и примеры. Но вот работать с ним, не зная большого количества нюансов, очень тяжело. Весной выходит новая версия и я надеюсь на существенные улучшение. А также в моих планах стоит мини-проект на каком-нибудь другом движке, чтобы сравнить.
И ту проблему с максимальной скоростью в box2d я запомню надолго.
В процессе Game Jam вполне можно учиться. Начиная этот проект, мы не знали почти ничего ни о разработке игр, ни о библиотеках, которыми пользовались. И основная часть времени ушла именно на изучение этих вещей. Несмотря на это мы все же успели довести игру до завершённого состояния.
Не обязательного много функционала. Я немного удивлён тому, что многим людям понравилась наша игра. Да, они не сидят в ней каждый вечер, но получают удовольствие от одной-двух небольших сессий. А ведь в нашей игре нет ни оригинальной идеи, ни большого количества функционала, ни какой-либо истории. То же самое можно сказать и о большинстве игр в Game Jam, которые получили положительные оценки.
(Game) Jam это отличный повод попробовать. При этом не важно что: идею, новую библиотеку, свои силы. Когда есть чёткая цель и твой результат должны увидеть другие, это очень мотивирует не раскисать и выкладываться по полной. И даже если результат получится хуже ожидаемого, его будет не жалко выбросить, вынести для себя уроки и двигаться вперёд!
Ссылки на ресурсы:
- selim.co/snowbox — сама игра. Мы не подвеграли её стресс-тестированию, поэтому далеко не уверен, что она выдержит всех желающих посмотреть. Если сервер будет лежать, можете попробовать mock — selim.co/snowbox/#mock
- github.com/wowselim/gameserver — репозиторий серверного кода
- github.com/bugy/snowbox-ui — репозиторий клиента
- itch.io/jam/game-off-2017 — страница Game Jam
- itch.io/jam/game-off-2017/rate/199650 — страница с голосованием игры
- opengameart.org — основной источник игровых ресурсов
- freesound.org — игровые звуки были взяты отсюда
Всем спасибо за уделённое время и хорошего настроения!
Комментарии (35)
MAXInator
26.01.2018 11:23Сколько раз мы в неё ни играли, так и не заметили никаких проблем, как и не слышали их от других игроков.
Странно. Потому что проблема ловится в первую же минуту — персонаж «залип» на подъеме в верхнюю часть экрана. Уперся лицом в забор и отказался менять направление движения.bugy Автор
26.01.2018 11:27Точно, обманул я :( Эта проблема проявляется когда фокус из окна уходит. И Phaser не замечает отжатия клавишы и лишь перебором клавиш 10-20 раз это иногда лечится… Но баг не совсем наш :)
Проявляется он не так часто, поэтому я решил не делать workaround для этого.MAXInator
26.01.2018 12:23А еще положение персонажей почему-то разное для разных игроков. Посмотрите на ровность «стеночки»:
Игрок 1bugy Автор
26.01.2018 12:31И хорошо бы добавить отброс персонажа, в которого попали.
Оно есть, но только на сервере и на клиенте это не показывается.
Именно из-за этого
положение персонажей почему-то разное для разных игроков
Мини-баг, который не влияет на процесс игры :)
Но спасибо за комментарий и наблюдение!
test3d
26.01.2018 12:01Уперся лицом в забор и отказался менять направление движения.
Это не баг, это фича — ловить нубов и набивать на них фраги.
test3d
26.01.2018 11:46Ой, сколько вас набежало то! Предлагаю правила:
1. Перестаньте только в меня кидаться, я первая зашла а теперь в топе снизу.
2. Заходите под своими никами на ГикТаймс
3. Способ разбиться на 2 команды — команда А — ник начинается с «А.», например «A.John», команда B — ник начинается с «B.», например «B.George». В своих не кидаемся! Кто без команды — тот против всех.
VaskivskyiYe
26.01.2018 12:37В Edge вообще не играбельно. Постоянно залипает ход в одну сторону, а у стенки вообще всё залипает. Думал, я туплю, но нет — оказалось ещё не выстрелить. Надо заходить через другой браузер…
lleo_aha
26.01.2018 13:30Как умудряетесь снежки так быстро кидать?))
bugy Автор
26.01.2018 13:34Просто нажимая клавишу часто. Важный момент — запас снежков ограничен (см. правый нижний угол). Потом они постепенно восстанавливаются. Соответственно пока снежки есть, можно хоть все 5 одновременно бросить. А потом бросать только со скоростью восстановления.
(Этот запас многие вообще не замечают, это к вопросу об игровом тестировании)test3d
26.01.2018 20:15Просто нажимая клавишу часто.
Гениально. Ресурс механической кнопки на современных мышках достаточно большой — при обычной работе кнопки на несколько лет всем хватает. Но если в вашей игре выигрышная стратегия — постоянно и непрерывно нажимать клавишу мыши, метая снежки (игрок займётся наведением), то тут явно требуется автоматизация. Есть 2 варианта:
1. Я могу написать автокликер — читерскую утилиту на ваш случай, посажу хук на клик мыши (магия WinAPI), проверю что фокус в окне браузера, нагенерирую кликов — и вуаля, буду строчить как из пулемёта не напрягая пальцы. А из браузера, у вас клиент на JS, античит вы не сделаете. Короче — кому чит на SnowBox за $10 с носа?
2. Как автор игры, вы должны разобраться как играют в вашу игру, какие приёмы применяют игроки, какие стратегии сейчас выигрышные. Игроки уже знают больше вас, вам же некогда играть. Если в геймплее есть занудное действие (например, 100500 кликов мышкой), то его нужно автоматизировать в игре (авто-выстрел что ли). Или иначе — сделайте эту стратегию невыгодной: долгая перезарядка, дорогие «патроны», штраф за промах, в статистике падает оценка меткости, усталость… что то такое.
Мы плавно подошли к вопросу баланса.bugy Автор
26.01.2018 20:29Абсолютно согласен! Это как раз к вопросу об игровых тестах.
И именно эту проблему я хотел исправить в первую очередь, но проект уже был сданtest3d
26.01.2018 22:20Уважаемый bugy, примите себе как правило:
1. Никогда не оправдывайтесь и не извиняйтесь ни перед кем
(передо мной можно)
2. Вы создали свой мир, родили в муках, как полагается — это факт.
А что уж там юзеры начудят — даже я не берусь предсказать. Сегодня, например, было вот так:
robo2k
26.01.2018 13:40А зачем вообще было писать разный код для клиента и сервера? Почему нельзя сначала было написать рабочий код для локальной машины, а после этого добавить синхронизацию состояний с сервером?
bugy Автор
26.01.2018 13:47Не совсем понял ваш вопрос. Отвечу на то, что точно понял:
1. Нельзя было терять ни минуты. Т.е. если бы сперва закончили клиент, а потом принялись бы за сервер, точно не успели его сделать.
2. На клиенте и на сервере разная физика. Например, столкновения движущихся объектов на клиенте не проверяются, потому что клиент не может знать реальное положение объектов в данный момент времениrobo2k
26.01.2018 14:02В смысле можно было использовать вообще полностью одинаковый код для клиента и сервера. Просто еще до кучи добавить синхронизацию.
bugy Автор
26.01.2018 14:18Это трудно достижимо по ряду причин:
1. Разные движки на клиенте и сервере. Которые работают по-разному
2. Логика на клиенте не может быть полностью такой же как на сервере, т.к. состояния на клиенте и сервере всегда разные. А на клиенте присутствует логика, которая не нужна серверу (например прозрачность деревьев)
3. Сервер — java (можно считать это требованием), клиент — JSrobo2k
26.01.2018 14:39Все три пункта идут от того, что вы изначально планировали обратный подход. Но в тех игровых движках, которые я знаю, клиент и сервер используют одинаковый игровой код, а сетевое взаимодействие реализуется так, что клиент отправляет на сервер пользовательские команды, а а сервер на клиент — снапшоты игрового мира.
bugy Автор
26.01.2018 15:01Все три пункта идут от того, что вы изначально планировали обратный подход.
По пунктам 1 и 3 (разные движки и языки) я соглашусь. Можно было бы выбрать другие технологии и тогда можно было бы частично одинаковый код.
Пункт 2 же про более оптимальное и точное поведение. На вышеупомянутых примерах:
1. Прозрачность объектов. Зачем серверу знать об этом и тратить на это вычислительные ресурсы? Более того, в нашем случае сервер даже не знает о том, как выглядят деревья. Для него существует только та часть ствола, которая является препятствием.
2. Столкновения динамических объектов. Какая бы ни была идеальная синхронизация, состояния объектов в двух независимых процессах будут отличаться. Соответственно клиент не может со 100% уверенностью гарантировать (вот кто-то так же думает)
Подобные различия можно было бы вынести и использовать дополнительно к общей логике, здесь я согласен.
Отдельный вопрос по нагрузке на I/O. Слать постоянные снапшоты нам не хотелось. От этого подхода мы отказались почти сразу.
test3d
26.01.2018 15:57bugy, а будет ли статистика по серверу — сколько игроков за сегодня было (размер хабра-эффекта), среднее время в игре, кто откуда (география) — ну и самое главное: кто же всё-таки сегодня победил по очкам?
bugy Автор
26.01.2018 16:24test3d, у вас очень высокие ожидания от нашей игры :) Никакой подобной статистики не ведется. Более того, у нас даже нет никаких логов (настраивая второпях linux service, я не добавил отправку stdout в какой-нибудь файлик).
test3d
26.01.2018 16:39Минимальный вариант «для ленивых» — на страничку selim.co/snowbox прикрутить на входе Google Analytics, или что-то подобное.
mindjammer
26.01.2018 18:28При каких условиях, кстати, твой ник в таблице очков на первом высвечивается крупными буквами? Некоторое время висел в топе, пару раз заметил, что ник вдруг стал огромным :) Скрин снять не успел, от игры невозможно оторваться!
bugy Автор
26.01.2018 18:38Это похоже на ещё один баг. Вроде как при изменении списка игроков, иногда шрифт слетает. Точнее не скажу, т.к. это не так часто проявлялось.
Спасибо за комплимент игре :)mindjammer
26.01.2018 18:47Ох, а я-то подумал, что это поощрение за длительное пребывание на 1-м месте :)
Игра реально затягивает. Очень классно, что при своей простоте в ней при этом есть определённые фишки, позволяющие создать свою стратегию боя и защиты от снежков, а не просто мутозить кнопку мыши :)
Печаль только от лагов, когда заходит много игроков сразу. :(bugy Автор
26.01.2018 18:53Ого, вот за последний комментарий особое спасибо! Т.е. всё-таки игра не выдерживает более 10 игроков сразу. Надо будет её по-стресс-тестировать
test3d
26.01.2018 22:50Игра реально затягивает. Очень классно, что при своей простоте в ней при этом есть определённые фишки, позволяющие создать свою стратегию боя и защиты от снежков, а не просто мутозить кнопку мыши :)
mindjammer, поддерживаю. Мы сегодня компашкой играли — нашли свою стратегию боя и защиты, всех нагнули и вылезли в топ. Простота в игре только внешняя (графика — закос под примитив), на самом деле механика сделана довольно таки правильно. Автор то ли скрывает, то ли сам еще не осознал — фишка игры нынче в сражении между игроками. Задача разработчиков — дать честное поле боя для всех, а уж мы там подерёмся. И даже как бы баги игры стали не баги, а фичи, это тайное знание доступное старпёрам (напомню, игра на ГикТаймс опубликована сегодня, я зашла первая, значит я самая древняя).
Игра реально затягивает.
Что-то в ней есть. Моя задача — убедить авторов не забивать на свой эксперимент, а продолжить свои опыты, не потеряв это «что-то». Они нащупали — играбельность. Это как золото в Калифорнии найти, такое не бросают.
mindjammer
27.01.2018 00:51Однозначно не забивать! Добавить командные бои, с полем побольше, туда же добавить снежных крепостей парочку для каждой из сторон, сделать индивидуальный и командный счёт. Геймплей оставить всё таким же простым, кмк. Всё, это готовая бомба!
ingumsky
26.01.2018 23:46Зашёл посмотреть, что получилось, но, видимо, в неудачный момент – на сервере никого, поэтому удалось только побегать и покидать снежки в пустоту, но мне кажется, что у игры есть перспективы. Развлечься с её помощью можно определённо (но были бы хотя бы боты...) По-моему, для первой игры у вас получилось просто отлично.
test3d
Уважаемый bugy, это перевод статьи или ваша игра?
Автору игры и статьи: box2d тут явно лишний, и он время у вас съел. Хватило бы и формулы пересечения прямоугольников либо окружностей, они просты.
И зайдите кто-нибудь на http://selim.co/snowbox/, мне снежком кинуть не в кого! Я стою в центре, у дерева, по нику узнаете.
bugy Автор
Это наша игра и статья.
Касаемо box2d — возможно это был сильный оверхед, зато без собственных велосипедов в данном плане гораздо приятнее. И опыт использования движков на будущее.
PS зашел на сервер — кто-то там бегает уже :)
test3d
Отличная игра для конкурса и статья.
Как насчёт SnowBox 2.0 и продолжения статьи?
Думаю своих идей у вас хватает, да и пользователи подкинули. Из очевидного:
1. Надо чат, простенький, или возможность сказать что-то (всплывающий бабл со словами) — возможность общения
матомбесценна2. Селим, уберите очевидный способ чита — заходим на сервер дважды с разных вкладок браузера и набиваем фраги на своём же клоне. Не пускать клонов: IP клиента серверу через вебсокеты известен и куки тоже пригодятся.
3. Строим ледяные крепости — надо. Сейчас «крепость» можно построить из множества своих клонов, то есть возможность уже есть, но читерская.
4. Хочется
набигать, грабить корованыиграть за 2 команды (или более), прокачка персонажа и соответственно хранение этого счастья на сервере, разные локации — и т.д. и т.п.bugy Автор
Спасибо большое за фидбек! Касаемо продолжения, очень двоякие мысли. С одной стороны это был проект «попробовать и выкинуть», с другой стороны в процессе создания захотелось сделать что-то более стоящее из этого начинания. Но после того как закончился этот интенсивный месяц, осталось желание не делать абсолютно ничего, т.к. выдохлись. Сейчас уже отошли и посмотрим как жить дальше.
Два из ваших пожеланий для нас новые: чат и командное соревнование.
Остальное планировалось/хотелось, но к сожалению не успелось.
test3d
Да? Тогда я внесу еще несколько ценных предложений в духе времени:
1. Игровая валюта — Snowball. За сноуболы покупаются модные скины, лыжи и эпический скорострельный снегомёт
2. На сайте игры можно купить сноуболы за рубли, доллары и биткойны
3. Премиум аккаунты — удвоенная скорострельность, утроенная скорость прокачки, уникальные шапочка, шарфик и варежки в подарок
4. Выберите краудфандинговую площадку для сбора средств на разработку SnowBox 2.0
5. Прикрутите к игре блокчейн, чтобы точно взлетело
6. Выпустите ICO токены
7. Конвертация сноуболов в деньги для игроков, дайте людям заработать, ваши %-ы
…
100. Мышь и клавиатура — это скучно. Нужен свой, уникальный беспроводной игровой контроллер на Arduino
test3d
В моём прошлом каменте перебор с иронией, я пародирую нынешний гейм-дев, «монетезацию», разные модные тренды и все такое. Не ведитесь.
А теперь о серьёзном, мужайтесь.
В дело вступили 2 профи бета-тестера, мои племянники, возраст 8 и 9 лет. Сейчас всё решает молодое поколение. Мы провели час жесткого теста (нет, мы не уронили сервер, и это хорошо). Перевожу их замечания с их языка на обычный язык, выводы комиссии:
1. Нужен чат, или в любом другом виде возможность общения игроков текстом.
2. Голосовой чат не нужен, для такого геймеры сейчас используют сторонние программы типа Discord, TeamSpeek, RaidCall & etc., а между-собой-друзья используют Скайп, Телеграм и WatsApp. Собственно текстовый чат в игре им нужен чтобы договориться о канале голосового общения (это команда) или чтобы обругать противника.
3. Прокачка персонажа нужна. Многие заходят в игру, играют 2 минуты и выходят — потому что нет роста.
4. Скины. Сейчас у вас их 2 (мальчик и девочка). Короче еще просят — допустим скины дают за прокачку персонажа. Нужно: Снеговик, Снежная Королева, Человек-Паук и ещё разные (я всех не запомнила).
5. Боты, которыми управляет сервер, на случай если никого на сервере нет.