2D弹性碰撞'粘贴'问题

时间:2013-03-19 06:13:49

标签: c# 2d collision-detection collision

我有一个模拟多个圆在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;
    }
}

1 个答案:

答案 0 :(得分:1)

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

当您观察具有某个时间间隔dt的物体时,您可以观察两个圆圈之间的某个交点并调用您的碰撞方法,但在下一个时间步骤中它们仍可能重叠,尽管它们在前一次碰撞后朝不同的方向前进步骤

要减少此效果,您可以尝试较低的时间步长,以便可以减少对象之间的重叠比率。 作为一个更复杂的解决方案,您可以为每个步骤保留一个碰撞对象的列表,在迭代期间,如果当前相交的圆圈在上一步中有任何“事务”,则可以检查此列表。

相关问题