FPS制御について

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

FPS制御について

#1

投稿記事 by 黒猫 » 9年前

毎度お世話になります。

http://dixq.net/g/03_14.html
こちらのページを参考にし、FPSを制御するプログラムを作ってみました。
そこでひとつ疑問なのですが、UpdateとWaitの関数はMain関数のどの部分に入れたら良いのでしょうか?
このページではScreenFlipの直後にWaitを入れ、Drawの直前にUpdateを入れていますが、
同じように入れると微妙にずれてしまいます。(許容範囲なのかもしれませんが)
よろしくお願いします。

コード:

//FPS計算
bool Fps_Update() {
	//1フレーム目なら時刻を記憶
	if (count == 0) {
		start_time = GetNowCount();
	}
	//平均を計算
	if (count == FPS_AVE) {
		int t = GetNowCount();
		fps = 1000.f / ((t - start_time) / (float)FPS_AVE);
		count = 0;
		start_time = t;
	}
	count++;
	return TRUE;
}

//待機関数
void Fps_Wait() {
	//処理にかかった時間
	took_time = GetNowCount() - start_time;
	//設定されたFPSにするために待機するべき時間
	wait_time = count * 1000 / FPS - took_time;
	//待機する必要があれば待機
	if (wait_time > 0) {
		Sleep(wait_time);
	}
}

コード:

//ループごとに実行
bool Process() {
	//裏画面を表画面に描画処理
	if (ScreenFlip() != 0) {
		ERROR_MESSAGE("0004:Flipに失敗しました。");
		return FALSE;
	}
	//メッセージ処理
	if (ProcessMessage() != 0) {
		ERROR_MESSAGE("0003:メッセージ処理に失敗しました。");
		return FALSE;
	}
	//裏画面クリア処理
	if (ClearDrawScreen() != 0) {
		ERROR_MESSAGE("0005:画面クリアに失敗しました。");
		return FALSE;
	}
	//キーボードの入力処理
	if (UpdateKey() != 0) {
		ERROR_MESSAGE("0006:キーボードの入力処理に失敗しました。");
		return FALSE;
	}
	return TRUE;
}

//メイン関数
int WINAPI WinMain(HINSTANCE h1, HINSTANCE hp, LPSTR lpC, int nC) {

	//メイン初期化
	if (!Main_Init()) return -1;

	//最初にタイトル画面を表示
	GameMode gamemode = Title;

	int game_stat = 0;		//各モードのステータス変数
	bool flag = TRUE;		//起動フラグ

	//メインループ
	while (Process() && flag) {
           //ここに実際の処理があります
	}

	//DXライブラリの終了
	DxLib_End();
	return 0;
}

アバター
Ketty
記事: 102
登録日時: 10年前

Re: FPS制御について

#2

投稿記事 by Ketty » 9年前

主題から外れるのですが、
boolとBOOLを混同されてませんか??

boolは真偽(true, false)ですが、
BOOLはint型(TRUE:1(非0), FALSE:0)です。

よって、例えば

コード:

bool flag = TRUE;       //起動フラグ
の部分は、

コード:

bool flag = true;       //起動フラグ
// もしくは
BOOL flag = TRUE;       //起動フラグ
とするのが正しいと思いますよ。

Fps_UpdateやProcessといった関数もtrue/falseでなくTRUE/FALSEを返してしまっていますので、
今のうちに、boolなのかBOOL(int型)なのかきっちりされるのがよいと思います。

黒猫

Re: FPS制御について

#3

投稿記事 by 黒猫 » 9年前

>>Kettyさん

なるほど!そうだったのですか!
私はCを勉強しててC++についてはろくに勉強していなかったのでその辺りがゴッチャゴチャになっていたのだと思います。
BOOL型 TRUE(1) FALSE(0)は実質INT型
bool型 true falseこそが本当のbool型なのですね

今のうちに全てbool型で統一しました。
ありがとうございました。


本題の方、わかる方いましたらお願いします。
現在は次のように入れています。

コード:

