2013-03-21 5 views
1

2D 공간에서 움직이는 여러 원이있는 시뮬레이션이 있는데, 둘 사이에 탄성 충돌이 있습니다.2D 볼 사이의 끌어 당김 력

입자 사이에 인력을 추가하여 입자가 질량 등에 따라 다른 입자쪽으로 이동하도록하고 싶습니다. 어떻게해야합니까?

내 충돌 관리 기능은 다음과 같습니다

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)); 
} 

각각의 볼 또는 입자가 임의의 질량과 반지름 생성합니다.

기능은 다음과 같이 방법의 업데이트 유형 내에서 호출됩니다

Vector2 globalGravity = new Vector2(0f, gravityScale/6000); 

    for (int i = 0; i < particles.Count(); i++) 
{ 
    particles[i].Update((float)updateTimer.Interval, globalGravity); 
    Vector2 position = particles[i].Position; 
    Vector2 velocity = particles[i].Velocity; 
    collisionWallCheck(ref position, ref velocity, particles[i].Radius); 
    particles[i].Position = position; 
    particles[i].Velocity = velocity; 


    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; 
     } 
    } 
} 

내가 각 볼의 초기 위치, 속도, 질량을 저장하고있다. 내가 분명히 할 필요가 및 구현하는 방법을 모르는 무엇

은 다음과 같습니다

  • 는 중력의 크기와 방향을 계산합니다.
  • 힘을 알면 각 신체의 가속도를 계산할 수 있습니다.
  • 가속도를 알면 새로운 속도를 계산할 수 있습니다.
  • 속도를 알면 새 위치를 계산할 수 있습니다.

나는 방정식을 근본적으로 흔들 렸고, 나는 두 개의 볼 사이에 인력을 만들어 시작하고 싶습니다.

스티븐의 제안을 사용하면 이것이 새로운 통합 코드입니다.

void updateTimer_Tick(object sender, EventArgs e) 
{ 
    const double G = 6.67398 * 0.00000000001; 

    for (int i = 0; i < particles.Count(); i++) 
    { 
     double sumX = 0; 
     double sumY = 0; 

     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(); 
       particles[k].initColorTable(); 
       totalCollisions++; 
       particles[i].Colliding = false; 
       particles[k].Colliding = false; 
      } 
      else 
      { 
       double distanceX = particles[i].Position.X - particles[k].Position.X; 
       double distanceY = particles[i].Position.Y - particles[k].Position.Y; 
       double r = Math.Sqrt(Math.Pow(distanceX, 2) + Math.Pow(distanceY, 2)); 
       double force = G * particles[i].Mass * particles[k].Mass/(r * r); 
       double theta = Math.Tan(distanceY/distanceX); 
       sumX += force * Math.Cos(theta); 
       sumY += force * Math.Sin(theta); 
       particles[i].Colliding = false; 
       particles[k].Colliding = false; 
      } 
     } 
     double netForce = Math.Sqrt(Math.Pow(sumX, 2) + Math.Pow(sumY, 2)); 
     double a = netForce/particles[i].Mass; 
     double aTheta = Math.Tan(sumY/sumX); 

     // Here we get accelerations for X and Y. You can probably figure out velocities from here. 
     double aX = a * Math.Cos(aTheta); 
     double aY = a * Math.Sin(aTheta); 
     Vector2 accel = new Vector2((float)aX, (float)aY); 

     particles[i].Update((float)updateTimer.Interval, accel); 
     //particles[i].Update((float)updateTimer.Interval, globalGravity); 
     Vector2 position = particles[i].Position; 
     Vector2 velocity = particles[i].Velocity; 
     collisionWallCheck(ref position, ref velocity, particles[i].Radius); 
     particles[i].Position = position; 
     particles[i].Velocity = velocity + accel; 
    } 
    Draw(); 
} 

입자에 대한 업데이트 기능은 간단하며 0,0 인 전역 중력 벡터를 사용하기 전에 간단합니다.

 public void Update(float timeStep, Vector2 gravity) 
     { 
      velocity = velocity + timeStep * gravity; 
      position = position + timeStep * velocity; 
     } 

내가 위치 모든 공을 자신의 질량을 알면 0

답변

5

각 물체에 작용하는 중력을 계산하는 것으로 시작하십시오. 이것은 G가 the gravitational constant이다

M1 및 M2는 두 물체의 질량이다
F = Gm1m2/r*r 

의해 주어진, R은 두 개의 오브젝트 사이의 거리이다.

이제 r은 벡터이므로, 이것을 별도의 구성 요소 인 Fx와 Fy로 나눌 수 있습니다.각 미사

