yaneSDK版、FPS調節

上のエラーから抜け出せない。また自分メモで目を背けようヽ(´ー`)ノ
てか今回もまた自分のアホさを戒めてるだけなんでよろ(;´д`)初心者向け。

遅いマシンでゲームを動かす場合、処理周期を落としてをゲーム成立を優先する方法がよくとられる。60FPS→30FPSなんてよく目にする。これの仕組みについて自分は今日初めて理解した。
まず下のコードを見てほしい。

void    CApp::MainThread() {		//メインスッドレ

    ///この辺省略

    CFPSTimer t;
    t.SetFPS(30);        //30FPSに設定

    //	コントローラのコンストラクタにファクトリーを渡す
    CSceneControl sc(smart_ptr<ISceneFactory>(new CMySceneFactory(this), true));
    sc.JumpScene(eSceneFirst);       //最初のシーンに移動

    while (IsThreadValid()){	//メインループ

	GetKey()->Input();
	if (GetKey()->IsKeyPress(0)) break;	//  ESCキーが押されたら終了

	sc.OnMove(pSecondary);              //移動
	IncFrame();                         //カウンタ増やす(BulletMLRunner::getTurn()用)
	sc.OnMove(pSecondary);              //移動
         IncFrame();                         //カウンタ増やす
	
	if (!t.ToBeSkip()){                 //フレームスキップがなければ描画
		pSecondary->Clear();
		sc.OnDraw(pSecondary);
		GetDraw()->OnDraw();
	}
         t.WaitFrame();                      //前の区切りから1/30秒過ぎるまで待つ
    }
}

こうやれば30FPSになるから、遅いノートとかでも大丈ぶい!とか思ってたのだが、実際に動かしてみるとそんなことはない。軽い場面では60FPSのときよりも粗いグラフィックになり、重い場面では何の効力もなく普通にガタガタ処理落ちする。まさに有害無益。
なぜこうなるのか。
それは自分が、FPS、描画周期、フレームスキップの意味を混同し、あるいは履き違えていたからだった。
まずFPSという用語だが、これはただのFramePerSecond(秒あたりのフレーム数)という意味しかなく、それが移動処理のフレーム数なのか、描画のフレーム数なのかはまったく関知しない
が、ゲームではFPSといえば専ら移動処理フレーム(すなわち全処理フレーム)のことを指すのが一般的なようだ。よってたいていのゲームでは設定で「描画周期」を半分にする、という項目があり、これを行ってもゲーム画面のFPS表示は通常と変わらず60基準になっている(描画は半分になるので画面が粗くなる)。けど、これたま〜に「FPS」を半分にするとか、30FPSにするとか表記してるゲームがあって、そのせいで混同しちゃうんだよねー(;´д`)てか俺。…ていうかさ、描画周期を半分にするっておかしいよな。半分にしたら余計に切羽詰って描画しないといけなくなるじゃん!正確には描画周波数を半分に、だよな。言葉変だけど。
あと俺の記憶違いかもしれないけど、30FPS設定にするとゲーム画面のFPS表示も30基準になるゲームがあった気がするんだよなあ…。なんかそれで上みたいなコード書けば30FPSで軽くなるとか勘違いしちまったみたい。
では正しい答えというものを探ってみましょう。
まず「FPS」という単語の意味を固定。コレは単位秒あたりの移動処理(スキップしない処理)のフレーム数を指す。つまり、コレは一つのゲームに対して一意の要素なのである。あるゲームにおいていかなる状況でも、(既定の)FPSは変動しない。60FPSと決めたなら、遅いマシンだから30FPSにする、とかそういうことは絶対にない。なぜなら、これを変動させると、秒あたりの移動処理回数が変動するので、キャラの動きが状況によって速くなったり遅くなったりしてしまうからだ。当然これではゲームは成立しない。
よって、最初に決めたFPS数値を維持し、処理時間を調整するのが上でのCFPSTimerクラスの役割なのである。しかし実際のFPS、すなわち実際の秒あたりの移動処理回数は、変動しうる。ゲーム中、60FPSから大幅に上がることはないが、大幅に下がることは遅いマシンでなら体験したことがあるだろう。
これを説明するために、1フレームの移動処理にかかる時間をOnMove、描画処理にかかる時間をOnDrawと表記する。この二つ以外の処理にかかる時間は0と仮定する。
固定であるはずのFPSが大きく下がる要因は一つ。

OnMove > 1/60秒

となっている時だ(60FPSならば)。このとき、OnDrawは制限時間の1/60秒を過ぎているので、当然スキップとなる。1フレームの間にとてつもなく重い処理を行って、移動処理だけで既定の時間を過ぎてしまうと、FPS表示は60からどんどんと下落していくのだ。
逆に、60FPSしっかり出ていて、描画も滑らかなときは

OnMove + OnDraw < 1/60秒

となっていることになる。ここから徐々に処理が重くなり、この条件は満たせなくなったものの、

OnMove + OnMove + OnDraw < 1/30秒

ならば、描画周波数を半分に(言いにくいな…)すれば60FPSを確保できることになる。画面は粗くなるが。さらに処理が重くなっても、

OnMove + OnMove + OnMove + OnDraw < 1/20秒

ならば、描画周波数を1/3にして60FPSが確保できる。以下同様にして、OnMoveが1/60秒に達するまでならば、描画を間引いていくことで移動処理の60FPSは確保できるのである。画面は見てられないほどに粗くなっていくが。(厳密には描画数が秒間数回にまで落ちたら強制的に描画を入れているので、FPSが下がりだす条件はもうちょっと早い)
んで、この条件計算をCFPSTimerは自動でやってくれているのである(たぶん)。だからプログラムでは最初に60FPSならSetFPS(60)としたあと、何もいじる必要はないのである。ただ1ループの間に移動処理を1回やり、スキップ条件を満たしてなければ描画処理も一回やり、最後に時間待ちをする。公式のサンプル通りの書き方でかまわない。これで遅いマシンでも軽い場面ではグラフィックが繊細に写ってなんら問題はないということでした。
じゃあ気になるのはいま世に出ているゲームたち。例えば東方シリーズは設定で描画数を1/2回、1/3回にできるが、これだと軽い場面でも描画は粗くなってしまうことになる(つまり最初に挙げたコードと同じ)。重いときの最小描画数を可変にして最大値を低く固定するなんてまったく意味がないから、重くなったときの描画数も1/2回、1/3回で固定なんだろうか。それだと描画処理が全体を圧迫してなおさらゲームにならなくなると想うんだが。となるとやっぱ描画周期を可変にするシステムが入っているとしか。となると設定で描画数を下げる意味がない…(以下クライン空間
うーん、このへんはまだよく勉強する必要がありますね。長文メモ読了乙でした。