Теория программирования игр

2D мир

Что такое двухмерная графика - не простой вопрос. Сейчас вообще довольно сложно определить, что есть двухмерно, а что трехмерно. За примерами далеко бегать не надо, они перед глазами. Мы видим типичное окошко в Windows, там нарисованы разные кнопочки, движочки, списки и т.д. Так вот утверждается, что они выглядят трехмерно, так как отбрасывают тень. В тоже время, игру построенную по типу незабвенного Doom называют псевдо-трехмерной, или даже почти двухмерной только потому, что там нельзя посмотреть вверх-вниз. Даже наличие третьей координаты - z не говорит об трехмерности. Пример - изометрическая графика, там есть координата - z, но программу назовут двух с половиной(!) мерной. Где граница между этими понятиями? На мой взгляд, зыбкая, но все же граница проходит в типе проекции экрана монитора на мир, что нарисован по ту сторону. Если проекция статична (в случаи с Windows и изометрической графикой) то это 2D. Если динамична (т.е. меняются углы) то это 3D.

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

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

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

Среди подобных объектов можно выделить следующие основные группы:

  1. линейные изображения (растровое представление линии)
  2. полигоны (набор линий, с возможностью закраски ограниченных этими линиями областей)
  3. сплошные объекты (закрашенный прямоугольник)
  4. изображения (прямоугольные матрицы пикселей)
  5. спрайты (изображения произвольной формы, но обычно представленные в виде прямоугольной матрицы с указанием некоторых точек как прозрачных)
  6. шрифты
  7. сплайны

Такие объекты как сплайны, полигоны, линии скорее характерны для рисовальных или проектировочных программ и для 3D приложений. Нас же больше должны интересовать оставшиеся объекты. Главные из которых это несомненно, спрайты и изображения.

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

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

Шрифт- этому понятию можно запросто посвятить целую книгу. Но в играх шрифт это обычно набор спрайтов или изображений, каждое из которых содержит какой-нибудь символ. Таким образом наибольшей популярностью пользуются именно растровые шрифты, благодаря великолепной скорости вывода, и возможности декоративного оформления последних для создания неповторимой атмосферы в игре. Можно даже сказать, что красивый легко читаемый шрифт очень украшает программу. Он является полноценным элементом общего дизайна программы. Вспомнить хотя бы Diablo, где все начальное меню построено на оригинальности шрифта…

Анимация

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

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

Первый - полностью перестроить все изображение. Собственно так и происходит при съемках кинофильмов. Этот способ применяется для динамически активных игр. Где каждый последующий кадр довольно-таки значительно отличается от предыдущего.

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

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

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

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

Итак методы борьбы с мерцанием:

Первый - изображение строится не в видеопамяти, а в другом месте. После построения нового кадра, он переносится в видеопамять. И эффект мерцания исчезает. Эффект несовпадения изображений остается, но решается если использовать ожидание обратного хода луча монитора, и копировать наше "другое место" в видеопамять как раз во время этого обратного хода. Возникает понятие виртуального буфера или виртуального экрана- это и есть то самое "другое место". По сути это полная копия матрицы используемой видеопамяти, только расположенная в системной памяти. Этот метод имеет следующие преимущества: на нем легко реализовать второй способ построения следующего кадра, ведь никто не заставляет нас стирать изображение в нашем виртуальном буфере, мы можем его просто немного модифицировать. Этот способ остается единственным для видеоадаптеров, в чьей памяти не умещаются парочка экранов. Например для 640*480*16bit в видеопамять умещается только один экран, второй приходится организовывать в системной памяти. Главный недостаток -требуется время (и не малое надо сказать) для копирования буфера в видеопамять.

