2009-05-11 2 views
3

저는 현재 Win32 API 및 C++의 프로그래밍 과정을위한 작은 공 물리 엔진을 작성하는 중입니다. 나는 GDI 백 버퍼 렌더러와 전체 GUI (조정할 더 많은 것들)를 마쳤지 만, 나는 완성에 가깝다. 마지막으로 공을 던지기 만하면되는 큰 장애물이 있습니다. (하지만이 문제는 직접 해결할 수 있습니다.)하지만 가장 큰 문제는 공이 튀는 것입니다. 무슨 일이 일어나는가하면 나는 공을 던져서 정말로 떨어지지만 한번 튀어 오르면 나는 그것을 풀어 주었다. 우스운 일은 특정 높이 이하에서만 발생합니다. (당신이 더 이상 코드 나 설명이 필요하면 문의하시기 바랍니다,하지만 너희들이 내 코드를 살펴 가질 수 있다면 나는 대단히 감사합니다.) 몇튀어 오르는 공이 에너지 보존 규칙을 따르지 않음

#void RunPhysics(OPTIONS &o, vector<BALL*> &b) 
{ 
    UINT simspeed = o.iSimSpeed; 
    DOUBLE DT; //Delta T 
    BOOL bounce; //for playing sound 

    DT= 1/o.REFRESH; 

    for(UINT i=0; i<b.size(); i++) 
    { 
     for(UINT k=0; k<simspeed; k++) 
     {   
      bounce=false; 

      //handle the X bounce 
      if(b.at(i)->rBall.left <= 0 && b.at(i)->dVelocityX < 0) //ball bounces against the left wall 
      { 
       b.at(i)->dVelocityX = b.at(i)->dVelocityX * -1 * b.at(i)->dBounceCof; 
       bounce=true; 
      } 
      else if(b.at(i)->rBall.right >= SCREEN_WIDTH && b.at(i)->dVelocityX > 0) //ball bounces against the right wall 
      {   
       b.at(i)->dVelocityX = b.at(i)->dVelocityX * -1 * b.at(i)->dBounceCof; 
       bounce=true; 
      } 
      //handle the Y bounce 
      if(b.at(i)->rBall.bottom >= SCREEN_HEIGHT && b.at(i)->dVelocityY > 0) //ball bounces against the left wall 
      { 
       //damping of the ball 
       if(b.at(i)->dVelocityY < 2+o.dGravity/o.REFRESH) 
       { 
        b.at(i)->dVelocityY = 0; 
       } 

       //decrease the Velocity of the ball according to the bouncecof 
       b.at(i)->dVelocityY = b.at(i)->dVelocityY * -1*b.at(i)->dBounceCof; 
       b.at(i)->dVelocityX = b.at(i)->dVelocityX * b.at(i)->dBounceCof; 

       bounce=true; 
      } 


      //gravity 
      b.at(i)->dVelocityY += (o.dGravity)/o.REFRESH; 
      b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER; 
      //METER IS DEFINED GLOBALLY AS 100 which is the amount of pixels in a meter 

      b.at(i)->pOrigin.x += b.at(i)->dVelocityX/o.REFRESH*METER; 

      b.at(i)->UpdateRect(); 
     } 
    } 
    return; 
} 
+0

DT는 1/o.REFRESH로 설정되고 나중에 o.REFRESH * DT에서 사용되므로 일부 논리 오류가 있거나 단순히 제거 할 수 있습니다. – schnaader

답변

1

좋아 :이 부분은 물리 코드 여기에있는 것들.

왼쪽 벽과 오른쪽 벽에 튀어 오르는 코드 경로가 다르지만 코드는 동일합니다. 코드가 동일하기 때문에 이러한 코드 경로를 결합하십시오.

기본 문제에 관해서는 : 나는 당신이 감쇠력/바운스 력을 적용한 후에 중력을 적용한다는 사실에 기인한다고 생각합니다.

0

dBounceCof가 1보다 큰 경우 예가 공을 더 높게 반올림합니다. 질문에 답할 수있는 모든 값이 없습니다.

