【问题标题】:2d Ball Collision Problem: no conservation of energy二维球碰撞问题:能量不守恒
【发布时间】:2011-06-27 20:28:13
【问题描述】:

我正在尝试编写一个简单的物理模拟,其中具有不同半径和质量的球在完全弹性和无摩擦的环境中弹跳。我在此资源之后编写了自己的代码:http://www.vobarian.com/collisions/2dcollisions2.pdf,我还从这里测试了代码:Ball to Ball Collision - Detection and Handling

问题已编辑

在 Rick Goldstein 和 Ralph 的帮助下,我的代码可以正常工作(有一个错字……)。非常感谢你的帮助。但是,我仍然对为什么其他算法对我不起作用感到困惑。球以正确的方向反弹,但系统的总能量永远不会守恒。速度越来越快,直到球开始在屏幕上的静态位置闪烁。我实际上想在我的程序中使用这段代码,因为它比我写的要简洁得多。

这是我编写的函数算法(尽管我确实从其他来源获取了第一部分)。它在一个 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));
}

如果你发现了什么,请告诉我。谢谢

【问题讨论】:

    标签: java android physics collision game-physics


    【解决方案1】:

    设置 v1nPost 的行中是否有错字?看起来分母应该是this.mass + b.mass,而不是this.mass * b.mass

    另外,由于您正在计算 thisb 之间的冲突,您是否正在检查以确保您没有在 bthis 之间进行相同的冲突,从而使应用的增量加倍碰撞中的每个参与气泡?

    【讨论】:

    • 是的,这是错字...我一定是在电脑前呆了太久,我检查了很多次数学。谢谢。不过请查看我的编辑,我真的很想让其他算法正常工作,但它绝对不是同一个问题
    • 至于你的第二点,我不检查我是否已经通过气泡解决了循环中的碰撞,但我认为这并不重要,因为我做的第一件事这个 resolveCollision 方法是将它们分开。当循环确实在碰撞中找到另一个球时,它将不再碰撞并且不会再次调用此方法
    • 当您计算mtd.normalize() 时,mtd 是否保持标准化?如果不是,我认为您需要将impulse 的计算更改为mtd.normalize().multiply(i)。除此之外,您可能正在查看累积的舍入误差,尤其是从转换到 b 的参考框架(“冲击速度”计算)。
    • 就是这样!现在效果很好。老实说,我不理解这个背后的所有数学原理,因为我只是从另一个来源中提取了它,所以非常感谢你帮助我解决这个问题。我一定会在其他线程上写一条评论,通知他们代码中有错误
    • 很高兴有帮助。我前世是物理学家,所以我做过一两次碰撞问题。干杯!
    【解决方案2】:

    我做了第一个猜测:getMass() 返回一个整数(或 int)(而不是浮点数或双精度数)?

    如果这是真的,那么你的问题是1 / getMass() 将产生一个整数值(并且只能是 1 或大多数时候为 0))。要解决此问题,请将 1 替换为 1.01.0f

    因为一般规则很简单: 如果你有一个数学运算(+、-、*、/),如果两个运算都不是浮点数据结构(double 或 float),则结果类型将为整数

    无论如何:可能还有第二个问题,可能你的计算不够精确。那么你应该使用 double 而不是 float。

    【讨论】:

    • 这是一个很好的观点。 getMass() 实际上返回一个字节,到目前为止,在我的代码中,所有气泡的质量都是 1。如果质量不同,我发现我会有问题。我会改的,非常感谢。
    【解决方案3】:

    有一部分看起来很奇怪:

    两种计算方式:

    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);
    

    是对称的,除了最后一个操作,第一个是*,第二个是+

    【讨论】:

    • 就是这样.. 非常感谢。不过请查看我的编辑,我现在正在尝试让其他算法工作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-27
    • 2020-01-10
    相关资源
    最近更新 更多