Графика для Windows средствами DirectDraw



Функции проверки столкновений - часть 3


Перед тем как рассматривать процедуру проверки на уровне пикселей, давайте рассмотрим функцию SpritesCollideRect(), в которой проверяется пересечение ограничивающих прямоугольников:


BOOL SpritesCollideRect(Sprite* sprite1, Sprite* sprite2) { CRect rect1 = sprite1->GetRect(); CRect rect2 = sprite2->GetRect(); CRect r = rect1 & rect2;

// Если все поля равны нулю, прямоугольники не пересекаются return !(r.left==0 && r.top==0 && r.right==0 && r.bottom==0); }


Пересечение ограничивающих прямоугольников проверяется в функции SpritesCollideRect() с помощью класса MFC CRect. Сначала для каждого спрайта вызывается функция Sprite::GetRect(). Она возвращает объект CRect, определяющий текущее положение и размеры каждого спрайта. Затем третий объект CRect инициализируется оператором пересечения класса CRect (& ), который вычисляет область пересечения двух своих операндов. Если пересечения не существует (два прямоугольника не перекрываются), все четыре поля CRect обнуляются. Этот признак используется для возврата TRUE в случае пересечения прямоугольников, и FALSE — в противном случае.

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

Листинг 9.1. Функция SpritesCollidePixel()


BOOL SpritesCollidePixel(Sprite* sprite1, Sprite* sprite2) { CRect rect1=sprite1->GetRect(); CRect rect2=sprite2->GetRect();

CRect irect = rect1 & rect2;

ASSERT(!(irect.left==0 && irect.top==0 && irect.right==0 && irect.bottom==0)); CRect r1target = rect1 & irect; r1target.OffsetRect( -rect1.left, -rect1.top ); r1target.right--; r1target.bottom--;

CRect r2target = rect2 & irect; r2target.OffsetRect( -rect2.left, -rect2.top ); r2target.right--; r2target.bottom--;

int width=irect.Width(); int height=irect.Height();

DDSURFACEDESC desc1, desc2; ZeroMemory( &desc1, sizeof(desc1) ); ZeroMemory( &desc2, sizeof(desc2) ); desc1.dwSize = sizeof(desc1); desc2.dwSize = sizeof(desc2);

BYTE* surfptr1; // Указывает на начало памяти поверхности BYTE* surfptr2; BYTE* pixel1; // Указывает на конкретные пиксели BYTE* pixel2; // в памяти поверхности BOOL ret=FALSE;

LPDIRECTDRAWSURFACE surf1=sprite1->GetSurf(); LPDIRECTDRAWSURFACE surf2=sprite2->GetSurf();

if (surf1==surf2) { surf1->Lock( 0, &desc1, DDLOCK_WAIT, 0 ); surfptr1=(BYTE*)desc1.lpSurface;

for (int yy=0;yy<height;yy++) { for (int xx=0;xx<width;xx++) { pixel1=surfptr1+(yy+r1target.top)*desc1.lPitch +(xx+r1target.left); pixel2=surfptr1+(yy+r2target.top)*desc1.lPitch +(xx+r2target.left); if (*pixel1 && *pixel2) { ret=TRUE; goto done_same_surf; } } }

done_same_surf: surf1->Unlock( surfptr1 ); return ret; }

surf1->Lock( 0, &desc1, DDLOCK_WAIT, 0 ); surfptr1=(BYTE*)desc1.lpSurface;

surf2->Lock( 0, &desc2, DDLOCK_WAIT, 0 ); surfptr2=(BYTE*)desc2.lpSurface;

for (int yy=0;yy<height;yy++) { for (int xx=0;xx<width;xx++) { pixel1=surfptr1+(yy+r1target.top)*desc1.lPitch +(xx+r1target.left); pixel2=surfptr2+(yy+r2target.top)*desc2.lPitch +(xx+r2target.left); if (*pixel1 && *pixel2) { ret=TRUE; goto done; } } }

done: surf2->Unlock( surfptr2 ); surf1->Unlock( surfptr1 );

return ret; }

<


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