Найти тему
Сделай игру

Игра "Боевые роботы". Первые итоги

Оглавление

Идея написать игру, где роботы, вооружённые различным оружием, будут перемещаться по карте и воевать друг с другом - не нова, однако крайне показательна. Поэтому, я за неё и взялся. И хотя даже приемлемый результат (процесс достижения занял 5 частей: первая, вторая, третья, четвёртая и пятая) ещё потребует значительных усилий, уже сейчас можно констатировать, что движение идёт успешно. О процессе создания игры я и хочу рассказать. Будет много букв и мало картинок.

Наш герой!
Наш герой!

Всё началось с ошибок

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

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

Я хотел свой движок

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

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

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

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

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

Много математики

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

Сперва - вычисления круглой зоны, которая будет строиться с указанным радиусом вокруг заданной точки (персонажа). Прежде всего, это использовалось для определения точек, на которые может пойти робот; потом - для определения радиусов стрельбы и обзора.

Более сложными были алгоритмы построения маршрута (и они, всё ещё, не то, чтобы сильно оптимальны; есть куда двигаться). Для поиска маршрута я использовал алгоритм Дейкстры, который, хотя и не является самым быстрым, является довольно точным. Улучшить его можно было бы, если бы при построении маршрута брать не всю карту (она может быть очень большой и вычисление может занять прилично времени и памяти), а лишь её часть; скажем, не более 2 радиусов обзора, чтобы иметь возможность найти дорогу через явные препятствия.

Самым интересным был алгоритм трассировки лучей, который понадобился для высвечивания видимых зон исходя не из радиусов обзора, а из точки обзора: всё то, что не закрывается высотными объектами карты - видно.

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

Индикация

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

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

Блокирующая модель

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

Стало ясно, что с анимациями всё становится непросто. Методов проб и ошибок было решено, что есть блокирующие анимации (не позволяют ни игроку, ни ИИ управлять роботами), а есть прочие, выполнение которых происходит независимо ни от чего.

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

Событийная модель

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

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

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

Особенно интересными стали "ожидающие события", которые сперва дожидаются выполнения определённых условий, а потом блокируют ввод.

Частным случаем были "всплывающие" циферки поражения, появляющиеся при детонации поверженного врага: их всплытие было визуальным событием, но оно уже не блокировано управление, позволяя игроку или ИИ походить, хотя событие ещё не завершилось.

Изменяемый игровой мир

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

Но учитывая тот факт, что далеко не всё может быть разрушено, можно не беспокоиться за баланс.

Выводы

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