Столкновение шара с мячом - обнаружение и обработка - PullRequest
258 голосов
/ 06 декабря 2008

С помощью сообщества Stack Overflow я написал довольно простой, но увлекательный симулятор физики.

alt text

Вы щелкаете мышью и запускаете шар. Он будет подпрыгивать и в конце концов остановится на «полу».

Моя следующая большая особенность, которую я хочу добавить, это столкновение мяча с мячом. Движение мяча разбито на вектор скорости x и y. У меня есть сила тяжести (небольшое уменьшение вектора y на каждом шаге), у меня есть трение (небольшое уменьшение обоих векторов при каждом столкновении со стеной). Шары честно перемещаются удивительно реалистичным способом.

Полагаю, мой вопрос состоит из двух частей:

  1. Каков наилучший метод обнаружения столкновения шара с шаром?
    У меня просто есть петля O (n ^ 2), которая перебирает каждый шар и проверяет каждый другой шар, чтобы увидеть, перекрывается ли его радиус?
  2. Какие уравнения я использую, чтобы справиться с столкновениями шара с шаром? Физика 101
    Как это влияет на скорость вращения двух шаров по векторам x / y? В каком направлении движутся два мяча? Как применить это к каждому шару?

alt text

Обработка обнаружения столкновений «стенок» и результирующих изменений вектора была легкой, но я вижу больше сложностей с столкновениями шара и шара. Со стенами мне просто нужно было взять отрицательное значение соответствующего вектора x или y, и оно пошло бы в правильном направлении. С шарами я не думаю, что это так.

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


Редактировать: ресурсы, которые я нашел полезными

2d Физика шаров с векторами: 2-мерные столкновения без тригонометрии.pdf
Пример обнаружения столкновения 2d Ball: Добавление обнаружения столкновения


Успех!

У меня отлично работает обнаружение и реакция на столкновение мячей!

Соответствующий код:

Обнаружение столкновения:

for (int i = 0; i < ballCount; i++)  
{  
    for (int j = i + 1; j < ballCount; j++)  
    {  
        if (balls[i].colliding(balls[j]))  
        {
            balls[i].resolveCollision(balls[j]);
        }
    }
}

Это проверит наличие столкновений между каждым мячом, но пропустит лишние проверки (если вам нужно проверить, сталкивается ли шар 1 с шаром 2, вам не нужно проверять, сталкивается ли шар 2 с шаром 1. Кроме того, он пропускает проверку столкновения с собой).

Затем в моем классе с мячом у меня есть методы colliding () и resolCollision ():

public boolean colliding(Ball ball)
{
    float xd = position.getX() - ball.position.getX();
    float yd = position.getY() - ball.position.getY();

    float sumRadius = getRadius() + ball.getRadius();
    float sqrRadius = sumRadius * sumRadius;

    float distSqr = (xd * xd) + (yd * yd);

    if (distSqr <= sqrRadius)
    {
        return true;
    }

    return false;
}

public void resolveCollision(Ball ball)
{
    // get the mtd
    Vector2d delta = (position.subtract(ball.position));
    float d = delta.getLength();
    // minimum translation distance to push balls apart after intersecting
    Vector2d mtd = delta.multiply(((getRadius() + ball.getRadius())-d)/d); 


    // resolve intersection --
    // inverse mass quantities
    float im1 = 1 / getMass(); 
    float im2 = 1 / ball.getMass();

    // push-pull them apart based off their mass
    position = position.add(mtd.multiply(im1 / (im1 + im2)));
    ball.position = ball.position.subtract(mtd.multiply(im2 / (im1 + im2)));

    // impact speed
    Vector2d v = (this.velocity.subtract(ball.velocity));
    float vn = v.dot(mtd.normalize());

    // sphere intersecting but moving away from each other already
    if (vn > 0.0f) return;

    // collision impulse
    float i = (-(1.0f + Constants.restitution) * vn) / (im1 + im2);
    Vector2d impulse = mtd.normalize().multiply(i);

    // change in momentum
    this.velocity = this.velocity.add(impulse.multiply(im1));
    ball.velocity = ball.velocity.subtract(impulse.multiply(im2));

}

Исходный код: Полный исходный код для шарового коллайдера.

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

Ответы [ 11 ]

2 голосов
/ 06 октября 2013

Я реализовал этот код в JavaScript, используя элемент HTML Canvas, и он производил прекрасное моделирование со скоростью 60 кадров в секунду. Я начал симуляцию с набора из дюжины шаров в случайных положениях и скоростях. Я обнаружил, что при более высоких скоростях скользящее столкновение между маленьким и большим шариками приводило к тому, что маленький шарик казался STICK краю большего шарика, и перемещался на угол около 90 градусов вокруг больший шар перед разделением. (Интересно, наблюдал ли кто-нибудь еще такое поведение?)

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

dot_velocity = ball_1.velocity.dot(ball_2.velocity);
mtd_factor = 1. + 0.5 * Math.abs(dot_velocity * Math.sin(collision_angle));
mtd.multplyScalar(mtd_factor);

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

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

...