Обнаружение столкновения: куча особых случаев?

8

Я пишу простой физический движок в 2D. Моя первая цель - заставить работать обнаружение столкновений. Я знаю, что мои объекты в конечном итоге будут состоять из примитивных форм, но мне было интересно - будет ли библиотека обнаружения столкновений состоять из набора специальных функций, таких как «rayAndLine», «rectangleRectangle», «rectangleCircle» и т. Д., Или Существует ли общая базовая структура для обнаружения столкновений, которая работает независимо от того, какие примитивы используются для создания формы?

Михаил Стаховский
источник
Вы спрашиваете о базовой структуре, но конкретно заявляете, что хотите создать эту часть самостоятельно. Можете ли вы прояснить последнее предложение, в котором возникает ваш фактический вопрос, чтобы более конкретно отделить вашу заботу о его создании от использования чужой структуры, которую они создали. Я также предоставлю ответ.
Джошуа Хеджес
Честная оценка. Я имел в виду основную теорию, из которой вытекает все обнаружение столкновений. Другими словами, если я пишу подсистему обнаружения коллизий, нужно ли мне писать одну функцию для каждого типа примитива / примитивного коллизии, или есть одна общая функция, которая работает независимо от того, какой это примитив?
Михаил Стаховский
Вроде. Я просто ответил на это. Есть некоторые, которые действительно хорошо обобщают решения, например, SAT работает для любого выпуклого многоугольника, и любой вогнутый многоугольник может быть разбит на выпуклые многоугольники, что заставляет его работать для любого многоугольника с некоторой работой. После этого вам придется специализироваться на кривых, сферах и овалах. Я обрисовал это ниже. Это большая тема для обсуждения, поэтому она длинная. Дайте мне знать, если у вас есть какие-либо вопросы о специфике или что-то еще
Джошуа Хеджес
2
Этот предыдущий вопрос об абстрагировании различных типов фигур также может быть полезен.
DMGregory
1
Чем больше общего кода, тем лучше. Если вы когда-нибудь использовали копирование и вставку, серьезно проверьте себя!
CorsiKa

Ответы:

9

Начало работы по обнаружению столкновений - отличная первая цель для вашего физического движка 2D. Хорошо, что вы решили, что сейчас вы конкретно работаете в 2D, поскольку не все правила в 2D работают в 3D, несмотря на большое количество алгоритмов, связанных с n-размерностью, в какой-то момент вы должны специализировать их (сделайте больше конкретный вариант, например, как перекрестное произведение удовлетворяет только идентичности Якоби в 3D).

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

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

Основные элементы этого процесса должны быть настолько абстрактными, насколько это возможно, в то время как элементарные элементы (наименьшие полезные фрагменты данных / методы) должны быть специфическими для отдельных целей и быть полезными для составления вместе. В нашем случае почти единственным полезным атомарным представлением является 2D-вектор, который должен быть единственным классом объекта, который допускает выражение структуры (x, y), и имеет методы для всех основных математических операций, которые полезны для векторных вычислений в 2D. Сложение, вычитание, нормализация, нормаль (перпендикулярно), кросс-произведение, скалярное произведение, величина / длина и все остальное, с чем вы сталкиваетесь, что конкретно присуще векторам -> векторным операциям или вектору -> действительным числам Если вы используете язык, основанный на классах, простое использование class Vectorкаждого из них как функции-члена или перегрузки оператора будет очень хорошо.

После того, как все атомарные типы будут построены, вы могли бы объединить их алгоритмы в другой слой поверх нашего атомарного типа Vector. Мое движение к будет Lineи Curve. Здесь мы решим, что a Curveвыходит за рамки этого и требует большой специализации (концепция, которую вы упоминаете выше как создание множества специальных случаев). Из Vectorя также хотел бы составить Rectangleкак Vectorпримитив 4 , составить Circleиз вектора с использованием а Vectorи а radius, а затем я бы также составить Polygonиз Vector. Polygonдолжен быть сделан из, Vectorа не Lineздесь, потому что каждая линия будет иметь двойную точку с последней линией в многоугольнике.

Теперь у вас есть фигуры, но мы не знаем, что с ними делать.

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

