我一直致力于制作物理引擎,并在处理圆形碰撞时遇到了问题。在大多数情况下,该程序似乎可以很好地解决冲突。然而,在较低速度下,圆圈开始彼此重叠。
为了说明问题,我做了以下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。
答案 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())));
}
}
}
}