Проблема столкновения 2d шара: нет сохранения энергии - PullRequest
4 голосов
/ 15 февраля 2011

Я пытаюсь написать простую физическую симуляцию, в которой шары с различными радиусами и массами подпрыгивают в абсолютно упругой и свободной от трения среде.Я написал свой собственный код после этого ресурса: http://www.vobarian.com/collisions/2dcollisions2.pdf, и я также проверил код здесь: Столкновение шара с мячом - обнаружение и обработка

РЕДАКТИРОВАНИЕ ВОПРОСА

С помощью Рика Гольдштейна и Ральфа я получил свой код для работы (была опечатка ..).Большое спасибо за вашу помощь.Однако я все еще не понимаю, почему другой алгоритм не работает для меня.Шары отскакивают в правильных направлениях, но полная энергия системы никогда не сохраняется.Скорости становятся все быстрее и быстрее, пока шары не начнут мигать в статических положениях на экране.Я на самом деле хочу использовать этот код в моей программе, потому что он намного более лаконичен, чем тот, который я написал.

Вот функциональный алгоритм, который я написал (хотя я взял первый бит из этого другого источника).Это в классе Bubble:

public void resolveCollision(Bubble b)
{
    // get the minimum translation distance
    Vector2 delta = (position.subtract(b.position));
    float d = delta.getMagnitude();
    // minimum translation distance to push balls apart after intersecting
    Vector2 mtd = delta.multiply(((getRadius() + b.getRadius())-d)/d); 

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

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

    //get the unit normal and unit tanget vectors
    Vector2 uN = b.position.subtract(this.position).normalize();
    Vector2 uT = new Vector2(-uN.Y, uN.X);

    //project ball 1 & 2 's velocities onto the collision axis
    float v1n = uN.dot(this.velocity);
    float v1t = uT.dot(this.velocity);
    float v2n = uN.dot(b.velocity);
    float v2t = uT.dot(b.velocity);

    //calculate the post collision normal velocities (tangent velocities don't change)
    float v1nPost = (v1n*(this.mass-b.mass) + 2*b.mass*v2n)/(this.mass+b.mass);
    float v2nPost = (v2n*(b.mass-this.mass) + 2*this.mass*v1n)/(this.mass+b.mass);

    //convert scalar velocities to vectors
    Vector2 postV1N = uN.multiply(v1nPost);
    Vector2 postV1T = uT.multiply(v1t);
    Vector2 postV2N = uN.multiply(v2nPost);
    Vector2 postV2T = uT.multiply(v2t);

    //change the balls velocities
    this.velocity = postV1N.add(postV1T);
    b.velocity = postV2N.add(postV2T);
}

А вот тот, который не работает

public void resolveCollision(Bubble b)
{
    // get the minimum translation distance
    Vector2 delta = (position.subtract(b.position));
    float d = delta.getMagnitude();
    // minimum translation distance to push balls apart after intersecting
    Vector2 mtd = delta.multiply(((getRadius() + b.getRadius())-d)/d); 

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

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

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

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

    // collision impulse (1f is the coefficient of restitution)
    float i = (-(1.0f + 1f) * vn) / (im1 + im2);
    Vector2 impulse = mtd.multiply(i);

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

Дайте мне знать, если найдете что-нибудь.Спасибо

Ответы [ 3 ]

6 голосов
/ 15 февраля 2011

Есть ли опечатка в строке, которая устанавливает v1nPost?Похоже, знаменатель должен быть this.mass + b.mass, а не this.mass * b.mass.

Кроме того, поскольку вы вычисляете коллизию между this и b, проверяете ли вы, что вы тожеделать то же самое столкновение между b и this, таким образом удваивая дельту, примененную к каждому участвующему в столкновении пузырю?

3 голосов
/ 15 февраля 2011

Я делаю первое предположение: getMass () возвращает целое число (или целое число) (а не число с плавающей запятой или двойное число)?

Если это так, то проблема в том, что 1 / getMass() приведет к целочисленному значению (и может быть только 1 или чаще всего 0)). Чтобы исправить это, замените 1 на 1.0 или 1.0f

Потому что общее правило простое: Если у вас есть математическая операция (+, -, *, /), результирующий тип будет целочисленным, если ни один из обоих операторов не является структурой данных с плавающей запятой (double или float)

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

1 голос
/ 15 февраля 2011

Часть, которая выглядит странно:

Два вычисления:

float v1nPost = (v1n*(this.mass-b.mass) + 2*b.mass*v2n)/(this.mass*b.mass);
float v2nPost = (v2n*(b.mass-this.mass) + 2*this.mass*v1n)/(this.mass+b.mass);

симметричны, кроме последней операции, в первой это *, во второй +

...