Чтение онлайн

ЖАНРЫ

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

Трухильо Стэн

Шрифт:

Если ограничивающие прямоугольники пересекаются, необходимо продолжить проверку. Мы вызываем функцию SpritesCollidePixel и также передаем ей два указателя на объекты Sprite. Если эта проверка окажется неудачной, SpritesCollide возвращает FALSE; в противном случае она возвращает TRUE, что говорит о столкновении спрайтов.

Перед тем как рассматривать процедуру проверки на уровне пикселей, давайте рассмотрим функцию 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;

}

Функция SpritesCollidePixel состоит из четырех этапов. Она делает следующее:

1. Определяет положения и размеры обоих спрайтов, а также вычисляет область их пересечения.

2. Вычисляет области спрайтов, для которых потребуется проверка на уровне пикселей.

3. Если оба спрайта находятся на одной поверхности — выполняет проверку, для чего сначала блокирует поверхность, а затем просматривает ее память в соответствии с положением обоих спрайтов. Если спрайты находятся на разных поверхностях, функция блокирует обе поверхности и просматривает память каждой из них.

4. Снимает блокировку с обеих поверхностей и возвращает TRUE или FALSE.

На этапе 1 мы инициализируем два объекта CRect функцией Sprite::GetRect. Функция GetRect возвращает прямоугольник CRect, представляющий положение и размеры спрайта. Затем оператор & (оператор пересечения класса CRect) определяет область пересечения двух прямоугольников. Ниже снова приведен соответствующий фрагмент листинга 9.1:

Поделиться с друзьями: