DirectX Графика в проектах Delphi



         

Проверка столкновений - часть 6


procedure TfrmDD.FormDestroy(Sender: TObject);
var
i : Integer;
begin
if Assigned(FDD) then begin
if Assigned(FDDPal) then FDDPal := nil;
for i := 0 to NumSprites - 1 do begin
if Assignedfspr [i].FSpriteSurface) then begin spr [i].FSpriteSurface._Release;
spr [i].FSpriteSurface := nil;
end;
spr [i].Free;
end;
if Assigned(FDDSPrimary) then begin FDDSPrimary. Release;
FDDSPrimary := nil;
end;
FDD._Release; FDD := nil;
end;
end;

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

function TfrmDD.SpritesCollidePixel(Spritel, Sprite2 : TSprite) : BOOL;
var
Rectl : TRect;
Rect2 : TRect;
IRect : TRect;
rltarget : TRect;
r2target : TRect;
locWidth : Integer;
locHeight : Integer;
Descl, Desc2 : TDDSURFACEDESC2;
Ret : BOOL;
Surfptrl : POINTER; // Указатели на начало области памяти поверхности
Surfptr2 : POINTER;
Pixel1 : PBYTE; // Пикселы поверхностей
Pixel2 : PBYTE;
XX, YY : Integer;
label
Done ;
begin
// Прямоугольники, ограничивающие спрайты
Rectl := Spritel.GetRect;
Rect2 := Sprite2.GetRect;
// Вычисляем точку пересечения прямоугольников
IntersectRect (IRect, Rectl, Rect2);
// Если нет пересечения прямоугольников, спрайты сталкиваться не могут
if (IRect.Left = 0) and (IRect.Top = 0) and
(IRect.Right = 0) and (IRect.Bottom = 0) then begin
Result := FALSE;
Exit;
end;
// Находим положение области пересечения для каждого спрайта
IntersectRect (rltarget, Rectl, IRect);
OffsetRect(rltarget, -Rectl.Left, -Rectl.Top);
IntersectRect (r2target, Rect2, IRect);
OffsetRect(r2target, -Rect2.Left, -Rect2.Top);
r2target.Right := r2target.Right - 1;
r2target.Bottom := r2target.Bottom - 1;
// Предыдущие две строки обеспечивают корректное нахождение
// размеров области пересечения
locWidth := IRect.Right - IRect.Left;
locHeight := IRect.Bottom - IRect.Top;
// Подготавливаем структуры для работы с памятью поверхностей
ZeroMemory (gdescl, SizeOf(descl));
descl.dwSize := SizeOf(descl);
ZeroMemory (@desc2, SizeOf(desc2));
desc2.dwSize := SizeOf(desc2);
Ret := False;
// Запираем поверхности спрайтов
Spritel.FSpriteSurface.Lock(nil, descl, DDLOCK_WAIT, 0) ;
Surfptrl := descl.IpSurface;
Sprite2.FSpriteSurface.Lock(nil, desc2, DDLOCK_WAIT, 0) ;
Surfptr2 := desc2.IpSurface;
// Просмотр содержимого пикселов для каждого спрайта
//в пределах области пересечения
for YY := 0 to locHeight - 1 do
for XX := 0 to locWidth - 1 do begin
// Для оптимизации эти действия можно свернуть в одну строку
Pixell := PByte (Integer (Surfptrl) + (yy+rltarget.Top) *descl. IPitcht (xx+rltarget.Left));
Pixel2 := PByte (Integer (Surfptr2) + (yy+retarget. Top) Mesc2 . IPiccr,. (xx+r2target.Left));
if (Р1хе11Л о 191) and (Pixel2A <> 191) then begin
Ret := True; // Найдено пересечение, выходим
goto Done;
end;
end;
Done:
Sprite2.FSpriteSurface.Unlock(nil);
Spritel.FSpriteSurface.Unlock(nil);
Result := Ret;
end;




Содержание  Назад  Вперед