Конечно движок это через чур загнуто сказано,ну оно похоже на движок:)
Побудило меня на это то,что я фанат серии игра дум и ее модов,портов и т.д.(короче дум-задрот).меня всегда влекла атмосферность этой игры и еще со школы я мечтал написать свое вульфенштейно или думо подобное двигло.
Вот и зародились у меня некоторые темы.
Язык: Си.
Среда разработки: борланд Си 3.1
Поехали.
Итак движок будет под ДОС как вы поняли и рисоваться он будет методом рейкастинга.
В чем суть методики.
Это преобразование супер просто формы данных (в нашем случае обыкновенная матрица) в псевдотрехмерную проекцию с помощью пускания лучей из точки обзора в ее объем.
Выглядит это вот так:
Побудило меня на это то,что я фанат серии игра дум и ее модов,портов и т.д.(короче дум-задрот).меня всегда влекла атмосферность этой игры и еще со школы я мечтал написать свое вульфенштейно или думо подобное двигло.
Вот и зародились у меня некоторые темы.
Язык: Си.
Среда разработки: борланд Си 3.1
Поехали.
Итак движок будет под ДОС как вы поняли и рисоваться он будет методом рейкастинга.
В чем суть методики.
Это преобразование супер просто формы данных (в нашем случае обыкновенная матрица) в псевдотрехмерную проекцию с помощью пускания лучей из точки обзора в ее объем.
Выглядит это вот так:
на первом куске- двумерная карта и точка обзора откуда испускаются лучи,на втором куске трехмерная(псевдо) проекция.
Особенности в том,что стенки будут всегда перпендикулярны полу.за счет этого этот метод выигрывает в скорости,так как можно пускать один луч для всего столба экрана.
А так же стенки будут представлять собой равносторонние квадраты.
размеры желательно принимать такие,что бы можно было представить двойку в степени,операции сдвига работают намного быстрее умножения и деления.
начнем писать код и походу дела его толковать.
из хидеров нам понадобится
#include<graphics.h>
#include<math.h>
#include<dos.h>
#include<conio.h>
#include<stdlib.h>
начальные переменные
float rad;
int scan, exitt=0,pres=0, speed=2, anglspd=3, curangl=-30;
тут понятно я думаю,скэн коды клавиш,выход,нажата клавиша,скорость движения по карте,скорость поворота в сторону,текущая позиция взгляда.
int KARTE[16][16]={
{1,9,9,9,9,9,9,9,9,9,9,9,9,9,1},
{9,0,0,0,0,0,0,0,0,0,0,0,0,0,4},
{9,0,0,0,0,0,0,0,0,0,0,0,0,0,4},
{9,0,0,0,0,0,0,0,0,0,0,0,0,0,4},
{9,0,0,0,0,0,0,0,0,0,0,0,0,0,4},
{9,0,0,0,0,0,0,0,0,0,0,0,0,0,4},
{9,0,0,0,0,7,7,7,7,7,7,7,7,0,4},
{9,0,0,0,0,7,0,0,0,0,0,0,0,0,4},
{9,0,0,0,0,0,0,0,0,0,0,0,0,0,4},
{9,0,0,0,0,7,0,0,0,0,0,0,0,0,4},
{9,0,0,0,0,7,7,7,7,7,7,7,7,0,4},
{9,0,0,0,0,0,0,0,0,0,0,0,0,0,4},
{9,0,0,0,0,0,0,0,0,0,0,0,0,0,4},
{9,0,0,0,0,0,0,0,0,0,0,0,0,0,4},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,4},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
};
вот и сама карта,она размерами 16х16.
мы находимся в точке которая помечена зеленым и смотрим в сторону где помечено красным.
карта это матрица(двумерный массив,который будет проектироваться в псевдотрехмерный мир)
каждая цифра отличная от 0 будет стеной (пола и потолка нет,я это спиздил у вульфенштэйна :D) и каждая цифра же одновременно окрашивает стену в цвет в соответствии с цветами драйвера EGAVGA.Bgi (его присутствие,к сожалению,необходимо).
Теперь что касается управления
void interrupt (*oldint9)(); // указатель на первичное прерывание клавиатуры
void interrupt newint9()
перехватываем int9 (прерывание клавиатуры) и в новом обработчике ставим свои кнопки управления(стрелки)
выглядит это следующим образом:
static int kbrdvalue;
scan = inportb(0x60); // будем читать скэн-коды клавиш
if(scan == 1)
exitt = 1; // эск- выход
else
{
if(scan == 72) // стрелки будут клавишами перемещения
pres = 1;
else
{
if(scan == 80)
pres = 2;
else
{
if(scan == 75)
pres = 3;
else
{
if(scan == 77)
pres = 4;
else
{
pres = -1;
пояснение в комментариях.
так же нужно сделать сброс контоллера прерываний клавиатуры,процедурку я нашел в тырнетах:
kbrdvalue = inportb(0x61); // сбросим контроллер прерываний клавиатуры, т.к. мы не одни в системе (хотя это и ДОС)
outportb(0x61, kbrdvalue | 0x80);
outportb(0x61, kbrdvalue);
outportb(0x20, 0x20);
начинаем основную часть:
initgraph(&gdriver, &gmode, "C:\\bc\\BGI"); // инициализируем графич.режим
xmax = getmaxx();
ymax = getmaxy();
rad = 3.1415926535897932384626433832795/180.0;
vlx = xmax/fov;
получаем размеры экрана.затем нам понадобятся радианы,ну и в конце по алгоритму значение vlx будет переходом от столбца к столбцу.
FOV как вы поняли это field of vision равное 60 градусам (можно поиздеваться с градусами и получить прикольные наркоманские эффекты):)
теперь установим наши прерывания
oldint9 = getvect(9); // для установки первоначального значения получим вектор прерывания клавиатуры
setvect(9,newint9);
ну и основной цикл:
for(angle = curangl; angle <= curangl+fov;angle++) // получаем угол (в градусах)
{
if(angle<0)
tmpangl = angle + 360;
else
{
if(angle>360)
tmpangl = angle - 360;
else
tmpangl = angle;
}
// вычисляем расстояние от нас до стенки (это тоже взято из алгоритма)
xb = sin(angle*rad);
yb = cos(angle*rad);
bx = px;
by = py;
l = 0;
xbtmp = xb;
ybtmp = yb;
do {
bx = bx + xb; // находим первое ближайшее пересечение (т.к луч идет в квадрат и сталкивается с точками)
by = by + yb;
l = l + 0.5; // отображение стенок (можно регулировать отдаленность)
fy = (int)by/10; // примерное наше расположение в квадрате (можно где то от 8 до 12, что бы не застрять в стенке) (как вы поняли каждое значение-это еще один квадрат)
fx = (int)bx/10;
k = KARTE[fx][fy];
}while(k == 0);
dd = (2*ymax) / l; //высоты столбца
hp1 = ymax/2-dd; // находим верхние и нижние точки откуда сможем отрисовывать столбцы
hp2 = ymax/2+dd;
setfillstyle(1,k);
bar(x,hp1,x+vlx,hp2); // рисуем двухмерными прямоугольниками
setfillstyle(1,ceiling);
bar(x,1,x+vlx,hp1-1); //потолок
setfillstyle(1,ground);
bar(x,hp2+1,x+vlx,ymax); //пол
setlinestyle(SOLID_LINE, 1, 1); // окантовка-сплошная черная линия
setcolor(0);
line (x,hp1,x+vlx,hp1);
line (x,hp2,x+vlx,hp2);
x = x+vlx;
}
// тут просто- если нажали- изменяем координаты и углы
if(pres == 1)
{
px = px +speed*xbtmp;
py = py +speed*ybtmp;
}
if(pres == 2)
{
px = px - speed*xbtmp;
py = py - speed*ybtmp;
}
if(pres == 3)
curangl -= anglspd;
if(pres == 4)
curangl += anglspd;
if(exitt == 1) // если выход- выполняем восстановления векторов прерываний и перевод в первоначальный режим экрана
{
disable();
setvect(9,oldint9);
kbrdvalue = inportb(0x61);
outportb(0x61, kbrdvalue | 0x80);
outportb(0x61, kbrdvalue);
outportb(0x20, 0x20);
enable();
closegraph();
exit(0);
}
}
}
вот и все!)
вот как выглядит это кривое отродие:
Я думаю его немного улучшить, но думаю максимум на чем я закончу это что натяну на него текстуры и усе)))
в прочем хочется еще попробовать на паскале поколдовать,есть алгоритм по сложнее,но и двигло получается более-менее не квадратное,в общем посмотрим как пойдет.
ну и под конец думаю сделать очень простой двиг на delphi с opengl или D3D рендером.А пока вот что имеем,и то уверяю что писать такое не совсем просто.
Спасибо за внимание).
Здравствуй, DooD.
ОтветитьУдалитьНе сохранились ли у тебя фулл исходники этой софтинки? Самому написать что-то руководствуясь статьей не удалось.
Здрасте,вот как раз не так давно я опять задумывался об этом и ковыряя инет нашел немного полезной инфы,так попытаюсь реализовать сверхуебищную псевдотрехмерную игру, где уже будут бродить человечки или что то вроде,так что я думаю лучше немного подождем и посмотрим что выйдет.в целом сорцы могу закрекпить,хотя они и так полные :-)
Удалить