s6. FPSを表示する。
FPSとはFlame per secondの略で、1秒間に何フレームかを表すものです。
先ほど5節で1秒間に60フレームに統一する関数を作りましたね。
では、実際に現在秒間何フレームで動作しているか表示する関数を作って見ましょう。
FPSを表示する方法として以下の方法をとります。
1回の処理にかかった時間を60回計測します。
60回の計測値の平均を出します。1000を1回の処理の平均時間で割ります。
すると良質なFPSが計算できますね。平均を取らずに毎回FPSを計算すると、
表示数値がチラチラしてしまうので、時間をおいてFPSの表示数値を変更する必要があります。
では実際に関数を作っていきましょう。
とりあえずFPSを表示する関数をvoid fps(){とでも書いておきます。
ループカウンタ用の i と、1回の処理時間の平均を格納するave, そして60回分の計測データを格納するf[60]を用意します。
int i;
static int ave=0,f[60];
後者2つは関数を抜けたときにデータが失われないようstatic変数で宣言しておきましょう。
waitは先ほどの関数で格納しました。1回の処理にかかった時間です。
f[count%60]=wait;
countは1回の処理で1増えるカウンタです。このように書くことでcountの値が60を超えても
何度も0から59まで順番に指定することが出来ます。配列にwaitを格納していきましょう。
何度もfps関数がよばれ、60回目、つまりcount%60==59になったら平均をだしましょう。
if(count%60==59){
ave=0;
for(i=0;i<60;i++)
ave+=f[i];
ave/=60;
}
そして、1000から平均でわってやってFPSを出しましょう。%.1fという書き方は、小数点第1位まで表示するという書き方です。
DrawFormatString(0,0,GetColor(255,255,255),"%.1f",1000.0/(double)ave);
ここで注意してください!!aveが0の時は割ってはいけません。
数学の常識で数値は0で割ってはいけないというお約束がありますね?
「そんなの知らない」「知ってるけど、なんで0で割っちゃだめなの?」と疑問に思った方、遠慮なく掲示板ででも聞いてください。
とりあえず皆さん習っているはずです。sin cos tanの表にもタンジェントが90°の時「値無し」となっているはずですよ。
まぁそれはおいておいて、ですからif(ave != 0)を必ず書いておきましょう。計算出来ないのでバグがおきてしまいます。
これらのことをまとめるとこうなります。
void fps(){ int i; static int t=0,ave=0,f[60]; f[count%60]=GetNowCount()-t; t=GetNowCount(); if(count%60==59){ ave=0; for(i=0;i<60;i++) ave+=f[i]; ave/=60; } if(ave!=0){ DrawFormatString(0, 0,GetColor(255,255,255),"%.1fFPS",1000.0/(double)ave); DrawFormatString(0,20,GetColor(255,255,255),"%dms" ,ave); } return; }
全てのことをまとめて書くと以下のサンプルプログラムのようになります。
以下のサンプルプログラムは上で紹介した関数をそのまま貼り付けて、メインから呼んでいるだけです。
#include "DxLib.h" int count=0; char Key[256]; void wait_fanc(){ int term; static int t=0; term = GetNowCount()-t; if(16-term>0) Sleep(16-term); t=GetNowCount(); return; } void fps(){ int i; static int t=0,ave=0,f[60]; f[count%60]=GetNowCount()-t; t=GetNowCount(); if(count%60==59){ ave=0; for(i=0;i<60;i++) ave+=f[i]; ave/=60; } if(ave!=0){ DrawFormatString(0, 0,GetColor(255,255,255),"%.1fFPS",1000.0/(double)ave); DrawFormatString(0,20,GetColor(255,255,255),"%dms" ,ave); } return; } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){ if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; SetDrawScreen( DX_SCREEN_BACK ); while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && Key[KEY_INPUT_ESCAPE]==0){ fps(); count++; ScreenFlip(); wait_fanc(); } DxLib_End(); return 0; }
実行画面
- Remical Soft -