ページ 1 / 1
FPSが60にならない・・
Posted: 2009年6月09日(火) 19:23
by チルチル
龍神録のコードを参考にゲームプログラミングの館のwait_fanc関数の中身を変更してみたんですが
FPSが60になりません、どこか間違っているでしょうか?
環境はDXライブラリです
#include "DxLib.h"
int Key[256];
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[/url]){
char GetHitKeyStateAll_Key[256];
GetHitKeyStateAll( GetHitKeyStateAll_Key );
for(int i=0;i<256;i++){
if(GetHitKeyStateAll_Key==1) GetHitKeyStateAll_InputKey++;
else GetHitKeyStateAll_InputKey=0;
}
return 0;
}
int count=0;
void wait_fanc(){
int term;
static int t=0;
if( count%60==1 )t=GetNowCount();
if( count%60==60 )term=1000+t-GetNowCount();
else term=(1000.0/60)*(count%60)+t-GetNowCount();
if(term>0)Sleep(term);
}
void fps(){
int i;
static int t=0,ave=0,f[60];
f[count%60]=GetNowCount()-t;
t=GetNowCount();
if(count%60==59){
ave=0;
for(i=0;i<60;i++)
ave+=f;
ave/=60;
}
if(ave!=0){
DrawFormatString(0, 0,GetColor(255,255,255),"%.1fFPS",1000.0/(double)ave);
DrawFormatString(0,20,GetColor(255,255,255),"%dms" ,ave);
}
return;
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
ChangeWindowMode(TRUE);SetOutApplicationLogValidFlag( FALSE );
if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
//↑メッセージ処理 ↑画面をクリア ↑入力状態を保存 ↑ESCが押されていない
fps();
count++;
ScreenFlip();
wait_fanc();
}
DxLib_End();
return 0;
}
Re:FPSが60にならない・・
Posted: 2009年6月10日(水) 00:20
by チルチル
関数を呼ぶ場所の関係上カウンタが一周目で既に1になっているのが紛らわしかったりしますけどね・・
Re:FPSが60にならない・・
Posted: 2009年6月10日(水) 07:45
by sizuma
走り読みですから、処理の内容は確かめてませんが・・・・
wait_fanc()の
>if( count%60==60 )term=1000+t-GetNowCount();
が到達不可なコードになりますよね?
1から呼び出されるなら
>if( count%60==0 )term=1000+t-GetNowCount();
でいけるんじゃないですか?
どちらにしろ、僕の脆弱マシンじゃぁたぶんFPSは60にならないですが(笑
Re:FPSが60にならない・・
Posted: 2009年6月10日(水) 17:45
by チルチル
あ~そういえばそうですね・・
とりあえず修正しました
しかしまだ60にならないですね・・
#include "DxLib.h"
int Key[256];
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[/url]){
char GetHitKeyStateAll_Key[256];
GetHitKeyStateAll( GetHitKeyStateAll_Key );
for(int i=0;i<256;i++){
if(GetHitKeyStateAll_Key==1) GetHitKeyStateAll_InputKey++;
else GetHitKeyStateAll_InputKey=0;
}
return 0;
}
int count=0;
void wait_fanc(){
int term;
static int t=0;
if( count%60==1 )t=GetNowCount();
if( count%60==0 )term=1000+t-GetNowCount();
else term=(1000.0/60)*(count%60)+t-GetNowCount();
if(term>0)Sleep(term);
}
void fps(){
int i;
static int t=0,ave=0,f[60];
f[count%60]=GetNowCount()-t;
t=GetNowCount();
if(count%60==59){
ave=0;
for(i=0;i<60;i++)
ave+=f;
ave/=60;
}
if(ave!=0){
DrawFormatString(0, 0,GetColor(255,255,255),"%.1fFPS",1000.0/(double)ave);
DrawFormatString(0,20,GetColor(255,255,255),"%dms" ,ave);
}
return;
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
ChangeWindowMode(TRUE);SetOutApplicationLogValidFlag( FALSE );
if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
//↑メッセージ処理 ↑画面をクリア ↑入力状態を保存 ↑ESCが押されていない
fps();
count++;
ScreenFlip();
wait_fanc();
}
DxLib_End();
return 0;
}
Re:FPSが60にならない・・
Posted: 2009年6月10日(水) 22:35
by チルチル
しかし管理人さんのコードに比べて短すぎますかね・・
Re:FPSが60にならない・・
Posted: 2009年6月11日(木) 10:20
by Libra
t=GetNowCount();
を1フレームで呼び出す回数が多すぎるのが原因です。
また、wait_funcの
if( count%60==1 )t=GetNowCount();
if( count%60==0 )term=1000+t-GetNowCount();
else term=(1000.0/60)*(count%60)+t-GetNowCount();
でやっている事の意図が不明です。
Re:FPSが60にならない・・
Posted: 2009年6月11日(木) 10:58
by ねこ
ひとまず
「60フレーム周期で手前に遅れてるフレームがあったら今回遅れていなくてもスリープさせず補正していく」
処理を実装したい、という認識でOKですかね?
まずcountが1の時に
「if( count%60==1 )t=GetNowCount();」
でtに現在時間が入り
if( count%60==0 )term=1000+t-GetNowCount();
else term=(1000.0/60)*(count%60)+t-GetNowCount();
↑のelseで「t-GetNowCount()」はほぼ0になります。
つまりcountが1の時強制的に16ミリ秒スリープさせる処理になってるんですね。
このフレームでの処理が0.6秒以内に終わらなければ計算上FPS60にならない気がします。
Re:FPSが60にならない・・
Posted: 2009年6月11日(木) 18:38
by チルチル
>>「60フレーム周期で手前に遅れてるフレームがあったら今回遅れていなくてもスリープさせず補正していく」
そんな感じです
void wait_fanc(){
--count;
int term=GetNowCount();
static int t=0;
if( count%60==0 )t=term,term=0;
else if( count%60==59 )term=1000+t-term;
else term=(1000.0/60)*(count%60)+t-term;
if(term>0)Sleep(term);
++count;
}
とりあえずcountを内部補正してます
最初の時の待ち時間は思い付かなかったので
待たないで次のフレームで2回分待ってます
Re:FPSが60にならない・・
Posted: 2009年6月11日(木) 19:03
by ねこ
初回はDxLib_Initの後とかに「term = GetNowCount();」としておくのが良いかと思います。
その際termはグローバル変数にしておきます。
<「60フレーム周期で手前に遅れてるフレームがあったら今回遅れていなくてもスリープさせず補正していく」
ただこの処理、意図的にcount%60==1の時に過負荷をかければ分かると思いますが
凄くガクンガクン動く結果になりますよ。特殊な意図があってしているなら良いと思いますが
普通のゲームにはお勧めできません。
Re:FPSが60にならない・・
Posted: 2009年6月11日(木) 20:13
by チルチル
まあ確かにガクガクしますよね・・
しかしまだ60になる気配がないです・・
Re:FPSが60にならない・・
Posted: 2009年6月11日(木) 23:06
by チルチル
う~ん何でかな?
Re:FPSが60にならない・・
Posted: 2009年6月11日(木) 23:46
by Libra
答えはNo:34863の書き込みでねこさんが既に出してます。
Re:FPSが60にならない・・
Posted: 2009年6月12日(金) 00:35
by 御津凪
折角なので私が使っている方法を適当にDXライブラリで書いてみました。
int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
ChangeWindowMode(TRUE);
SetWaitVSyncFlag(TRUE);
if( DxLib_Init() == -1 ) return -1;
DWORD beginTick = GetTickCount();
DWORD nowTick;
LONGLONG prevTick;
LONGLONG tickOne = (1000LL << 32) / 60;
LONGLONG tick;
DWORD loop;
prevTick = nowTick = 0;
DWORD fps = 0,fps_show = 0; // FPS : 1秒あたりのフレーム描画回数
DWORD mps = 0,mps_show = 0; // MPS : 1秒あたりのループ回数
DWORD tickSec = 1000;
while(ProcessMessage() == 0){
ClearDrawScreen();
begin:
nowTick = GetTickCount() - beginTick;
tick = ((LONGLONG)nowTick << 32) - prevTick;
if(tick < tickOne){
Sleep((tickOne - tick) >> 32);
goto begin;
}
while(tickSec <= nowTick){
fps_show = fps;
fps = 0;
mps_show = mps;
mps = 0;
tickSec += 1000;
}
++fps;
for(loop = (DWORD)(tick / tickOne); loop > 0; --loop, prevTick += tickOne){
++mps;
// ここに毎回行う処理を入れる
DrawFormatString(32, 32, GetColor( 255 , 255 , 255 ), "FPS: %2d, MPS: %2d.", fps_show, mps_show);
}
if(CheckHitKey(KEY_INPUT_ESCAPE) != 0) break;
ScreenFlip();
}
DxLib_End();
return 0;
}
この方法だと、 FPS は 60 を維持できなくても、
ループ回数(MPS)は必ず平均 60 回になるようになっています。
ねこさんの方法もそうですが、この方法はフレームスキップする処理です。
ガクガクするのは、補正した時の処理状態は画面に反映しないため、
見ている側は動作が重くなったとき、表示が飛び飛びに見えます。
(ちなみに、上のコードは for 文を外せばフレームスキップしないようになっています)
Re:FPSが60にならない・・
Posted: 2009年6月12日(金) 20:04
by チルチル
>>初回はDxLib_Initの後とかに「term = GetNowCount();」としておくのが良いかと思います
これの事でしょうか?
なんだか初回がうまく動くようになるだけで
それ以降の処理には影響しないように見えますが・・
御津凪さんの方法も良さそうですが
ゲームプログラミングの館の構造でかなり作ってしまったので
導入は無理そうです・・
Re:FPSが60にならない・・
Posted: 2009年6月12日(金) 20:40
by ねこ
VC2008 Expressならデバッグの方法は分かるでしょうか?
Debugでビルドしてブレイクしたい行でF9を押すと処理を中断します。
FPSが60未満の場合、というIF文を作ってその中でブレイクをかけます。
その時の平均値、または別途毎回のterm値を保持する配列等を作って置いて
60FPS未満の時の配列の中身を調べます。
1回じゃ分からないなら何回か実行して不自然なSleepがかかっている個所を探します。
これで原因を追究して下さい。
提示した以外に処理があるならなおのこと環境は違いますし、自身で解決するしかないと思います。
Re:FPSが60にならない・・
Posted: 2009年6月12日(金) 20:59
by チルチル
う~んそのようですね
とりあえずこの問題は保留にしておきます
どうもありがとうございました