простой алгоритм столкновения прямоугольника 2D, который также определяет, с какими сторонами сталкиваются прямоугольники?

16

Сначала я попробовал реализовать прямоугольное пересечение, которое хорошо работает. Однако, когда мне нужно применить физическую систему, такую ​​как векторы скорости, ускорения и направления, мне нужно будет найти способ определить, какая сторона прямоугольников сталкивается. Теперь в моей системе нет повернутого прямоугольника, поэтому это упростило проблему. Однако я не мог найти простой способ определить, какая сторона прямоугольника столкнулась. Я уже однажды имел дело с этой проблемой, но с треском провалился.

В прошлом я определял расстояние между каждой параллельной прямоугольной стороной и проверял, близко ли это расстояние к 0 (используйте некоторый первоначально определенный диапазон расстояний) или равно 0. Однако для арифметики с плавающей точкой это оказывается нестабильным, поскольку неизвестного времени. Иногда прямоугольники фактически пересекаются друг с другом, прежде чем они достигнут определенного диапазона.

С другой стороны, я думал о создании нескольких прямоугольников, каждый прямоугольник для каждой стороны. Однако, подумав еще раз, это будет то же самое, что параллельная сторона с проверкой диапазона расстояний, просто этот диапазон расстояний является шириной каждого мини-прямоугольника.

Поэтому какое-либо предложение к этой проблеме?

user1542
источник
Вы используете дискретное или непрерывное обновление позиции? (Вы обновляете свою скорость с помощью ускорения один раз за каждый кадр, а затем вычисляете положение или используете функцию для экстраполяции положения)
Кейси Кубалл

Ответы:

24

Адаптировано из моего ответа "Какая сторона была поражена?" :

Я предлагаю вычислить сумму Минковского для B и A, которая является новым прямоугольником, и проверить, где находится центр прямоугольника A относительно этого нового прямоугольника (чтобы узнать , происходит ли столкновение) и его диагоналей (чтобы узнать, где произошло столкновение). это происходит):

float w = 0.5 * (A.width() + B.width());
float h = 0.5 * (A.height() + B.height());
float dx = A.centerX() - B.centerX();
float dy = A.centerY() - B.centerY();

if (abs(dx) <= w && abs(dy) <= h)
{
    /* collision! */
    float wy = w * dy;
    float hx = h * dx;

    if (wy > hx)
        if (wy > -hx)
            /* collision at the top */
        else
            /* on the left */
    else
        if (wy > -hx)
            /* on the right */
        else
            /* at the bottom */
}
Сэм Хоцевар
источник
1
Я хотел бы добавить, что «верх» и «низ» относятся к вашей системе координат. Например, в моей игре (0,0) вверху слева, поэтому они инвертированы из вашего примера. Просто что-то иметь в виду.
Neikos
отличное решение, очень хорошо сработало для моих нужд.
Opiatefuchs
1
Есть ли какой-то сбой, когда dx становится 0 или dy становится 0 или и тем, и другим? Позвольте мне объяснить это ... если dx = 0 && dy == 0, это означает, что оба прямоугольника находятся в одном и том же источнике, то алгоритм возвращает основание по умолчанию? если любой из них равен 0, то ожидается правильный результат. Так что, я думаю, этот алгоритм корректен за исключением случая, когда dx == 0 && dy == 0, который должен быть неопределенным, а не нижним. Итак, будьте осторожны и спасибо.
Prasanth
1
Теперь мне было интересно, что происходит, когда dx == dy, w == h ... тогда и код решает, что результат равен одной стороне, когда он на самом деле не определен ... представьте, что два квадрата пересекаются так, что центр одного квадрата находится в угол другого квадрата и центр другого квадрата в углу первого квадрата. Здесь сторона должна быть неопределенной - она ​​не правая или нижняя. Это оба ?!
Prasanth