Обнаружение коллизий с широкой фазой - это процесс разделения областей, в которых мы заботимся о том, что может / могло / действительно сталкиваться, и разделяя их для узкофазного процесса. В 2D я бы обычно рекомендовал для этого использовать дерево квадов. Для этого нам понадобится наш, который Rectangleмы построили ранее, и обеспечить его обнаружением коллизий AABB. Это означает ограничивающий прямоугольник с выравниванием по оси, и мы используем его для определения того, что для невращающегося прямоугольника A, Bвнутри которого нет ни одной части прямоугольника A. Из предположения следует, что Bвнутри не может существовать никакой части, Aпоскольку столкновение существует, если они пересекаются.

Четырехъядерное дерево - это рекурсивный процесс, в котором вы определяете максимальную глубину или позволяете количеству объектов вместо этого предотвращать бесконечную глубину рекурсии. Он группирует физические тела в 4 области (отсюда и название) и должен позволять вам обращаться к каждому квадру отдельно. Затем вы входите в каждый из этих четырех четырехугольников и выполняете тот же процесс, который я не буду кратко описывать здесь, но он доступен здесь: https://gamedevelopment.tutsplus.com/tutorials/quick-tip-use-quadtrees- на обнаружение-вероятные-столкновений-в-2d пространства - Gamedev-374

Узкое фазовое столкновениеэто процесс прохождения ваших групп фигур, который мы уже определили, столкнется / может / действительно столкнуться и выполнит более дискретную проверку столкновения, в этот момент времени мы начинаем заботиться, вращаются ли объекты или нет (я выиграл ' Если вы пройдете эти фазы столкновения, посмотрите на обнаружение столкновения с угловым моментом) и какую форму на самом деле имеет их тело столкновения. Для выполнения этой части коллизии вы должны специализировать свои методы, как описано выше (создание специальных функций для AABBvsCircle, OBBvsCircle, CirclevsCircle, PolygonvsPoint, PolygonvsCircle, PointvsCircle и т. Д.). Однако сами эти методы также можно выполнять многоуровневым способом. как указано выше.

Ваши примитивные проверки разделения являются дискретными, специализированными методами обнаружения столкновений или общих из них , как СБ в зависимости от случая использования и все должно просто возвращать либо истинное / ложное значение, или возвращать реляционный объект , такие как Manifold, Joint, и CollisionObjectт.д. , которые будет иметь связь с двумя фигурами, находящимися в столкновении, и любой информацией о них, необходимой для разрешения столкновения, например, насколько глубоко они сталкиваются или с какой скоростью (какие данные вам нужны в вашем коллекторе, зависит от того, какой метод разрешения вы используете). Затем этот объект вы передаете объекту, Solverкоторый должен абстрагироваться от различий между всеми различными формами, которые могут столкнуться, принимая только Manifoldи не принимая какую-либо конкретную информацию о формах.

Резюме . SolverПримем Manifoldпроизведенное, столкнув некоторый примитив Aс некоторым примитивом B, используя сначала широкую фазовую группировку (все против мира), а затем узкую фазовую детекцию (A против B), и если формы не являются полигонными, они должны быть специализированными, Solverтогда получаются либо новые Vectors для позиций и скоростей столкнувшихся фигур, или объекта, который затем PhysicsEnvironmentили Worldможет использовать для разрешения столкновения на своих потомках, затем, наконец, обновите QuadTreeи повторите этот процесс для следующего кадра. Если обе сталкивающиеся фигуры являются полигонами, то специализация должна проводиться только с точки зрения увеличения производительности, в противном случае просто используется теорема о разделении осей.

Джошуа Хеджес
источник
1
Отличный ответ, спасибо. Мне любопытно, хотя: я изначально думал основывать свой самый примитивный объект на точке, а затем строить вектор оттуда. Я вижу из вашего ответа, что это не обязательно лучший выбор. Это почему?
Михаил Стаховский
1
Причина этого в том, что в двух измерениях вектор и точка имеют одно и то же определение. a Vector direction,Magnitudeможно принять как a, Point x,yесли вы просто игнорируете некоторые операции, которые Vectorпредоставляет. Лучшее в этом - то, что вы можете игнорировать эти операции сейчас, когда вы хотите определить такие вещи, как момент импульса, а не изменять типы объектов. Тогда это почти дело вкуса, потому что то, что разработчики игр называют «точечными», математики действительно называют «вектором». Поэтому называйте это как хотите, главное, что он предлагает.
Джошуа Хеджес
1
В языке стиля C, если бы я хотел использовать определение «Point» для читабельности, я бы просто использовал typedefего в векторе или псевдоним «Point», чтобы обозначать то же самое, что и «Vector».
Джошуа Хеджес