Ваша обеспокоенность, выраженная в комментарии к первому ответу, верна, но плохая новость заключается в том, что не существует простого способа ее обойти.То, что вы должны искать, называется непрерывное обнаружение столкновений с упрощенной версией, описанной в моем ответе на несколько похожий вопрос:
В основном для каждогоПеремещая объект в вашей сцене, вы должны рассчитать момент следующего столкновения в пределах доли кадра 0<t0<1
, затем продвинуть позиции к этому моменту t0 в кадре, обновить скорости из-за столкновения и перейти к следующему столкновению t0<t1<1
,пока вы не достигнете времени tn=1
(конец кадра), убедившись, что вы не застряли в середине кадра из-за округления расчетных или «загнанных» объектов.Для сферических коллайдеров это обычно делается с помощью пересечения капсула против капсулы (для пар объектов) и капсула против коробки для границ.
InВ отличие от простого двигателя из ответа, на который я ссылаюсь, Unity имеет непрерывное обнаружение столкновений .Таким образом, вы можете включить непрерывные столкновения и непрерывную динамику, что в вычислительном отношении очень дорого.
Вы также можете попробовать использовать RigidBody.SweepTest , который возвращает информацию о ближайшем столкновении.Обратите внимание, что даже при наличии RigidBody.SweepTestAll это не очень помогает.Не только потому, что он возвращает только первые 128 столкновений, но и потому, что он не обрабатывает их, поскольку нет отражения.Для физически правильного поведения вы должны сделать то, что описано выше - время до первого столкновения и скорость обновления.Либо с физическим движком, либо самостоятельно.Это очень дорого, и не многие игры делают это, даже читерство с использованием упрощенных объектов (сферы являются самыми дешевыми, поскольку две развернутые сферы представляют собой две капсулы, а их пересечение - относительно дешевый расчет), но количество шагов, особенно в «загнутых»«случай, когда объектам некуда идти, и поэтому постоянно сталкиваются может быть очень большим, и таких случаев бывает больше, чем можно ожидать.
Для сложных объектов вы вряд ли сможете добиться большего успеха, чем SweepTest,если вы не запускаете его на основе более простых примитивов, таких как Physics.BoxCast
или Physics.SphereCast
.Опять же, даже если есть Physics.BoxCastAll
и Physics.SphereCastAll
, они не особенно полезны, поскольку гарантируется только первое столкновение.Эти xxxCastAll - это те функции, которые вы написали, которые вы искали, поэтому попробуйте, они могут работать достаточно хорошо для вашего варианта использования.