Как бороться с угловыми столкновениями в 2D?

22

Я пишу 2D-игру XNA сверху вниз. Так как это мой первый опыт, я сам пытаюсь написать материал по физике и столкновениям, чтобы изучить его.

Всякий раз, когда мой спрайт-игрок пытается переместиться в положение, где его границы пересекаются с краем стены, я определяю угол отскока (угол падения = угол отражения) и заставляю игрока отскакивать от стены и избегать столкновения. ,

У меня проблемы с выяснением, как справиться с ситуацией, когда мой спрайт пересекается с двумя краями стены одновременно, хотя, например, он попадает в угол.

угловое столкновение

Мой код в настоящее время говорит мне, что два края стены были пересечены, но не то, по какому краю он бы ударил первым и, следовательно, по какому краю отскочить.

Что такое математический тест, чтобы выбрать, какой край отскочить? Это легко увидеть, глядя на это, но я изо всех сил пытаюсь выяснить математический тест для этого.

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

Ответы:

9

Если подсчитать , как далеко в переместилась, вы , вероятно , может основывать его на дельте х и у координаты углов, которые пересекаются. Я надеюсь, что это имеет смысл, я не могу придумать лучшего способа выразить это.WallPlayer Sprite

Так, например, если вы посмотрите на свою диаграмму. Возьмите xзначение верхнего левого угла Player Sprite(после перемещения) и вычтите xзначение нижнего правого угла Wall. Сделайте то же самое для yзначений, а затем посмотрите, какое из них больше. Ключ в том, что если один больше другого, то, Player Spriteвероятно, пересекается на этой стороне.

Вот пример изображения (это подраздел вашего изображения с добавленными моими собственными строками):

пример пересечения

Теперь вы видите, что синяя линия больше, чем зеленая. В этом случае синяя линия также находится на той стороне, от Player Spriteкоторой можно было бы ожидать отскока.

Если два значения равны, они попадают прямо в угол.

Теперь есть небольшая проблема с этим. Если Player Spriteон движется очень быстро или столкновение находится очень близко к углу, возможно, что оно Player Spriteпойдет дальше Wallв неправильном направлении. В этом случае вам, вероятно, придется проверить скорость движущегося объекта. (См . Ответ Натана Рида .)

Примечание: я думаю, что по сути пытаюсь описать обнаружение коллизий SAT, о котором упоминал @Blau, но я потратил много времени на написание этого, поэтому я все равно опубликую его. Надеюсь, это поможет вам.

Ричард Марскелл - Дракир
источник
Спасибо Дракир! И я предполагаю, что если моя стена вращается относительно спрайта, это немного сложнее, но тот же принцип применим. Ищите минимальный вектор смещения длины, который будет означать, что спрайт не столкнется со стеной. Затем используйте стену, которая является нормальной для этого вектора, как мою, чтобы отскочить.
TerryB
@TerryB - Вращение добавляет немного больше сложности. Возможно, вы захотите прочитать о выровненных по оси ограничивающих прямоугольниках (AABB). По сути, вы все еще используете тот же принцип, что и выше, проверяя наименьший прямоугольник, в который будет помещаться повернутый объект, но оси которого выровнены по декартовым осям. Представьте, что у вас есть квадрат и вы повернули его на 45 градусов, чтобы сделать его ромбом. Расчет столкновения на этом будет трудным и дорогостоящим, поэтому сначала проверьте, находится ли объект даже рядом с ним, используя AABB, представляющий собой квадрат, где каждая точка алмаза касается каждой стороны в середине.
Ричард Марскелл - Дракир
Затем, когда вы узнаете, что он рядом, вы можете выполнить более дорогостоящие вычисления, чтобы увидеть, пересекаются ли они по углам (что, вероятно, должно быть совсем другим вопросом :)).
Ричард Марскелл - Дракир
1
-1, поскольку минимальное смещение не всегда дает правильный ответ на вопрос «какой край столкнулся первым»; смотри мой ответ.
Натан Рид
@NathanReed - Именно поэтому я упомянул проверку скорости в моем параграфе «Теперь, есть небольшая проблема с этим».
Ричард Марскелл - Дракир
15

Минимальное смещение не всегда дает правильный ответ, для которого край был достигнут первым. Рассмотрим этот случай:

случай, который нарушает алгоритм кратчайшего смещения

Это происходит, когда скорость достаточно высока, чтобы блок перемещался довольно далеко в течение одного кадра. Чтобы правильно определить, какое ребро было нанесено первым, вам нужно будет установить линейное уравнение, которое нужно решить на время столкновения с каждым ребром. В этом случае, описанном в схеме ОП, соответствующие уравнения:

timeXCollision = (player.left - wall.right) / -player.velocity.x
timeYCollision = (wall.bottom - player.top) / player.velocity.y

(Предполагается, что система координат по оси Y направлена ​​вверх по оси Y.) В общем, вам придется использовать знаки компонентов X и Y player.velocity, чтобы определить, какую пару ребер необходимо проверить. В любом случае, как только вы вычислили время столкновения, более раннее из двух столкновений - это то, с чем вам нужно справиться.

Натан Рид
источник
1
Не могли бы вы привести пример того, как ваши две переменные могут быть реализованы?
BjarkeCK
1

Вам нужно SAT Collision Detection

По сути, вам нужно искать минимальный вектор смещения, который вычитается одному из объектов, чтобы они не пересекались.

На вашем изображении минимальное смещение - оранжевый сегмент.

введите описание изображения здесь

Blau
источник
4
-1, поскольку минимальное смещение не всегда дает правильный ответ на вопрос «какой край столкнулся первым»; смотри мой ответ.
Натан Рид
кто это спрашивает?
Блау
Вопрос задает это. «Мой код в настоящее время говорит мне, что два края стены были пересечены, но не то, по какому краю он бы ударил первым и, следовательно, по какому краю отскочить».
Натан Рид
первый? проблема не в том, что является первым, оно сталкивается с двумя ребрами одновременно, ... дело в том, какой край отскочить, вы выбрали один метод, который вам подходит, я выбрал метод, который хорошо для меня, оба действительны
Блау
1
Если вы хотите принять дизайнерское решение, чтобы объекты проходили мимо друг друга, как если бы они были закруглены или скошены по углам, это ваше решение, и оно вполне может быть правильным для вашего игрового процесса. Но я не думаю, что вопрос заключается в проектном решении; он математически спрашивает, как отразить выровненные по оси прямоугольники друг от друга. Это не вопрос интерпретации; эта математическая задача имеет четкий и правильный ответ, от какого края отскочить.
Натан Рид
0

Ответили на подобный вопрос здесь

Вы можете рассмотреть возможность проверки предыдущих позиций

Например: если ваша левая сторона была ранее справа от их правой стороны, и вы сталкиваетесь, то произошло столкновение правой руки.

Если вы сделаете это, просто разрешите столкновения по оси Y, проверьте, сталкиваетесь ли вы с чем-либо, затем разрешите столкновения по оси X.

ultifinitus
источник