if Lookupdown > 1 then Lookupdown := 1;

end;

// Клавиша , голову опускаем вниз

if KeyBuffer[DIK_NEXT] and $80 <> 0 then begin

Lookupdown := Lookupdown - 0.05;

if Lookupdown < -1 then Lookupdown := -1;

end;

end;

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

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

function TfrmD3D.TestRender (const XPos, ZPos, RotY : Single) : BOOL;

var

i : Integer; matView : TD3DMatrix; d3dlr : TD3DLOCKED_RECT;

dwDstPitch : DWORD; DWColor : DWORD;

В : Byte; // Доля синего пиксела контрольной точки

begin

В := 0; // Предотвращение замечаний компилятора

// Смотрим на сцену из новой точки, по вертикали - ближе к полу

SetViewMatrix(matView, D3DVector(XPos, 0,1, ZPos),

D3DVector(XPos + cos(RotY), 0.1,

ZPos -sin(RotY)), ZVector); // Упрощенное воспроизведение сцены

with FD3DDevice do begin

Clear(0, nil, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER,

$000000FF, 1.0, 0); BeginScene;

// Отключаем источники света

-SetRenderState(D3DRS_LIGHTING, DWORD (False)); // Использовать диффузный компонент описания вершин SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);

SetTransform(D3DTS_VIEW, matView);

SetStreamSource(0, FD3DVB, SizeOf(TNormDiffTextVertex));

SetVertexShader(D3DFVF_NORMDIFFTEXTVERTEX); SetTransform(D3DTS_WORLD, IdentityMatrix);

end;

// Рисуем только комнату

for i := 0 to NumTriangles - 1 do with FD3DDevice do

DrawPrimitive(D3DPT_TRIANGLELIST, 1*3, 1);

with FD3DDevice do begin

EndScene;

// Получаем доступ к заднему буферу

GetBackBuffer (О, D3DBACKBUFFER_TYPE_MONO, FD3SurfBack);

SetRenderState(D3DRS_LIGHTING, DWORD (True));

end;

// Запираем задний буфер

FD3SurfBack.LockRect (d3dlr, nil, D3DLOCK_READONLY);

dwDstPitch := d3dlr.Pitch;

// Определяем долю синего в контрольной точке case

FD3DfmtFullscreen of D3DFMT_X8R8G8B8 : begin

DWColor := PDWORD (DWORD(d3dlr.pBits) + TestPointY * dwDstPitch +

TestPointX * 4)^; В := DWColor and $lf;

end;

D3DFMT_R5G6B5 : begin

DWColor := PDWORD (DWORD(d3dlr.pBits) + TestPointY * dwDstPitch +

TestPointX * 2}Л; В := DWColor and $lf;

end;

end;

FDSSurfBack.UnLockRect;

// Нет синего цвета, значит можно пройти

Result := not (В <> 0);

end;

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

Если установлен 24-битный режим, соответствующий формату D3DFMT_R8G8B8, то Х-координату контрольной точки надо умножить на 3, именно столько байт отводится для одного пиксела в этом режиме.

Контрольная точка для определения столкновения с препятствиями берется одна - посередине экрана по горизонтали, на 10 пикселов выше нижней границы экрана:

ScreenWidth := GetSystemMetrics(SM_CXSCREEN);

ScreenHeight := GetSystemMetrics(SM_CYSCREEN);

TestPointX := ScreenWidth div 2;

TestPointY := DWORD{ScreenHeight - 10);

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

Перейти на страницу:

Похожие книги