Поскольку это основано на вашем другом вопросе, я дам решение, когда прямоугольник будет выровнен по оси.
Сначала вы строите прямоугольник текущего объекта со следующими значениями:
int boxLeft = box.X;
int boxRight = boxLeft + box.Width;
int boxTop = box.Y;
int boxBottom = boxTop + box.Height;
Далее у вас должна быть позиция старого объекта (которую вы можете сохранить на каждом объекте или просто передать функции), чтобы создать прямоугольник старого объекта (когда он не сталкивался):
int oldBoxLeft = box.OldX;
int oldBoxRight = oldBoxLeft + box.Width;
int oldBoxTop = box.OldY;
int oldBoxBottom = oldBoxTop + box.Height;
Теперь, чтобы узнать, откуда произошло столкновение, вы должны найти сторону, где старая позиция не находилась в зоне столкновения и где находится ее новая позиция. Потому что, когда вы думаете об этом, это то, что происходит, когда вы сталкиваетесь: сторона, которая не сталкивалась, входит в другой прямоугольник.
Вот как вы могли бы это сделать (эти функции предполагают наличие коллизии. Их не следует вызывать, если коллизии нет):
bool collidedFromLeft(Object otherObj)
{
return oldBoxRight < otherObj.Left && // was not colliding
boxRight >= otherObj.Left;
}
Ринс и повторить.
bool collidedFromRight(Object otherObj)
{
return oldBoxLeft >= otherObj.Right && // was not colliding
boxLeft < otherObj.Right;
}
bool collidedFromTop(Object otherObj)
{
return oldBoxBottom < otherObj.Top && // was not colliding
boxBottom >= otherObj.Top;
}
bool collidedFromBottom(Object otherObj)
{
return oldBoxTop >= otherObj.Bottom && // was not colliding
boxTop < otherObj.Bottom;
}
Теперь для фактического использования с ответом на столкновение из другого вопроса:
if (collidedFromTop(otherObj) || collidedFromBottom(otherObj))
obj.Velocity.Y = -obj.Velocity.Y;
if (collidedFromLeft(otherObj) || collidedFromRight(otherObj))
obj.Velocity.X = -obj.Velocity.X;
Опять же, это не может быть лучшим решением, но это так, как я обычно иду для обнаружения столкновений.
Поскольку вопрос частично идентичен этому вопросу , я буду использовать некоторые части своего ответа, чтобы попытаться ответить на ваш вопрос.
Давайте определим контекст и некоторые переменные, чтобы сделать следующее объяснение более понятным. Форма представления, которую мы будем использовать здесь, вероятно, не соответствует форме ваших собственных данных, но это должно быть проще для понимания (на самом деле вы можете использовать следующие методы, используя представления другого типа, как только вы поймете принцип)
Итак, мы рассмотрим выровненную ограничивающую ось (или ориентированную ограниченную рамку ) и движущуюся сущность .
Ограничительная рамка состоит из 4 сторон, и мы определим каждую из них как:
Side1 = [x1, y1, x2, y2] (две точки [x1, y1] и [x2, y2])
Движущийся объект определяется как вектор скорости (позиция + скорость):
позиция [posX, posY] и скорость [speedX, speedY] .
Вы можете определить, какая сторона AABB / OBB поражена вектором, используя следующий метод:
1 / Найти точки пересечения между бесконечными линиями, проходящими через четыре стороны AABB, и бесконечной линией, проходящей через позицию объекта (предварительное столкновение), которые используют вектор скорости объекта как наклон. (Вы можете найти точку столкновения или неопределенное число, которое соответствует параллелям или перекрывающимся линиям)
2 / Как только вы знаете точки пересечения (если они существуют), вы можете искать те, которые находятся в границах сегмента.
3 / Наконец, если в списке все еще есть несколько точек (вектор скорости может проходить через несколько сторон), вы можете искать ближайшую точку от начала объекта, используя величины вектора от пересечения до начала объекта.
Тогда вы можете определить угол столкновения с помощью простого точечного произведения.
----------
Больше деталей:
1 / Найти пересечения
a / Определить бесконечные линии (Ax + Bx = D), используя их параметрические формы (P (t) = Po + tD).
Я использовал значения точек сущности, чтобы проиллюстрировать метод, но это точно такой же метод, чтобы определить 4 боковые бесконечные линии ограничительной рамки (используйте Po = [x1, y1] и D = [x2-x1; y2-y1] вместо).
b / Далее, чтобы найти пересечение двух бесконечных линий, мы можем решить следующую систему:
который дает следующие координаты для перехвата:
Если знаменатель ((A1 * B2) - (A2 * B1)) равен нулю, то обе линии параллельны или пересекаются, в противном случае вы должны найти пересечение.
2 / Проверка границ сегмента. Поскольку это легко проверить, нет необходимости в дополнительных деталях.
3 / Поиск ближайшей точки. Если в списке все еще есть несколько точек, мы можем найти, какая сторона является ближайшей к исходной точке объекта.
a / Определить вектор, идущий от точки пересечения к точке происхождения объекта
б / Рассчитать векторную величину
4 / Теперь, когда вы знаете, какая сторона будет поражена, вы можете определить угол, используя точечное произведение.
а / Пусть S = [х2-х1; у2-у1] будет боковой вектор , который будет удар и Е = [SpeedX; Speedy] будет вектор скорости объекта.
Используя векторное правило скалярного произведения мы знаем , что
Таким образом, мы можем определить θ, немного манипулируя этим уравнением ...
с
Примечание. Как я уже говорил в другой ветке вопросов, это, вероятно, не самый эффективный и не самый простой способ сделать это, это только то, что приходит на ум, и некоторая часть математики может помочь.
Я не проверял конкретный пример OBB (я сделал с AABB), но он должен работать тоже.
источник
Простой способ - разрешить столкновение, а затем перевести блок столкновения движущегося объекта на один пиксель в каждом направлении по очереди и посмотреть, какие из них приводят к столкновению.
Если вы хотите сделать это «правильно» и с повернутыми формами столкновений или произвольными многоугольниками, я предлагаю прочитать теорему о разделяющей оси. Например, у программного обеспечения Metanet (создателей игры для N) есть отличная статья о SAT . Они также обсуждают физику.
источник
Одним из способов было бы вращать мир вокруг вашего прямоугольника. «Мир» в данном случае - это только те объекты, которые вас волнуют: прямоугольник и шар. Вы вращаете прямоугольник вокруг его центра до тех пор, пока его границы не выровняются с осями x- / y, а затем вращаете шар на ту же величину.
Важным моментом здесь является то, что вы вращаете шар вокруг центра прямоугольника, а не его собственного.
Тогда вы можете легко проверить на столкновение так же, как и с любым другим не повернутым прямоугольником.
Другим вариантом является обработка прямоугольника как четырех отдельных отрезков и проверка на столкновение с каждым из них в отдельности. Это позволяет вам проверить на столкновение и выяснить, какая сторона столкнулась одновременно.
источник
Я использовал фиксированные углы в моих расчетах, но это должно помочь вам
источник