Движок рейкастинга внутри Factorio
Несмотря на ограничения движка, он имеет множество функций. Например, можно менять горизонтальный угол обзора (FOV), вплоть до 360° (разумеется, изображение при таком FOV будет сильно искажённым).
Более того, можно менять направление каждого отдельного луча. Эту функцию можно, например, использовать для добавления слепого пятна в центре экрана:
Можно сделать одну сторону экрана зеркальным отображением другой:
Или превратить экран в своеобразный калейдоскоп:
Движок способен распознавать коллизии: игрок не может проходить сквозь стены. Объекты, которые рендерятся движком, не обязаны быть статичными, они могут поворачиваться, перемещаться и растягиваться. Их можно комбинировать с системой распознавания коллизий. Даже движущиеся объекты, например, куб-компаньон, могут быть твёрдыми.
Игры от первого лица — это в первую очередь шутеры, поэтому автор движка добавил кнопку стрельбы и… многопользовательский режим. На карте уровня присутствуют два игрока, изначально находящихся на разных сторонах симметричной карты. Второй игрок тоже имеет распознавание коллизий и может стрелять.
На карте Factorio движок состоит из нескольких компонентов. Во-первых, это экран, который ArrowGMaximus изготовил на основе архитектуры, придуманной DaveMcW. Разрешение было снижено до 107×80 пикселей минус несколько «битых» пикселей, занятых подстанциями. Это было сделано для снижения лага (маленькое изображение генерировать проще). Каждый пиксель экрана может иметь один из восьми цветов.
Кнопки — это квадраты сундуков запроса. Комбинаторы определяют, когда из них достают предметы, а боты кладут их обратно.
Генерация энергии выполняется ядерными реакторами.
Далее идёт логика, определяющая победителя игры и выполняющая её сброс:
Рядом находится логика, используемая для анимирования куба-компаньона и дверей:
Весь проект состоит примерно из 300 тысяч деталей, если считать только лампы и комбинаторы. Карта настолько велика, что на скриншоте сгенерировался не весь рельеф. Справа видна логика первого игрока, слева — логика второго.
У каждого игрока есть 107 блоков рейкастинга. Благодаря этому все необходимые для кадра лучи можно вычислять параллельно.
Сразу под блоками рейкастинга расположена основная часть логики распознавания коллизий.
Приблизив камеру, можно рассмотреть логику очень важных поворотов. Например, здесь есть схема для выполнения поворотов игрока. Благодаря ей игрок движется в нужном направлении при нажатии кнопки «вперёд». Там же расположена логика, отвечающая за правильную ориентацию модели врага и пуль.
Теперь рассмотрим сам движок рейкастинга. Для начала нужно объяснить, как работает сам рейкастинг. Смысл рейкастинга заключается в испускании лучей из камеры и рендеринге на экране всего того, с чем они столкнутся.
Так как разрешение экрана по горизонтали составляет 107 пикселей, нам нужно 107 лучей. Каждый из них направлен под немного отличающимся углом. Чтобы реализовать это, нам для начала необходимо некое описание мира. Мир состоит из набора прямоугольников.
Каждый из этих прямоугольников можно задать пятью числами. Четыре числа — это координаты x и y его конечных точек, а пятое число обозначает текстуру, которую нужно отображать на прямоугольнике. Далее нам нужно перемещать весь мир таким образом, чтобы игрок оказывался в координате 0, 0. На изображении показана логика, запоминающая позицию игрока, и логика, перемещающую мир, пока игрок не достигнет координаты 0, 0. Справа мы видим генератор тактовой частоты. Он синхронизирует различные части системы, генерируя импульс через каждые 45 тактов игры. Движок тоже генерирует изображение каждые 45 тактов игры.
Затем нам нужно повернуть мир, чтобы луч (или линия видимости) соответствовала оси x. Это сильно упрощает наш мир. Так как ось x соответствует лучу, можно устранить все прямоугольники, не пересекающиеся с лучом. Все прямоугольники, обе конечные точки которых находятся выше или ниже оси x никогда не столкнутся с лучом, то есть они находятся вне лини видимости луча.
На карте Factorio есть логика, поворачивающая мир, и логика, упрощающая мир. Также там есть пятое число, описывающее каждый четырёхугольник.
Для следующего шага нам необходимо найти два свойства прямоугольников. Первое — это расстояние до игрока. Это необходимо для того, чтобы понять, какой из прямоугольников находится ближе всего, а также для того, чтобы определить, какого размера должна рендериться текстура. Чем дальше объекты от игрока, тем они выглядят меньше. Второе свойство — это часть прямоугольника, с которой столкнулся луч. Текстуры обычно шире одного пикселя, поэтому нужно определить, какую часть текстуры нужно отображать. Мы можем вычислить оба эти свойства по точке пересечения прямоугольника с осью x. На бумаге это сделать достаточно легко, но не так просто в Factorio. Вместо непосредственного вычисления точки пересечения мы можем аппроксимировать точку пересечения, а затем повышать точность аппроксимации, пока она не станет достаточно хорошей. В качестве первой аппроксимации используется средняя точка между двумя конечными точками прямоугольника. Чтобы усовершенствовать аппроксимацию, мы повторяем процедуру вычисления средней точки, но заменяем одну из конечных точек предыдущей аппроксимацией. Если предыдущая средняя точка находилась выше оси x, то мы заменяем конечную точку, которая была выше оси x. Если она находилась ниже оси x, то мы заменяем конечную точку ниже оси x. При каждой такой операции мы приближаемся к истинному пересечению. Суммарно мы вычисляем среднюю точку восемь раз. Это может не дать нам точного пересечения, но для игры с таким низким разрешением этого достаточно.
На карте Factorio мы видим логику, находящую пересечение, восемь раз выполняя вычисления средней точки. Также рядом расположена логика поиска ближайшего прямоугольника. Именно этот прямоугольник и нужно рендерить. На этом этап рейкастинга в движке заканчивается. Результаты рейкастинга передаются в блоки текстурирования. Результат состоит из идентификатора текстуры, которую нужно отрисовать, расстояния от прямоугольника до камеры и той части текстуры, которую нужно отрисовать. Но это результаты для одного луча, поэтому передаётся 107 таких результатов. Эта информация передаётся сюда:
Текстуры часто содержат повторения. Для примера возьмём текстуру стены, она многократно повторяется.
Вместо хранения большой текстуры хранится только небольшая её часть, которая повторяется много раз. А если текстура симметрична, её можно отзеркалить, поэтому достаточно хранить только половину текстуры. Также логика фильтрует результаты, чтобы инструкция рендеринга оказывалась только в том текстурном блоке, который содержит соответствующую текстуру.
Теперь поговорим о самих текстурных блоках. Они содержат самое большое количество комбинаторов этой системы. Они такие большие, потому что каждая текстура сохранена в них множество раз (а именно 138), каждая копия с немного отличающимся масштабом. Благодаря этому в Factorio не требуется выполнять масштабирование текстур. Достаточно просто выбрать подходящую. Разные срезы текстуры хранятся один под другим. Разные масштабы — рядом друг с другом. Расстановка всех устройств была бы слишком трудоёмкой задачей, поэтому автор написал скрипт для преобразования изображений непосредственно в чертёж. Каждая группа из восьми комбинаторов содержит один срез текстуры.
Последняя часть системы — место хранения экранов Game over и победы:
Новые версии движка
В версии движка 2.0 автор полностью переделал систему построения изображения. Теперь оно формируется конвейерами, на которые при помощи идеально синхронизированных манипуляторов устанавливаются разноцветные предметы. Благодаря этому удалось увеличить разрешение экрана до 256×144 и количество цветов до 48, а также избавиться от «битых» пикселей. Однако в новой системе смена кадра производится «подъёмом» вверх предметов, составляющих предыдущий кадр. В движке появилась поддержка изогнутых стен, а также была усовершенствована технология масштабирования текстур, благодаря чему появилась возможность прыжков и приседаний.
Новый экран
Внутреннее устройство экрана: конвейеры и манипуляторы
Вся структура движка была переделана и усовершенствована, теперь количество составляющих его устройств уменьшено на 97%
В версии 2.1 ArrowGMaximus добавил пользовательский интерфейс из Doom (который пока не связан с игрой), для чего пришлось увеличить разрешение экрана до 256×187
В интерфейсе есть работающие счётчики здоровья, брони, амуниции и ключей.
Также автор импортировал анимированные модели оружия из Doom.
Для хранения ресурсов ему пришлось увеличить количество элементов движка с 5843 до 8504. В основном это постоянные комбинаторы, хранящие в себе новую графику.
На правах рекламы
VDS для игровых серверов с посуточной оплатой. Защита от DDoS-атак включена в тариф, возможность использовать любые операционные системы, а главное — доступные цены. Попробуйте прямо сейчас!
Подписывайтесь на наш чат в Telegram.