0

我有一个在 2D 空间中移动的多个圆圈的模拟。

它们之间存在碰撞检测,弹性碰撞在 95% 的时间内都有效。然而,偶尔,当两个球相互撞击时,它们会相互粘连并重叠,经常在被粘在一起的同时相互绕行。

我不确定如何解决这个问题。

我的碰撞管理功能如下所示:

void manageCollision(Particle particleA, Particle particleB)
{
    float distanceX = particleA.Position.X - particleB.Position.X;
    float distanceY = particleA.Position.Y - particleB.Position.Y;
    double collisionAngle = Math.Atan2(distanceY, distanceX);
    double pA_magnitude = Math.Sqrt(particleA.Velocity.X * particleA.Velocity.X + particleA.Velocity.Y * particleA.Velocity.Y);
    double pB_magnitude = Math.Sqrt(particleB.Velocity.X * particleB.Velocity.X + particleB.Velocity.Y * particleB.Velocity.Y);
    double pA_direction = Math.Atan2(particleA.Velocity.Y, particleA.Velocity.X);
    double pB_direction = Math.Atan2(particleB.Velocity.Y, particleB.Velocity.X);
    double pA_newVelocityX = pA_magnitude * Math.Cos(pA_direction - collisionAngle);
    double pA_newVelocityY = pA_magnitude * Math.Sin(pA_direction - collisionAngle);
    double pB_newVelocityX = pB_magnitude * Math.Cos(pB_direction - collisionAngle);
    double pB_newVelocityY = pB_magnitude * Math.Sin(pB_direction - collisionAngle);
    double pA_finalVelocityX = ((particleA.Mass - particleB.Mass) * pA_newVelocityX + (particleB.Mass + particleB.Mass) * pB_newVelocityX) / (particleA.Mass + particleB.Mass);
    double pB_finalVelocityX = ((particleA.Mass + particleA.Mass) * pA_newVelocityX + (particleB.Mass - particleA.Mass) * pB_newVelocityX) / (particleA.Mass + particleB.Mass);
    double pA_finalVelocityY = pA_newVelocityY;
    double pB_finalVelocityY = pB_newVelocityY;
    particleA.Velocity = new Vector2((float)(Math.Cos(collisionAngle) * pA_finalVelocityX + Math.Cos(collisionAngle + Math.PI / 2) * pA_finalVelocityY), (float)(Math.Sin(collisionAngle) * pA_finalVelocityX + Math.Sin(collisionAngle + Math.PI / 2) * pA_finalVelocityY));
    particleB.Velocity = new Vector2((float)(Math.Cos(collisionAngle) * pB_finalVelocityX + Math.Cos(collisionAngle + Math.PI / 2) * pB_finalVelocityY), (float)(Math.Sin(collisionAngle) * pB_finalVelocityX + Math.Sin(collisionAngle + Math.PI / 2) * pB_finalVelocityY));
}

每个球或粒子以随机的质量和半径生成。

该函数在更新类型的方法中调用,如下所示:

Particle pA = particles[i];
for (int k = i + 1; k < particles.Count(); k++)
{
    Particle pB = particles[k];
    Vector2 delta = pA.Position - pB.Position;
    float dist = delta.Length();

    if (dist < particles[i].Radius + particles[k].Radius && !particles[i].Colliding && !particles[k].Colliding)
    {
        particles[i].Colliding = true;
        particles[k].Colliding = true;
        manageCollision(particles[i], particles[k]);
        particles[i].initColorTable(); // Upon collision, change the color
        particles[k].initColorTable();
        totalCollisions++;
    }
    else
    {
        particles[i].Colliding = false;
        particles[k].Colliding = false;
    }
}
4

1 回答 1

1

这种情况源于离散计算和持续时间的大步长。

当您以某个时间间隔 dt 观察对象时,您可以观察两个圆之间的某些交点并调用您的碰撞方法,但在下一个时间步中,尽管它们在上一步碰撞后朝不同的方向前进,但它们仍可能重叠。

为了减少这种影响,您可以尝试使用较低的时间步长,这样可以减少对象之间的重叠率。作为更复杂的解决方案,您可以为每一步保留碰撞对象的列表,并且在迭代期间,如果当前相交的圆圈在上一步中有任何“事件”,您可以检查此列表。

于 2013-03-19T06:46:17.153 回答