Fx = F * cos(theta) 
Fy = F * sin(theta) 

그것을 모든 다른 물체에 작용하는 중력의 힘을 계산 : 다음과 같이이 작업을 수행 할 수 있습니다. Sum the vectors 그물 중력을 얻을 수 있습니다. (참고 - 해당 링크는 관심사로 사용할 수 있지만 그 시점까지 오랜 시간이 걸립니다.) 이 시점에서 가속도를 계산할 수있는 각 객체에 대한 순 강제력을 갖게됩니다. 다음은이 지점에 도착하는 코드이다 :

const double G = 6.67398 * 0.00000000001; 

for (int i = 0; i < particles.Count(); i++) 
{ 
    double sumX = 0; 
    double sumY = 0; 

    for (int j = 0; j < particles.Count(); j++) 
    { 
     // Don't add attraction to self 
     if (i == j) 
      continue; 

     double distanceX = particles[i].Position.X - particles[j].Position.X; 
     double distanceY = particles[i].Position.Y - particles[j].Position.Y; 
     double r = Math.Sqrt(Math.Pow(distanceX, 2) + Math.Pow(distanceY, 2)); 
     double force = G * particles[i].Mass * particles[j].Mass/(r * r); 
     double theta = Math.Tan(distanceY/distanceX); 
     sumX += force * Math.Cos(theta); 
     sumY += force * Math.Sin(theta); 
    } 

    double netForce = Math.Sqrt(Math.Pow(sumX, 2) + Math.Pow(sumY, 2)); 
    double a = netForce/particles[i].Mass; 
    double aTheta = Math.Tan(sumY/sumX); 

    // Here we get accelerations for X and Y. You can probably figure out velocities from here. 
    double aX = a * Math.Cos(aTheta); 
    double aY = a * Math.Sin(aTheta); 
} 

주의 사항

이 계정에 0 값과 같은 물건을하지 않습니다 - 당신은 특별한 경우를 처리하기 위해이 코드를 정리해야합니다 충돌없이 실행됩니다.

모든 힘을 계산할 때까지 위치를 업데이트하지 마십시오. 그렇지 않으면 목록의 나중 요소에 대해 해제됩니다.

주목할 가치가있는 또 다른 것 :이 알고리즘은 O (n^2)입니다. 따라서 당신이 몇 개 이상의 시체를 가지고 있다면 그것은 많은 처리를 할 것입니다. 그것은 불행히도 그것은 단지 방법입니다. 많은 수의 시체에 대해 중력 매력을 계산하는 빠른 방법을 찾으면 NASA에 전화해야합니다.

좌표계에 따라 y 벡터가 뒤 바뀌는 것을 볼 수 있습니다. 이것은 유클리드 기하학이 y의 양의 값을 "올라가는"것으로 생각하기 때문입니다. 반면 프로그래머는 y를 화면 상단에서 "아래로 내려가는"양의 단위로 측정하는 경향이 있기 때문입니다. 이것은 당신의 각과 물건으로 혼란을 재생할 수 있습니다.

+0

아주 좋은 설명, 고맙습니다. 이 코드는 어디에 추가해야합니까? – Edge

+0

코드를 삽입하는 것보다는 코드를 병합해야합니다. 내가 넣은 것들은 각 입자에 대한 중력 때문에 가속도를 계산합니다. 당신은 다른 힘 (충돌 등)으로 인한 가속에 그것을 추가하기를 원할 것입니다. 그런 다음 합계 된 가속도 (Vector2 여야 함)를 사용하여 새 속도를 결정한 다음 위치를 지정하십시오. 요점은 파티클이 어디에 위치하는지 계산을 분리해야한다는 것입니다. 배치에서 모든 것을 계산 한 다음 일괄 적으로 업데이트합니다. –

+0

나는 당신의 제안을 구현하려고 시도했지만, 이제는 볼에 아무 것도 표시되지 않습니다. 내가 뭔가 잘못했다고 가정하고있어. – Edge

0

의 경우에 대처하는 방법을 지금 확실 해요, 당신은 힘의 벡터가 두 기관 사이의 느낌 계산할 수 있습니다. 공 'A'에서 다른 모든 공까지 'B', 'A'에서 'C', 'A'에서 'D'등으로 'A'를 찾은 다음 A의 모든 벡터를 A에 작용하는 힘의 최종 벡터를 얻으십시오. B -> A, B -> C, 등등을 반복하여 B의 벡터를 찾으십시오. 이 모든 작업을 수행하고 새 속도를 계산하고 단계 사이의 시간 간격을 조정합니다.