Journeyman Geekの回答(私の編集が拒否されたため)に加えて、コーディングパート/開発者の視点に興味のある人々のために:
プログラマーの観点からは、興味のある人にとっては、DOS時間はすべてのCPUティックが重要であったため、プログラマーはコードを可能な限り高速に保ちました。
プログラムが最大CPU速度で実行される典型的なシナリオは、次の単純なものです(擬似C):
int main()
{
while(true)
{
}
}
これは永遠に実行されます。今、このコードスニペットを擬似DOSゲームに変えましょう。
int main()
{
bool GameRunning = true;
while(GameRunning)
{
ProcessUserMouseAndKeyboardInput();
ProcessGamePhysics();
DrawGameOnScreen();
//close game
if(Pressed(KEY_ESCAPE))
{
GameRunning = false;
}
}
}
DrawGameOnScreen
関数がダブルバッファリング/ V-sync(DOSゲームが作成された当時は高額だった)を使用しない限り、ゲームは最大CPU速度で実行されます。現代のモバイルi7では、これは1秒あたり約1,000,000〜5,000,000回実行されます(ラップトップの構成と現在のCPU使用量に依存します)。
これは、64ビットウィンドウで最新のCPUでDOSゲームを動作させることができれば、物理処理が「想定」されている場合、人間がプレイするには速すぎる1000(1000!)FPSを取得できることを意味します。 50-60 fpsの間。
今日の開発者ができることは:
- ゲームでV-Syncを有効にします(*ウィンドウアプリケーションでは使用できません** [別名フルスクリーンアプリでのみ使用可能])
- 最後の更新間の時間差を測定し、時間差に従って物理学を更新して、FPSレートに関係なくゲーム/プログラムを同じ速度で効果的に実行します
- プログラムでフレームレートを制限する
***グラフィックカード/ドライバー/ OSの構成によっては、可能性があります。
ポイント1については、実際には「プログラミング」ではないため、例を示しません。グラフィック機能を使用しているだけです。
ポイント2と3については、対応するコードスニペットと説明を示します。
2:
int main()
{
bool GameRunning = true;
long long LastTick = GetCurrentTime();
long long TimeDifference;
while(GameRunning)
{
TimeDifference = GetCurrentTime()-LastTick;
LastTick = GetCurrentTime();
//process movement based on how many time passed and which keys are pressed
ProcessUserMouseAndKeyboardInput(TimeDifference);
//pass the time difference to the physics engine so it can calculate anything time-based
ProcessGamePhysics(TimeDifference);
DrawGameOnScreen();
//close game if escape is pressed
if(Pressed(KEY_ESCAPE))
{
GameRunning = false;
}
}
}
ここでは、ユーザー入力と物理学が時間差を考慮に入れているのを見ることができますが、ループが可能な限り高速で実行されているため、画面上で1000+ FPSを取得できます。物理エンジンはどれだけ時間が経過したかを知っているため、「仮定なし」や「特定のフレームレート」に依存する必要はなく、ゲームはどのCPUでも同じ速度で動作します。
3:
フレームレートをたとえば30 FPSに制限するために開発者ができることは、実際にはそれほど難しくありません。
int main()
{
bool GameRunning = true;
long long LastTick = GetCurrentTime();
long long TimeDifference;
double FPS_WE_WANT = 30;
//how many milliseconds need to pass before we need to draw again so we get the framerate we want?
double TimeToPassBeforeNextDraw = 1000.0/FPS_WE_WANT;
//For the geek programmers: note, this is pseudo code so I don't care for variable types and return types..
double LastDraw = GetCurrentTime();
while(GameRunning)
{
TimeDifference = GetCurrentTime()-LastTick;
LastTick = GetCurrentTime();
//process movement based on how many time passed and which keys are pressed
ProcessUserMouseAndKeyboardInput(TimeDifference);
//pass the time difference to the physics engine so it can calculate anything time-based
ProcessGamePhysics(TimeDifference);
//if certain amount of milliseconds pass...
if(LastTick-LastDraw >= TimeToPassBeforeNextDraw)
{
//draw our game
DrawGameOnScreen();
//and save when we last drawn the game
LastDraw = LastTick;
}
//close game if escape is pressed
if(Pressed(KEY_ESCAPE))
{
GameRunning = false;
}
}
}
ここで何が起こるかは、プログラムが何ミリ秒経過したかをカウントし、特定の量(33ミリ秒)に達すると、ゲーム画面を再描画し、実質的に〜30近くのフレームレートを適用することです。
また、開発者によっては、上記のコードをわずかに変更して、すべての処理を30 fpsに制限することもできます。
int main()
{
bool GameRunning = true;
long long LastTick = GetCurrentTime();
long long TimeDifference;
double FPS_WE_WANT = 30;
//how many miliseconds need to pass before we need to draw again so we get the framerate we want?
double TimeToPassBeforeNextDraw = 1000.0/FPS_WE_WANT;
//For the geek programmers: note, this is pseudo code so I don't care for variable types and return types..
double LastDraw = GetCurrentTime();
while(GameRunning)
{
LastTick = GetCurrentTime();
TimeDifference = LastTick-LastDraw;
//if certain amount of miliseconds pass...
if(TimeDifference >= TimeToPassBeforeNextDraw)
{
//process movement based on how many time passed and which keys are pressed
ProcessUserMouseAndKeyboardInput(TimeDifference);
//pass the time difference to the physics engine so it can calculate anything time-based
ProcessGamePhysics(TimeDifference);
//draw our game
DrawGameOnScreen();
//and save when we last drawn the game
LastDraw = LastTick;
//close game if escape is pressed
if(Pressed(KEY_ESCAPE))
{
GameRunning = false;
}
}
}
}
他にもいくつかの方法があり、そのうちのいくつかは本当に嫌いです。
たとえば、を使用しsleep(<amount of milliseconds>)
ます。
これはフレームレートを制限する方法の1つですが、ゲームの処理に3ミリ秒以上かかるとどうなりますか?そして、スリープを実行します...
これにより、sleep()
原因となるはずのフレームレートよりもフレームレートが低くなります。
たとえば、スリープ時間を16ミリ秒とします。これにより、プログラムは60 Hzで実行されます。データ、入力、描画、その他すべての処理に5ミリ秒かかります。1ループで21ミリ秒になり、50 Hzをわずかに下回る結果になりますが、60 Hzのままになることは簡単ですが、スリープのために不可能です。
1つの解決策は、処理時間を測定し、必要な睡眠から処理時間を差し引くという形で適応スリープを作成し、「バグ」を修正することです。
int main()
{
bool GameRunning = true;
long long LastTick = GetCurrentTime();
long long TimeDifference;
long long NeededSleep;
while(GameRunning)
{
TimeDifference = GetCurrentTime()-LastTick;
LastTick = GetCurrentTime();
//process movement based on how many time passed and which keys are pressed
ProcessUserMouseAndKeyboardInput(TimeDifference);
//pass the time difference to the physics engine so it can calculate anything time-based
ProcessGamePhysics(TimeDifference);
//draw our game
DrawGameOnScreen();
//close game if escape is pressed
if(Pressed(KEY_ESCAPE))
{
GameRunning = false;
}
NeededSleep = 33 - (GetCurrentTime()-LastTick);
if(NeededSleep > 0)
{
Sleep(NeededSleep);
}
}
}