Машина спрайт вид сверху

10 полезных сайтов с 2D ресурсами для игр

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

С развитием HTML5 и мобильных платформ 2D-игры возвращаются в моду. Заниматься такими проектами, будь то браузерные игры, игры на телефон или для ПК, стало легче благодаря таким инструментам, как Unity, и онлайн-ресурсам с игровыми ассетами. Ниже представлен список из 10 лучших сайтов с 2D-ресурсами для игр – как платными, так и бесплатными.

*Сайты перечислены в случайном порядке*

Крупнейший сайт с платными игровыми ассетами. Использовать движок Unity для работы необязательно – чтобы получить доступ к ресурсам на Asset Store, нужно лишь загрузить его бесплатную версию. Скачанные файлы будут сохранены в папку проекта Unity, откуда их можно импортировать в любой игровой 2D движок.

Стоит отметить, что Unity в руках умелого разработчика обладает огромным потенциалом, о чем свидетельствует большое количество успешных 2D игр (чего только стоит популярная Bad Piggies от Rovio). А Unity Asset Store предлагает широчайший выбор 2D ассетов.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

GameDev Market – относительно новый сайт, удобно организованный по категориям контента (как и Super Game Asset, о котором пойдет речь ниже). Здесь вы найдете как 2D, так и 3D ресурсы, включая UI, спрайты персонажей, иконки и окружения. Художники выставляют ассеты на продажу, и ассортимент растет с каждым днем.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Graphicriver – один из самых популярных ресурсов шаблонных изображений. В связи с развитием казуальных мобильных игр, там появилась отдельная категория с 2D ассетами. До размещения на сайте весь контент проходит внутреннюю проверку, а после публикации любой пользователь может оставить свою оценку и отзыв. Итого: это надежный, активно развивающийся сайт под пристальным модерированием Envato.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Scirra – компания-разработчик Construct 2, популярного 2D редактора на HTML5, у которой недавно появился собственный магазин ассетов. Здесь можно найти аудио-, графические ресурсы и даже готовые игровые шаблоны для Construct 2. Впрочем, для работы можно использовать и любой другой 2D редактор.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Если вы создаете RPG или игру с изометрической графикой – этот сайт для вас. Здесь вы найдете самые высококачественные ассеты: красочные иконки для RPG (пожалуй, лучшие из доступных онлайн), 2D спрайты, анимированные спрайты персонажей и огромные изометрические карты. Что немаловажно, большинство представленных ресурсов выполнены в одном стиле.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Исчерпывающий ресурс для разработчиков игр с открытым исходным кодом, Open Game Art можно назвать крупнейшим собранием игровых ассетов со свободной лицензией. Все материалы – от спрайтов до иконок – можно загрузить по лицензиям GNU или Creative Commons. Это отличный сайт для новичков, но многие ассеты отличаются по визуальному стилю, поэтому их придется тщательно отбирать.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Game-icons.net – лучший сайт с бесплатными иконками, которых здесь ни много ни мало 2000. Несмотря на то что все иконки черно-белого цвета, они достаточно универсальные и могут быть использованы для обозначения действий, заклинаний, навыков, предметов и т. п. Приятный бонус – векторный формат.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Источник

Создание псевдотрёхмерной гоночной игры

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

В детстве я редко ходил в залы аркадных автоматов, потому что особо в них не нуждался, ведь дома у меня были потрясающие игры для C64… но есть три аркадные игры, на которые у меня всегда находились деньги — Donkey Kong, Dragons Lair и Outrun…

… и я очень любил Outrun — скорость, холмы, пальмы и музыка, даже на слабой версии для C64.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Поэтому я решил попробовать написать олдскульную псевдотрёхмерную гоночную игру в стиле Outrun, Pitstop или Pole position. Я не планирую собрать полную и завершённую игру, но мне кажется, будет интересно заново изучить механики, при помощи которых эти игры реализовывали свои трюки. Кривые, холмы, спрайты и ощущение скорости…

Итак, вот мой «проект на выходные», который в итоге занял пять или шесть недель по выходным

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

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

Можно также поиграть

О производительности

Производительность этой игры очень сильно зависит от машины/браузера. В современных браузерах она работает хорошо, особенно в тех, где есть GPU-ускорение canvas, но плохой графический драйвер может привести к зависанию. В игре можно менять разрешение рендеринга и расстоянием отрисовки.

О структуре кода

Так получилось, что проект реализован на Javascript (из-за простоты прототипирования), но он не предназначен для демонстрации техник или рекомендованных приёмов Javascript. На самом деле, для простоты понимания Javascript каждого примера встроен непосредственно в HTML-страницу (ужас!); хуже того, в нём используются глобальные переменные и функции.

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

Часть 1. Прямые дороги.

Итак, как же нам приступить к созданию псевдотрёхмерной гоночной игры?

Ну, нам потребуется

Закончили читать статью Лу? Отлично! Мы будем создавать вариацию его техники «Realistic Hills Using 3d-Projected Segments». Мы будем делать это постепенно, на протяжении следующих четырёх частей. Но начнём мы сейчас, с версии v1, и создадим очень простую геометрию прямой дороги, спроецировав её на HTML5-элемент canvas.

Немного тригонометрии

Прежде чем заняться реализацией, давайте воспользуемся основами тригонометрии, чтобы вспомнить, как спроецировать точку в 3D-мире на 2D-экран.

В самом простейшем случае, если не касаться векторов и матриц, для 3D-проецирования используется закон подобных треугольников.

Используем следующие обозначения:

как показано на схеме:

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Можно было также нарисовать похожую схему в виде сверху вместо вида сбоку, и вывести похожее уравнение для вычисления координаты X экрана:

Где w = половина ширины дороги (от камеры до края дороги).

Как видите, для x, и y мы выполняем масштабирование на коэффициент

Системы координат

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

Если подходить более формально, то нам нужно выполнять:

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Примечание: в настоящей 3d-системе между этапами 1 и 2 выполняется этап поворота, но поскольку мы будем имитировать кривые, то поворот нам не нужен.

Проецирование

Формальные уравнения проецирования можно представить следующим образом:

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Примечание: в полнофункциональной 3d-системе нам нужно было бы более формально задать класс Vector и Matrix для выполнения более надёжной 3d-математики, и если мы бы сделали это, то стоило бы просто использовать WebGL (или его аналог)… но в нашем проекте это не требуется. Я хотел придерживаться олдскульной псевдотрёхмерности для создания игры в стиле Outrun.

Ещё немного тригонометрии

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Последним куском головоломки станет способ вычисления d — расстояния от камеры до плоскости проецирования.

Вместо того, чтобы просто прописывать жёстко заданное значение d, более полезно будет вычислять его из нужной вертикальной области обзора. Благодаря этому мы сможем при необходимости «зумить» камеру.

Задавая fov как одну (из множества) переменных, мы сможем настраивать область обзора для тонкой подстройки алгоритма рендеринга.

Структура кода на Javascript

В начале статьи я уже сказал, что код не совсем соответствует рекомендациям по написанию Javascript — это «быстрое и грязное» демо с простыми глобальными переменными и функциями. Однако поскольку я собираюсь создать четыре отдельные версии (прямые, кривые, холмы и спрайты), то буду хранить некоторые многократно используемые методы внутри common.js в рамках следующих модулей:

