2013-03-19 1 views
0

2D 공간에서 움직이는 여러 개의 원이있는 시뮬레이션이 있습니다.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

이러한 상황은 이산 계산 및 지속 시간의 큰 스텝 크기로부터 유래한다.

시간 간격 dt가있는 물체를 관찰하면 두 원 사이의 교차점을 관찰하고 충돌 방법을 호출 할 수 있지만 다음 시간 단계에서는 충돌이 발생한 후 서로 다른 방향으로 가고 있지만 여전히 겹칠 수 있습니다. 이전 단계.

이 효과를 줄이려면 개체 사이의 겹치는 비율을 줄 이도록 시간 단계 크기를 낮추십시오. 더 복잡한 솔루션으로 모든 단계에서 충돌 한 개체의 목록을 유지할 수 있으며 반복하는 동안 현재 교차 된 원에 이전 단계에서 "업무"가있는 경우이 목록을 확인할 수 있습니다.