Подтвердить что ты не робот

Круговое столкновение

Я собираюсь разработать игру с двумя мячами, в которой сталкиваются два шара (круги). Теперь у меня возникла проблема с определением точки столкновения (фактически, определяя, сталкиваются ли они по оси x/y). У меня есть идея, что, когда разница между координатой y из 2 шаров больше, чем разность координат x, они сталкиваются по своей оси y, в противном случае они сталкиваются по оси x. Правильно ли моя идея? Я реализовал это в своих играх. Обычно он работает хорошо, но иногда он терпит неудачу. Может ли кто-нибудь сказать мне, правильна ли моя идея? Если нет, то почему, и лучший способ?

При столкновении по оси х я имею в виду круг 1-го, 4-го, 5-го или 8-го октанов, ось у означает круг 2-го, 3-го, 6-го или 7-го октантов.

Спасибо заранее!

4b9b3361

Ответ 1

Столкновение между кругами легко. Представьте, что есть два круга:

  • C1 с центром (x1, y1) и радиусом r1;
  • C2 с центром (x2, y2) и радиусом r2.

Представьте, что между этими двумя центральными точками существует линия. Расстояние от центра указывает на край любого круга, по определению, равно их соответствующим радиусам. Итак:

  • если края кругов касаются, расстояние между центрами равно r1 + r2;
  • любое большее расстояние, и круги не касаются или не сталкиваются; и
  • меньше, а затем столкнуться.

Таким образом, вы можете обнаружить столкновение, если:

(x2-x1)^2 + (y1-y2)^2 <= (r1+r2)^2

означает, что расстояние между центральными точками меньше суммы радиусов.

Тот же принцип может быть применен для обнаружения столкновений между сферами в трех измерениях.

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

        (x1,y1)
        |\
        | \
        |  \ sqrt((x2-x1)^2 + (y2-y1)^2) = r1+r2
|y2-y1| |   \
        |    \
        |   X \
(x1,y2) +------+ (x2,y2)
         |x2-x1|

Выражения |x2-x1| и |y2-y1| являются абсолютными значениями. Итак, для угла X:

        |y2 - y1|
sin X =  -------
         r1 + r2

        |x2 - x1|
cos X =  -------
         r1 + r2

        |y2 - y1|
tan X =  -------
        |x2 - x1|

Как только у вас есть угол, вы можете вычислить точку пересечения, применив их к новому треугольнику:

  +
  |\
  | \
b |  \ r2
  |   \
  |  X \
  +-----+
     a

где:

        a
cos X = --
        r2

так

a = r2 cos X

Из предыдущих формул:

       |x2 - x1|
a = r2 -------
        r1 + r2

После того, как у вас есть a и b, вы можете вычислить точку столкновения в терминах (x2, y2) смещения по (a, b), если это необходимо. Вам даже не нужно вычислять для этого синусы, косинусы или инверсные синусы или косинусы. Или любые квадратные корни в этом отношении. Так быстро.

Но если вам не нужен точный угол или точка столкновения, и вы просто хотите октант, вы можете оптимизировать это дальше, поняв что-то о касательных, что:

  • 0 <= tan X <= 1 для 0 <= X <= 45 градусов;
  • tan X >= 1 для 45 <= X <= 90
  • 0 >= tan X >= -1 для 0 >= X = > -45;
  • tan X <= -1 для -45 >= X = > -90; и
  • tan X = tan (X + 180) = tan (X-180).

Эти четыре градусные диапазоны соответствуют четырем октантам cirlce. Остальные четыре смещены на 180 градусов. Как показано выше, тангенс можно вычислить просто так:

        |y2 - y1|
tan X =  -------
        |x2 - x1|

Потерять абсолютные значения, и это отношение скажет вам, из какого из четырех октантов находится столкновение (по указанным касательным диапазонам). Чтобы выработать точный октант, просто сравните x1 и x2, чтобы определить, что является самым левым.

Октант столкновения на другом одиночном смещен (октант 1 на C1 означает октант 5 на C2, 2 и 6, 3 и 7, 4 и 8 и т.д.).

Ответ 2

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

Ball 1:  center: p1=(x1,y1)  radius: r1
Ball 2:  center: p2=(x2,y2)  radius: r2

collision distance: R= r1 + r2
actual distance:    r12= sqrt( (x2-x1)^2 + (y2-y2)^2 )

Коллизия будет происходить всякий раз (r12 < R). Как говорит Артелиус, они не должны сталкиваться с осями x/y, они сталкиваются под определенным углом. Кроме того, вы действительно не хотите этого угла; вам нужен вектор столкновения. В этом разница между центрами двух кругов, когда они сталкиваются:

collision vector: d12= (x2-x1,y2-y1) = (dx,dy)
actual distance:  r12= sqrt( dx*dx + dy*dy )

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

collision point:  pcollision= ( (x1*r2+x2*r1)/(r1+r2), (y1*r2+y2*r1)/(r1+r2) )