Как обычно, исходный код находится в окончательной документации.

Простой игровой цикл

Прежде чем что-то рендерить, нам нужен игровой цикл. Если вы читали любую из моих предыдущих статей про игры (pong, breakout, tetris, snakes или boulderdash), то уже видели примеры моего любимого игрового цикла с фиксированным шагом времени.

Я не буду вдаваться глубоко в подробности, и просто повторно использую часть кода из предыдущих игр, чтобы создать игровой цикл с фиксированным шагом времени при помощи requestAnimationFrame.

Принцип заключается в том, что каждый из моих четырёх примеров может вызывать Game.run(. ) and и использовать собственные версии

Повторюсь, это переделка идей из моих предыдущих игр на canvas, поэтому если вам непонятно, как работает игровой цикл, то вернитесь к одной из предыдущих статей.

Изображения и спрайты

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

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Спрайтшит был сгенерирован с помощью небольшого таска Rake и Ruby Gem sprite-factory.

Примечание: фоны созданы мной при помощи Inkscape, а большинство спрайтов — это графика, позаимствованная из старой версии Outrun для Genesis и использованная в качестве обучающих примеров.

Игровые переменные

В дополнение к изображениям фонов и спрайтов нам понадобится несколько игровых переменных, а именно:

Управляем Ferrari

Состоянием игрока управляют следующие переменные:

Не волнуйтесь, он станет намного сложнее, когда в готовой версии мы добавим спрайты и распознавание коллизий.

Геометрия дороги

Каждый из этих сегментов дороги в конце концов будет спроецирован из его мировых координат, чтобы он превратился в 2d-полигон в экранных координатах. Для каждого сегмента мы храним две точки, p1 — это центр наиболее близкого к камере ребра, а p2 — центр самого дальнего от камеры ребра.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

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

Мы храним отдельную rumbleLength потому, что у нас могут быть красивые детализированные кривые и холмы, но в то же время и горизонтальные полосы. Если каждый следующий сегмент будет иметь другой цвет, то это создаст нехороший эффект стробоскопа. Поэтому мы хотим иметь множество мелких сегментов, но сгруппировать их вместе, чтобы образовать отдельные горизонтальные полосы.

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

Рендеринг фона

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

Рендеринг дороги

Затем функция render итеративно проходит по всем сегментам и проецирует p1 и p2 каждого сегмента из мировых координат в экранные, при необходимости обрезая сегмент, а в противном случае выполняя его рендеринг:

Выше мы уже видели вычисления, необходимые для проецирования точки; версия на javascript объединяет преобразование, проецирование и масштабирование в один метод:

Кроме вычисления экранных x и y для каждых точек p1 и p2 мы используем те же вычисления проецирования для вычисления спроецированной ширины (w) сегмента.

Имея экранные координаты x и y точек p1 и p2, а также спроецированную ширину дороги w, мы можем довольно просто вычислить при помощи вспомогательной функции Render.segment все полигоны, необходимые ей для рендеринга травы, дороги, горизонтальных полос и разделительных линий, воспользовавшись общей вспомогательной функцией Render.polygon (см. common.js ).

Рендеринг машины

Наконец, последнее, что требуется методу render — это рендеринг Ferrari:

Вспомогательная функция Render.player использует метод canvas под названием drawImage для рендеринга спрайта, предварительно отмасштабировав его при помощи того же масштабирования проекции, которое использовалось раньше:

Где z в данном случае — это относительное расстояние от машины до камеры, хранящееся в переменной playerZ.

Кроме того, функция немного «трясёт» машину на высоких скоростях, добавляя в уравнение масштабирования немного случайности, зависящей от speed/maxSpeed.

И вот что у нас получилось:

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Заключение

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

Часть 2. Кривые.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

В этой части мы подробнее расскажем, как работают кривые.

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

Нам нужна была только мировая координата z для каждой точки, потому что на прямых дорогах и x, и y были равны нулю.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Если бы мы создавали полнофункциональную 3d-систему, то могли бы реализовать кривые, вычисляя x и z полосы многоугольников, показанных выше. Однако такой тип геометрии будет довольно непросто вычислять, и для этого потребуется добавить в уравнения проецирования этап 3d-поворота…

… если бы мы двинулись этим путём, то лучше было бы использовать WebGL или его аналоги, но этот проект не у нашего проекта другие задачи. Мы просто хотим использовать для имитации кривых олдскульные псевдотрёхмерные трюки.

Поэтому вы наверно удивитесь, узнав, что мы вообще не будем вычислять координаты x сегментов дороги…

Вместо этого мы воспользуемся советом Лу:

«чтобы искривить дорогу, достаточно просто изменить позицию центральной линии формы кривой… начиная с низа экрана, величина сдвига центра дороги влево или вправо постепенно увеличивается».

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

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

То есть теперь, с учётом функции добавления одного сегмента к геометрии…

мы можем создать метод для плавного входа, нахождения и плавного выхода с искривлённой дороги:

… а поверх можно наложить дополнительную геометрию, например, S-образные кривые:

Изменения в методе update()

Единственные изменения, которые необходимо внести в метод update() — это приложение своего рода центробежной силы, когда машина движется по кривой.

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

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

Рендеринг кривых

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Для реализации кривых нам нужно следующее:

Изменим метод render() следующим образом:

Фон с параллаксным скроллингом

Наконец, нам нужно выполнять скроллинг параллаксных слоёв фона, храня смещение для каждого слоя…

… и увеличивая его во время update() в зависимости от величины curve текущего сегмента игрока и его скорости…

… а затем использовать использовать это смещение при выполнении render() слоёв фона.

Заключение

Итак, вот мы и получили фальшивые псевдотрёхмерные кривые:

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Рендеринг кривых выполняется всего в нескольких строках кода, но может быть сложно понять (и описать), что же конкретно здесь происходит. Существует множество способов имитации кривых и очень легко забрести при их реализации в тупик. Ещё проще увлечься посторонней задачей и попробовать сделать всё «правильно»; прежде чем успеете осознать это, вы начнёте создавать полнофункциональную 3d-систему с матрицами, поворотами и настоящей 3d-геометрией… которые, как я сказал, не являются нашей задачей.

При написании этой статьи я был уверен, что в моей реализации кривых определённо есть проблемы. Пытаясь визуализировать алгоритм, я не понимал, зачем мне понадобились два значения накопителей dx и x вместо одного… а если я не могу чего-то полностью объяснить, то где-то что-то пошло не так…

… но время работы над проектом «на выходные» почти истекло, и, честно говоря, кривые кажутся мне вполне красивыми, и в конечном итоге, это самое важное.

Источник

Реализация псевдо-3D в гоночных играх

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Введение

