Як боротися з кутовими зіткненнями в 2D?


22

Я пишу гру "2d XNA" зверху вниз. З моєї першої я намагаюся писати фізику та речі зіткнення, щоб навчитися цьому.

Кожен раз, коли мій символ спрайта гравця намагається перейти в положення, де його межі перетинаються з краєм стіни, я визначаю кут відскоку (кут падіння = кут відображення), і я змушую гравця відскакувати від стіни і уникати зіткнення .

У мене виникають труднощі з розумінням того, як вирішити ситуацію, коли мій спрайт перетинається з двома краями стіни одночасно, хоча, наприклад, він потрапляє в кут.

кутове зіткнення

На даний момент мій код говорить про те, що два краї стіни перетиналися, але не той край, який би вдарив спочатку, а отже, який край відскакувати.

Що таке математичний тест, щоб вибрати край, який слід відскочити? Зрозуміло це, дивлячись на це, але я намагаюся розібратися з математичним тестом.



Дякую Тетрад. Я бачив це, але, схоже, м'яч поводився б по-різному до моєї прямокутної проблеми. У випадку, зображеному вище, прямокутний спрайт потрапив би в нижній край стіни і відскочив від неї. Бічний край стіни ніколи б не ввійшов у рівняння. Я просто не знаю, як це виразити в коді та прийняти це рішення.
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

(Це передбачає X-праву систему Y-up координат.) Загалом, вам потрібно буде використовувати знаки X і Y компонентів player.velocity, щоб визначити, яку пару країв потрібно перевірити. У будь-якому випадку, коли ви обчислюєте час зіткнення, більш раннє з двох - це зіткнення, з яким вам потрібно впоратися.


1
Чи можете ви надати приклад того, як можна було реалізувати дві ваші змінні?
BjarkeCK

1

Вам потрібно SAT Collision Detection

В основному потрібно шукати вектор мінімального переміщення, який, підданий одному з об'єктів, не дозволяє їм перетинатися.

У вашому зображенні мінімальний зсув - це помаранчевий сегмент.

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


4
-1 оскільки мінімальний зсув не завжди дає правильну відповідь на те, "який край зіткнувся перший"; дивіться мою відповідь.
Натан Рід

хто це запитує?
Блау

Питання це задає. "Мій код наразі говорить про те, що два краї стіни перетиналися, але не той край, який би вдарив спочатку, а отже, який край відскакувати".
Натан Рід

спочатку? проблема не в тому, що є першим, вона стикається з двома краями одночасно, ... справа в тому, який край відскочити, ви вибрали один спосіб, який вам підходить, я вибрав метод, який є добре для мене, обидва дійсні
Блау

1
Якщо ви хочете прийняти дизайнерське рішення, щоб дозволити предметам ковзати повз один одного так, ніби вони були закруглені або скошені по кутах, це ваше рішення, і цілком може бути правильним для вашого геймплея. Але я не думаю, що питання задається питанням дизайнерського рішення; Математично задається питанням, як відбити прямокутні прямокутники один від одного. Це не питання тлумачення; ця математична проблема має чітку і правильну відповідь, на який край відскакувати.
Натан Рід

0

Відповів подібне питання тут

Ви можете розглянути можливість перевірки попередніх позицій-

Наприклад: якщо ваш лівий бік раніше був праворуч від їх правого боку, і ви стикаєтесь, то сталося зіткнення правої руки.

Якщо ви це зробите, просто вирішіть зіткнення y осі, перевірте, чи не стикаєтесь ні з чим, а потім вирішіть зіткнення по осі x.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.