更新:发现我使用半径作为直径,这就是mtd过度补偿的原因。
另一个更新:我的球重叠的原因似乎是因为每次碰撞只有一次检查。经过一些研究,有些人说,你可以防止与堆积的物体重叠的方法之一是递归地执行碰撞检查。这在某种程度上起作用,我怀疑如果物理学更准确,它会更好。如果我找到更多解决方案,我会再次更新。另外,我正在使用Simucal's collision correction code.
嗨,StackOverflow。我编写了一个处理程序,一段时间后回模拟球物理。基本上,我有大量的球(1000),重力打开。检测效果很好,但我的问题是,当它们在各个方向与其他球弹跳时,它们开始表现得很奇怪。
我非常有信心这涉及到处理。在大多数情况下,我使用Jay Conrod的代码。一个不同的部分是
if (distance > 1.0)
return;
我已改为
if (distance < 1.0)
return;
因为碰撞甚至没有用第一段代码执行,我猜这是一个错字。
当我使用他的代码时球重叠,这不是我想要的。我试图修复它是将球移到彼此的边缘:
float angle = atan2(y - collider.y, x - collider.x);
float distance = dist(x,y, balls[ID2].x,balls[ID2].y);
x = collider.x + radius * cos(angle);
y = collider.y + radius * sin(angle);
这是不对的,我很确定。
我在之前的球到球话题中尝试了校正算法:
// get the mtd
Vector2d delta = (position.subtract(ball.position));
float d = delta.getLength();
// minimum translation distance to push balls apart after intersecting
Vector2d mtd = delta.multiply(((getRadius() + ball.getRadius())-d)/d);
// resolve intersection --
// inverse mass quantities
float im1 = 1 / getMass();
float im2 = 1 / ball.getMass();
// push-pull them apart based off their mass
position = position.add(mtd.multiply(im1 / (im1 + im2)));
ball.position = ball.position.subtract(mtd.multiply(im2 / (im1 + im2)));
除了我的版本不使用向量,并且每个球的权重是1.我得到的结果是:
PVector delta = new PVector(collider.x - x, collider.y - y);
float d = delta.mag();
PVector mtd = new PVector(delta.x * ((radius + collider.radius - d) / d), delta.y * ((radius + collider.radius - d) / d));
// push-pull apart based on mass
x -= mtd.x * 0.5;
y -= mtd.y * 0.5;
collider.x += mtd.x * 0.5;
collider.y += mtd.y * 0.5;
此代码似乎过度纠正了冲突。这对我没有意义,因为除了这个以外我不会修改每个球的x和y值。
我的代码的其他部分可能是错误的,但我不知道。这是我正在使用的整个球对球碰撞处理的片段:
if (alreadyCollided.contains(new Integer(ID2))) // if the ball has already collided with this, then we don't need to reperform the collision algorithm
return;
Ball collider = (Ball) objects.get(ID2);
PVector collision = new PVector(x - collider.x, y - collider.y);
float distance = collision.mag();
if (distance == 0) {
collision = new PVector(1,0);
distance = 1;
}
if (distance < 1)
return;
PVector velocity = new PVector(vx,vy);
PVector velocity2 = new PVector(collider.vx, collider.vy);
collision.div(distance); // normalize the distance
float aci = velocity.dot(collision);
float bci = velocity2.dot(collision);
float acf = bci;
float bcf = aci;
vx += (acf - aci) * collision.x;
vy += (acf - aci) * collision.y;
collider.vx += (bcf - bci) * collision.x;
collider.vy += (bcf - bci) * collision.y;
alreadyCollided.add(new Integer(ID2));
collider.alreadyCollided.add(new Integer(ID));
PVector delta = new PVector(collider.x - x, collider.y - y);
float d = delta.mag();
PVector mtd = new PVector(delta.x * ((radius + collider.radius - d) / d), delta.y * ((radius + collider.radius - d) / d));
// push-pull apart based on mass
x -= mtd.x * 0.2;
y -= mtd.y * 0.2;
collider.x += mtd.x * 0.2;
collider.y += mtd.y * 0.2;
答案 0 :(得分:2)
您的“结果代码”看起来是正确的。你有一个显示过校正的简单测试用例(例如x 1 = 0,x 1 = 3,y 1 = y 2 = 0,r 1 = r 2 = 2)?
另外,如果忽略重叠并保留其他所有内容,你会得到很好的效果,就像球是软橡胶一样吗?
修改:
这部分错了:
PVector velocity = new PVector(vx,vy);
...
collider.vy += (bcf - bci) * collision.y;
当两个球靠近时,它们阻尼彼此的速度直到它们都停止。但从好的方面来说,你已经发明了固体(只是开玩笑)。关闭重叠的东西,在这部分工作之前不要担心。
如果不了解基础物理,让这部分工作几乎是不可能的。你需要一只手吗?