フレームスキップについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
bz9

フレームスキップについて

#1

投稿記事 by bz9 » 12年前

龍神録プログラミングの館の「きっちりFPSを制御してみよう」


のページにあるコードを使っているのですが、
内部の処理が間に合わなかった時に
動作がもたもたしてしまうので、
そうなったときは描画をせずに当たり判定などの処理だけやって
次のループで描画のような フレームスキップを行いたいのですが
どのようなコードを書けばいいのでしょうか。

コード:

//FLAME fps になるようにfpsを計算・制御
void fps_wait(){
    int term,i,gnt;
    static int t=0;
    if(fps_count==0){//60フレームの1回目なら
        if(t==0)//完全に最初ならまたない
            term=0;
        else//前回記録した時間を元に計算
            term=count0t+1000-GetNowCount();
    }
    else    //待つべき時間=現在あるべき時刻-現在の時刻
        term = (int)(count0t+fps_count*(1000.0/FLAME))-GetNowCount();

    if(term>0)//待つべき時間だけ待つ
        Sleep(term);

    gnt=GetNowCount();

    if(fps_count==0)//60フレームに1度基準を作る
        count0t=gnt;
    f[fps_count]=gnt-t;//1周した時間を記録
    t=gnt;
    //平均計算
    if(fps_count==FLAME-1){
        ave=0;
        for(i=0;i<FLAME;i++)
            ave+=f[i];
        ave/=FLAME;
    }
    fps_count = (++fps_count)%FLAME ;
}

bz9

Re: フレームスキップについて

#2

投稿記事 by bz9 » 12年前

すいません。答えづらい質問を書いてしまいました。

間に合わなかった時に
なので、何かの基準の時間を過ぎてしまった時に描画を省けばいいはずなんですが、
その基準の時間がわかりません。

基準の時間を出す方法を考えているんですが全くわかりません。

以前 ave変数の値より大幅にループにかかった時間が長ければ
スキップさせようと試みたんですが、

平均の値が入っているので 遅いPCで実行した時に フレームスキップされませんでした。

基準の時間は何から求めればいいのでしょうか。

nil
記事: 428
登録日時: 13年前

Re: フレームスキップについて

#3

投稿記事 by nil » 12年前

画面のリフレッシュレートが60の場合、
DXライブラリは1/60秒ごとに描画を行います。

つまり1フレームは1/60秒であり、この時間を過ぎた場合にフレームスキップを行えばいいことになります。

アバター
Dixq (管理人)
管理人
記事: 1662
登録日時: 14年前
住所: 北海道札幌市
連絡を取る:

Re: フレームスキップについて

#4

投稿記事 by Dixq (管理人) » 12年前

処理が非常に分かりにくかったので書き直してみました。
スキップすべきフレーム数を計算する仕組みも入っています。

「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フレームの処理時間」になりますから、前述のコードのようになります。

bz9

Re: フレームスキップについて

#5

投稿記事 by bz9 » 12年前

なるほど~ そういうことですか。
と心のなかで思いつつ、

何でわからなかったんだろう
という気持ちで複雑な・・・・(泣)

えっと
1フレームで使うと想定している時間よりも
使ってしまった時間が大きければ スキップする なので

1フレームで使うと想定している時間から
使ってしまった時間をひいて マイナスだったら スキップ するという事ですか・・・

やっぱり僕はまだまだですね・・・

よくわかりました。 ありがとうございました

閉鎖

“C言語何でも質問掲示板” へ戻る