bool Process() {
	//裏画面を表画面に描画処理
	if (ScreenFlip() != 0) {
		ERROR_MESSAGE("0004:Flipに失敗しました。");
		return false;
	}
	//FPS制御処理
	Fps_Wait();
	if (!Fps_Update()) {
		ERROR_MESSAGE("0015:FPS制御処理に失敗しました。");
		return false;
	}
	//
この部分に入れると動作はするのですが、59.9または59.8程度で固定されていて60.0になることはありません。
入れる場所が違うのでしょうか?それともこれぐらいの誤差は許容範囲内なのでしょうか?

アバター
Ketty
記事: 102
登録日時: 10年前

Re: FPS制御について

#4

投稿記事 by Ketty » 9年前

Fps_Wait関数の入れる場所については言及しかねるのですが、
「特定のFPSで動作させる方法」
http://dixq.net/g/03_14.html
このURLどおりにされても症状は変わらないのですよね?

であれば、よろしければ一度、以下をお試しください。
「きっちりFPSを制御してみよう」
http://dixq.net/rp/43.html

もしかしたら、それで解決されるかもしれません。
オフトピック
私の環境(モニタ)では「きっちりFPSを制御してみよう」でもダメでした。
FPS制御について、私も悩んでいるところでして、私も黒猫さんと同じ症状(FPSが59.8くらい)です。
今のところ、解決策としては、ISLeさんがブログで公開してくださっているやり方が一番有効そうです。
あれなら私の環境でもFPS60.000・・・と表示されることを確認しました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: FPS制御について

#5

投稿記事 by softya(ソフト屋) » 9年前

ScreenFlip()も一種の同期処理ですので、このやりかたは2重に同期処理をしていることになります。
そのため、やり方しだいでは表示上はきっちりFPS60にならない事があります。
ScreenFlip()の同期をやめてしまえば60FPSと表示されるかもしれません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
Ketty
記事: 102
登録日時: 10年前

Re: FPS制御について

#6

投稿記事 by Ketty » 9年前

>>softyaさん
私は質問者さんではないので、以下にオフトピックとして書かせていただきますが、
別トピックにすべきでしたらご指摘くださいm(__)m
オフトピック
>ScreenFlip()の同期をやめてしまえば
これは、たぶん過去にもよく出ていた垂直同期待ちを切る(SetWaitVSyncFlag( FALSE );する)というお話だと思うのですが、
これだと、FPS60と表示されるかもしれないかわりに、ティアリングが発生して画面がガタガタ引っかかるような感じになる、という懸念がでますよね。

垂直同期待ちを切らずに、かつFPS60を安定させたいという要求は、一般的でないのでしょうか?
今は、ISLeさんの「処理落ちしても一定のFPS制御」がその解決策かもしれないと思っているのですが、
web検索する限りではこれ以外の方法をみつけられておりません。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: FPS制御について

#7

投稿記事 by softya(ソフト屋) » 9年前

私の答えは一般的かはおいておいて、60FPSにする方法をお答えした次第です。
表示上60FPSとなるのと、59.8FPSと表示されているけどScreenFlip()の垂直同期待ちのお陰で実質は60FPSであるって事で問題がないのであれば、それはそれで良いかも知れません。

言われるとおり、ISLeさんのこちらの方法の方が表示として正確に近いと思います。
「処理落ちしても一定のFPS制御: ISLeのビデオゲーム工房」
http://isle.cocolog-nifty.com/blog/2011 ... -927b.html

DXライブラリを改造してScreenFlip()の中で制御すればもっと正確にはなると思いますが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
Ketty
記事: 102
登録日時: 10年前

Re: FPS制御について

#8

投稿記事 by Ketty » 9年前

>>softyaさん
ご回答くださりありがとうございます。
なるほど、理解できました(^^)

トピックを占有してしまったので、あとは黒猫さんにバトンタッチして、
私の疑問はここで切り上げさせていただきますm(__)m

黒猫

Re: FPS制御について

#9

投稿記事 by 黒猫 » 9年前

返信が遅くなりました。
申し訳ありません。

>>Kettyさん
同じことでお悩みだったのですね。
こちらのサイトで紹介されているように作ってみても結果は変わりませんでした。(環境依存なのでしょうか?)
ご紹介されたISLeさんの記事は検索で引っかかったので見たことがあります。
ですが、私の経験・知識不足で内容を理解することが出来ませんでした。

>>softyaさん
ScreenFlip()はモニタのリフレッシュレートに合わせて同期をとってくれると理解しております。
同期処理をScreenFlip()のみに任せた場合、リフレッシュレートが違う環境で動作させるとスピードが異なるという問題を解決したいと思っております。
表示上の数値もできれば改善したいですが、実質60FPSで固定されているのであれば、それはそれで問題ないようにも思えます。
(実際のゲーム画面でFPS値を表示させることは考えていないので。)

今の私には理解することが難しい(垂直同期等も理解できていない)ようなので、ひとまずFPSの表示値を正確にすることは諦め、解決とします。
ありがとうございました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: FPS制御について

#10

投稿記事 by softya(ソフト屋) » 9年前

秒間フレーム数(FPS)決め打ちでタイミングを制御せずに経過時間(ms)で動きを制御すれば、FPSの差は大抵吸収されます。
つまり、フレームカウントをタイミングに使わないって方法です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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