1

そこで、SDL_Delay関数を使用して をキャップするゲーム ループを作成しました。次のframes per secondようになります。

//While the user hasn't qui

while( stateID != STATE_EXIT )
{
    //Start the frame timer
    fps.start();

    //Do state event handling
    currentState->handle_events();

    //Do state logic
    currentState->logic();

    //Change state if needed
    change_state();

    //Do state rendering
    currentState->render();

    //Update the screen
    if( SDL_Flip( screen ) == -1 )
    {
        return 1;    
    }

    //Cap the frame rate
    if( fps.get_ticks() < 1000 / FRAMES_PER_SECOND )
    {
        SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.get_ticks() );
    }
}

そのため、ゲームを実行すると60 frames per second(これは私が想定する「アイ キャップ」です)、依然として遅延タイプの動きが見られます。つまり、フレームが独立して表示され、動きが滑らかでないことがわかります。
これは、どうやらSDL_Delay関数が正確すぎて+,- 15 milliseconds、フレーム間の違いが私が望んでいるものよりも大きいためです。
(これらはすべて私の仮定です)

そのため、この問題の解決に役立つ優れた正確なタイマーを探しています。

助言がありますか?

4

5 に答える 5

4

Windowsでスレッドのスリープを1ミリ秒未満にする方法にも同様の質問があると思います

しかし、私自身ゲームプログラマーとして、フレームレートを管理するためにスリープ機能に依存していません(それらが取るパラメーターは最小限です)。画面にできるだけ速く物を描くだけです。ゲームループにたくさんの関数呼び出しがあり、それらを呼び出す頻度を追跡しています。たとえば、ゲームの応答性を高めるために入力を頻繁に(1000x /秒)チェックしますが、ネットワークの受信トレイを100x/秒以上チェックしません。

例えば:

#define NW_CHECK_INTERVAL    10
#define INPUT_CHECK_INTERVAL  1
uint32_t last_nw_check = 0, last_input_check = 0;

while (game_running) {
    uint32_t now = SDL_GetTicks();

    if (now - last_nw_check > NW_CHECK_INTERVAL) {
        check_network();
        last_nw_check = now;
    }

    if (now - last_input_check > INPUT_CHECK_INTERVAL) {
        check_input();
        last_input_check = now;
    }

    check_video();

    // and so on...
}
于 2012-09-26T14:35:27.947 に答える
2

そのために QueryPerformanceCounter / Frequency を使用します。

LARGE_INTEGER start, end, tps; //tps = ticks per second
QueryPerformanceFrequency( &tps );
QueryPerformanceCounter( &start );
QueryPerformanceCounter( &end );
int usPassed = (end.QuadPart - start.QuadPart) * 1000000 / tps.QuadPart;
于 2012-09-26T14:33:31.207 に答える
2

を使用して、MIDIシーケンスのタイミングを計るために作成した小さな待機関数を次に示しますQueryPerformanceCounter

void wait(int waitTime) {
    LARGE_INTEGER time1, time2, freq;

    if(waitTime == 0)
        return;

    QueryPerformanceCounter(&time1);
    QueryPerformanceFrequency(&freq);

    do {
        QueryPerformanceCounter(&time2);
    } while((time2.QuadPart - time1.QuadPart) * 1000000ll / freq.QuadPart < waitTime);
}

ティックをマイクロ秒に変換するには、ティックの差を計算し、1,000,000 (マイクロ秒/秒) を掛けて、1 秒あたりのティックの頻度で割ります。

たとえば、高解像度カウンターの精度が 1 マイクロ秒にまで低下することはほとんどありません。たとえば、10 マイクロ秒待機する必要があり、精度/頻度が 6 マイクロ秒ごとに 1 ティックである場合、10 マイクロ秒の待機は実際には 12 マイクロ秒以上になります。繰り返しますが、この周波数はシステムに依存し、システムごとに異なります。

また、Windows はリアルタイム オペレーティング システムではありません。プロセスはいつでもプリエンプトされる可能性があり、プロセスがいつ再スケジュールされるかを決定するのは Windows 次第です。アプリケーションはこの関数の途中でプリエンプトされる可能性があり、予想される待機時間が経過してからしばらく経つまで再起動されません。あなたがそれについてできることはあまりありませんが、それが起こったとしてもおそらく気付かないでしょう.

于 2012-09-26T14:31:41.463 に答える
0

60 fame per second is just the frequency of power in US (50 in Europe, Africa and Asia are somehow mixed) and is the frequency of video refreshing for hardware comfortable reasons (It can be an integer multiple on more sophisticated monitors). It was a mandatory constrains for CRT dispaly, and it is still a comfortable reference for LCD (that's how frequently the frame buffer is uploaded to the display)

The eye-cap is no more than 20-25 fps - not to be confused with retina persistency, that's about one-half - and that's why TV interlace two squares upon every refresh.

independently on the timing accuracy, whatever hardware device cannot be updated during its buffer-scan (otherwise the image changes while it is shown, resulting in half-drawn broken frames), hence, if you go faster than one half of the device refresh you are queued behind it and forced to wait for it.

60 fps in a game loop serves only to help CPU manufacturers to sell new faster CPUs. Slow down under 25 and everything will look more fluid.

于 2012-09-26T15:05:49.000 に答える
0

SDL_遅延:

This function waits a specified number of milliseconds before returning. It waits at least the specified time, but possible longer due to OS scheduling. The delay granularity is at least 10 ms. Some platforms have shorter clock ticks but this is the most common.

この関数で観察される実際の遅延は、OS の設定によって異なります。Mutimedia Timer API、特にtimeBeginPeriod 関数を調べて、割り込み頻度を要件に合わせることをお勧めし ます。

タイマー分解能の取得と設定では、割り込み周期を約 1ms に変更する方法の例を示します。これにより、15ms のヒックアップがなくなります。ところで: アイキャッチ期間は約 40ms です。

固定周期のタイミングの取得は、Waitable Timer Objectsによっても対処できます。しかし、マルチメディア タイマーの使用は、適切な解決策を得るために必須です。

他のツールを使用してタイミング機能を改善する方法については、ここで説明します。

于 2012-09-26T15:44:51.637 に答える