DXライブラリとC言語でゲーム制作日記5コード目。DXライブラリを使ってフレームレートを制御する方法について。きちんと設定しないと環境によっては大変な目に遭います(友人にテストプレイを頼む時とか特に)。
フレームレートを制御したい
PCゲームをやると必ずと言っていい程耳にするのがフレームレート。1秒間に60回画面が描写される、60FPSだと滑らかに動くというあれ。一人称視点ゲーム(FirstPersonShooting)の略ではない。
このフレームレート、基本60FPS前提での話のためどのゲームでも60FPSで動くのかと思いきゃ実はユーザの環境依存だったりする。
DXライブラリを使ってゲームを作る場合、以下のwhile()の部分がゲームのメイン処理になる。
// while(裏画面を表画面に反映, メッセージ処理, 画面クリア) while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) { //ここでキー入力状態とかプレイヤーの状態とかをあれこれ更新する }
60FPSで動かす場合、1秒間にこのwhile()の部分が60回処理するわけだがこれはモニターのリフレッシュレートの値に依存していて120Hzだったりすると倍の120回処理されることになる。なのでゲーム速度が大きく変わってしまう。
ということでフレームレート制御関数は大事。
フレームレートを制御する
さっそくコードをペタリ。60FPSで固定するコード。今回もゲームプログラミングの館さんから拝借。例によって専用のcpp/hファイルを作成。
FpsControll.h
#ifndef DEF_FPSCONTROLL_H #define DEF_FPSCONTROLL_H void FpsControll_Initialize(); bool FpsControll_Update(); void FpsControll_Draw(); void FpsControll_Wait(); #endif
FpsControll.cpp
#include <math.h> #include "DxLib.h" #include "FpsControll.h" static int mStartTime; //測定開始時刻 static int mCount; //カウンタ static float mFps; //fps static const int N = 60; //平均を取るサンプル数 static const int FPS = 60; //設定したFPS //初期化 void FpsControll_Initialize() { mStartTime = GetNowCount(); mCount = 0; mFps = 0; } //FPS制御 bool FpsControll_Update() { if (mCount == 0) { //1フレーム目なら時刻を記憶 mStartTime = GetNowCount(); } if (mCount == N) { //60フレーム目なら平均を計算する int t = GetNowCount(); mFps = 1000.f / ((t - mStartTime) / (float)N); mCount = 0; mStartTime = t; } mCount++; return true; } //FPS表示 void FpsControll_Draw() { DrawFormatString(0, 0, GetColor(255, 255, 255), "%.1f", mFps); } void FpsControll_Wait() { int tookTime = GetNowCount() - mStartTime; //かかった時間 int waitTime = mCount * 1000 / FPS - tookTime; //待つべき時間 if (waitTime > 0) { Sleep(waitTime); //待機 } }
これで60FPS固定になるらしいが、自分の環境では残念ながら43~45FPS当たりでウロウロと低フレームレート状態になってしまった。そんな時は垂直同期を切ってあげると正常に動くようになる。垂直同期の設定を変える時はDxLib_Init()関数の前に読んで設定すること。
//垂直同期を切る SetWaitVSyncFlag(0); // DXライブラリ初期化処理 if (DxLib_Init() < 0) { //エラーなら終了する return -1; }
ゲームのメイン処理となるwhile()部分に先ほどのフレームレート制御関数を挿入。
// while(裏画面を表画面に反映, メッセージ処理, 画面クリア) while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) { //フレームレート制御 FpsControll_Update(); //ここに他のゲーム処理(シーン切り替えとかプレイヤーとか敵とか) //フレームレート表示 FpsControll_Draw(); //待機 FpsControll_Wait(); }
4年ほど前モニターを買い替えた後自作ゲームを動かしてみたらなんか動きが妙に遅いという違和感があったが原因はリフレッシュレートの違いだったのだろう…(調べると前のモニターは75Hzだった)。
コメント