Посекторный движок
Посекторный движок для ЗD-шутера
Destr
Основная идея двига - это движок, опи─
санный в "Adventurer #13: Обмен опытом -
Как написать 3D игру типа DOOM".
(http://zxpress.ru/article.php?id=10028)
Но мне не удалось переделать их код под
свои представления, поэтому изложу просто
общие принципы. Основное отличие - это не
заливать стенки.
Т.е. имеем мир, устроеный из выпуклых
секторов и отображем только пол и потолок.
Всё это для ускорения (хочется ведь побо─
льше фреймов).
Итак, берется сектор - например, такой:
Камера находится в точке 0, "взгляд"
направлен по стрелке.
Надо спроецировать все точки сектора в
перспективу и обрезать ПО ГРАНИЦАМ ЭКРАНА.
Как именно проецировать - решать каждому,
но очевидно,что перспективная проекция тут
наиболее приемлема,т.е. "вверх" на рисунке
- это Z ("вглубь" экрана).
Получим что-то типа того:
Красный прямоугольник - это экран, т.е.
всё, что снаружи, - уже невидимо.
"Пол" у нас есть :)
Теперь, если мы хотим высоту пола и по─
толка во всех секторах одинаковыми (а это
даст прирост кадров в секунду,т.е. потолок
не надо проецировать отдельно), то "пото─
лок" можно получить простым отражением
"пола" вверх ногами.
Если разные высоты потолка всё таки хо─
чется, а тратить время на проекцию потолка
всё равно жалко, то можно пойти на компро─
мисс - печатать потолок не с серединным
отражением, а со смещением.
Это если смещение вниз, эффект другой
высоты есть, хотя и небезупречный.
Если хочется выше, то и смещение должно
быть вверх.
Но, как видно на рисунке, придётся ещё
раз клипировать по верхней границе.
Это не идёт на пользу в плане скорости.
Теперь осталось соединить углы (те, что
видны на экране)- и вид "в комнату" готов.
Чтобы визуальный эффект объёма был ощу─
тимей - надо бы залить пол и потолок.
На Speccy для этого достаточно заливки
"через строчку" (опять же, для скорости).
Итак мы получили залитый пол, потолок и
голые стенки. Накладывать на них текстуру
- долго, а у нас ставка на скорость. Для
шутера вполне пойдёт,если все стенки будут
белыми,- главное атмосфера.
Теперь о связи между секторами. Для то─
го, чтоб из одного сектора видеть содержи─
мое других,надо пробежаться обработчиком и
по соседним. Какой из них видим полностью
или частично, выяснить нетрудно, а вот с
отображением есть нюансы.
Сперва надо построить самый дальний ви─
димый сектор,потом тот,что поближе - и так
по мере приближения к камере. Но! Построе─
ние идёт после ПОЛНОЙ обработки всех сек─
торов, что ближе к камере,- и вот почему.
Допустим, мы хотим расширить наш мини-мир
на один сектор, например, так:
Зелёным цветом показана "спайка" между
секторами.
Проецируем:
Разворачиваем "потолок"
Здесь синим цветом выделены ГРАНИЦЫ
КЛИПИРОВАНИЯ для "дальнего" сектора. Если
из него видно что-то ещё более далёкое,оно
будет клипироватся уже по следующему ребру
"спайки" (или границе экрана, если ребро
за него вылазит).
Здесь выигрыш в скорости в том, что эти
границы - всегда строго вертикальны,а зна─
чит,математика получается не сильно затра─
тная. Потолки рисуются последовательно, и,
соответственно, их стыки не будут даже ви─
дны (ведь заливать всё это можно побайтно,
а то и по паре байт).
Если оставлять одинаковую высоту пола/
потолка для всех секторов, то можно их не
заливать и получить движок, который будет
довольно шустрым, но примитивным. По слож─
ности он будет как классический квадратный
рейкастовый двиг, но с возможностью любых
углов, зато без текстур.
Если делать возможность разных высот
потолка, то можно делать не просто коридо─
ры-комнаты, но и межкомнатные двери (и они
даже смогут раздвигаться, открывая взору,
что там за ними), но скорость расчётов и
отрисовки так упадёт, что шутер уже не по─
строишь,а красивую бродилку-лабиринт можно
сделать и на движке 3D Construction Kit...
Для всего этого (даже для самого прос─
того варианта,без заливок) нужна математи─
ка хорошая (8.8 как минимум) и быстрая.Где
такую взять, мне неизвестно,а то,что я сам
наизобретал, показывать крайне не рекомен─
дуется.
Наверняка можно адаптировать Адвенчур─
ный #13 двиг из статьи (которыйDUKEmain),
но сперва придётся разложить его по пол─
кам, что у меня, опять же, не вышло.
Однако если всё-таки удастся сделать
проволочную бегалку, то встаёт в полный
рост вопрос,что там делать.Нужны ведь вра─
ги, нужно оружие, а выводить это всё тоже
очень долго. Скрепя сердце, можно выводить
оружие развёрнутыми (и,следовательно,боль─
шими по объёму памяти) процедурами, но с
масштабированными врагами такое, наверное,
не получится.
Также довольно остро стоит вопрос о пе─
ремещениях внутри сектора и "упирания" в
стенку. Тут могут помочь заранее просчи─
таные массивы всех стенок для всех секто─
ров, но даже в этом случае довольно много
времени после КАЖДОГО шага игрока будет
тратиться на проверку "не пытаемся ли мы
лезть на стену", чтобы если это так,то пе─
ремещения не делать. В таких случаях поло─
жено "скользить" вдоль стены, а это тоже
непростая задача. Правда,можно хранить ка─
ждый сектор не только как массив координат
описывающих точек,но и ещё как набор неких
"векторов", тогда достаточно будет склады─
вать их направление с направлением текуще─
го взгляда и делать шаг в результирующем
направлении. Но это в теории, на практике
неизвестно, получится ли.
Есть мысль, что можно скрестить сектор─
ную организацию с рейкастингом. Например,
не обсчитывать все сектора, а только те,
которые попадаюся на глаза в текущей пози─
ции. Это можно сделать, подготовив сперва
массив, который будет заполняться номерами
секторов, которые зацепляет испускаемый из
камеры веер. Конечно, он (веер) не будет
слишком частым (далеко не на каждый пик─
сель). Возможно,это ускорит расчёты,а воз─
можно, и наоборот...
* * *
Ред.:
Смотрите демоверсию в приложении.
Чтобы быстрее заливать пол и потолок
серым цветом,лучше использовать чересстро─
чную сеточку, например, 25-процентную.
(Предполагается, что экран изначально
очищен значением#ff,линии нарисованы но─
ликами.)
Идём сверху каждого столбца экрана до
середины, изначальноc=#ff:
ld a,c
and (hl);накапливаем нолики в столбце
inc h
and (hl);накапливаем нолики в столбце
ld c,a
;c=маска, какие биты в этом байте надо
;затекстурить (единички), напр. %11111000
;(hl)=линии, которые надо наложить (нолики
;на фоне единичек), напр. %11111001
and d;e;строка текстуры,напр.%10111011
;a=%10111000
cpl
;a=%01000111
and c
;a=%01000000
xor (hl)
cpl
ld (hl),a;%10111001
inc h
или
(Предполагается, что экран изначально
очищен значением #00, линии нарисованы
единичками,c=#00.)
ld a,c
or (hl);накапливаем единички в столбце
inc h
or (hl);накапливаем единички в столбце
ld c,a
;c=маска, какие биты в этом байте надо
;затекстурить (нолики), напр. %00000111
;(hl)=линии, которые надо наложить (1
;на фоне 0), напр. %00000110
or d;e;строка текстуры, напр.%01000100
;a=%01000111
cpl
;a=%10111000
or c
cpl
;a=%01000000
or (hl)
ld (hl),a;%01000110
inc h
Аналогично заливаем пол - идём снизу
каждого столбца экрана до середины.
Оба варианта занимают 50 тактов на 2
байта, но работают прямо в экране.
Если работаем в буфере, а штриховки на─
кладываются целыми знакоместными столбца─
ми,то можно залить столбец через
xor (hl):ld (hl),a:inc l
(18 тактов на байт),
а потом перебросить на экран с текстурой
через
pop bc
ld a,c:and e:ld (hl),a:inc h
ld a,b:and d:ld (hl),a:inc h
(24 такта на байт).
Итого 42. Это при сплошной текстуре.
При чересстрочной убирается каждый вто─
рой ld (hl),a в заливке и каждый второй
ld a,b:and d:ld (hl),a (с возможной заме─
нойinc h:inc hнаld h,N) в текстуриро─
вании, остаётся 20(19) тактов на байт.
Чтобы сэкономить скорость,можно помнить
для каждого знакоместного столбца экрана,
какая у него сейчас высота (минимально по
всем линиям, попавшим в этот стоблец,кроме
вертикальных). И текстурить только на эту
высоту.
Other articles: