- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Графика для Windows средствами DirectDraw - Стэн Трухильо
Шрифт:
Интервал:
Закладка:
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:
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<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;
}
Сначала мы блокируем поверхность, чтобы получить доступ к ее памяти. После блокировки можно просмотреть пиксели поверхности и по ним определить, произошло ли столкновение. Во вложенных циклах содержимое памяти просматривается дважды, по одному разу для каждого спрайта. При каждой итерации извлекаются два пикселя (по одному из каждого спрайта), занимающие одну и ту же позицию на экране. Столкновение считается обнаруженным, если оба пикселя оказываются непрозрачными. Наконец, на этапе 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<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;
Этот фрагмент похож на приведенный выше, за исключением того, что в нем блокируются обе поверхности и каждая из них просматривается по отдельности. Столкновение снова обнаруживается по совпадению двух непрозрачных пикселей. Перед тем как функция возвращает TRUE или FALSE, она снимает блокировку с обеих поверхностей.
Класс Sprite
В коде предыдущего раздела класс Sprite использовался для представления спрайтов, проверяемых на столкновение. Давайте посмотрим, как он реализован.
Как мы уже видели, класс Sprite содержит ряд функций, с помощью которых при проверке столкновений можно получить сведения о каждом спрайте. В частности, функция GetRect() возвращает контурный прямоугольник спрайта, а функция GetSurf() — поверхность, на которой находится спрайт. Однако класс Sprite не ограничивается функциями простого контейнера для данных спрайта. Он предназначен не столько для обнаружения столкновений, сколько для их обработки.
На обнаруженное столкновение необходимо как-то прореагировать. Подробности обработки столкновения определяются приложением, но как проверка, так и обработка подчиняются некоторым общим правилам.
При столкновении двух спрайтов каждый из них может изменить направление движения или измениться иным образом (например, исчезнуть из кадра, как это бывает при уничтожении цели в компьютерных играх). Тем не менее необходимо соблюдать осторожность и не изменять статус спрайта до тех пор, пока проверка столкновений не будет выполнена для всех спрайтов. В противном случае могут возникнуть непредсказуемые ошибки.
Рассмотрим столкновение, в котором участвуют два спрайта. Наш код должен обнаруживать столкновение и сообщать об этом спрайтам. Предположим, один из спрайтов получает уведомление, немедленно вычисляет новую траекторию и изменяет свое положение. Когда сообщение о столкновении дойдет до второго спрайта, столкнувшийся с ним спрайт уже будет находиться в новом месте. Более того, перемещение первого спрайта может привести к тому, что для второго спрайта предыдущего столкновения как бы и не будет.