処理が非常に分かりにくかったので書き直してみました。
スキップすべきフレーム数を計算する仕組みも入っています。
「FPS」に好きな値を入れればそのFPSで動作します。
平均FPS値を計算するタイミングはSAMPLE_Nで指定します。今のままだと2秒に一度更新します。
メイン部ではfps_getSkipFrameNum()の返り値の数だけ描画処理をスキップすればよいです。
コード:
#include "../include/GV.h"
const static int FPS = 60; //FPS
const static int SAMPLE_N = 120; //平均を取るサンプル数
const static float FRAME_T = (1000.f/FPS); //1フレームの時間
static int mStartTime; //測定開始時刻
static int mCount; //カウンタ
static int mWaitTime; //待機時間
static int mSkipFrameNum; //スキップすべきフレーム数
static float mFps; //fps
//更新
void fps_update(){
int t = GetNowCount();
if( mStartTime != 0 ){//最初の1回目以外通る
int gameTime = FRAME_T*mCount;
int realTime = t-mStartTime;
int sub = gameTime - realTime;
mWaitTime = sub > 0 ? sub : 0;
mSkipFrameNum = sub < 0 ? (int)( -sub / FRAME_T ) : 0;
}
if( mCount == 0 ){ //1フレーム目なら時刻を記憶
mStartTime = GetNowCount();
}
if( mCount == SAMPLE_N ){ //SAMPLE_Nフレーム目なら平均を計算する
mFps = 1000.f/((t-mStartTime)/(float)SAMPLE_N);//要0割チェック
mCount = 0;
mStartTime = t;
}
mCount++;
}
//描画
void fps_draw(int x, int y){
DrawFormatString(x, y, GetColor(255,255,255), "[%.1f]", mFps);
}
//待機
void fps_wait(){
Sleep(mWaitTime);
}
//スキップすべきフレーム数を返す
int fps_getSkipFrameNum(){
return mSkipFrameNum;
}
このコードのポイントは
コード:
int gameTime = FRAME_T*mCount;
int realTime = t-mStartTime;
int sub = gameTime - realTime;
mWaitTime = sub > 0 ? sub : 0;
mSkipFrameNum = sub < 0 ? (int)( -sub / FRAME_T ) : 0;
です。
1フレームにかかるべき時間は60FPSなら16.6666...msですから、mCountフレーム計算した時のゲーム時間は「16.6666...*mCount」になります。
現実にかかった時間はt-mStartTimeになります。
その差をsubに入れています。
subがプラスだということは、現実の時間が少ない=つまりPCスペックが高くて処理が早く終わり過ぎだということになりますから、subだけSleepすればいいことになります。
逆に
subがマイナスだということは、現実の時間が多い=つまりPCスペックが低くて処理が追いついていないということになりますから、フレームスキップが必要になります。
そのフレーム数は「足らない時間/1フレームの処理時間」になりますから、前述のコードのようになります。