FPS管理
FPSは60で決めうちにしてしまいましょう。
例えば「この動作の後40フレーム待機して、その後あっちに50フレームかけて移動して…」なんてことを泥臭く書いていくことになるのでこの数字は終始一貫して変更されるべきではありません。
また60と定義しておいて困ることはまず無いです。
さて、FPS管理のためには時間経過を知る必要があります。
// SDL_Initではグラフィックス以外にもタイマーや音声機能の初期化も行うことができる。 if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { fprintf(stderr, "SDLの初期化に失敗しました: %s\n", SDL_GetError()); return false; } (中略) static void waitFps() { static const int msPerFrame = (int)(1000.0 / 60 + 1); // 1000msを60分して四捨五入。1フレームあたりにかけられる時間。 static int last = 0; // 前回のwaitFps終了時間。 int now = SDL_GetTicks(); // SDL初期化後からの経過時間(ms単位)。 int difference = now - last; if(difference < msPerFrame) { // 1フレームあたりにかけられる時間より早く動作と描画が終わったとき SDL_Delay(last + msPerFrame - now); last += msPerFrame; } else { // 処理落ちが発生したとき last = now; } }
これをdraw()の後に挟んでやります。
そうすれば大雑把ですが処理落ちが発生しない限りおよそ60fpsで動作する「はず」ですね。
しかし実際の動作FPSを表示できないと不安。ちょっと改良しましょう。
// // 60fpsに固定できるように適切な時間待機する。 // 戻り値: 最近1秒間の平均FPS。 // static float waitFps() { // staticなローカル変数は関数を抜けてからも値が保持されることに注意。 static const int msPerFrame = (int)(1000.0 / 60 + 1); // 1000msを60分して四捨五入。1フレームあたりにかけられる時間。 static int last = 0; // 前回のwaitFps終了時間。 int now = SDL_GetTicks(); // SDL初期化後からの経過時間(ms単位)。 int difference = now - last; if(difference < msPerFrame) { // 1フレームあたりにかけられる時間より早く動作と描画が終わったとき SDL_Delay(last + msPerFrame - now); last += msPerFrame; } else { // 処理落ちが発生したとき last = now; } // 1秒間の平均FPSも算出する。 // static int lastAveraged = 0; // 前回、1秒間の平均FPSを算出した時間。 static int callCount = 0; // 前回、1秒間の平均FPSを算出してからwaitFps()が呼ばれた回数。 static float averageFps = 60; // 最近1秒間の平均FPS。 ++callCount; if(lastAveraged + 1000 < now) { averageFps = (float)callCount / (now - lastAveraged) * 1000; lastAveraged = now; callCount = 0; } return averageFps; }
DEBUG_OUT(("fps=%f\n", waitFps())); とかやって結果を確認してみてください。
59程度のFPSになっているでしょうか。
本当はもっとちゃんと60に近づけるべきなんですが、今回はてきとーに。