2013-03-19 9 views
7

私は現在、C++で物理エンジンを作成する過程で、コンピュータゲームプログラミングを大学に行っています。可変タイムステップを導入する際のトラブル

私はそれが

私の問題をステッピング我々は時間になるだろう現在の深さに適しているとして、不正確にもかかわらず、のGetTickCount()メソッド経由でタイムステップを導入するように求めてきた今、私が持っているということです導入されたタイムステップベースのムーブメントでは、更新機能の2つの異なるオーバーライドによってスクリーンに描画されたオブジェクトは機能していないようです。

コード内にブレークポイントを追加することで、mElapsedTimeが値を渡すように見えないように見え、私は困惑しています。

申し訳ありませんが、この記事があまりにも漠然としていたり​​、トピックから外れていたりすると、できるだけ多くの文脈を提供しようとしました。これが私の最初の投稿です。粒子クラス(例えばpos.x =速度のアップデートでより容易な乗算にfloat型のmElapsed時間、:

編集(frameStartTimeパラメータは、ちょうどフレームが更新され、描かれる前に、ダニ・カウントを取ります)。 x * timeStep)これが符号なしlongからfloatへのキャストの理由です。それはまだ冗長ですか?私が思う

void Simulation::gameLoopDelay(DWORD frameStartTime) 
{ 
    DWORD presetFrameInterval = 16; 
    DWORD frameProcessingTime = GetTickCount() - frameStartTime; 

    if (frameProcessingTime < presetFrameInterval) 
    { 
     Sleep(presetFrameInterval - frameProcessingTime); 
    } 

    mElapsedTime = (float)frameProcessingTime/1000.0f; 
} 
+0

良い最初の質問です。あなたの 'presetFrameInterval'は定数でなければならないことと、最後の行の' float'へのキャストは冗長であるということです。 'mElapsedTime'は' float'ですか?関連するコードを取って完全な関連コードだけを使って完全なサンプルに凝縮する方法はありますか? – chris

+0

あなた自身で問題をデバッグしようとしているための名誉です。しかし、このコードスニペットだけでは、私たちがあなたに伝えることはあまりありません。ここで明らかに間違ったことはありません。 –

+0

私が潜在的に間違っているのは、スリープ後の経過時間がSleep()に渡された要求インターバルまで正確であるという仮定です。それは確かにそうでない*。睡眠から出た後にGetTickCount()を再設定せずにどれくらいの時間を過ごしたかは分かりません。 (そして質問のための小道具; **大半の最初の質問よりも遠すぎる**最初の質問ではなくても)あなたは分析して、最初に助けようとしました。 – WhozCraig

答えて

1

あなたは十分な情報を提供していないため、私は絶対に確信していませんが、私が見る最初の問題は、Sleep(...)に関係なくmElapsedTime = (float)frameProcessingTime/1000.0f;です。言い換えれば、あなたは睡眠を考慮に入れることを忘れていました。これを行うには、Sleep(...)を呼び出した後にGetTickCount()を再フェッチする必要があります。しかし、その場合でも、あなたのコードはあまりにも定型的でエラーを起こしやすくなります。あなたのニーズに合わせて、このクラスを利用する方法は簡単です

class Stopwatch { 
public: 
    Stopwatch(): _start(0), _elapsed(0), _running(false) {} 

    void 
    start() { 
    if (_running) 
     return; 

    _running = true; 
    _start = GetTickCount(); 
    } 

    void 
    stop() { 
    if (!_running) 
     return; 

    _elapsed += GetTickCount() - _start; 
    _running = false; 
    } 

    void 
    reset() { 
    _running = false; 
    _elapsed = 0; 
    } 

    void 
    restart() { 
    _running = true; 
    _elapsed = 0; 
    _start = GetTickCount(); 
    } 

    bool 
    isRunning() const { 
    return _running; 
    } 

    DWORD 
    elapsed() const { 
    return _running ? _elapsed + (GetTickCount() - _start) : _elapsed); 
    } 

    bool 
    hasExpired(DWORD interval) const { 
    return elapsed() > interval; 
    } 

private: 
    DWORD _start; 
    DWORD _elapsed; 
    bool _running; 
}; 

:単純なタスクを行う、小さな柔軟性、および再利用可能なクラスを書くことによって、あなたの問題に近づいて