Второй - использование видеостраниц. Видеостраница- область памяти видеоадаптера, достаточная для хранения всей матрицы изображения. Например, для разрешения 640*480*8bit размер такой матрицы составляет примерно 300 килобайт, значит в "мегабайтный" видеоадаптер при желании можно уместить 3 страницы. Итак, мы строим новый кадр в "теневой" странице, затем переключаем видеостраницы, делая "теневую" страницу видимой, а видимую - теневой. Причем операция переключения происходит практически мгновенно. Обычно переключение синхронизируют с разверткой монитора и таким образом избегают обоих напастей. Преимущества: "мгновенная" смена кадров. Недостатки: А что если приложение не успевает генерировать кадры с частотой развертки? Тогда происходит парадокс: частота кадров уменьшается в двое, так как переключение мы будем делать только при следующем проходе луча! Поэтому зачастую (особенно в тестах) отключают синхронизацию с частотой развертки. Еще недостаток, это медленный доступ к видеопамяти, ведь операция записи в видеопамять медленнее такой же операции с основной памятью и соответственно если некоторые точки перекрываются все новыми и новыми спрайтами несколько раз, то получается, что быстрее, как это не парадоксально, создать изображение в буфере, а затем скопировать его в видеопамять. Конечно можно привести аргументы против, вроде современная память типа SGRAM быстрее основной и т.д. Но пока существуют другие адаптеры с медленной памятью, это можно назвать недостатком.

Третий - это синхронизация с кадровой разверткой, идеальный вариант, рассмотренный выше.

Четвертый - метод сравнения (достоверно известно, что он используется в играх Nascar Racing, Rebel Assault). Этот подход основывается на том предположении, что каждый последующий кадр изображения незначительно отличается от предыдущего. Для этого в оперативной памяти выделяется два буфера размером с экран. С каждым кадром изображение формируется то в первом, то во втором буфере (просто меняются местами указатели буферов). Для вывода на экран эти два буфера сравниваются между и выводятся только не совпадающие участки. Метод использует опять же тот факт, что обращение к видеопамяти происходит медленнее, чем к основной памяти.

Видеоадаптер

Как это не прискорбно звучит, но видеоадаптеры SVGA не совместимы друг с другом. Поэтому для использования в программах видеорежимов Super VGA надо либо строить библиотеку учитывающию особенности каждой модели, либо воспользоваться спецификацией VESA.

Вся память SVGA видеоадаптера разбита на на банки одинакового размера (обычно по 64 кб), при этом область адресного пространства 0xA000:0 -0xA000:0xFFFF соответствует выбранному банку. На каждый пиксель выделяется один байт при 256 цветах, два байта при 32К, 64К цветов, три или четыре байта при 16М цветов. Пиксели располагаются линейно в памяти, строка за строкой. Банк памяти, является как бы окном, через которое видна видеопамять. Начиная с VESA спецификации 2.0 появилась линейная организация видеопамяти в защищенном режиме работы процессора, без использования банков. Это существенно увеличило скорость работы приложений использующих эту возможность (на предоставлении интерфейса VESA 2.0, 3.0 основана работа популярной утилиты SciTech Display Doctor). Но практически все это удел DOS приложений, под Windows DirectX такая проблема обычно не стоит, т.к. там используются драйвера для конкретного видеоадаптера, позволяющие использовать все возможности конкретной модели. А работу с банками там осуществляет виртуальный драйвер, который отслеживает, переход границы сегмента и автоматически переключает банк, таким образом память для программиста выглядит абсолютно линейно.

Практически все современные видеоадаптеры поддерживают так называемые беспалитровые режимы - для каждого пикселя вместо индекса в палитре непосредственно задается его RGB-значение. Обычно такими режимами являются режимы HICOLOR (15 и 16 бит на пиксель) и TRUECOLOR (24 или 32 бита на пиксель). Видеопамять для этих режимов устроена аналогично 256-цветным режимам- под каждый пиксель отводится целое количество байт памяти (2 байта для HICOLOR и 3 или 4 байта для TRUECOLOR), все они расположены подряд и сгруппированы в банки.

Наиболее простой из беспалитровых режимов является организация режима TRUECOLOR - под каждую из трех компонент отводится по байту, если это 32-битный режим, то четвертый байт выделяется под коэффициент прозрачности - альфа. Возможны различные варианты чередования байтов, для 32-битного это ARGB, ABGR, RGBA и BGRA, для 24-битного это RGB и BGR.

Гораздо более сложнее устроен режим HICOLOR, где под каждый пиксель отводится 2 байта и возможны два варианта: первый- под каждую компоненту отводится по 5 бит, последний бит не используется это формат 5-5-5, а второй - 5 битами представлены только красная и синяя составляющая, а для зеленной используется 6 битов, это формат 5-6-5. Оба формата также делятся на два RGB и BGR.

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

Используются технологии uCoz