Зачем кому-то захочется создавать дороги в олдскульном стиле сегодня, когда каждый компьютер может на лету отрисовывать графику, состоящую из миллионов полигонов? Разве полигоны — не то же самое, только лучше? На самом деле нет. Полигоны действительно создают меньше искажений, но именно деформации в старых игровых движках дают такое сюрреалистическое, головокружительное чувство скорости, ощущаемое во многих дополигональных играх. Представьте, что область видимости управляется камерой. При движении по кривой в игре, использующей один из таких движков, похоже, что она заглядывает на кривую. Затем, когда дорога становится прямой, вид тоже выпрямляется. При движении в повороте с плохим обзором камера как будто заглядывает за выступ. И поскольку в таких играх не используется традиционный формат трасс с точными пространственными соотношениями, то можно без проблем создавать трассы, на которых игрок будет ездить с захватывающей дух скоростью. При этом не нужно беспокоиться о том, что объекты появляются на трассе быстрее, чем может среагировать игрок, потому что физическую реальность игры можно легко изменять в соответствии со стилем геймплея.

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

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

Насколько хорошо нужно разбираться в математике?

… знаете тригонометрию, то её будет вполне достаточно для понимания всего туториала
… знаете только алгебру и геометрию, то пропустите объяснение «области видимости»
… хотите избежать математических объяснений, то читайте разделы «Простейшая дорога», «Кривые и повороты», «Спрайты и данные» и «Холмы».

Это универсальная техника, и разбираться подробнее можно, просто добавляя соответствующие разделы. Если вы знаете сложную математику, то вам будет интересно, но если вы разбираетесь только в арифметике, до сможете достичь уровня детализации, созданного в таких играх, как Pole Position или в первой OutRun.

Насколько хорошо нужно знать программирование?

Если вы понимаете растровую графику, то это сильно поможет: достаточно знать, что такое строка развёртки (scanline), и что каждая строка состоит из ряда пикселей. Примеры программ написаны на псевдокоде, поэтому знание какого-то конкретного языка не требуется.

Растровые эффекты: небольшое предисловие

Псевдотрёхмерная дорога — это один из случаев более общего класса эффектов, называемых растровыми эффектами. Наиболее известные из растровых эффектов используются в Street Fighter II: при перемещении бойцов влево или вправо поверхность земли изменяется в перспективе. Но это на самом деле не 3D. Графика поверхности хранится как очень широкоугольный снимок. При скроллинге строки экрана, которые находятся «дальше», перемещаются медленнее, чем более близкие. То есть каждая строка на экране перемещается независимо от другой. Ниже показан конечный результат и то, как графика поверхности земли хранится в памяти

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Основы создания дорог

Введение в растровые дороги

Мы привыкли воспринимать 3D-эффекты в рамках полигонов, чьи вершины подвешены в трёхмерном пространстве. Однако старые компьютеры были недостаточно мощными, чтобы справляться с большим количеством трёхмерных вычислений. Поэтому чаще всего в старых играх использовались растровые эффекты. Это особые эффекты, создаваемые построчным изменением переменной. Это хорошо подходит для работы старого графического оборудования, имевшего аппаратное ускорение скроллинга и использовавшего режим индексированных цветов.

Растровый эффект псевдодороги на самом деле создавался почти так же, как эффект перспективы в Street Fighter II, где статичное изображение деформировалось для добавления иллюзии трёхмерности. Вот как это реализовывалось:

Большинство растровых дорог начинается с изображения плоской дороги. В сущности, это графическое изображение двух параллельных линий на земле, уходящих вдаль. При отдалении эти линии кажутся наблюдателю соединяющимися. Это основное правило перспективы. Кроме того, чтобы создать иллюзию движения, у большинства аркадных гоночных игр на дороге рисовались полосы. Перемещение этих полос на дороге достигалось или цикличным переключением цветов или изменением палитры каждой строки. Кривые и повороты выполнялись независимым скроллингом каждой строки, как в Street Fighter II.

Мы рассмотрим кривые и повороты в следующем разделе. А пока давайте сконцентрируемся на скроллинге дороги вперёд.

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

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

В этом изображении не хватает дорожной разметки, создающей хорошее ощущение перспективы. Для этого эффекта в играх, кроме прочей дорожной разметки, используются попеременные тёмные и светлые полосы. Чтобы добавить их, давайте определим переменную «положения текстуры». Эта переменная равна нулю внизу экрана и с каждой линией вверх увеличивает своё значение. Когда её значение ниже определённого числа, дорога рисуется одним оттенком. Когда значение выше этого числа, она рисуется другим оттенком. После превышения максимального значения переменная положения снова приравнивается к нулю, создавая повторяющийся шаблон.

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

Вот пример того, как меняется значение Z для каждой строки при движении вдаль. После переменных я написал то, что нужно прибавить, чтобы получить значения для следующей строки. Я назвал значения DDZ (дельта-дельта-Z), DZ (дельта-Z) и Z. DDZ остаётся постоянной, DZ меняется линейно, а Z — по кривой. Можно считать Z координатой положения Z, DZ — скоростью положения, а DDZ — ускорением положения (изменением ускорения). Учтите, что значение «4» выбрано произвольно, потому что удобно для этого примера.

DDZ = 4 DZ = 0 Z = 0 : dz += 4, z += 4

DDZ = 4 DZ = 4 Z = 4 : dz += 4, z += 8

DDZ = 4 DZ = 8 Z = 12 : dz += 4, z += 12

DDZ = 4 DZ = 12 Z = 24 : dz += 4, z += 16

DDZ = 4 DZ = 16 Z = 40 : и т.д.

Заметьте, что DZ изменяется первой, а потом используется для изменения Z. Это можно объяснить так: допустим, мы движемся по текстуре со скоростью 4. Это значит, что после первой строки мы считываем текстуру в положении 4. Следующая строка будет в положении 12. После неё 24. Таким образом, проход по текстуре происходит всё быстрее и быстрее. Поэтому я и называю эти переменные «положением текстуры» (место текстуры, которое мы считываем), «скоростью текстуры» (как быстро мы проходим через текстуру) и «ускорением текстуры» (насколько быстро меняется скорость текстуры).

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

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

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

Экскурс в математику: проекция трёхмерной перспективы

Существуют способы избавления от эффекта овсянки. Однако для их реализации нужны знания традиционной трёхмерной математики. Нам нужно найти способ трансляции 3D-координат, чтобы их можно было расположить на 2D-поверхности.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

На рисунке выше глаз (в левом нижнем углу) смотрит сквозь экран (синяя вертикальная линия) на объект в нашем трёхмерном мире («y_world»). Глаз находится на расстоянии «dist» от экрана, и на расстоянии «z_world» от объекта. Если вы занимались геометрией или тригонометрией, то могли заметить, что на картинке есть не один, а два треугольника. Первый треугольник — большой, от глаза до поверхности справа и вверх до объекта, на который смотрит глаз. Второй треугольник я закрасил жёлтым. Он образуется глазом, точкой на экране, в которой мы видим объект, и поверхностью.

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

Теперь нам нужно преобразовать уравнение, чтобы получить y_screen. Получаем:

То есть для нахождения координаты y объекта на экране мы берём координату y мира, умножаем её на расстояние от глаза до экрана, а затем делим на расстояние в мире. Разумеется, если мы так поступим, то центр взгляда будет в левом верхнем углу экрана! Чтобы убедиться в этом, достаточно подставить y_world=0. Для центрирования нужно прибавить к результату половину разрешения экрана. Уравнение можно немного упростить, если представить, что нос прижат к экрану. В этом случае dist=1. Получается следующее уравнение:

y_screen = (y_world/z_world) + (y_resolution/2)

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

Ещё математика: добавление области видимости к трёхмерной проекции

