Как получить данные о столкновениях из Physics.OverlapBox ()? - PullRequest
0 голосов
/ 15 сентября 2018

Я пытаюсь найти другие способы регистрации столкновений (кроме OnCollisionEnter() и OnCollisionExit()). В настоящее время я использую Physics.OverlapBox(), но мне нужно больше информации о столкновении; т.е. нормально, точка.

Я могу использовать Physics.BoxCast(), но проблема в том, что он перемещает коробку на заданное расстояние, и использование maxDistance = 0f не сработает.

Мне нужен метод проверки столкновений, аналогичный Physics.OverlapBox(), за исключением того, что он также возвращает информацию о всех столкновениях в приведении.

Любая помощь приветствуется. Спасибо.

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

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

В основном для каждогоПеремещая объект в вашей сцене, вы должны рассчитать момент следующего столкновения в пределах доли кадра 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 - это те функции, которые вы написали, которые вы искали, поэтому попробуйте, они могут работать достаточно хорошо для вашего варианта использования.

0 голосов
/ 15 сентября 2018

Вы можете использовать OverlapBox и Collider * ClosestPoint, чтобы выбрать одну точку перекрытия, и использовать ее для расчета столкновений.

Collider[] cols = Physics.OverlapBox(...);
Vector3 myPosition = transform.position; // for example

foreach (Collider col in cols) {
    Vector3 closestPoint = col.ClosestPoint(myPosition);
    Vector3 positionDifference = (closestPoint-myPosition);
    Vector3 overlapDirection = positionDifference.normalized; 
}

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

// ...

foreach (Collider col in cols) {
    Vector3 closestPoint = col.ClosestPoint(myPosition);
    Vector3 positionDifference = (closestPoint-myPosition);
    Vector3 overlapDirection = positionDifference.normalized; 

    RaycastHit hit;
    int layerMask = 1;  // Set to something that will only hit your object
    float raycastDistance = 10.0; // something greater than your object's largest radius, 
                                  // so that the ray doesn't start inside of your object
    Vector3 rayStart = myPosition + overlapDirection * raycastDistance;
    Vector3 rayDirection = -overlapDirection ;

    if (Physics.Raycast(rayStart, rayDirection, out hit, Mathf.Infinity, layerMask)) {
        Debug.Log(hit.normal);
        Debug.Log(hit.position);
    } else {
        // The ray missed your object, somehow. 
        // Most likely it started inside your object 
        // or there is a mistake in the layerMask
    }
}
...