FPSが60にならない・・

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

FPSが60にならない・・

#1

投稿記事 by チルチル » 16年前

龍神録のコードを参考にゲームプログラミングの館の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にならない・・

#2

投稿記事 by チルチル » 16年前

関数を呼ぶ場所の関係上カウンタが一周目で既に1になっているのが紛らわしかったりしますけどね・・

sizuma

Re:FPSが60にならない・・

#3

投稿記事 by sizuma » 16年前

走り読みですから、処理の内容は確かめてませんが・・・・

wait_fanc()の
>if( count%60==60 )term=1000+t-GetNowCount();
が到達不可なコードになりますよね?
1から呼び出されるなら
>if( count%60==0 )term=1000+t-GetNowCount();
でいけるんじゃないですか?

どちらにしろ、僕の脆弱マシンじゃぁたぶんFPSは60にならないですが(笑

チルチル

Re:FPSが60にならない・・

#4

投稿記事 by チルチル » 16年前

あ~そういえばそうですね・・
とりあえず修正しました
しかしまだ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にならない・・

#5

投稿記事 by チルチル » 16年前

しかし管理人さんのコードに比べて短すぎますかね・・

Libra

Re:FPSが60にならない・・

#6

投稿記事 by Libra » 16年前

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にならない・・

#7

投稿記事 by ねこ » 16年前

ひとまず
「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にならない・・

#8

投稿記事 by チルチル » 16年前

>>「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にならない・・

#9

投稿記事 by ねこ » 16年前

初回はDxLib_Initの後とかに「term = GetNowCount();」としておくのが良いかと思います。
その際termはグローバル変数にしておきます。

<「60フレーム周期で手前に遅れてるフレームがあったら今回遅れていなくてもスリープさせず補正していく」
ただこの処理、意図的にcount%60==1の時に過負荷をかければ分かると思いますが
凄くガクンガクン動く結果になりますよ。特殊な意図があってしているなら良いと思いますが
普通のゲームにはお勧めできません。

チルチル

Re:FPSが60にならない・・

#10

投稿記事 by チルチル » 16年前

まあ確かにガクガクしますよね・・
しかしまだ60になる気配がないです・・

チルチル

Re:FPSが60にならない・・

#11

投稿記事 by チルチル » 16年前

う~ん何でかな?

Libra

Re:FPSが60にならない・・

#12

投稿記事 by Libra » 16年前

答えはNo:34863の書き込みでねこさんが既に出してます。

御津凪

Re:FPSが60にならない・・

#13

投稿記事 by 御津凪 » 16年前

折角なので私が使っている方法を適当に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にならない・・

#14

投稿記事 by チルチル » 16年前

>>初回はDxLib_Initの後とかに「term = GetNowCount();」としておくのが良いかと思います

これの事でしょうか?
なんだか初回がうまく動くようになるだけで
それ以降の処理には影響しないように見えますが・・

御津凪さんの方法も良さそうですが
ゲームプログラミングの館の構造でかなり作ってしまったので
導入は無理そうです・・

ねこ

Re:FPSが60にならない・・

#15

投稿記事 by ねこ » 16年前

VC2008 Expressならデバッグの方法は分かるでしょうか?
Debugでビルドしてブレイクしたい行でF9を押すと処理を中断します。

FPSが60未満の場合、というIF文を作ってその中でブレイクをかけます。
その時の平均値、または別途毎回のterm値を保持する配列等を作って置いて
60FPS未満の時の配列の中身を調べます。
1回じゃ分からないなら何回か実行して不自然なSleepがかかっている個所を探します。
これで原因を追究して下さい。

提示した以外に処理があるならなおのこと環境は違いますし、自身で解決するしかないと思います。

チルチル

Re:FPSが60にならない・・

#16

投稿記事 by チルチル » 16年前

う~んそのようですね

とりあえずこの問題は保留にしておきます

どうもありがとうございました

閉鎖

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