Вообще-то это обычно не нужно для большинства «дорожных» движков. Но это полезно для того, чтобы параметры проецирования не зависели от разрешения, или для объектов, которые нужно вращать, или для интеграции с подлинными 3D-эффектами.

Давайте вернёмся к исходной формуле проецирования. Величина «dist» из уравнений выше здесь будет называться «scaling»:

y_screen = (y_world*scaling)/z_world + (y_resolution/2)

Идея заключатся в том, что нам нужно отмасштабировать все точки на экране на определённую величину, что позволит оставаться видимыми точкам в пределах области видимости (field-of-view, FOV). Для оси x FOV и оси y FOV нужны будут две константы.

Например, предположим, что мы работаем в разрешении 640×480 и хотим, чтобы FOV была равна 60 градусам. Мы видели схему трёхмерной проекции в виде сбоку. Для этого случая давайте посмотрим на схему проецируемого пространства в виде сверху:

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху
Один из способов решения проблемы — принять, что если объект находится с правой стороны нашей FOV, он должен отображаться на экране в положении x=640 (потому что разрешение экрана 640×480). Если посмотреть на схему, то можно заметить, что FOV можно разделить на два прямоугольных треугольника, в которых угол каждого равен fov_angle/2 (a/2). И поскольку наша FOV является конусом, то объект, находящийся на правом крае FOV, т.е. x=R*sin(a/2) и
z=R*cos(a/2), где R — любое значение радиуса. Мы можем, например, взять R=1. И нам нужно, чтобы объект отображался на экране в x_screen=640. Получаем следующее (с учётом основной формулы проецирования):

x_screen=640 fov_angle=60 y_world=sin(60/2) z_world=(60/2) x_resolution/2=320 scaling=?

x_screen = (y_world*scaling)/z_world + (x_resolution/2)

640 = (sin(30)*scaling/cos(30)) + 320

В общем случае: scaling = (x_resolution/2) / tan(fov_angle/2)

Мы заменили a/2 на 30 (половина от 60 градусов), обозначили sin/cos = tan, и вуаля! Можно проверить это, поместив объект в правый конец области видимости, подставив эти значения в исходное уравнение проецирования и убедившись, что X принимает значение 640. Например, точка (x, z) с координатами (20, 34.64) окажется в X=640, потому что 20 — это 40*sin(30), а 34.64 — это 40*cos(30).

Нужно заметить, что значения FOV для горизонтальной (x) и вертикальной (y) осей будут разными у стандартного и широкоэкранного монитора в горизонтальном положении.

Более точная дорога: использование Z-карты

Для решения проблемы с перспективной нам нужно создать предварительно вычисленный список расстояний для каждой строки экрана. Если вкратце, то проблема заключается в описании плоскости в 3D.

Чтобы понять, как это работает, представьте сначала двухмерный аналог: линию! Для описания горизонтальной линии в 2D, можно сказать, что для каждой пары координат (x, y) координата y будет одной и той же.

Если мы выведем её в трёхмерное пространство, то линия станет плоскостью: для каждого расстояния x и z координата y будет оставаться той же! Если рассматривать плоскую горизонтальную поверхность, то не важно, насколько далеко расположена камера, y будет постоянной. Также не важно, насколько далеко влево или вправо расположена точка, значение y всегда будет таким же.

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

Сначала возьмём уравнение из предыдущего раздела:

Y_screen = (Y_world / Z) + (y_resolution / 2)

Поскольку у нас есть Y_screen (каждая строка), преобразуем уравнение, чтобы найти Z:

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

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

Хотя мы знаем расстояние для каждого ряда экрана, может оказаться полезным кэшировать для каждой строки или ширину дороги, или коэффициент масштабирования. Коэффициент масштабирования противоположен расстоянию, выбранному таким образом, что значение на строке, в которой графическое изображение машины игрока находится больше всего, равнялось 1. Его можно использовать для масштабирования спрайтов на заданной строке или для определения ширины дороги.

Кривые и повороты

Чтобы сделать дорогу кривой, надо просто изменить положение центральной линии по форме кривой. Для этого можно использовать пару способов. Один способ — это такой же способ, которым создавались положения Z в разделе «Простейшая дорога»: с помощью трёх переменных. То есть начиная с низа экрана величина, на которую смещается центр дороги влево или вправо каждую строку, стабильно увеличивается. Как и в случае со считыванием текстуры, мы можем считать эти переменные положением центральной линии (кривой), скоростью кривой и ускорением кривой.

Однако у этого способа есть проблемы. Одна из них в том, что не очень удобно создание S-образных кривых. Ещё одно ограничение: вход в поворот выглядит точно так же, как и выход их него: дорога загибается, а потом просто разгибается.

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

Когда мы начинаем отрисовывать дорогу, то начинаем с того, что смотрим на базовую точку и соответственно устанавливаем параметры отрисовки. С приближением поворота его строка сегмента находится на расстоянии и приближается к игроку почти как любой другой дорожный объект, за исключением того, что она должна спускаться вниз по экрану с постоянным темпом. То есть при конкретной скорости, с которой движется игрок, сегментный разделитель опускается вниз по экрану на такое же количество линий за кадр. Или, если используется Z-карта, на то же количество элементов z-карты за кадр. Если бы сегмент «ускорялся» по направлению к игроку, как делают 3d-объекты на трассе, то дорога бы изгибалась слишком резко.

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

Ниже показаны две дороги: одна прямая, за которой идёт левый поворот, а другая с изгибом влево, за которым идёт прямая. В обоих этих случаях положение сегмента находится на полпути вниз по Z-карте (или на полпути вниз по экрану). Другими словами, дорога начинает изгибаться или становиться прямой на полпути вниз по дороге. На первом рисунке камера входит в поворот, а на втором — выходит из него.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

А вот та же техника и то же положение сегмента, применённые к S-образной кривой:

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

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

Давайте проиллюстрируем вышесказанное кодом:

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

Чтобы иллюзия была полной, нужно добавить графику горизонта. С приближением кривой горизонт не меняется (или перемещается незначительно). Затем, когда кривая полностью отрисована, принимается, что машина поворачивает по ней, а горизонт быстро прокручивается в направлении, противоположном направлению кривой. Когда кривая снова выпрямляется, фон продолжает прокручиваться, пока кривая не закончится. Если вы используете сегменты, то можно просто выполнять прокрутку (скроллинг) горизонта в соответствии с настройками базового сегмента.

Общая формула кривых

Изучив технику кривых, подробно описанную в разделе «Простейшая дорога», мы можем сделать интересный вывод. Этот вывод больше относится к математике, чем к изложенному выше материалу, и его можно спокойно пропустить, если ваш графический движок не должен быть независимым от разрешения или использует технику «3d-спроецированных сегментов», рассмотренную в разделе о холмах.