Чтобы выяснить, как найти новую скорость шаров (и в целом, чтобы сделать больше смысла из всей ситуации), вы, вероятно, должны найти книгу физики средней школы или эквивалент. К сожалению, я не знаю хорошего веб-учебника - предложения, кто-нибудь?

О, и если вы все еще хотите придерживаться оси x/y, я думаю, что у вас все получилось правильно:

if( abs(dx) > abs(dy) ) then { x-axis } else { y-axis }

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

Ответ 3

Этот сайт объясняет физику, выводит алгоритм, и обеспечивает код для коллизий двумерных шаров.

Вычислите октант после того, как эта функция вычислит следующее: положение точки столкновения относительно центра масс тела a; положение точки столкновения относительно центра масс тела a

/**
This function calulates the velocities after a 2D collision vaf, vbf, waf and wbf from information about the colliding bodies
@param double e coefficient of restitution which depends on the nature of the two colliding materials
@param double ma total mass of body a
@param double mb total mass of body b
@param double Ia inertia for body a.
@param double Ib inertia for body b.
@param vector ra position of collision point relative to centre of mass of body a in absolute coordinates (if this is
                 known in local body coordinates it must be converted before this is called).
@param vector rb position of collision point relative to centre of mass of body b in absolute coordinates (if this is
                 known in local body coordinates it must be converted before this is called).
@param vector n normal to collision point, the line along which the impulse acts.
@param vector vai initial velocity of centre of mass on object a
@param vector vbi initial velocity of centre of mass on object b
@param vector wai initial angular velocity of object a
@param vector wbi initial angular velocity of object b
@param vector vaf final velocity of centre of mass on object a
@param vector vbf final velocity of centre of mass on object a
@param vector waf final angular velocity of object a
@param vector wbf final angular velocity of object b
*/
CollisionResponce(double e,double ma,double mb,matrix Ia,matrix Ib,vector ra,vector rb,vector n,
    vector vai, vector vbi, vector wai, vector wbi, vector vaf, vector vbf, vector waf, vector wbf) {
  double k=1/(ma*ma)+ 2/(ma*mb) +1/(mb*mb) - ra.x*ra.x/(ma*Ia) - rb.x*rb.x/(ma*Ib)  - ra.y*ra.y/(ma*Ia)
    - ra.y*ra.y/(mb*Ia) - ra.x*ra.x/(mb*Ia) - rb.x*rb.x/(mb*Ib) - rb.y*rb.y/(ma*Ib)
    - rb.y*rb.y/(mb*Ib) + ra.y*ra.y*rb.x*rb.x/(Ia*Ib) + ra.x*ra.x*rb.y*rb.y/(Ia*Ib) - 2*ra.x*ra.y*rb.x*rb.y/(Ia*Ib);
  double Jx = (e+1)/k * (Vai.x - Vbi.x)( 1/ma - ra.x*ra.x/Ia + 1/mb - rb.x*rb.x/Ib)
     - (e+1)/k * (Vai.y - Vbi.y) (ra.x*ra.y / Ia + rb.x*rb.y / Ib);
  double Jy = - (e+1)/k * (Vai.x - Vbi.x) (ra.x*ra.y / Ia + rb.x*rb.y / Ib)
     + (e+1)/k  * (Vai.y - Vbi.y) ( 1/ma - ra.y*ra.y/Ia + 1/mb - rb.y*rb.y/Ib);
  Vaf.x = Vai.x - Jx/Ma;
  Vaf.y = Vai.y - Jy/Ma;
  Vbf.x = Vbi.x - Jx/Mb;
  Vbf.y = Vbi.y - Jy/Mb;
  waf.x = wai.x - (Jx*ra.y - Jy*ra.x) /Ia;
  waf.y = wai.y - (Jx*ra.y - Jy*ra.x) /Ia;
  wbf.x = wbi.x - (Jx*rb.y - Jy*rb.x) /Ib;
  wbf.y = wbi.y - (Jx*rb.y - Jy*rb.x) /Ib;
}

Ответ 4

Точка, с которой они сталкиваются, находится на линии между серединами двух окружностей, а ее расстояние от любой средней точки - это радиус соответствующего круга.

Ответ 5

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

В любом случае, если вы будете реализовывать свое решение (сравнение по осям X и Y), вы получите хороший старый пинг-понг! http://en.wikipedia.org/wiki/Pong
:)

Ответ 6

Чтобы более точно ответить на ваш вопрос: Да, в соответствии с правилами и требованиями, которые вы выкладываете, эти шары сталкиваются по оси Y, если разница в Y больше, чем разница в X, когда шарики касаются.

Если это то, что вы реализуете, тогда вы получаете правильный ответ на вопрос "Столкновение по оси X или Y?". Но я думаю, что причина, по которой вы получаете так много ответов, что вы не можете использовать, заключается в том, что либо

  • вы задаете неправильный вопрос (не здесь - в вашей программе); или

  • вы неправильно используете ответ.

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