4

통합의 오일러 방법을 사용하고 있습니다. 시간 간격 (DT)이 너무 클 수 있습니다. 또한 Y 좌표를 업데이트 행의 실수 것 같다 :

b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER; 

을 이미 속도로 중력을 추가 한, 그래서 당신은 위치에 추가 할 필요가 없습니다 당신은 곱하지 않습니다 DT에 의한 속도. 이것은 다음과 같아야합니다 :

b.at(i)->pOrigin.y += b.at(i)->dVelocityY * DT; 

또한 단위 (METER가 사용되는 방식)와 관련하여 약간의 혼란이있는 것으로 보입니다.

+0

충돌 바운스가있는 오일러 방법을 사용하지 마십시오. 충돌 감지시, 순간 및 새로운 위치의 보존을 통해 속도를 재 계산하십시오. – Joshua

+0

만약 내가 당신의 방법을 사용한다면, 공이 y 방향으로 전혀 움직이지 않는다. 어쨌든 덕분에 –

+0

@ Joshua : 저는 개인적으로 (아주 성공적으로) 가변 시간 세분화를 사용했습니다. 계산 한계에 부딪 치지 않는 한 매력처럼 작동합니다. –

1

RunPhysics는 언제 호출합니까? 타이머 루프에서? 이 코드는 근사치이며 정확한 계산이 아닙니다. 델타 t의 짧은 간격에서, 볼은 이미 자신의 위치와 속도를 알고리즘에서 고려하지 않았으며 실수를 거의 일으키지 않는 리터 비트로 변경했습니다. 공이 땅에 떨어질 때까지의 시간을 계산하고 변경 사항을 예측해야합니다.

그리고 중력이 이미 속도에 포함되어 있습니다, 그래서 두 번 여기를 추가하지 마십시오 :

b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER;

을 그런데 : 임시 변수에 (내가) b.at 저장, 당신은 그래서 모든 라인에서 다시 계산할 필요가 없습니다.

Ball* CurrentBall = b.at(i); 
0

나는 위치에 대한 방정식을 잘 생각하지 않습니다 :

b.at(i)->dVelocityY += (o.dGravity)/o.REFRESH; 

v=v0+gt입니다 - 잘 보인다, 내가 dGravity*DT 대신 dGravity/REFRESH_FREQ 써서 있지만.

b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER; 

그러나 이것은 벗어난 것처럼 보입니다. 이것은 p = p0+v + 1/2gt^2과 동등합니다.당신은한다고

  • *이 바로
  • 당신은 픽셀/m에 의한 중력 용어를 확장하는 단위를 얻을 수있는 시간을 속도를 곱 있지만 속도 용어입니다. 따라서 METER로 곱해야합니다.
  • 속도를 업데이트 할 때 이미 중력 효과를 설명 했으므로 중력 항을 다시 추가 할 필요가 없습니다.
0

빠른 답장을 보내 주셔서 감사합니다. 미안, 내가 더 분명해야 했어, RunPhysics는 PeekMessage 후에 실행 beiing입니다. 또한 모니터의 재생 빈도보다 초당 계산이 더 이상 필요하지 않도록 프레임 리미터를 추가했습니다. 그러므로 내 dleta는 새로 고침 빈도로 1 초를 나눈 값입니다. 어쩌면 내 DT는 실제로 계산하기에는 너무 작지만 두 배의 가치가 있습니까 ??? 손해 배상액은 조정 가능하지만 0.9에서 시작합니다.

+0

dt가 50ms에서 2us 사이이면 작동합니다. 이것을 낮추어 시뮬레이션을보다 정확하지만 CPU주기가 더 길어 지도록하십시오. Euler를 사용하는 경우 2-10ms의 dt를 사용할 수 있습니다. – Macke

0

바운스 할 때 위치를 재 계산하여 벽의 올바른 위치에서 튀어 나오게해야합니다.

e.e. 바운스가 발생했을 때의 정확한 시점을 분석하고, 그 방향 변경 (부분적으로 "계산 프레임")을 기반으로 새로운 속도/위치를 계산하여 공이 벽을 넘어 "더 이상"움직이지 않도록하십시오. 각 바운스.