Рассматривая пример кривой, использующей «Z», из раздела «Простейшая дорога», можно заметить, что z-положение (или x-положение) заданной строки является суммой возрастающего ряда чисел (например, 1 + 2 + 3 + 4). Такой ряд называется арифметическим рядом или арифметической прогрессией. Если использовать вместо 1 + 2 + 3 + 4, например 2 + 4 + 6 + 8 или 2*1 + 2*2 + 2*3 + 2*4, можно получить более резкую кривую. «2» в этом случае — переменная segment.dx. Её можно также факторизировать, получив 2(1 + 2 + 3 + 4)! Теперь всё, что нужно сделать — найти формулу, описывающую 1 + 2 +… + N, где N — количество строк, составляющих кривую. Известно, что сумма арифметической прогрессии равна N(N+1)/2. Поэтому формулу можно записать как s = A * [ N(N+1)/2 ], где A — резкость кривой, а s — сумма. Это уравнение можно ещё преобразовать для добавления стартовой точки, например, центра дороги снизу экрана. Если мы обозначим её за «x», то получим s = x + A * [ N(N+1)/2 ].

Теперь у нас есть формула для описания кривой. Мы хотим получить ответ на вопрос «зная стартовую точку x и N строк кривой, каким должно быть A, чтобы кривая достигла в конце x-положения, равного s?» Преобразовав уравнение для нахождения A, мы получим A = 2(s — x)/[n(n+1)]. Это значит, что резкость заданной кривой может храниться относительно положения X, что делает графический движок независимым от разрешения.

Повороты в перспективном стиле

Гораздо менее интересно, когда при поворотах в игре двигается только спрайт машины. Поэтому вместо перемещения спрайта автомобиля игрока мы оставим его в центре экрана и будем двигать дорогу, и что более важно, двигать положение центральной линии в передней (т.е. нижней) части экрана. Теперь примем, что игрок будет всегда смотреть на дорогу, поэтому сделаем так, чтобы дорога заканчивалась в центре экрана. Для этого будет нужна переменная угла дороги. Поэтому вычислим разницу между центром экрана и положением передней части дороги, а затем разделим на высотe графики дороги. Это даст нам величину для перемещения центра дороги на каждой строке.

Спрайты и данные

Расположение объектов и масштабирование

Спрайты нужно отрисовывать сзади вперёд. Иногда такой способ называют алгоритмом художника. Для этого нужно заранее определить, где на экране должен отрисовываться каждый объект, а затем отрисовать объекты на разных этапах.

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

Положение X объекта необходимо отслеживать относительно центра дороги. Тогда простейшим способом горизонтального позиционирования спрайта является умножение значения на коэффициент масштаба текущей строки (величину, обратную Z) и прибавление результата к центру дороги.

Хранение данных трассы

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

Однако если вы используете систему с сегментацией, то можно просто использовать список команд. Расстояние, которое занимает каждая команда, аналогична скорости перемещения невидимого сегмента к низу экрана. Это также позволяет создать формат трассы, работающий для тайловой карты, позволяющей передать довольно реалистичную географию трассы. То есть каждый тайл может быть одним сегментом. Резкий поворот может повернуть трассу на 90 градусов, а более плавный — на 45 градусов.

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

Если хотите, чтобы дорога выглядела более точной, сделайте так, чтобы Z для каждой строки соответствовала номеру строки графической текстуры. И вуаля! Единая затекстуренная дорога!

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

Холмы

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

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

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

Спуски с холмов делаются похожим образом: если положение отрисовки увеличивается, а не уменьшается, то мы опустимся ниже последней отрисованной строки. Разумеется, строки, находящиеся ниже горизонта, не будут видимы на экране. Отрисовываются только линии, находящиеся на один или больше пикселей выше последней строки. Однако нам всё равно нужно отслеживать объекты, находящиеся ниже горизонта. Для этого нужно учесть положение Y каждого спрайта при обходе Z-карты. Может помочь создание Z-карты, большей, чем необходимо для плоской дороги. Таким образом при растяжении буфера она не станет слишком пикселизированной.

Теперь нам нужно сдвинуть горизонт, чтобы для игрока картинка была убедительной. Я люблю использовать фон в стиле игры «Lotus»: в ней горизонт не просто состоит из очертаний неба, но и из графики отдалённой земли. Когда холм поднимается вверх (увеличивая область видимости), горизонт должен немного опуститься вниз относительно верхней части дороги. Когда холм спускается вниз и камера «упирается» в холм (ограничивая область видимости), горизонт должен подниматься вверх.

Вот как выглядит эффект для спуска с холма и подъёма на него, разумеется, без графики горизонта:

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверхуМашина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Подведение итогов: дальнейшее развитие растровых дорог

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

Однако, для создания более впечатляющей дороги вам может понадобиться преувеличить эффект. В любой из этих формул кривых можно использовать высокие значения ddx или ddy, но dx или dy не должны превышать разумных значений. Пользователь YouTube Foppygames обнаружил ещё один трюк, создающий более крутые кривые из этих формул с накоплением: нужно для каждой строки умножать значение dx или dy на значение z! Это делает кривую более крутой на расстоянии, чем она есть на переднем плане, и создаёт довольно убедительный эффект.

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

Можно также использовать умножение: для смещения дороги вправо можно, например, умножать положение x на 1,01 для каждой строки. Для смещения влево на ту же величину нужно умножить на 0,99 или 1/1,01 (величину, обратную 1,01). Однако, вооружившись знаниями о том, что многие старые процессоры не имели операций умножения или были слабы в нём, я остановился на технике накопления, потому что в ней используется только сложение. Она показалась мне более «аутентичным» способом создания изгибов дороги.

