описана нестандартная версия ASSERT(), использованная в программах этой книги.

Затем функция SpritesCollide() проверяет, пересекаются ли ограничивающие прямоугольники двух спрайтов. Эта проверка выполняется функцией SpritesCollideRect(), которая, как и SpritesCollide(), получает два указателя на объекты Sprite и возвращает логическое значение. Если прямоугольники не пересекаются (то есть SpritesCollideRect() возвращает FALSE), дальнейшая проверка не нужна, и функция возвращает FALSE — это означает, что два спрайта не сталкиваются.

Если ограничивающие прямоугольники пересекаются, необходимо продолжить проверку. Мы вызываем функцию 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.

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату