在 Stack Overflow 社区的帮助下,我编写了一个非常基本但有趣的物理模拟器。
您单击并拖动鼠标来发射一个球。它会反弹并最终停在“地板”上。
我要添加的下一个重要功能是球对球碰撞。球的运动被分解为 ax 和 y 速度矢量。我有重力(每一步 y 向量的小减少),我有摩擦(每次与墙壁碰撞时两个向量的小减少)。球以令人惊讶的逼真方式诚实地移动。
我想我的问题有两个部分:
- 检测球对球碰撞的最佳方法是什么?
我是否只有一个 O(n^2) 循环遍历每个球并检查每个其他球以查看其半径是否重叠? - 我用什么方程来处理球对球的碰撞?物理 101
它如何影响两个球的速度 x/y 向量?两个球朝哪个方向飞去?我如何将其应用于每个球?
处理“墙壁”的碰撞检测和由此产生的矢量变化很容易,但我看到球碰撞更复杂。对于墙壁,我只需要取适当的 x 或 y 向量的负值,然后它就会朝着正确的方向前进。对于球,我不认为是那样的。
一些快速澄清:为简单起见,我现在可以完全弹性碰撞,而且我所有的球现在都具有相同的质量,但我将来可能会改变它。
编辑:我发现有用的资源
带有向量的 2d Ball 物理:2-Dimensional Collisions without Trigonometry.pdf
2d Ball 碰撞检测示例:添加碰撞检测
成功!
我的球碰撞检测和响应工作得很好!
相关代码:
碰撞检测:
for (int i = 0; i < ballCount; i++)
{
for (int j = i + 1; j < ballCount; j++)
{
if (balls[i].colliding(balls[j]))
{
balls[i].resolveCollision(balls[j]);
}
}
}
这将检查每个球之间的碰撞但跳过冗余检查(如果您必须检查球 1 是否与球 2 碰撞,那么您不需要检查球 2 是否与球 1 碰撞。此外,它会跳过检查与自身的碰撞)。
然后,在我的球类中,我有我的 colliding() 和 resolveCollision() 方法:
public boolean colliding(Ball ball)
{
float xd = position.getX() - ball.position.getX();
float yd = position.getY() - ball.position.getY();
float sumRadius = getRadius() + ball.getRadius();
float sqrRadius = sumRadius * sumRadius;
float distSqr = (xd * xd) + (yd * yd);
if (distSqr <= sqrRadius)
{
return true;
}
return false;
}
public void resolveCollision(Ball ball)
{
// 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)));
// impact speed
Vector2d v = (this.velocity.subtract(ball.velocity));
float vn = v.dot(mtd.normalize());
// sphere intersecting but moving away from each other already
if (vn > 0.0f) return;
// collision impulse
float i = (-(1.0f + Constants.restitution) * vn) / (im1 + im2);
Vector2d impulse = mtd.normalize().multiply(i);
// change in momentum
this.velocity = this.velocity.add(impulse.multiply(im1));
ball.velocity = ball.velocity.subtract(impulse.multiply(im2));
}
源代码:球对球对撞机的完整源代码。
如果有人对如何改进这个基本的物理模拟器有一些建议,请告诉我!我还没有补充的一件事是角动量,所以球会更真实地滚动。还有其他建议吗?发表评论!