В некоторых играх, например, в OutRun, даже используется система простых сплайнов (по крайней мере, если судить по сделанному на основе реверс-инжиниринга отличному порту на C++ Cannonball.

Вот так, играя и экспериментируя, вы сможете выбрать самую подходящую вам технику!

… или продолжить чтение, чтобы узнать хитрый трюк, смешивающий 3d-полигоны. Он почти так же быстр, даже более убедителен и может воспроизводиться на том же старом растровом оборудовании. Заинтригованы?

Настоящие 3d-спроецированные сегменты

Сравнение 3d-спроецированных сегментов и растровых дорог

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

Известно, что этот трюк использовался в таких играх как Road Rash и Test Drive II: The Duel. Вот в чём он заключается: трасса состоит из полигональных сегментов. Однако вместо перемещения в полном 3d-пространстве, они двигаются только относительно камеры. Для кривых дорога по-прежнему наклоняется влево или вправо, почти так же, как в растровых дорогах: здесь нет действительного вращения, которое бы присутствовало при поворотах на кривой в полностью полигональном движке.

Вот краткое объяснение принципа:

Во-первых, разобьём дорогу на полигональные четырёхугольники. Каждый из них будет называться сегментом. Как и сегмент в полностью растровой дороге, здесь каждый сегмент по-прежнему имеет величину кривой (ddx), и или величину холма (ddy), или положение y, определяющее его высоту. Разумеется, они могут иметь и другие атрибуты, например, изменение графики поверхности.

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

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

При рендеринге мы первым делом находим положение y на экране каждого 3d-сегмента с помощью формулы screen_y = world_y/z. Или если деление слишком медленное, то можно найти высоту над землёй заданного сегмента, умножив высоту сегмента на коэффициент масштабирования для этой строки. Затем её можно вычесть из обратной z-карты (эта карта представляет собой ответ на вопрос: каким будет y для каждого положения z плоской дороги?), чтобы найти окончательное положение на экране.

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

Теперь нам нужно научиться прокручивать эти сегменты, перемещать весь объём полигонов, двигающихся по направлению к камере. Когда самый ближний полигон сегмента проходит через камеру, нужно переместить всю дорогу обратно в начальную точку, чтобы она замкнулась. Это похоже на то, как можно реализовать скроллинг двухмерного тайлового поля скроллингом вверх на один тайл, а при его достижении все тайлы смещаются и загружаются новые данные тайловой карты. Здесь мы скроллим вверх на один сегмент, и при его достижении мы перемещаем дорогу назад и загружаем новые данные дороги.

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

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

У Джейка на codeincomplete.com есть прекрасное решение этой проблемы. Вместо изменения положения x дороги при движении вдоль сегмента стоит менять начальное значение dx с 0 на что-то, что держит дорогу в центре при движении по сегменту. Для этого используется следующая формула:

Процент сегмента может быть в пределах от 0 до 1.0 и возвращается в исходное значение при пересечении камерой сегментов.

С точки зрения математики это делает X дороги функцией её Z. Другими словами, мы сохраняем одну и ту же форму кривой, вне зависимости от того, как скроллятся аппроксимирующие её точки. Самый передний сегмент «перетаскивается на место» с остальной частью дороги, и это значит, что последующее положение X сегментов размещается правильно. Вы чётко это заметите, если протестируете способ с дорогой из нескольких полигонов. Это решает следующие проблемы при прохождении сегмента (принимая, что форма кривой не меняется):

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

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

Вариации и технологии рендеринга

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

Заметьте, что каждое начало и каждый конец сегмента дороги совершенно горизонтальны. Это значит, что они всегда начинаются и заканчиваются на одной строке развёртки. Почти так же, как полностью псевдотрёхмерная дорога рендерится на тайловом оборудовании скроллингом графики плоской дороги, можно повторить эту технику для трёхмерных сегментов. Подробнее об этом см. в разделе «Специальное оборудование для дорог». Хотя в нём рассматривается оборудование аркадных автоматов, изначально предназначенное для отрисовки эффектов дороги, ту же самую технику можно воссоздать в простых двухмерных спрайтовых системах с помощью вертикального скроллинга графики дороги вместе с горизонтальным.

Дополнительное чтение о трёхмерных спроецированных сегментах

Поскольку моя демонстрация такой вариации ещё не готова, я рекомендую изучить потрясающее руководство Code inComplete, если вам интересны подробности этой техники.

Усовершествования

В большинстве аркадных гоночных игр одновременно обрабатывается множество дорог. Хотя самая очевидная причина для этого — наличие на экране одновременно нескольких дорог, но таким образом можно достичь и других эффектов. Например, в OutRun используется нескольло дорог для создания шестиполосного шоссе. Это позволяет игре с лёгкостью расширять и сужать дорогу, а также создавать удобные разветвления. При этом две дороги накладываются друг на друга и одной из них отдаётся приоритет отрисовки. Вот знаменитое начало OutRun с двумя дорогами и без них (посмотрите на правую часть кустов):

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверхуМашина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

И, что ещё более важно, ниже показан пример шоссе, на котором наложены две дороги для создания шести полос, со второй дорогой и без неё:

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверхуМашина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Схожие эффекты

Бесконечная «шахматная доска»

Бесконечная «шахматная доска» в аркадной игре Space Harrier является простой вариацией техники создания дорог. Как и в случае с дорогами, игра содержит графику линий, приближающихся к игроку в перспективной проекции. Фактически, в Space Harrier используется то же оборудование, что и в Hang-On.

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

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверхуМашина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

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

Изучение на примерах

Специальное оборудование для дорог

Несмотря на то, что существует множество способов рендеринга дорог, интересно, что во многих аркадных играх использовалось оборудование, разработанное специально для этой цели. Эти чипы автоматизировали принципы отрисовки дорог, но не сами вычисления дорог. В качестве типичного примера можно привести «дорожный» чип OutRun компании Sega, использованный в таких играх, как Super Hang-on, Outrun и Space Harrier.

Во-первых, чип имел собственную графическую память. В этой дорожной ПЗУ практически хранился перспективный вид дороги, плоский, центрированный и без искривлений. Программист приблизительно указывал для каждой строки экрана ту строку перспективной графики, которую нужно отрисовать. Каждая строка также имела смещение по X (для искривления дороги) и каждая строка имела различную цветовую палитру (для отрисовки дорожной маркировки и симуляции движения). Для демонстрации примера вот несколько изображений дорожной графики из гоночной игры Sega вместе с той дорогой, которая отображалась в игре (выражаю особую благодарность Чарльзу Макдональду (Charles MacDonald) за его приложение для просмотра дорог):

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Первое, что вы могли заметить — это то, что графика дороги имеет гораздо большее разрешение, чем игровая графика. В этих примерах дорога имеет разрешение до 512×256, а разрешение игрового дисплея всего 320×224. Это даёт графическому движку достаточный объём графики, позволяющий снизить количество искажений. Также можно заметить, что перспектива дороги, хранящаяся в ПЗУ, совершенно отличается от перспективы, отображаемой в игре. Так вышло потому, что графика в ПЗУ хранит только то, как дорога может выглядеть при различной ширине дороги. Выбор нужных строк для каждой строки экрана из большого графического изображения — задача программы.

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

Если вы занимаетесь хакингом ПЗУ, то можете изучить примеры «дорожных» чипов в файлах MAME src/mame/video/segaic16.c и src/mame/video/taitoic.c. Учтите, что дорожная графика Sega хранится в двухбитном планарном формате, а центр графики может иметь четвёртый цвет (жёлтая линия, показанная на рисунках выше).

Enduro — это примечательная игра. Она выпущена в 1983 году для невероятно слабой игровой консоли 70-х годов. Но ей всё равно удаётся создать убедительный эффект дороги, дополненный переменами погоды и сменой дня и ночи. Кроме того, эта игра захватывает даже сегодня!

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху
Скриншот Enduro

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

Чтобы лучше понять, почему Enduro выглядит именно так, давайте рассмотрим ограничения Atari 2600. Консоль Atari 2600 была разработана для игр в стиле Combat (танковых игр) и Pong. Поэтому она могла отображать только два спрайта, два квадрата, обозначающих снаряды каждого из игроков, квадрат, представляющий собой мяч, и фон низкого разрешения. И это всё.

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

А теперь вернёмся к нашей теме. Можно отрисовать дорогу с помощью блоков фона, но разрешение слишком низкое, чтобы быть эффективным. Поэтому в гоночных играх Atari использовались два графических объекта снаряда или мяча для отрисовки левой и правой стороны дороги, почти так же, как их можно было использовать для отрисовки линий. Enduro, в частности, использовала спрайт снаряда первого игрока и спрайт мяча для отрисовки левой и правой сторон. В Pole Position использовались оба спрайта снарядов для отрисовки сторон дороги, а затем использовался спрайт мяча для отрисовки пунктирной линии в центре.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху
Скриншоты Pole Position на 2600 для сравнения

Мы не обсудили то, как построчно перемещались объекты на Atari 2600. Графический чип Atari имел функцию под названием HMOVE (horizontal move, горизонтальный сдвиг). Он позволял программисту очень просто устанавливать смещение каждой строки для всех объектов. Программисту нужно было всего лишь указать, на сколько пикселей нужно сдвинуться различным объектам, затем вызвать HMOVE, и вуаля — все они сдвигались согласно нужным значениям!

В Enduro эта функция использовалась для отрисовки кривых. Если вкратце, Enduro создавала в памяти таблицу того, как изменяются значения HMOVE левой и правой сторон при отрисовке экрана. Она занимала почти половину доступной памяти Atari 2600. Поскольку память Atari была так мала, это значение считывалось только для каждых четырёх строк. Для левой и правой сторон дороги использовались две разные таблицы.

Когда дорога прямая, все значения массива для правой стороны дороги были равны 8. HMOVE использует только верхние 4 бита, поэтому значение 8, загруженное в HMOVE, не сдвигало стороны дороги. Нижние 4 бита использовались как приблизительная форма фиксированной запятой.

Например, вот как выглядит кривая в памяти при её приближении (горизонт — это конец массива):

Заметьте, что увеличивающиеся значения кривой постепенно перезаписывают меньшие значения, смещаясь к передней части экрана для создания иллюзии того, что кривая приближается к игроку. А что Enduro делает с этими данными? Вот часть когда, использованная для записи кривой для правой стороны дороги.

Для каждой строки развёртки дороги:

Описанная выше последовательность равна 09,12,0b,14. Она приведёт к тому, что мяч будет перемещаться каждую вторую строку на эти 4 строки. Но постепенно нижний полубайт станет достаточно большим, чтобы процедура сместила спрайт мяча на две строки в столбце влево. Шаблон затем свернётся, но после ещё нескольких строк сторона дороги снова сместится на две строки в столбце. В сущности, это пример простой и чрезвычайно быстрой математики с фиксированной запятой.

Есть ещё одно препятствие в реализации дорожной системы на таком слабом оборудовании: позиционирование спрайтов. В более сложных системах спрайты можно позиционировать горизонтально на дороге как процент от ширины дороги. Но это требует умножения с фиксированной или плавающей запятой, а эти операции выполняются очень медленно в процессоре 6502. Для сравненияя, в Enduro есть всего три возможных позиций для машин, что экономит вычислительные ресурсы.

И у Road Rash, и у Road Rash на 3do потрясающие графические движки. Оригинальная версия игры для Genesis обеспечивала ощущение относительно точной трёхмерности на процессоре Genesis 68000 с частотой 7,25 МГц, а также справлялась с масштабированием объектов на дороге в реальном времени. Версия для 3do была не менее удивительной, потому что оказалась смешением техник 3D и псевдо-3D. Они были мастерски объединены, давая игроку потрясающее ощущение скорости.

Как я упоминал выше, движки Road Rash и Road Rash для 3do были смешением хитростей 3D и псевдо-3D. В них использовалась техника, схожая с описанной в разделе «Настоящие 3d-спроецированные сегменты»: холмы находятся в 3D-пространстве, а кривые дороги — нет. В кривых Road Rash используется тот же метод, описанный в этой статье, и каждый сегмент дороги имеет собственное значение DDX или «ускорения по x». Каждый сегмент также имеет высоту, относительную к высоте последнего сегмента. На экране одновременно присутствует 50 сегментов.

Но Road Rash для 3do действительно интересна тем, что программисты добавили свёртывание, усиливающее ощущение скорости: удалённые от камеры объекты двигаются медленнее, а объекты рядом с камерой — быстрее.

В Road Rash для 3do также добавлены полигональные объекты на обочинах, чьи координаты по X по-прежнему относительны к дороге. Они используются для создания холмов, зданий и других сложных элементов. На это уходит большой объём данных, поэтому геометрия и текстуры загружаются с диска в процессе прохождения трассы.

S.T.U.N. Runner: аркадные автоматы против Lynx

S.T.U.N. Runner в момент выпуска на аркадных автоматах в 1989 году была удивительной игрой. В ней использовалась технология полностью трёхмерных полигонов с заливкой. Она предлагала игроку взяться за управление футуристическим гоночным аппаратом, летящим по извивающимся коридорам с головокружительной скоростью.

Немного позже я увидел версию для Atari Lynx. Консоль Atari Lynx была портативной системой, выпущенной примерно в одно время с оригинальным Game Boy. Как и в Game Boy, в ней установлен 8-битный процессор на 4 МГц. Значит, порт был ужасным, правда? Ну, посмотрите видео сами:

На самом деле, порт был фантастическим! Он стал почти идеальным и ухватил всё то, что делало игру на аркадных автоматах такой потрясающей. И это на портативном оборудовании эры Game Boy. Как же им это удалось?

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

Для воссоздания скорости аркадного автомата Lynx-версия S.T.U.N. Runner вернулась к псевдо-3D движку. Куски полигонов, из которых состоят стены, на самом деле являются спрайтами. В сущности, это объекты на обочине, которые приклеены к дороге, почти так же, как объекты на обочинах в любой другой псевдотрёхмерной гоночной игре. Они отрисовываются с помощью алгоритма художника (сзади вперёд). Это создаёт убедительную иллюзию полигональной графики и позволяет воспользоваться сильными сторонами оборудования. А для экономии места в картридже один спрайт не составлял полное кольцо графики тоннеля. Это не только экономит место на отсутствии пустых, прозрачных пикселей, но и позволяет использовать функцию горизонтального отражения графического оборудования.

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

Если вам интересно узнать об этом подробнее, то прочитайте интервью с автором оригинала на AtariAge.

Дороги на Commodore 64

Эта информация принадлежит Саймону Николу (Simon Nicol), нашедшему отличную технику для быстрых дорог на C64.

Для начала небольшое предисловие: на многих консольных системах псевдотрёхмерные дороги создавались отрисовкой прямой дороги с тайлами и построчным скроллингом, чтобы создать видимость искривления. Однако для игры с нормальным уровнем кадров в секунду такой способ был слишком быстрым на Commodore 64.

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

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверхуМашина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Power Drift интересна тем, что это одна из немногих известных мне игр, в которых использовалось 3D на основе спрайтов. Каждый фрагмент трассы — это небольшой кусок спрайта, и созданный Sega облёт камерой демонстрировал это. У меня нет доказательств, но я думаю, что в таких играх, как F1 Exhaust Heat и RadMobile использовалась похожая система. Стоит также заметить, что будка с автоматом Power Drift могла наклоняться почти на 45 градусов, поэтому в ней было важно пристёгиваться ремнём. Скриншоты взяты с system16.com.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверхуМашина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Реверс-инжиниринг Racin’ Force был выполнен Чальзом Макдональдом. Racin’ Force работает на печатной плате Konami GX, у которой есть дочерняя плата с функциями воксельного движка. Это оборудование основано на старом оборудовании, которое могло отрисовывать всего лишь напольные карты в стиле mode 7 консоли SNES. Его возможности были расширены и позволили создавать карту высот с помощью умной техники: она проецирует на плоскую 3D-поверхность не только тайловую карту, но и информацию о высотах для каждого пикселя на свою собственную отдельную 3D-плоскость. Затем для каждого пикселя экрана она ищет информацию о высотах на спроецированной карте высот и при необходимости экструдирует каждый пиксель вверх. Скриншоты взяты с system16.com.

Дальнейшие исследования

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

Эта формула получает мировые координаты x или y объекта, z объекта, и возвращает координату x или y пикселя. Или при известных мировых и экранных координатах возвращает местоположение по z.

Масштаб определяет область видимости (field-of-view, FOV) и может быть найден следующим образом:

Быстрая линейная интерполяция

Здесь предполагается, что все числа представлены в виде 16.16 с фиксированной запятой. y1 и y2 — это два значения, между которыми нужно выполнить интеполяцию, а d — это 16-битное дробное расстояние между двумя точками. Например, если d=$7fff, то это будет середина между двумя значениями. Это полезно для определения того, где между двумя сегментами находится значение.

Арифметика с фиксированной запятой

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

Умножение с фиксированной запятой выполняется хитрее, чем сложение. В этой операции умножаются два числа, а затем смещаются вправо на количество битов, отведённых под дробные части. Из-за переполнения смещение иногда может понадобиться перед умножением, а не после. См. пример умножения с фиксированной запятой в разделе „Быстрая линейная интерполяция“.

Вот простая формула поворота точки. В статье я вкратце упоминал о ней как об очень затратной операции. Как вы видите, в ней используется не менее двух поисков по таблице, четырёх операций умножения и двух сложений, но значения синуса и косинуса можно использовать повторно для каждой точки. Поворот для холмов означает вращение по координатам Z и Y, а не по X и Y. Вывод этой формулы см. в разделе Поворот осей.

Избавление от деления

Вместо деления на координату z объекта в стандартных формулах проецирования, можно воспользоваться свойствами дороги для ускорения вычислений. Допустим, у нас есть положение z и y 3D-сегмента, и нам нужно найти, какой строке экрана он соответствует. Сначала мы считываем z-карту, пока не доберёмся до положения z 3D-сегмента. Затем умножаем высоту сегмента на соответствующее значение масштабирования. Результатом будет количество пикселей над дорогой, к которым принадлежит сегмент.

Использование Z как значения масштабирования

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

Обычно процедура масштабирования имеет параметры, такие как x, y и коэффициент масштабирования. Но поскольку коэффициент равен 1/z, можно повторно использовать значение Z этого спрайта! Однако нам всё равно нужен будет коэффициент масштабирования для определения границ спрайта, чтобы центрировать его при масштабировании.

Плохая строка — в графическом чипе C64 VIC II на первом пикселе каждого тайла фона VIC подменяет процессор, чтобы вставить больше данных, например, цвета. Поскольку для вычислений программе остаётся меньше циклов, это называется плохими строками.

Карта высот — массив значений высот. В полигональном или воксельном ландшафтном движке это может быть двухмерный массив (представьте ландшафт в виде сверху). Однако в дорожном движке карте высот достаточно быть одномерной (представьте ландшафт в виде сбоку).

Режим индексированных цветов — в старых системах с малым количеством цветов на экране обычно использовались режимы индексированных цветов. Одни из самых популярных режимов индексированных цветов — 256-цветные режимы VGA. В этих режимах каждый пиксель был представлен байтом. Каждый байт хранил значение индекса от 0 до 255. При отрисовке экрана число индекса для каждого пикселя находилось в палитре. Каждая запись в палитре могла быть одним из 262 144 возможных цветов VGA. В результате, даже хотя одновременно на экране могло быть всего 256 цветов, пользователь мог выбирать каждый цвет из гораздо большей палитры.

Линейная интерполяция — процесс получения промежуточных значений из множества данных отрисовкой линий между точками.

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

Режим планарной графики — это режим, в котором N-битное изображение составлялось из N однобитных изображений, комбинировавшихся для получения конечного изображения. Он противоположен большинству графических режимов (иногда называющихся chunky), в которых N-битное изображение составляется из N-битных значений пикселей.

Эффект растра — это графический трюк, использующий природу большинства компьютерных (растровых) дисплеев на основе строк развёртки.

Коэффициент масштабирования — величина, обратная Z. Число, на которое нужно умножить масштаб объекта на заданном расстоянии по оси Z.

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

Трёхмерный сегмент (дороги) — я использую этот термин для обозначения горизонтальной линии, имеющей и расстояние по Z, и высоту по Y в мировых координатах. В отличие от вершины, которая может быть 3D-точкой, трёхмерный сегмент будет 3D-линией, чьи левая и правая конечные точки по оси X являются плюс и минус бесконечностями.

Воксель — трёхмерный пиксель. Воксельные ландшафтные движки и движки с трассировкой лучей стали популярными благодаря игре Commanche: Maximum Overkill.

Z-карта — таблица поиска, привязывающая каждую строку экрана к расстоянию по Z.

Галерея

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

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

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

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Это первая псевдотрёхмерная игра с плавным перемещением, которую я помню. Сегодня она не очень впечатляет графически.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Ещё один shoot em up для Atari в стиле Roadblasters. В нём есть очень красивый эффект прыжка, при котором перспектива слоя дороги смещается, из-за чего ближайшие объекты пропадают с экрана. В этой игре интересно проецируются объекты на различных расстояниях до земли.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Этот сиквел Outrun — отличный пример холмов, похожих на „американские горки“. Всё довольно преувеличено, в результате чего получилась сверхбыстрая гоночная игра, но с хорошей управляемостью.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

В версии Road Rash для 32-битного поколения консолей всё было затекстурировано, а здания умно отрисовывались рядом с обочиной. Поэтому у многих складывалось впечатление, что это полностью полигональная игра, быстро работающая на 3do. Однако то, как объекты изгибаются по краям, свёртывание зданий и то, что невозможно было повернуть назад, доказывает, что это не совсем полигональная игра. Резкие линии на дорожном покрытии дают намёк на систему спроецированных сегментов. Трассы очень детализированы и разнообразны. Road Rash 16-битного поколения тоже сделана качественно, у неё гибкий движок с небольшой долей фальшивого текстурирования (но он был медленным).

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Предшественница Pole Position с холмами и мостами. Есть ли недостатки? В игре отсутствуют переходы из холмов в мосты и в кривые. Для неё использовалось аналоговое оборудование масштабирования графики.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Не знаю, о чём думали создатели Spy Hunter II. Хорошая идея, плохое исполнение. Эффекты дороги очень похожи на Turbo, но переходы сделаны чуть получше.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Эта техника настолько быстрая, что даже на слабом Commodore 64 можно было играть в гоночную игру с разделением экрана.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Enduro демонстрирует использование псевдо-3D на Atari 2600.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

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

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

В Lotus использована техника довольно изогнутых холмов. Интересно, что Lotus отрисовывала верхнюю часть дороги поверх горизонта, а затем заливала зазор сплошным цветом для имитации спуска с холма.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

Я не знаю точно, как создавалась графика Test Drive 2. Хоть и очевидно, что гонка не полигональная, но очень старается реалистично воспроизводить множество дорог. Игра похожа на серию Need for Speed, но обогнала её на несколько лет по времени выпуска.

Машина спрайт вид сверху. Смотреть фото Машина спрайт вид сверху. Смотреть картинку Машина спрайт вид сверху. Картинка про Машина спрайт вид сверху. Фото Машина спрайт вид сверху

При поворотах в этой игре смещается не только перспектива, но и дорога немного скользит влево или вправо.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *