低速的2D圆形碰撞会导致重叠

时间:2017-07-22 11:02:44

标签: java processing physics collision physics-engine

我一直致力于制作物理引擎,并在处理圆形碰撞时遇到了问题。在大多数情况下,该程序似乎可以很好地解决冲突。然而,在较低速度下,圆圈开始彼此重叠。

为了说明问题,我做了以下gif file。我还在物体之间增加了引力,因为它有助于更​​好地说明问题
我将在下面发布相关代码。表示圆圈的对象的类定义,没有大多数方法:

class Mover {
  PVector pos;
  PVector vel;
  PVector acc;
  float ang = 0;
  float angVel = 0;
  float angAcc = 0;
  float mass;

  float getRadius() {
    return mass/10;
  }

  void update() {
    vel.add(acc);
    pos.add(vel);
    acc.mult(0);
    angVel += angAcc;
    ang += angVel;
    angAcc = 0;
  }  
}

检查collsions的代码:

  boolean checkCollision(Mover m) {
    float d = pos.dist(m.pos);
    float dvel = vel.dist(m.vel);
    PVector pos21 = m.pos.copy().sub(pos);
    PVector vel21 = m.vel.copy().sub(vel);
    if(d < getRadius() + m.getRadius() + dvel && vel21.dot(pos21) < 0) return true;
    return false;
  }

最后在这个类之外,使用ArrayList处理对象,这是解决冲突的代码:

  void applyCollisions() {
    for(int i = 0; i < movers.size(); i++) {
      for(int j = i + 1; j < movers.size(); j++) {
        Mover mi = movers.get(i);
        Mover mj = movers.get(j);
       if(mi.checkCollision(mj)) {
         PVector v1 = mi.vel.copy();
         PVector v2 = mj.vel.copy();
         PVector x1 = mi.pos.copy();
         PVector x2 = mj.pos.copy();
         PVector x12 = x1.copy().sub(x2);
         PVector v12 = v1.copy().sub(v2);
         PVector x21 = x2.copy().sub(x1);
         PVector v21 = v2.copy().sub(v1);
         float m1 = mi.mass, m2 = mj.mass;
         mi.angVel = mi.calcAngVel(x12.normalize().mult(mi.getRadius()));
         mj.angVel = mj.calcAngVel(x21.normalize().mult(mi.getRadius()));
         mi.vel.sub(x12.mult((2*m2/(m1 + m2))*(v12.dot(x12)/x12.magSq())));
         mj.vel.sub(x21.mult((2*m1/(m1 + m2))*(v21.dot(x21)/x21.magSq())));
       }
      }
    }
  }

冲突解决方案基于维基百科上的以下formula

1 个答案:

答案 0 :(得分:1)

感谢您的建议。我设法找到了解决方案。我认为问题在于,当物体的速度很小时,重力加速度比碰撞响应强,因此将物体拉到另一个物体中。我按照建议手动移动对象来解决问题。

Here是更改的结果。以下是更新的applyCollisions功能。

  void applyCollisions() {
    for(int i = 0; i < movers.size(); i++) {
      for(int j = i + 1; j < movers.size(); j++) {
        Mover mi = movers.get(i);
        Mover mj = movers.get(j);
       if(mi.checkCollision(mj)) {
         PVector v1 = mi.vel.copy();
         PVector v2 = mj.vel.copy();
         PVector x1 = mi.pos.copy();
         PVector x2 = mj.pos.copy();
         PVector x12 = x1.copy().sub(x2);
         PVector v12 = v1.copy().sub(v2);
         PVector x21 = x2.copy().sub(x1);
         PVector v21 = v2.copy().sub(v1);
         float m1 = mi.mass, m2 = mj.mass;
         //Added to solve the issue:
         float overlapp = mi.getRadius() + mj.getRadius() - x12.mag();
         mi.pos = mi.pos.add(x12.normalize().mult(overlapp/2));
         mj.pos = mj.pos.add(x21.normalize().mult(overlapp/2));
         //The rest is unchanged
         mi.angVel = mi.calcAngVel(x12.normalize().mult(mi.getRadius()));
         mj.angVel = mj.calcAngVel(x21.normalize().mult(mi.getRadius()));
         mi.vel.sub(x12.mult((2*m2/(m1 + m2))*(v12.dot(x12)/x12.magSq())));
         mj.vel.sub(x21.mult((2*m1/(m1 + m2))*(v21.dot(x21)/x21.magSq())));
       }
      }
    }
  }