Стэн Трухильо - Графика для Windows средствами DirectDraw
- Название:Графика для Windows средствами DirectDraw
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стэн Трухильо - Графика для Windows средствами DirectDraw краткое содержание
Графика для Windows средствами DirectDraw - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
3. Если оба спрайта находятся на одной поверхности — выполняет проверку, для чего сначала блокирует поверхность, а затем просматривает ее память в соответствии с положением обоих спрайтов. Если спрайты находятся на разных поверхностях, функция блокирует обе поверхности и просматривает память каждой из них.
4. Снимает блокировку с обеих поверхностей и возвращает TRUEили FALSE.
На этапе 1 мы инициализируем два объекта CRectфункцией Sprite::GetRect(). Функция GetRect()возвращает прямоугольник CRect, представляющий положение и размеры спрайта. Затем оператор &(оператор пересечения класса CRect) определяет область пересечения двух прямоугольников. Ниже снова приведен соответствующий фрагмент листинга 9.1:
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));
Как мы узнали из функции SpritesCollideRect(), оператор пересечения класса CRectобнуляет все четыре поля CRect, если операнды не пересекаются. В этом случае функцию SpritesCollidePixel()вызывать не следует, поэтому о такой ситуации сообщает макрос ASSERT().
На этапе 2 мы вычисляем область каждого спрайта, для которой должна осуществляться проверка пикселей. Для этого снова используется оператор пересечения:
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--;
В прямоугольниках r1targetи r2targetхранятся области спрайтов, для которых потребуется проверка на уровне пикселей. После того как пересечение будет найдено, оба прямоугольника сдвигаются функцией CRect::OffsetRect()так, чтобы левый верхний угол имел координаты (0, 0). Это объясняется тем, что поля rightи bottomобъектов CRectбудут использоваться для обращений к поверхностям обоих спрайтов, а это требует перехода к локальным системам координат этих поверхностей.
Также обратите внимание на то, что правый и нижний края каждого прямоугольника обрезаются на один пиксель. Это связано с особенностями реализации CRect.
Кое-что о классе CRect
Класс MFC CRectреализован так, чтобы при вычитании поля leftиз поля rightполучалась ширина прямоугольника. Такой подход удобен, но смысл поля rightнесколько изменяется. Например, рассмотрим прямоугольник, у которого поле leftравно 0, а полю rightприсвоено значение 4. В соответствии с реализацией класса CRectтакой прямоугольник имеет ширину в 4 пикселя, но если использовать эти же значения для обращений к пикселям, ширина прямоугольника окажется равной 5 пикселям (поскольку в нее будут включены пиксели с номерами от 0 до 4). Такие же расхождения возникают и для полей topи bottom. Следовательно, чтобы использовать поля CRectдля работы с пикселями, необходимо уменьшить на 1 значения полей rightи bottom.
Настоящая проверка столкновений происходит на этапе 3. Способ ее выполнения зависит от того, используют ли оба спрайта одну и ту же поверхность или нет. Сначала мы получаем поверхности обоих спрайтов функцией Sprite::GetSurf():
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
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;
}
Сначала мы блокируем поверхность, чтобы получить доступ к ее памяти. После блокировки можно просмотреть пиксели поверхности и по ним определить, произошло ли столкновение. Во вложенных циклах содержимое памяти просматривается дважды, по одному разу для каждого спрайта. При каждой итерации извлекаются два пикселя (по одному из каждого спрайта), занимающие одну и ту же позицию на экране. Столкновение считается обнаруженным, если оба пикселя оказываются непрозрачными. Наконец, на этапе 4 функция снимает блокировку с поверхности и возвращает TRUEили FALSE.
Если два спрайта находятся на разных поверхностях, проверка столкновений выполняется другим фрагментом функции SpritesCollidePixel(). Ниже снова приведен соответствующий фрагмент листинга 9.1:
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
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;
Этот фрагмент похож на приведенный выше, за исключением того, что в нем блокируются обе поверхности и каждая из них просматривается по отдельности. Столкновение снова обнаруживается по совпадению двух непрозрачных пикселей. Перед тем как функция возвращает TRUEили FALSE, она снимает блокировку с обеих поверхностей.
Класс Sprite
В коде предыдущего раздела класс Spriteиспользовался для представления спрайтов, проверяемых на столкновение. Давайте посмотрим, как он реализован.
Как мы уже видели, класс Spriteсодержит ряд функций, с помощью которых при проверке столкновений можно получить сведения о каждом спрайте. В частности, функция GetRect()возвращает контурный прямоугольник спрайта, а функция GetSurf()— поверхность, на которой находится спрайт. Однако класс Spriteне ограничивается функциями простого контейнера для данных спрайта. Он предназначен не столько для обнаружения столкновений, сколько для их обработки.
На обнаруженное столкновение необходимо как-то прореагировать. Подробности обработки столкновения определяются приложением, но как проверка, так и обработка подчиняются некоторым общим правилам.
При столкновении двух спрайтов каждый из них может изменить направление движения или измениться иным образом (например, исчезнуть из кадра, как это бывает при уничтожении цели в компьютерных играх). Тем не менее необходимо соблюдать осторожность и не изменять статус спрайта до тех пор, пока проверка столкновений не будет выполнена для всех спрайтов. В противном случае могут возникнуть непредсказуемые ошибки.
Читать дальшеИнтервал:
Закладка: