Re: 垂直同期信号待ちしないでfpsを制限したい ( No.1 ) |
- 名前:すっぴー 日時:2014/03/18 18:54
以下が実装です
class Fps{
int mStartTime; //測定開始時刻
int mVSTime;
int mfpsCount; //カウンタ
double mFps; //fps
static const int N; //平均を取る時間(ms)
int FPS; //設定したFPS
public:
int Update();
int Draw();
int Wait();
double Getfps();
void Setfps(int _fps);
Fps(void);
};
const int Fps::N = 500;
Fps::Fps(void)
{
mStartTime = 0;
mVSTime = 0;
mfpsCount = 0;
mFps = 0;
FPS = 60;
}
int Fps::Update(){
++mfpsCount; //カウンタを加算
mVSTime = GetNowCount();
if(mVSTime - mStartTime > N){
mFps = mfpsCount / double((mVSTime - mStartTime) * 1.0 / 1000);
mfpsCount = 0;
mStartTime = mVSTime;
}
return 0;
}
int Fps::Draw(){
DrawFormatString(0, 0, GetColor(255,255,255), "%.1ffps", mFps);
return 0;
}
int Fps::Wait(){
int tookTime = GetNowCount() - mVSTime; //かかった時間
int waitTime = 1000/FPS - tookTime; //待つべき時間
if( waitTime > 0 ) Sleep(waitTime); //待機
return 0;
}
double Fps::Getfps(){
return mFps;
}
void Fps::Setfps(int _fps){
FPS = _fps;
}
class FlipScreenProxy{
private:
LONGLONG mLastCount;
LONGLONG mRateInterval;
Fps fps;
public:
FlipScreenProxy(int rate = 60){
mRateInterval = (1000000 / rate);
mLastCount = GetNowHiPerformanceCount();
}
void SetRefreshRate(int rate){
mRateInterval = (1000000 / rate);
mLastCount = GetNowHiPerformanceCount();
}
int ScreenFlip(){
LONGLONG NowCount = GetNowHiPerformanceCount();
fps.Draw();
DrawFormatString(0,100,GetColor(255,0,0),"%d",NowCount - mLastCount);
if (NowCount - mLastCount > mRateInterval){
//if (true){
fps.Update();
DrawFormatString(0, 200, GetColor(0, 255, 0), "%d", NowCount - mLastCount);
mLastCount = GetNowHiPerformanceCount();
DxLib::ScreenFlip();
}
//fps.Wait();
return 0;
}
};
|
Re: 垂直同期信号待ちしないでfpsを制限したい ( No.2 ) |
- 名前:すっぴー 日時:2014/03/18 18:56
追記
ゲームのループ処理はすべてmsベースで行っているため、fps変動によるゲーム速度の変動はありません。
|
Re: 垂直同期信号待ちしないでfpsを制限したい ( No.3 ) |
- 名前:softya(ソフト屋) 日時:2014/03/18 20:48
メインループは垂直同期のままで、スレッドで入力を管理したほうが安定的に良いかと思います。
ところで一般的なキーボードで10msの周期でちゃんと入力取れますでしょうか? ゲーマー向きキーボードならともかくチャタリングを考えると難しい気がするのです。実際にPCで確かめたことがないので誤情報かもしれませんので参考程度にお願いします。
|
Re: 垂直同期信号待ちしないでfpsを制限したい ( No.4 ) |
- 名前:すっぴー 日時:2014/03/20 08:01
メインループとは別のスレッドで入力系統を管理するループを作成し、非同期的に処理を行う、という解釈でよいのでしょうか…?
それですとやはり16msごとにしか入力を処理できないため、どうしても精度が落ちてしまうように感じるのですが…
キーボードが高精度の入力を行えるか、ということに関しましては、
初期にフレームベースで作成した時よりも明らかに高精度になっていましたので、問題ないかと思われます。
|
Re: 垂直同期信号待ちしないでfpsを制限したい ( No.5 ) |
- 名前:softya(ソフト屋) 日時:2014/03/20 10:34
とりあえず十分に速度が出るのなら、16.66msの半分=120fpsで描画以外の処理するのはどうでしょうか?
そうすれば難しい制御せずに2回に1回描画するだけで済みそうです。
|
Re: 垂直同期信号待ちしないでfpsを制限したい ( No.6 ) |
- 名前:管理人 日時:2014/03/21 22:22
私の環境では fps.Wait() を有効にしなくても 30fps になることはありませんでした
推測ですが載せて頂いたクラスを使ったゲームループを行った場合メインスレッドは休むことなく
走り続けるので、CPUのコア数に余裕が無いときは Direct3D のスレッドの時間まで奪ってしまい、
ScreenFlip 内部で呼んでいる Direct3D の処理が間に合わず、4回目の ScreenFlip 時に
『まだ前回の ScreenFlip の処理が終わってないので待っててね』と、37ms, 50ms またさせる
ことになってしまっているのかもしれません、それが Wait 関数を呼ぶことで Sleep が実行され、
Direct3D のスレッドに処理をする余裕が生まれて症状が改善されたのではないかと思います
|
Re: 垂直同期信号待ちしないでfpsを制限したい ( No.7 ) |
- 名前:すっぴー(解決) 日時:2014/03/22 20:00
早すぎる処理も考え物、ということですか…
私の環境でもSleep(2)程度でfpsを60にすることができました。このあたりの数値を外部ファイルから読み込むことで何とかしようと思います。
ユーザー任せ、というのは欠陥でしかないですが…
ソフト屋様、管理人様、ありがとうございました。
|