2017-05-02 25 views
7

OpenGL GLUTコードを使用してゲームをプログラミングしています。ゲームのメインループの各繰り返しで消費される時間を測定するゲーム開発技術を適用しています。前回の更新に比例してゲームシーンが更新されます。これを達成するために、私はループの始めにこれを持っています:C++時間の計測が遅すぎる

void logicLoop() { 

    float finalTime = (float) clock()/CLOCKS_PER_SEC; 
    float deltaTime = finalTime - initialTime; 
    initialTime = finalTime; 

    ... 
    // Here I move things using deltaTime value 
    ... 
} 

私はゲームに弾丸を追加したときに問題が発生しました。 2秒間に弾丸がターゲットに当たっていない場合は、それを破壊する必要があります。その後、私がやったことは一瞬への参照を保持するために弾丸が、このように作成した:

class Bullet: public GameObject { 

    float birthday; 

public: 
    Bullet() { 
     ... 
     // Some initialization staff 
     ... 

     birthday = (float) clock()/CLOCKS_PER_SEC; 
    } 

    float getBirthday() { return birthday; } 

} 

そして私はちょうどfinalTimeとdeltaTime測定を超えてロジックにこれを追加しました:

if (bullet != NULL) { 
    if (finalTime - bullet->getBirthday() > 2) { 
     world.remove(bullet); 
     bullet = NULL; 
    } 
} 

それは素晴らしそうに見えましたが、コードを実行すると、弾丸はあまりにも多くの時間を生かしています。問題を探して、私は(finalTime - bullet-> getBirthday())の値を表示し、秒単位で測定された時間ではないように、実際には非常に遅くなるのを見ました。

問題はどこですか?しかし、結果は数秒で終わるので、弾丸は2秒で取り除かれます。

+3

わからないがここで起こっていただきましたが、あなたがC++ 11を持っている場合は、使用してみてください[ '' ](http://en.cppreference.com/w/cpp/header/chrono)および保存することができます'std :: chrono :: time_point'を追加しました。 – NathanOliver

+0

なぜ 'glutGet(GLUT_ELAPSED_TIME)'を使わないのですか? – genpfault

+0

@genpfault:おそらく明らかであるようにも見えますが、ドキュメンテーションには言いませんが、それは壁の時間だよね? –

答えて

10

これはよくある間違いです。 clock()は実際の時間の経過を測定しません。 CPUがこの特定のプロセスを実行している間に経過した時間を測定します。

他のプロセスもCPU時間がかかるので、2つのクロックは同じではありません。あなたのオペレーティングシステムが他のプロセスのコードを実行しているときは、これが "スリープ"しているときも含めて、clock()にはカウントされません。そして、あなたのプログラムが複数のCPUを持つシステム上でマルチスレッド化されている場合、clock()は「ダブルカウント」時間になるかもしれません!

人間はOSのタイムスライスについての知識や認識を持っていません。実際の時間の実際の経過(「壁の時間」として知られています)を認識するだけです。最終的には、clock()のタイムベースが壁の時間と異なることがわかります。

Do not use clock() to measure wall time!

代わりgettimeofday()またはclock_gettime()ような何かをしたいです。システム時間を変える人の影響を和らげるために、私は個人的に壁の時間と同期しているが、コンピュータの時間を遊んでいる人々の影響を受けない任意のエポックを持つシステムの "単調時計"で、clock_gettime()を個人的にお勧めします設定。 (ニーズがである場合は明らかにポータブル代替に切り替える。)これは、実際に議論さ

the cppreference.com page for clock()に:

std::clock時間が速いか遅いウォールクロックよりも進めることができる、プログラムに与えられた実行リソースに依存オペレーティングシステムによって異なります。たとえば、CPUが他のプロセスと共有されている場合、std::clock時間は壁時計よりも遅く進む可能性があります。一方、現在のプロセスがマルチスレッドで、複数の実行コアが使用可能な場合は、std::clock時間が壁時計よりも早く進む場合があります。

何が起こっているのかわからないときは、使用しているすべての機能についてドキュメントを読むという習慣を身につけてください。

編集: GLUT自体には、これに便利な便利な機能があります。 glutGet(GLUT_ELAPSED_TIME)には、glutInit()に電話をかけてからの経過時間(ミリ秒)が表示されます。だから私はあなたがここに必要なものだと思う。 GLUT(または他のOpenGLの他の部分)がすでに壁の時間を定期的に要求している場合、そしてこの関数が単にすでに取得した時刻&hellipを照会する場合は、若干性能が向上する可能性があります。不要なセカンドシステムコール(コストがかからない)を節約できます。

+0

これは正解です。低レイテンシシステムでは、 'clock_gettime'を使ってアプリケーションをクロッキングします。 – Viet

1

Windowsの場合は、かなり正確な時間測定を行うQueryPerformanceFrequency/QueryPerformanceCounterを使用できます。

例を示します。

#include <Windows.h> 
using namespace std; 

int main() 
    { 
    LARGE_INTEGER freq = {0, 0}; 
    QueryPerformanceFrequency(&freq); 

    LARGE_INTEGER startTime = {0, 0}; 
    QueryPerformanceCounter(&startTime); 

    // STUFF. 
    for(size_t i = 0; i < 100; ++i) { 
     cout << i << endl; 
     } 

    LARGE_INTEGER stopTime = {0, 0}; 
    QueryPerformanceCounter(&stopTime); 

    const double ellapsed = ((double)stopTime.QuadPart - (double)startTime.QuadPart)/freq.QuadPart; 
    cout << "Ellapsed: " << ellapsed << endl; 

    return 0; 
    } 
+0

MSDNが非常に貧弱であるため、これは確かにわかりにくいですが、この_seems_はプロセスに依存しない安定したものであるため、Windows上での選択は非常に便利です。 –