Unity: игнорирование 2D-столкновений на основе таких контекстов, как траектория или скорость

Я просмотрел документацию и не могу найти способа добиться простейшего управления контактами с помощью встроенного физического движка.

У меня есть ситуация, когда 2D-столкновения следует игнорировать, когда, например, 2 объекта движутся в одинаковых направлениях с одинаковой скоростью (в основном, когда расстояние вычитания их векторов скорости слишком мало)...

Эти объекты находятся в слоях, которые определяют другие типы объектов, с которыми они должны сталкиваться в обычных обстоятельствах. Количество пересекающихся (и не сталкивающихся) объектов может увеличиваться произвольно. Таким образом, смена слоев не является жизнеспособным вариантом.

Используя обычный box2d, я бы использовал b2ContactListener.PreSolve для фильтрации объектов на основе их масок и дополнительных параметров в зависимости от масок. Что эквивалентно 2D API Unity?


person Coyote    schedule 24.07.2014    source источник
comment
Вы искали методы OnCollision___2D и OnTrigger___2D?? Вы можете изменить слой столкновения для разных направлений, и столкновения будут происходить автоматически.   -  person Savlon    schedule 24.07.2014
comment
@Savlon: Насколько я понимаю, OnCollision2D срабатывает после разрешения коллизий ... Я ошибаюсь? Если нет, есть ли способ отменить результат при его срабатывании? Я уже использую слои для 4 разных типов объектов и 4 разных игроков. У меня есть произвольное количество объектов, и если мое понимание слоев неверно, я не понимаю, как то, что вы предлагаете, может быть достигнуто с помощью слоев.   -  person Coyote    schedule 24.07.2014
comment
Что произойдет, если вы отключите соответствующие компоненты Rigidbody в OnCollisionEnter2D()? Дает ли это результаты, которые вы ищете?   -  person S.C.    schedule 24.07.2014
comment
@AldourCheng rigidbody2D.active = false делает объекты просто неактивными. coll.rigidbody.collisionDetectionMode = CollisionDetectionMode2D.None не производит видимого эффекта. Если вы имели в виду деактивацию коллайдеров, то нет. Потому что тогда объекты с отключенными коллайдерами не будут сталкиваться ни с другими взаимно исключаемыми объектами, движущимися в другую сторону, ни со стенами, ни с другими объектами, с которыми они должны столкнуться. Есть ли способ отменить столкновение в OnCollisionEnter2D?   -  person Coyote    schedule 24.07.2014
comment
@Coyote Вы имеете в виду, что хотите временно отключить воздействие на объект встроенного физического движка? Согласно руководству, за это отвечает Rigidbody. А что, если вы отключите управление физикой?   -  person S.C.    schedule 24.07.2014
comment
@AldourCheng Нет, я имею в виду, что я хочу, чтобы объект временно не сталкивался с другими объектами, движущимися в очень похожем направлении с такой же скоростью. Я хочу дать возможность некоторым типам объектов, которые обычно сталкиваются, не сталкиваться, если расстояние относительной скорости (coll.relativeVelocity.magnitude) достаточно мало. Это очень просто сделать с любым физическим движком с 90-х годов. И я изо всех сил пытаюсь сделать это с помощью Unity.   -  person Coyote    schedule 24.07.2014
comment
@Coyote AFAIK, нет открытых методов, обеспечивающих точную функциональность. Самый близкий способ, который я могу придумать, чтобы имитировать то, что вы сделали с Box2D, - это то, что предложил @Savlon: использование OnCollision_2D или OnTrigger_2D для сброса скоростей объектов до их предыдущих значений до столкновения.   -  person S.C.    schedule 24.07.2014
comment
@AldourCheng Как вы думаете, это не помешает другим столкновениям, которые могут произойти в том же цикле? как столкновения со стенами и другими объектами?   -  person Coyote    schedule 24.07.2014
comment
Да мешает. Предложения от @Leoson, кажется, единственный оставшийся путь. Будет здорово, если кто-нибудь сможет просветить меня более изощренными методами решения проблемы.   -  person S.C.    schedule 25.07.2014


Ответы (1)


Единственный известный мне способ изменить поведение столкновений во время выполнения — отключить столкновения между двумя слоями или между двумя коллайдерами.

Если ваши объекты уже находятся на разных слоях, вы можете отключить (и включить) коллизии между ними через Physics2D.IgnoreLayerCollision() .

Если вы не хотите отключать целые слои, вы можете указать два коллайдера, которые должны игнорировать друг друга, с помощью Physics2D.IgnoreCollision()

Поскольку не существует метода, вызываемого до столкновения, вам нужно либо самостоятельно проверить, какие объекты могут столкнуться, и включить или отключить столкновение, либо использовать OnCollisionEnter2D() и отключить столкновение впоследствии. Для второго способа вам нужно будет сохранить скорости до столкновения и установить их снова после того, как столкновение произошло.

Чтобы добавить некоторую предварительную проверку, вы можете добавить второй коллайдер большего размера вокруг объекта и установить его как триггер. Во время OnTriggerEnter2D() вы можете проверить, должно ли произойти фактическое столкновение.

person Stefan Hoffmann    schedule 24.07.2014
comment
Пока я использую Physics2D.IgnoreCollision(). Но у некоторых объектов есть несколько коллайдеров, и процесс, даже если он автоматизирован, не очень интересен, так как тогда мне нужно добавить специальные триггеры, чтобы проверить, игнорируют ли объекты в настоящее время друг друга, если да, удалите их после их пересечения... и затем... Как вы не игнорируете столкновения? - person Coyote; 25.07.2014
comment
@Coyote для повторного включения коллизий использует третий параметр: IgnoreCollision(collider1, collider2, false) - person Stefan Hoffmann; 25.07.2014
comment
Это тоже не сработает. Когда объекты сталкиваются, возвращение скорости после столкновения также отменяет изменения скорости, которые произошли с другими объектами, и позиции также неверны. - person Coyote; 07.08.2014
comment
@Coyote, если они неверны, вы, очевидно, неправильно их установили. Как уже говорилось в ответе, вам нужно сохранить их значения до того, как произойдет столкновение. Может быть, проще написать собственное поведение при столкновении и просто использовать функцию триггера, предоставляемую Unity. Не зная больше о вашем проекте, невозможно сказать, какой подход может быть лучшим. - person Stefan Hoffmann; 07.08.2014
comment
Когда другие компоненты добавляют силы и обновляют скорость, кэшированные значения не обновляются. По сути, я должен сообщить всем другим компонентам о системе кэширования, чтобы этот обходной путь начал работать... Объекты, для которых не требуется обходной путь, продолжают работать по назначению, объекты с обходным путем и без других компонентов/объектов, изменяющих свои силы, не вести себя правильно. Я все еще озадачен отсутствием обратного вызова предварительного решателя в единстве... - person Coyote; 22.08.2014