Многоразовый класс столкновений сверху вниз

8

Я недавно взял моногам и работаю над простой игрой сверху вниз, чтобы начать и изучить основы.
У меня есть движение и вращение, чтобы следовать за мышью, но я застрял в столкновениях.
То, что я хочу знать, в основном, две вещи:

  1. Как лучше всего справляться со столкновениями? Я знаю, что это Rectangle.Intersects(Rectangle1, Rectangle2)возвращает перекрывающийся прямоугольник, но, поскольку движение сверху вниз происходит по оси x / y, я хотел бы знать, где происходит столкновение, поэтому я могу создать своего рода «скольжение по стене», когда игрок не получает застрял на стене.
    Является ли проверка координат х / у игроков по координатам твердых объектов, а затем бросить игрока в его предыдущее положение, если он входит в границы твердого объекта, действительно лучший подход? Что ты предлагаешь?
  2. Что было бы лучшим способом применить столкновения ко всем телам, NPC и т. Д.? В настоящее время я думаю о создании gameObjectкласса, от которого все объекты будут наследовать и просто обрабатывать столкновения там.

Спасибо за чтение и надеюсь, что кто-то может дать мне несколько советов.

Элия ​​Джон
источник
Для некоторых мыслей по поводу вашего второго вопроса, посмотрите на этот ответ об игровой архитектуре .
Эндрю Рассел

Ответы:

9

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


Так что, если ваши объекты представлены прямоугольниками (также известными как «Выровненные ограничивающие прямоугольники оси»), и они сталкиваются в данном кадре следующим образом:

коллизия


Затем вы должны измерить количество взаимопроникновения на каждой оси. Затем выберите ось с наименьшим количеством взаимопроникновения и разделите объекты вдоль этой оси.

отдельный


Затем вы зарегистрируете это как «столкновение» и примените соответствующую динамику.

Например, если вы хотите скользить вдоль стены, вы просто обнулите скорость на оси, которую вы разделили (ось X, на рисунке выше), оставив скорость только на другой оси.

Но вы также можете применить трение или заставить объекты отскакивать друг от друга.


Вот отличный интерактивный учебник, который показывает, как сделать это более подробно.

Хотя, если вы собираетесь пойти далеко по этому пути (что-то большее, чем простые AABB-коллизии), вы можете рассмотреть возможность использования существующего механизма, такого как Farseer Physics .


Наконец, примечание о реализации (если вы не идете по пути Farseer): Rectangleиспользуются intзначения, которые в большинстве случаев не подходят для физики. Попробуйте создать свой собственный AABBкласс, который использует floatвместо этого.

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

Эндрю Рассел
источник
Может быть, есть кое-что, чего я не понимаю, но разве этот подход не ошибочен? Я проиллюстрировал проблему здесь: jmp.sh/jEW2lvR Это иногда приводило бы к странному поведению.
BjarkeCK
@BjarkeCK: Да, вам нужно проделать дополнительную работу для обработки подобных случаев. Я недостаточно хорошо разбираюсь, чтобы полностью объяснить, как правильно с ними обращаться (я просто использую Farseer и называю это днем). Возможно, взгляните на «Раздел 5» этой ссылки .
Эндрю Рассел
1

1: Я также работал над относительно простой игрой сверху вниз, и после недели (-ов?) Борьбы я использовал своего рода пошаговый подход к обнаружению столкновений и реагированию на них. Основная причина заключается в том, что использование кратчайшего количества взаимопроникновения в некоторых случаях приведет к «телепортации» в новую позицию, в которой ранее не было движущегося объекта.

поэтому, когда объект хочет двигаться,

  1. Я создаю ограничивающую рамку объекта в позиции объекта + вектор moveAmount, создавая своего рода целевую ограничивающую рамку
  2. затем я проверяю этот ограничивающий прямоугольник на предмет любых пересечений с игровыми объектами, плитками и т. д., если они есть, я добавляю их в новый список, который содержит все потенциальные столкновения для текущего кадра
  3. если пересечений нет, объект движется. но если есть пересечение,
  4. Я разделил искомое движение на «ступеньки». затем я запускаю цикл для количества шагов, которые у меня есть. каждый шаг перемещает объект только на 1 пиксель в направлении x и y.
  5. для каждого шага я проверяю каждую новую спроецированную позицию на наличие столкновений, если ничего не добавляю, я добавляю вектор движения шага в окончательный вектор движения.
  6. если есть столкновение (пересечение возвращает true), я сравниваю предыдущую позицию (позицию на предыдущем шаге) движущегося объекта с тем, с чем он сталкивается.
  7. в зависимости от этой предыдущей позиции я прекращаю движение вдоль конфликтующей оси (например, если движущийся объект сталкивается с сталкивающимся объектом сверху, я устанавливаю значение y вектора перемещения равным 0 и т. д.).
  8. Я повторяю это для каждого последующего шага, складывая скорректированные векторы шагов вместе, чтобы сделать один окончательный скорректированный вектор moveAmount, который я могу безопасно использовать для перемещения объекта без каких-либо столкновений.

этот подход гарантирует, что объект «отскакивает» назад, чтобы исправить предыдущее положение, и он позволяет скользить по стенам, объектам, чему угодно.

2: я сам использую статический класс столкновения, который может использоваться чем угодно. он содержит методы обнаружения столкновений и векторной корректировки, которые можно вызывать практически любым способом. в моем случае это не имеет значения, вызваны ли эти методы из "мастерского" класса игры или каким-либо подклассом объекта, потому что класс столкновений создает новый список каждый кадр для всех прямоугольников, с которыми пересекается движущийся объект. эти прямоугольники могут быть из плиток, украшений, неигровых персонажей, независимо от того, что имеет границы и является встречным. это означает, что абсолютная необходимость для всех игровых объектов, которые могут сталкиваться, состоит в том, чтобы иметь границы прямоугольника. если они есть, класс столкновений будет обрабатывать все остальное.

надеюсь, это было понятно.

средний
источник
0

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

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

2: я всегда рекомендую Entity-Systems .

Филипе Борхес
источник