2009-05-11 4 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

@ジョシュア:私は個人的に(大成功に)可変時間セグメンテーションを使用しています。あなたが計算上の限界に耐えない限り、それは魅力のように機能します。 –

1

いつRunPhysicsを呼び出しますか?タイマーループで?このコードは単なる近似であり、正確な計算ではありません。デルタtの短い間隔では、ボールはすでに自分の位置と速度をあなたのアルゴリズムでは考慮されておらず、間違いがほとんどないリットビットに変更しました。ボールが地面に当たるまでの時間を計算し、その変化を予測する必要があります。

と重力はすでに速度に含まれているので、二度それをここに追加しないでください:

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

をところで:あなたので、一時的な変数にb.at(i)を保存しますすべての行でそれを再計算する必要はありません。

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に等価です。

  • あなたは速度を掛けるべき*単位を取得する時間権利
  • あなたはピクセル/メートルによる重力項ではなく、速度項をスケーリングしています。それではMETERを掛けるべきです
  • 速度を更新したときに重力の効果を既に説明しているので、重力項を再度追加する必要はありません。
0

すばやくお返事ありがとうございます!申し訳ありませんが、私はもっと明確にすべきだった、RunPhysicsはPeekMessageの後に実行beiingです。また、フレームリミッタを追加して、モニタのリフレッシュレートよりも毎秒計算が行われないようにしました。したがって、私のdletaは、リフレッシュレートで1秒を割りました。たぶん私のDTは実際には計算するには小さすぎますが、それは二重の値ですか?私の返済額は調整可能ですが、0.9から始まります。

+0

dtは50msと2usの間であればうまくいくはずです。それを下げて、より正確ではあるがCPUサイクルが重くなるようにしてください。 オイラーを使用している場合は、2〜10 msのdtを使用します。 – Macke

0

バウンス時のあなたの位置を再計算して、壁の正しい場所から跳ね返る必要があります。

I.e.バウンスが発生したときの正確な時点を解決し、その方向変更に基づいて新しい速度/位置を計算し(部分的に「計算の枠組み」に)、ボールが壁を越えて移動しないようにします。それぞれバウンスします。

W.r.t.タイムステップでは、my answer hereをチェックしてみてください。

+0

私のタイマーはそれとまったく同じです:P時間間隔の変化がモニターのリフレッシュに応じて。私はそれが短期間のように壁を越えてバウンスしても構わないし、反発の尻に影響を与えてはならないという点は、壁を越えてバウンスしたときに再びスピードを落とすことで補償されるべきだ。 –

+0

Doあなたはあなたのdtの上限を持っていますか?最大0.05sのように?フレームごとに計算ループを数回試してみましたか? (10または50のように) – Macke

0

リジッドボディシミュレーションでは、積分を衝突の瞬間まで実行してから、速度を調整して衝突の侵入を防ぎ、積分を再開する必要があります。剛体が近似であるという事実をカバーするのは、瞬間的なクルーの一種です。

これらの2つのステップ(力を統合して衝突を解決する)を組み合わせていることになります。あなたが示したようなシンプルなシミュレーションの場合、垂直バウンスを扱った反復で重力ビットをスキップするだけで十分でしょう。

さらに高度なシミュレーションでは、衝突の実際のインスタンスで衝突を含む間隔(dt)を分割します。衝突まで積分し、速度を調整して衝突を解決し、残りの時間間隔で積分します。しかし、これはあなたの状況のた​​めに過度のように見えます。

+0

おかげで、私は重力を持っている理由は、私の目標はすべての調整を保つことだからです。エフェクトが表示されている限り、近似であれば気にしません。多分軌道をどのように計算するかの例を示してください。 –

1

アンサー!!アンサー!!回答!しかし、私は他のアカウントを忘れてしまったので、私はそれにフラグを立てることができません:-(

本当にありがとうございました!いくつかのコード最適化を行うことができましたが、実際に問題の解決策はありませんでした。私はちょうど紙で座って、私のプログラムから手に入れたすべての価値を計算し始めました。私の問題の解決策を見つける: 問題は、自分の速度(whithの訂正されたコード)を更新するときに、何も問題がないということです。 Win32でElipse()を描画するとポイントがLONGになり、すべての10進数値が失われるという問題がありました。それは、verryの長い期間の後で、値の速度が小数点値から出てくると、何かが起こり、それに伴ってボールが高くなるほど、結果(私の症状の1つ)が改善されることを意味します。この問題は本当にシンプルで、私のボールの真の位置(小数点を含む)を含んでいたボールクラスに余分なダブル値を追加しました。RenderFrame()では、エリープを描画するためにdoubleのフロアまたはシーリング値を取るだけですが、すべての計算ではDouble値を使用します。もう一度お返事いただきありがとうございます。STACKOVERFLOW PEOPLE ROCK !!!

関連する問題