Разработка браузерной онлайн игры на meteor
Здравствуйте, меня зовут Александр Зеленин и я веб-разработчик. Последние полгода занимался разработкой многопользовательской космической браузерной стратегии. На текущий момент мы уже находимся на стадии закрытого бета тестирования (доступного для вложившихся) и запустили компанию на бумстартере.
В этом посте хочу рассказать про процесс разработки игры с нуля силами двух человек.
Оглавление
- Предпосылки
- Выбор платформы и инструментов взаимодействия
- Начало разработки
- Баланс ресурсов
- Военный баланс
- Выгрузка на живые сервера и обновление
- Спустя 5 месяцев
- Техническая часть
- Ответы на вопросы
- Итог
Предпосылки
После нового года я был в поисках интересного проекта. В свободное время я почитывал joyreactor, и наткнулся на интересную игру, которую проводил с аудиторией всего сайта один парень, под ником AlanWake. Игра представляла из себя комикс с вариантами развития, за которые голосовали посетители + свои варианты в комментариях. Победивший вариант получал развитие. После пары выпусков появились «фанатские» версии этой вселенной, и в итоге всё вышло из-под контроля. К седьмому выпуску уже сам автор запутался в том, что происходит, т.к. не было никакого контроля, а фанаты хотели, чтобы дополнительные истории так же учитывались.
В восьмом выпуске «Канал связи закрылся».
За всего пару недель игра собрала больше четырёх тысяч подписчиков. Я написал автору с предложением разработать полноценную игру и посмотреть, что из этого выйдет.
Выбор платформы и инструментов взаимодействия
Перед нами стоял выбор: браузер, мобильное приложение, Steam (или любая другая площадка) игра.
Взвесив все за и против, выбор пал на браузерный вариант: работает на большинстве устройств примерно одинаково, впоследствии игру можно конвертировать в приложение (как мобильное, так и настольное), да и для начала игры требуется минимальное количество действий.
В качестве инструмента взаимодействия друг с другом выбрали realtimeboard — онлайн доску, на которой можно писать текст, размещать картинки, рисовать и всё это удобно связывать друг с другом. Файлы же синхронизировали через папку в дропбоксе.
Игра начала обретать структуру.
Мы довольно быстро определились с требованиями и форматом игры.
Обсудили массу схожих игр, постаравшись выделить самое лучшее, убрав неприятные моменты.
Требования:
- Это PvE игра.
- Игра циклична (цикл примерно год). За это время игроки либо побеждают, либо проигрывают (все)
- Игра должна идти размеренно, что бы было время рисовать комиксы между событиями
- Игра не должна требовать постоянного присутствия и поднятия по будильнику, при этом снабжая контентом тех, кто хочет больше.
- Пожертвования не должны значительно влиять на геймплей, приоритетно декоративные
- Дополнительные аккаунты не дают преимуществ
- Игра должна нравится нам самим
Начало разработки
За пару дней был сделан прототип на node с bootstrap«ом, в котором была возможность зарегистрироваться, строить шахты и радоваться притоку ресурсов. Когда стало ясно, что двигаемся в нужном направлении, я решил, что буду разрабатывать всё на новом для меня meteor (как оказалось впоследствии, не зря), аргументировав это тем, что даже если с игрой будут проблемы, то, как минимум, будут хорошие знания новой технологии.
Развернул рабочее окружение, поставил метеор и начал писать.
Метеор мне сразу понравился:
- Развёртка одной командой
- Множество готовых библиотек, подключаемых легче, чем когда либо (в прочем, на ноду не сильно сложнее)
- Автоматическое обновление страниц, при изменении контента (даже картинок)
- Бьютифаер/углифаер кода, в зависимости от окружения
- Средства для дебага
- Возможность писать в БД из консоли браузера (отключаемое для продакшена)
- Разбиение кода на Клиент, Сервер и Общее.
- «Реактивность». Моментальное отображение изменений в базе у всех клиентов.
Последнее мне сначала не понравилось, т.к. предпочитаю больший контроль, но, как оказалось, я просто не дочитал документацию, и всё замечательно настраивается.
Из минусов могу только отметить его невозможность работы с кольцевыми ссылками. Можно, конечно, сказать, что любую задачу можно решить и без них… да, можно. Но это ровно тоже самое как говорить, что goto всегда плох (для большинства программистов плох, т.к. не умеют использовать, да. Было уже в ряде статей тут.).
Баланс ресурсов
Спустя какое-то время пришло время просчитать баланс. Со «сроком» игры мы определились сразу, так что именно это время бралось за основу. Максимально через год у пользователя уже должно быть «всё». В принципе капа можно достичь и значительно быстрее, но в целом расчёт был на обычных пользователей.
Для расчёта стоимости строений они были выписаны в таблицу, им был указан максимальный уровень указаны стоимости «от балды». Написал простенькую экспоненциальную формулу для расчёта добычи. Были пожелания по начальной и конечной (на последнем уровне) добычи — их брали просто из головы, как «комфортные» цифры.
После того как всё было занесено в таблицу хоть в каком-то виде, начал подбирать коэффициенты для стоимости и добычи, смотря как меняются цены и время строительства (от первого до последнего уровня), подбирая примерно так, чтобы требовали около 4 месяцев вне зависимости от других факторов.
Как только коэффициенты были подобраны, получился ожидаемый график развития. Ещё немного подкрутили цены, формулу и можно внедрять!
Я сразу же постарался заложить возможность варьировать баланс, в зависимости от тестов, т.е. увеличивать/уменьшать количество уровней влияя на «плавность» развития, при этом сохраняя начальные и конечные значения.
У нас есть три основных ресурса (люди, металл, кристалл), и два дополнительных (честь, грязные галактические кредиты). В зависимости от стадии игры ощущается нехватка тех или иных ресурсов (кроме кредитов), но, если грамотно спланировать всё (что удалось некоторым нашим тестерам) можно развиваться практически без простоев.
Военный баланс
Битвы у нас разделяются на два типа: наземные и космические.
В наземных напрямую поучаствовать нельзя — это прямая сюжетная линия. На Землю можно отправлять войска, они присоединяются к объединённой армии всех игроков. Передвижения этой армии контролируются ежедневными опросами всего сервера.
На текущий момент есть по 10 видов юнитов с каждой стороны. У каждого юнита есть параметры атаки, защиты, приоритеты атаки, а также особые характеристики (атакует/не атакует воздушные цели, триггерные способности и т.п.). Для успешных операций необходима хотя бы минимальная координация игроков сервера, чтобы отсылать необходимые для ближайших боёв подкрепления, в зависимости от типа точки и видов противников.
Космические же наоборот, индивидуальны для каждого игрока.
На текущий момент есть по 4 вида кораблей + флагман, а также торговое судно.
Баланс высчитывался схожим образом. Т.е. за основу брали стоимость, и снабжали её характеристиками, добавляя бонусы.
Так же в космосе сделали разделение по миссиям. Можно выбрать тип и уровень миссии, посмотреть примерное количество войск (как в третьих героях) и в бой.
Ах, да. Как решить вопрос со вставанием по будильнику что бы спасти флот? Легко. Сделайте так, чтобы флоту игрока так или иначе был Конец, и, конечно же впишите это в геймплей.
Выгрузка на живые сервера и обновление
После создания файла настроек для Meteor Up выгрузка обновления представляет из себя всего 1 команду:
mup deploy
Всё. Метеор сам загружается на продакшен, обновляет файлы, запускает нужное количество процессов, сам перезапускается, если упал и обновляет всё на клиентах.
Спустя 5 месяцев
В игру уже можно более-менее играть. Здания строятся, ресурсы капают, задания выдаются, флоты летают, армия строится. Пришло время заявить о себе.
Было решено в качестве старта запуститься на бумстартере, т.к. аудитория изначально исключительно русскоговорящая. Пару недель готовили, склепали ролик на коленке и запустились.
Первые два дня это пост о новости для ключевой аудитории — «конверсия» 1 к 5. Т.е. каждый 5 посетивший страницу на бумстартере сделал вклад.
Дальше интересно, но, в принципе, ожидаемо. Публикации на различных новостных ресурсах, в игровых пабликах и т.п. — конверсия близка к нулю. Т.е. основной эффект был от заранее подготовленной аудитории. От остальных — почти нет.
Всплеск через пять дней — выход очередного комикса на реакторе.
На текущий день зарегистрировано 365 пользователей. Онлайн, в среднем, держится в районе 75–150 человек.
Загрузка превышает 5% только в момент обновления. Высокие скачки потребления и времени ответа — обновление игры, равносильно тому что все разом нажали F5 со сбросом кеша. По предварительным подсчетам сервер должен выдерживать до 5 000 человек онлайн без сбоев, при условии, что обновления будут приходится на малый онлайн.
Буквально вчера в результате сбоя процессы падали в течении секунды и вновь поднимались, загрузка выросла до 50%, но при этом на саму игру это не повлияло никак, за исключением пустого списка участников в чате. Т.е. даже в критической ситуации система достаточно стабильна.
Теперь рабочая доска выглядит так, и управлять контентом становится всё сложнее.
Кстати, вот эта большая часть справа — правки и предложения от пользователей. Хотя, вероятно, не корректно сравнивать, т.к. тексты и описания мы не размещали на доске, но всё же.
Техническая часть
В метеоре очень удобно разделение кода: клиентская часть (client), общая часть (lib) и серверная (server). Общая часть доступна в обоих частях проекта равнозначно, что позволяет положить в неё все основные объекты игры, которые требуются и там и там.
CSS
Для стилей я использовать Stylus, потому что он мне очень нравится. Во-первых, у него приятный синтаксис, из которого убрано всё лишнее, а во-вторых он собирается в css на ноде, без каких-либо дополнительных языков. Ну и готовый модуль пересобирает и подгружает на страницу стили прямо на лету. Стили разбиты по релевантным файлам, но самый «жирный» main, из него ещё не всё разнесено — время рефакторинга ещё придет.HTML
Все шаблоны пишутся для шаблонизатора Spacebars, встроенного в метеор. Я не очень люблю logicless шаблонизаторы, и пришлось мириться с рядом моментов. Я считаю что должна быть возможность описывать всё, относящееся исключительно к внешнему виду прямо в шаблонах. Для каждого простейшего сравнения необходимо заводить хелпер. Даже для обычного сравнения:
UI.registerHelper('eq', function (a, b) {
return a === b;
});
Ну что ж, видимо это ограничение из-за реактивности. Но в остальном шаблонизатор хороший. С областями видимости работает замечательно, шаблоны сменять позволяет легко, писать их тоже не трудно.Роутер
Для определения путей приложения использовал iron router. Довольно удобный и добротно сделаный роутер, позволяет навесить определённые действия на переход по ссылке, достаточно гибко позволяет описывать пути, даёт возможность передать нужные данные сразу в шаблон, а не только через хелперы.
Router.route('/logout', function () {
Meteor.logout();
this.redirect('index');
});
Контроллеры
Не совсем корректно. Контроллеров тут, как таковых, нет на фронте. К каждому шаблону можно привязать helpers и events. Хелперы возвращают значения в шаблон, а события отвечают за действия в нём. В качестве композитора страниц выступает, в принципе, роутер.
Хотя, конечно же, никто не мешает разнести логические элементы по разным файлам и удобно сгруппировать.Игровые объекты
Есть класс Item, содержащие совсем базовые данные, которые есть/могут быть у каждого объекта: имя, описание, требования, эффекты. Так же содержит базовые методы, такие как price (), currentLevel (), meetConditions (), has () и т.п.
От него уже наследуются объекты с дополнительным/изменённым поведением: GlobalItem, Building, Unit, EnemyUnit, Hero, Research, GlobalResearch.
Объекты с приставкой Global являются общими на весь сервер, и реализуют соответствующие механики общих вложений в исследование/героя.Система эффектов
Мне крайне нравится система эффектов, которую удалось сделать. Каждый объект может обладать одним, или несколькими эффектами. Эффекты разделаются на 4 типа: влияющие на добычу, влияющие на цену (и время), влияющие на боевые характеристики, а также специальные эффекты, которые уникальны.
Вот пример описания эффекта одного из улучшений:
new Game.Effect.Military({
pretext: '+',
aftertext: '% к броне пехоты',
condition: {
type: 'unit',
group: 'ground',
special: 'infantry'
},
priority: 2,
affect: 'life',
result: function(level) {
level = level || this.currentLevel();
return level * 30;
}
})
Можно описать текст до и после значения, описать объект, к которому применим эффект по ряду критериев (если не указывать ни одного критерия — эффект действует на всё, на что применим). Приоритет — порядок при вычислениях итогового значения: нечетные приоритеты имеют фиксированые значения, четные процентные. Т.е. если у нас есть эффект, который дает +10 брони с приоритетом 1, а потом эффект, который дает 30% с приоритетом 2, и после него ещё один +5 с приоритетом 3, то в итоге получим (базовая броня + 10) * 1.3 + 5.
Если есть несколько эффектов с одинаковым приоритетом — они сперва суммируются, и уже затем применяются. Например, 2 эффекта по 10% дадут множитель (1 + (0.1 + 0.1)).
Специальные эффекты могут влиять на уникальные параметры игры, например, снижая время перезарядки гипердвигателей (встречается всего в 1 месте).
Таким образом мы реализовали гибкую систему взаимодействий строений, улучшений и всего остального.
Можно получить список эффектов, применимых к объекту, и работать с ними как вздумается. Например, вывести из чего составляется приток населения.
Задания
Мы разделили задания на: линейка заданий, тригерное задание, ежедневное задание. Крутейшей особенностью в плане реализации является то, что я могу привязаться абсолютно к любому событию в игре, как-то на выдачу задания так и условия выполнения.
Достигалось это простым способом — задание имеет функцию, возвращающую true/false, выполнено ли задание. Например:
isDone: function() {
return Game.Buildings.has('residential', 'house');
}
Таким образом можно навесить событие хоть на сообщение в чате, хоть на вход в игру после дождичка в четверг.
Ежедневные задания, на текущий момент, представляют из себя просто опрос, с несколькими вариантами ответа, и варианты развязки, частично случайные, частично зависящие от каких-либо действий ранее.
Работа с базой
По умолчанию метеор поставляется с MongoDB. Это очень удобная документо-ориентированная бд. Легко масштабируется, легко писать запросы, легко модифицировать. Хранит все данные в JSON, и, не имея строгой структуры, позволяет добавлять/убирать поля на лету, благодоря чему, по сути, миграции не требуются (за исключением случаев, когда новые поля старых записей надо заполнить значениями).
Для работы с определённой коллекцией я заводил отдельный класс, и всё что требовалось — гнал через него. Например, для списания ресурсов достаточно вызвать Game.Resources.spend (price);
Ответы на вопросы
Почему браузерная? Я думал браузерные игры вымерли.
1) Я знаю возможности браузера лучше чем других платформ
2) Работает на большинстве устройств без дополнительной доработки.
3) Возможность собрать полноценные приложения в будущем без больших трудозатрат
Вам хватит 200 000 рублей что бы сделать игру?
Игра уже на стадии бета тестирования. Этих средств нам хватит что бы выпустить все запланированные компоненты.
Что будет если вы не соберете средства?
Будем искать инвестора.
По сути без рекламы мы собрали неплохую стартовую аудиторию, а это уже что-то да стоит.
Когда полноценный запуск и что там будет?
Запуск планируется в середине октября.
Здания, улучшения, общие улучшения, герои, наземные войска, комические войска, различные виды космических боев, общие (всем сервером) бои на Земле, временные усилители, личная палата с декорациями, которую все могут смотреть, альянсы, босы, куча различных заданий с отсылками к играм, книгам, фильмам и различным событиям. А так же комикс, на развитие которого влияет каждый игрок.
Итог
Пройден большой путь, но на отдых нету времени. Ещё много всего запланировано, много надо успеть к релизу, который ожидается в октябре.
Спец код для тех, кому он нужен: «Habrahabr».
Буду очень рад ответить на любые вопросы касательно разработки и дополнить статью.
Если у вас нет хабра-аккаунта, но есть вопросы:
Почта: zav.work@gmail.com
Skype: Zav_39
Спасибо за внимание.