スタート。

第2に、なぜあなたはSleepを使用するのですか?私がフレーム遅延の例を見た最後の時間は、おもちゃゲームの作成に関するいくつかの厄介なチュートリアルで約5年前です。このものは古いゲームでは本当に人気がありましたが、現代のゲームでは意味がありません。もちろん、これがあなたの任務のための要件であれば、私はお詫びしますが、その発言は依然として適用されます。

最後に、自分自身の経験からリアルタイムの視覚化に関するアドバイスをいただきたいと思います。 しないGetTickCountなどの生の機能を持つ時間依存コードや、Windows API(またはLinux API、重要ではありません)プログラマの間で他の一般的なくせに書きます。これは、もう一度おもちゃゲームを作成する時代遅れのチュートリアルのようです。

次に使用するものは何ですか?さて、今日はうまく設計されており、信頼性の高いクロスプラットフォームのライブラリがあるため、Boostのように幸運です。あなたはおそらくそれに精通しているはずですが、そうでない場合は間違いなく実行する必要があります。あなたの特別な問題のために、時間とともに適切に働くように注意深く設計されたモジュールBoost.Chronoがあります。私はリアルタイムレンダリングを含むいくつかのプロジェクトでそれを使用しています。これは非常に堅牢で学習価値があることを認めなければなりません。

もう1つ、ライブラリBoost.Units - は、安定した正確な物理エンジンを作成するためにはでなければなりません。このライブラリは、さまざまな単位システムモデル(たとえば、SIまたはCGS)の単位(力、質量、速度、加速度など)と量のタイプセーフなサポートを提供します。これはテンプレートメタプログラミングに基づいているため、実行時にオーバーヘッドが発生しません。

もう一度、あなたの割り当てがおそらくそのようなことを許可しないことを理解します。しかし、私がここで言及したことは、皆さんにとって将来的に貴重なものになると私は信じています。ところで、それは実際の生活の問題を解決するために提供する大学の課題よりもどれだけ知っているべきかの良い例です。

さらに詳しい情報が必要な場合は、詳細が必要です。たとえば、ゲームのループ全体のコードを表示することから始めます。

+0

ありがとう、大変感謝しています。私はタイマーやそのようなものを抽象化するという概念を理解しています。私は自分自身のプログラミング(割り当てなど)でもこれを行いますが、この特定のチュートリアル実装では、このように実装するように言われました。プロジェクトの詳細を表示するには、ループ全体をポストすると、このようなサイトに適していると思われるよりも多くのコードが投稿されるようになるでしょうか?よく分かりません。 Boostライブラリに関するヒントをありがとう、私はそれについて前に聞いたことがあるが、実際にそれをまだチェックアウトしていないが、私は確かに今だと思う。 –

+0

あなたは時間**だけを扱うゲームループの部分、例えば 'frameStartTime'を含むものだけを投稿するかもしれません。 StackOverflowでは、〜200行の関数体全体を投稿すると、人々はあなたを抱き締めません。コードから最大限の関連情報を抽出し、簡単な例を投稿することができますが、同時に問題を完全に反映する必要があります。プレゼンテーションの目的でコードを縮小するスキルは、ここで質問するだけでなく、実際の制作にも役立ちます。 –

1

は、基本的に、あなたはこのようにコードを変更する必要があります。

void Simulation::gameLoopDelay(DWORD frameStartTime) 
{ 
    DWORD presetFrameInterval = 16; 
    DWORD frameProcessingTime = GetTickCount() - frameStartTime; 

    if (frameProcessingTime < presetFrameInterval) 
    { 
     Sleep(presetFrameInterval - frameProcessingTime); 
    } 

    frameProcessingTime = GetTickCount() - frameStartTime; 

    mElapsedTime = (float)frameProcessingTime/1000.0f; 
} 

これはおそらく、全体のスレッドをロックアウトされ、ここでSleepので、これを行うには、最もお勧めの方法ではありません。分数の時間にフレームを作成する方が良いでしょうが、これでコードが修正されると思います。

+0

答えをありがとう、私は与えられた両方の答えを読んだ後にこれを入れて、ティックカウントを再フェッチしました、非常にありがとう、私はおそらく私は私の割り当ての分数時間を見ていると思う睡眠に拘束されています()。 –