1

I have been working on making a Physics Engine and came across a problem when handling circle collisions. The program seems to resolve collisions just fine in most instances. However at lower speeds the circles begin to overlapp one another.

To illustrate the problem I have made the following gif file. I ahve also added gravitational attraction between the objects as it helps to illustrate the problem better.

I will post the relevnant code below. The class definition of the object that represents the circles withouth most of the methods:

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

The code that checks for 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;
  }

And finally outside this class the objects are handled with an ArrayList and this is the code that resolves collisions:

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

The collision resolution is based on the following formula found on Wikipedia.

AdiSuba
  • 21
  • 3
  • Add positional separation, i.e. move the position vectors of the colliding objects apart in direction of the collision normal by a percentage of the object penetration (overlap). – EvilTak Jul 22 '17 at 11:06
  • Your `checkCollision` method amounts to "the objects overlap AND are moving towards each other". Have you tried what happens if you remove the second half of this? That is, change the condition to `d < getRadius() + m.getRadius() + dvel` (that's the "they overlap" part). Remove `&& vel21.dot(pos21) < 0` - that's the "moving towards each other" part. – Dawood ibn Kareem Jul 22 '17 at 11:23
  • @Dawood ibn Kareem Removing `vel21.dot(pos21) < 0` doesn't actually fix the issue, they still overlap at times. Also it was added to fix an issue where somtimes two (or more) circles would become sort of entangled. The circles would become linked to one another and sort of twich. – AdiSuba Jul 22 '17 at 14:33
  • From studying your GIF more closely, it seems to me that the problem arises when a body collides with two others at the same time. I think that the mathematics that you're using to handle a collision only deals with the case where a body collides with one other body, not with two. You'll need to add up the changes in momentum due to collision with both bodies, based on the initial momentum of each body, rather than dealing with it as if it were two separate collisions. – Dawood ibn Kareem Jul 23 '17 at 00:12

1 Answers1

1

Thank you for your suggestions. I have managed to find a solution. I believe the problem was that when the objects had a small velocity gravitational acceleration was stronger than the collison response and therefore pulled the objects into one another. I fixed the problem by manually moving the objects apart as was suggested.

Here is the result of the changes. Below is the updated applyCollisions function.

  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())));
       }
      }
    }
  }
AdiSuba
  • 21
  • 3