2013-09-02 7 views
4

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

Основной алгоритм сейчас:

  1. Переместить объект
  2. Проверка столкновений
  3. Если произошло столкновение
    • Перемещение объекта на минимальное расстояние, чтобы разрешить коллизию.
    • Регулировка скорости на основе нормалей, масс, и т.д.

У меня есть один движущееся тело движется к двум, статические, безмассовых, тел.

Figure One

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

Figure Two

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

Figure Three

повторяю то же самое с этой коробкой, стараясь не двигаться динамическое поле так, чтобы она больше не сталкиваясь, а что толкает его обратно в первое поле. Это повторяется вечно. Является ли мой алгоритм фундаментальным недостатком?

ответ

1

Одно из возможных решений, которые могут быть устойчивы к проблеме, которую вы описали (полностью непроверенные):

  1. Переместите объект для полного времени шага dt

  2. Проверка столкновений с другими объектами, это может быть более одного объекта

  3. Рассчитать «время удара» путем интерполяции, которое представляет собой некоторое действительное число, меньшее, чем шаг времени. Сделайте это для каждого объекта, с которым вы столкнулись, и выберите минимальный. Это дает вам время для первого столкновения t_col < dt.

  4. Повторите последний шаг, но теперь переместите объект только на t_col так, чтобы он точно ударил объект, а затем начал скорость переключения и другую связанную с столкновением физику. Вы можете либо закончить шаг здесь, если вы ленивы (вероятно, хорошо, так как dt должен быть небольшим), или продолжить движение для другого dt - t_col и посмотреть, ударило ли вы что-то еще.

Это не то, что я придумал только сейчас, но похож на zero-cross detection, что Simulink использует для имитации именно этот вид прерывистых проблем.

3

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

Нам нужно выяснить, сколько нам нужно сжать (масштаб) v, чтобы поместить его в пересечение объекта. Усадка v будет иметь правильную величину, так что если мы двинемся назад в направлении -v на эту величину, то мы больше не пересекаемся.

Предположим, что пересечение состоит из x_intersection и компонента y_intersection. Чтобы узнать, насколько нам нужно двигаться назад, чтобы больше не пересекаться, нам нужно масштабировать исходный вектор v = (v_x, v_y). Если x_intersection является меньшим перекрестком, то мы масштабируем v на x_intersection/v_x и переместите наш объект обратно на -v * x_intersection/v_x. Это означает, что мы возвращаемся на -(x_intersection, x_intersection * v_y/v_x). Если y_intersection является меньшим пересечением, мы масштабируем v на y_intersection/v_y и перемещаем наш объект назад на -v * y_intersection/v_y = -(y_intersection * v_x/v_y, y_intersection).

Так что я бы сказал, что шаги в вашем алгоритме может быть:

  1. Переместить объект каким-либо перемещения вектора v
  2. Проверить для всех столкновений
  3. Если произошло столкновение

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

      given v = (v_x, v_y) 
      min_i = min(x_intersection/v_x, y_intersection/v_y)  
      
    • Найти минимальное масштабирование рациона по всем объектам.

      min_o = min(min_i) for all i 
      
    • Переместить объект назад в направлении вектора, полученного путем масштабирования отрицательного направления перемещения с минимальным коэффициентом. То есть v2 = (min_o*-v) где v2 - вектор, который мы используем для перемещения назад.

  4. Вернитесь к шагу 2

Например: сначала выбирают w:

w

Затем выберите u2:

u2

Готово:

enter image description here

+1

Ницца изображение, но ваша математика для расчета, как далеко идти назад, кажется мне неправильной.Поскольку 'min_o' может быть действительно маленьким значением,' 1/min_o' потенциально действительно большой. Также, если вы посмотрите на единицы, это кажется неправильным: оба 'v' и' min_o' являются расстояниями, поэтому '-v/min_o' безразмерен, вы не можете назначить это вектор расстояния' v2'. Я не совсем понимаю, как вы определяете 'min_o', но вы, вероятно, должны просто добавить или вычесть что-то или, как в моем ответе, просто вернуться к предыдущей позиции и повторить минимально возможный шаг. –

+0

@BasSwinckels О, дерьмо, да, ваше право. Я собирался масштабировать вектор 'v' до размера самого маленького пересечения, а затем вычесть его из' v'. Но для этого у меня есть шкала на 'v_x/min_o', если наименьшее пересечение находилось в направлении x или' v_y/min_o', если пересечение было в направлении y. В противном случае это не имеет размеров, как вы сказали. – cyon

+0

@BasSwinckels Хорошо, я отредактировал, и я думаю, что исправил математическую проблему. Новое масштабирование сохраняет единицы и не страдает, если 'min_o', если очень мало. Это должно быть правильное масштабирование, чтобы сжать 'v' вниз до необходимого размера, чтобы вписаться в пересечение объекта. – cyon

Смежные вопросы