w.r.t. 시간 단계에 따라 my answer here을 확인해보십시오.

+0

내 타이머는 정확히 다음과 같습니다. P 시간 간격이 바뀌는 모니터 새로 고침에 따라. 그리고 나는 짧은 시간 동안과 같이 벽을 넘어서 튀는 것을 꺼리지 않으며, 반발 엉덩이에 영향을 주어서는 안됩니다. (벽을 넘어서) 튀어 나와서 속도를 다시 낮추어야합니다. –

+0

Do 당신은 당신의 dt에 상한선이 있습니까? 최대 0.05 초와 비슷합니까? 프레임 당 여러 번 계산 루프를 실행 해 보셨습니까? (10 또는 50처럼) – Macke

0

강체 시뮬레이션에서 충돌 순간까지 통합을 실행 한 다음 속도가 충돌에서 침투하지 않도록 조정 한 다음 통합을 다시 시작해야합니다. 그것은 강체가 근사치라는 사실을 다루기 위해 일종의 즉각적인 단편입니다. (실제 볼은 충돌하는 동안 변형되므로 모델링이 어렵고 대부분의 경우 불필요합니다.)

두 가지 단계 (병력 통합과 충돌 해결)가 결합되었습니다. 앞에서 보았던 간단한 시뮬레이션을 위해 수직 반동을 처리 한 반복에서 중력 비트를 건너 뛰어도 충분합니다.

더 진보 된 시뮬레이션에서는 실제 충돌 인스턴스에서 충돌이 포함 된 간격 (dt)을 분할합니다. 충돌까지 통합하고 속도를 조정하여 충돌을 해결 한 다음 나머지 시간 동안 통합합니다. 그러나 이것은 당신의 상황에 과도한 것처럼 보입니다.

+0

감사합니다. 내 목표는 모든 것을 조정할 수 있기 때문에 중력을 갖고 싶은 이유입니다. 효과가 나타나는 한 근사치 일지라도 상관 없습니다. 어쩌면 궤도 계산 방법에 대한 몇 가지 예를 보여줄 수 있습니까? –

1

답하세요 !! 답변 !! 하지만 난 다른 계정을 잊어 버렸어. 나는 그걸 신고 할 수 없어 .--(

모든 훌륭한 답변을 주셔서 감사합니다. 제게 많은 도움을주었습니다. 당신이 준 답변은 실제로 정확했으며, 몇 가지 공식이 잘못되었습니다. 몇 가지 코드 최적화를 수행 할 수 있었지만 실제로 문제의 해결책은 없었습니다. 그래서 저는 종이 한 장을 들고 앉아서 프로그램에서 얻은 모든 값을 손으로 계산하기 시작했습니다. 두 시간이 걸렸습니다. O 내 문제에 대한 해결책을 찾으십시오 : 문제는 내가 내 속도 (whith 수정 코드)를 업데이 트로 나는 10 진수 값을 전혀 문제가 없다. 나중에 속도를 추가하여 Y의 위치를 ​​증가 델타 T는 결과가 verry 작은 값을 추가해야합니다. 문제는 이제 Win32에서 Elipse()를 그릴 때 점이 LONG이어서 모든 십진수 값이 손실된다는 것입니다. 즉, verry 오랜 기간이 지나서야 값의 속도가 10 진수 값에서 벗어나기 시작하고, 그와 함께 그 값이 높을수록 결과가 더 좋아집니다 (내 증상 중 하나). 이 문제는 내 볼의 실제 위치 (십진수 포함)가 포함 된 Ball 클래스에 추가 DOUBLE 값을 추가하는 것은 매우 간단합니다.RenderFrame()을 실행하는 동안 엘로어를 그리는 데 double의 바닥 또는 천장 값을 사용하지만 모든 계산에 대해 Double 값을 사용합니다. 다시 한 번 고마워요 모든 답장을 위해, STACKOVERFLOW PEOPLE ROCK !!!

관련 문제