在 Stack Overflow 社区的帮助下,我编写了一个相当基本但有趣的物理模拟器。
你可以通过点击和拖动鼠标来发射球。球会在周围弹跳并最终停在“地板”上。
我想要添加的下一个重要功能是球与球之间的碰撞。球的运动被分解为x和y速度向量。我有重力(每步减小y向量的大小),我有摩擦(每次与墙壁碰撞时,两个向量都会稍微减小)。球实际上以一种令人惊讶的逼真方式移动。
我想问的问题有两个部分:
- 检测球与球之间碰撞的最佳方法是什么?
我是否只需要使用O(n^2)循环,迭代每个球并检查每个其他球是否重叠半径? - 我应该使用哪些方程式来处理球与球之间的碰撞?物理学101
它如何影响两个球的速度x/y向量?两个球朝着什么方向飞出去?我如何将其应用于每个球?
处理“墙壁”碰撞检测和结果向量变化很容易,但我发现球与球之间的碰撞更为复杂。对于墙壁,我只需取适当的x或y向量的负值即可朝正确方向移动。对于球来说,我不认为是这样的。
一些快速澄清:为简单起见,我现在可以接受完全弹性碰撞,而且所有的球现在都有相同的质量,但我将来可能会改变。
编辑:我发现有用的资源
使用向量的2D球体物理学: 2-Dimensional Collisions Without Trigonometry.pdf
2D球体碰撞检测示例: Adding Collision Detection
成功!
我的球体碰撞检测和反应真的很好!
相关代码:
碰撞检测:
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));
}
源代码:球与球碰撞完整源代码。
如果有人有关于如何改进这个基本的物理模拟器的建议,请让我知道!我还未添加的一件事是角动量,这样球就会更真实地滚动。其他建议呢?请留言!
Vector2d impulse = mtd.multiply(i);
行应该是i乘以标准化的mtd向量。类似这样:Vector2d impulse = mtd.normalize().multiply(i);
- klenwell